Compare commits

..

40 Commits

Author SHA1 Message Date
17083c79ae Git 2.30.4
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-04-13 13:31:29 -07:00
0f85c4a30b setup: opt-out of check with safe.directory=*
With the addition of the safe.directory in 8959555ce
(setup_git_directory(): add an owner check for the top-level directory,
2022-03-02) released in v2.35.2, we are receiving feedback from a
variety of users about the feature.

Some users have a very large list of shared repositories and find it
cumbersome to add this config for every one of them.

In a more difficult case, certain workflows involve running Git commands
within containers. The container boundary prevents any global or system
config from communicating `safe.directory` values from the host into the
container. Further, the container almost always runs as a different user
than the owner of the directory in the host.

To simplify the reactions necessary for these users, extend the
definition of the safe.directory config value to include a possible '*'
value. This value implies that all directories are safe, providing a
single setting to opt-out of this protection.

Note that an empty assignment of safe.directory clears all previous
values, and this is already the case with the "if (!value || !*value)"
condition.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-04-13 12:42:51 -07:00
bb50ec3cc3 setup: fix safe.directory key not being checked
It seems that nothing is ever checking to make sure the safe directories
in the configs actually have the key safe.directory, so some unrelated
config that has a value with a certain directory would also make it a
safe directory.

Signed-off-by: Matheus Valadares <me@m28.io>
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-04-13 12:42:51 -07:00
e47363e5a8 t0033: add tests for safe.directory
It is difficult to change the ownership on a directory in our test
suite, so insert a new GIT_TEST_ASSUME_DIFFERENT_OWNER environment
variable to trick Git into thinking we are in a differently-owned
directory. This allows us to test that the config is parsed correctly.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-04-13 12:42:49 -07:00
cb95038137 Git 2.30.3
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2022-03-24 00:22:17 +01:00
fdcad5a53e Fix GIT_CEILING_DIRECTORIES with C:\ and the likes
When determining the length of the longest ancestor of a given path with
respect to to e.g. `GIT_CEILING_DIRECTORIES`, we special-case the root
directory by returning 0 (i.e. we pretend that the path `/` does not end
in a slash by virtually stripping it).

That is the correct behavior because when normalizing paths, the root
directory is special: all other directory paths have their trailing
slash stripped, but not the root directory's path (because it would
become the empty string, which is not a legal path).

However, this special-casing of the root directory in
`longest_ancestor_length()` completely forgets about Windows-style root
directories, e.g. `C:\`. These _also_ get normalized with a trailing
slash (because `C:` would actually refer to the current directory on
that drive, not necessarily to its root directory).

In fc56c7b34b (mingw: accomodate t0060-path-utils for MSYS2,
2016-01-27), we almost got it right. We noticed that
`longest_ancestor_length()` expects a slash _after_ the matched prefix,
and if the prefix already ends in a slash, the normalized path won't
ever match and -1 is returned.

But then that commit went astray: The correct fix is not to adjust the
_tests_ to expect an incorrect -1 when that function is fed a prefix
that ends in a slash, but instead to treat such a prefix as if the
trailing slash had been removed.

Likewise, that function needs to handle the case where it is fed a path
that ends in a slash (not only a prefix that ends in a slash): if it
matches the prefix (plus trailing slash), we still need to verify that
the path does not end there, otherwise the prefix is not actually an
ancestor of the path but identical to it (and we need to return -1 in
that case).

With these two adjustments, we no longer need to play games in t0060
where we only add `$rootoff` if the passed prefix is different from the
MSYS2 pseudo root, instead we also add it for the MSYS2 pseudo root
itself. We do have to be careful to skip that logic entirely for Windows
paths, though, because they do are not subject to that MSYS2 pseudo root
treatment.

This patch fixes the scenario where a user has set
`GIT_CEILING_DIRECTORIES=C:\`, which would be ignored otherwise.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2022-03-24 00:21:08 +01:00
8959555cee setup_git_directory(): add an owner check for the top-level directory
It poses a security risk to search for a git directory outside of the
directories owned by the current user.

For example, it is common e.g. in computer pools of educational
institutes to have a "scratch" space: a mounted disk with plenty of
space that is regularly swiped where any authenticated user can create
a directory to do their work. Merely navigating to such a space with a
Git-enabled `PS1` when there is a maliciously-crafted `/scratch/.git/`
can lead to a compromised account.

The same holds true in multi-user setups running Windows, as `C:\` is
writable to every authenticated user by default.

To plug this vulnerability, we stop Git from accepting top-level
directories owned by someone other than the current user. We avoid
looking at the ownership of each and every directories between the
current and the top-level one (if there are any between) to avoid
introducing a performance bottleneck.

This new default behavior is obviously incompatible with the concept of
shared repositories, where we expect the top-level directory to be owned
by only one of its legitimate users. To re-enable that use case, we add
support for adding exceptions from the new default behavior via the
config setting `safe.directory`.

The `safe.directory` config setting is only respected in the system and
global configs, not from repository configs or via the command-line, and
can have multiple values to allow for multiple shared repositories.

We are particularly careful to provide a helpful message to any user
trying to use a shared repository.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2022-03-21 13:16:26 +01:00
bdc77d1d68 Add a function to determine whether a path is owned by the current user
This function will be used in the next commit to prevent
`setup_git_directory()` from discovering a repository in a directory
that is owned by someone other than the current user.

Note: We cannot simply use `st.st_uid` on Windows just like we do on
Linux and other Unix-like platforms: according to
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions
this field is always zero on Windows (because Windows' idea of a user ID
does not fit into a single numerical value). Therefore, we have to do
something a little involved to replicate the same functionality there.

Also note: On Windows, a user's home directory is not actually owned by
said user, but by the administrator. For all practical purposes, it is
under the user's control, though, therefore we pretend that it is owned
by the user.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2022-03-21 13:16:26 +01:00
2a9a5862e5 Merge branch 'cb/mingw-gmtime-r'
Build fix on Windows.

* cb/mingw-gmtime-r:
  mingw: avoid fallback for {local,gm}time_r()

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2022-03-17 12:52:12 +01:00
6e7ad1e4c2 mingw: avoid fallback for {local,gm}time_r()
mingw-w64's pthread_unistd.h had a bug that mistakenly (because there is
no support for the *lockfile() functions required[1]) defined
_POSIX_THREAD_SAFE_FUNCTIONS and that was being worked around since
3ecd153a3b (compat/mingw: support MSys2-based MinGW build, 2016-01-14).

The bug was fixed in winphtreads, but as a side effect, leaves the
reentrant functions from time.h no longer visible and therefore breaks
the build.

Since the intention all along was to avoid using the fallback functions,
formalize the use of POSIX by setting the corresponding feature flag and
compile out the implementation for the fallback functions.

[1] https://unix.org/whitepapers/reentrant.html

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Acked-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-17 12:52:12 +01:00
94f6e3e283 Git 2.30.2
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:51:13 +01:00
e4e68081bb Sync with 2.29.3
* maint-2.29:
  Git 2.29.3
  Git 2.28.1
  Git 2.27.1
  Git 2.26.3
  Git 2.25.5
  Git 2.24.4
  Git 2.23.4
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:51:12 +01:00
0628636d0c Git 2.29.3
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:50:15 +01:00
d7bdabe52f Sync with 2.28.1
* maint-2.28:
  Git 2.28.1
  Git 2.27.1
  Git 2.26.3
  Git 2.25.5
  Git 2.24.4
  Git 2.23.4
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:50:14 +01:00
e4f4299859 Git 2.28.1
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:50:10 +01:00
3f01e56686 Sync with 2.27.1
* maint-2.27:
  Git 2.27.1
  Git 2.26.3
  Git 2.25.5
  Git 2.24.4
  Git 2.23.4
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:50:09 +01:00
6ff7f46039 Git 2.27.1
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:50:05 +01:00
2d1142a3e8 Sync with 2.26.3
* maint-2.26:
  Git 2.26.3
  Git 2.25.5
  Git 2.24.4
  Git 2.23.4
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:50:04 +01:00
a79fd20c71 Git 2.26.3
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:50:00 +01:00
8f80393c14 Sync with 2.25.5
* maint-2.25:
  Git 2.25.5
  Git 2.24.4
  Git 2.23.4
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:49:59 +01:00
42ce4c7930 Git 2.25.5
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:49:55 +01:00
97d1dcb1ef Sync with 2.24.4
* maint-2.24:
  Git 2.24.4
  Git 2.23.4
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:49:55 +01:00
06214d171b Git 2.24.4
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:49:50 +01:00
92ac04b8ee Sync with 2.23.4
* maint-2.23:
  Git 2.23.4
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:49:50 +01:00
d60b6a96f0 Git 2.23.4
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:49:46 +01:00
4bd06fd490 Sync with 2.22.5
* maint-2.22:
  Git 2.22.5
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:49:45 +01:00
c753e2a7a8 Git 2.22.5
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:49:41 +01:00
bcf08f33d8 Sync with 2.21.4
* maint-2.21:
  Git 2.21.4
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:49:41 +01:00
c735d7470e Git 2.21.4
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:49:36 +01:00
b1726b1a38 Sync with 2.20.5
* maint-2.20:
  Git 2.20.5
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:49:35 +01:00
8b1a5f33d3 Git 2.20.5
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:49:17 +01:00
804963848e Sync with 2.19.6
* maint-2.19:
  Git 2.19.6
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:49:17 +01:00
9fb2a1fb08 Git 2.19.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:47:48 +01:00
fb049fd85b Sync with 2.18.5
* maint-2.18:
  Git 2.18.5
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:47:47 +01:00
6eed462c8f Git 2.18.5
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:47:43 +01:00
9b77cec89b Sync with 2.17.6
* maint-2.17:
  Git 2.17.6
  unpack_trees(): start with a fresh lstat cache
  run-command: invalidate lstat cache after a command finished
  checkout: fix bug that makes checkout follow symlinks in leading path
2021-02-12 15:47:42 +01:00
6b82d3eea6 Git 2.17.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:47:02 +01:00
22539ec3b5 unpack_trees(): start with a fresh lstat cache
We really want to avoid relying on stale information.

Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:47:02 +01:00
0d58fef58a run-command: invalidate lstat cache after a command finished
In the previous commit, we intercepted calls to `rmdir()` to invalidate
the lstat cache in the successful case, so that the lstat cache could
not have the idea that a directory exists where there is none.

The same situation can arise, of course, when a separate process is
spawned (most notably, this is the case in `submodule_move_head()`).
Obviously, we cannot know whether a directory was removed in that
process, therefore we must invalidate the lstat cache afterwards.

Note: in contrast to `lstat_cache_aware_rmdir()`, we invalidate the
lstat cache even in case of an error: the process might have removed a
directory and still have failed afterwards.

Co-authored-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2021-02-12 15:47:02 +01:00
684dd4c2b4 checkout: fix bug that makes checkout follow symlinks in leading path
Before checking out a file, we have to confirm that all of its leading
components are real existing directories. And to reduce the number of
lstat() calls in this process, we cache the last leading path known to
contain only directories. However, when a path collision occurs (e.g.
when checking out case-sensitive files in case-insensitive file
systems), a cached path might have its file type changed on disk,
leaving the cache on an invalid state. Normally, this doesn't bring
any bad consequences as we usually check out files in index order, and
therefore, by the time the cached path becomes outdated, we no longer
need it anyway (because all files in that directory would have already
been written).

But, there are some users of the checkout machinery that do not always
follow the index order. In particular: checkout-index writes the paths
in the same order that they appear on the CLI (or stdin); and the
delayed checkout feature -- used when a long-running filter process
replies with "status=delayed" -- postpones the checkout of some entries,
thus modifying the checkout order.

When we have to check out an out-of-order entry and the lstat() cache is
invalid (due to a previous path collision), checkout_entry() may end up
using the invalid data and thrusting that the leading components are
real directories when, in reality, they are not. In the best case
scenario, where the directory was replaced by a regular file, the user
will get an error: "fatal: unable to create file 'foo/bar': Not a
directory". But if the directory was replaced by a symlink, checkout
could actually end up following the symlink and writing the file at a
wrong place, even outside the repository. Since delayed checkout is
affected by this bug, it could be used by an attacker to write
arbitrary files during the clone of a maliciously crafted repository.

Some candidate solutions considered were to disable the lstat() cache
during unordered checkouts or sort the entries before passing them to
the checkout machinery. But both ideas include some performance penalty
and they don't future-proof the code against new unordered use cases.

Instead, we now manually reset the lstat cache whenever we successfully
remove a directory. Note: We are not even checking whether the directory
was the same as the lstat cache points to because we might face a
scenario where the paths refer to the same location but differ due to
case folding, precomposed UTF-8 issues, or the presence of `..`
components in the path. Two regression tests, with case-collisions and
utf8-collisions, are also added for both checkout-index and delayed
checkout.

Note: to make the previously mentioned clone attack unfeasible, it would
be sufficient to reset the lstat cache only after the remove_subtree()
call inside checkout_entry(). This is the place where we would remove a
directory whose path collides with the path of another entry that we are
currently trying to check out (possibly a symlink). However, in the
interest of a thorough fix that does not leave Git open to
similar-but-not-identical attack vectors, we decided to intercept
all `rmdir()` calls in one fell swoop.

This addresses CVE-2021-21300.

Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
2021-02-12 15:47:02 +01:00
764 changed files with 9161 additions and 20996 deletions

1
.gitattributes vendored
View File

@ -6,7 +6,6 @@
*.pm eol=lf diff=perl
*.py eol=lf diff=python
*.bat eol=crlf
CODE_OF_CONDUCT.md -whitespace
/Documentation/**/*.txt eol=lf
/command-list.txt eol=lf
/GIT-VERSION-GEN eol=lf

View File

@ -289,7 +289,7 @@ jobs:
- jobname: osx-gcc
cc: gcc
pool: macos-latest
- jobname: linux-gcc-default
- jobname: GETTEXT_POISON
cc: gcc
pool: ubuntu-latest
env:

View File

@ -16,7 +16,7 @@ compiler:
matrix:
include:
- env: jobname=linux-gcc-default
- env: jobname=GETTEXT_POISON
os: linux
compiler:
addons:

View File

@ -8,64 +8,73 @@ 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.
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, 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.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
Examples of behavior that contributes to creating a positive environment
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
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior include:
Examples of unacceptable behavior by participants 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
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/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
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
## Our 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.
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
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.
Project maintainers 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, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## 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.
This Code of Conduct applies within all project spaces, and it also applies
when an individual is representing the project or its community in public
spaces. Examples of representing a project or community include using an
official project e-mail address, posting via an official social media account,
or acting as an appointed representative at an online or offline event.
Representation of a project may be further defined and clarified by project
maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
reported by contacting the project team at git@sfconservancy.org. All
complaints will be reviewed and investigated and will result in a response
that is deemed necessary and appropriate to the circumstances. The project
team is obligated to maintain confidentiality with regard to the reporter of
an incident. Further details of specific enforcement policies may be posted
separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
The project leadership team can be contacted by email as a whole at
git@sfconservancy.org, or individually:
- Ævar Arnfjörð Bjarmason <avarab@gmail.com>
@ -73,73 +82,12 @@ git@sfconservancy.org, or individually:
- Jeff King <peff@peff.net>
- Junio C Hamano <gitster@pobox.com>
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].
version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[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
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@ -21,7 +21,6 @@ MAN1_TXT += gitweb.txt
MAN5_TXT += gitattributes.txt
MAN5_TXT += githooks.txt
MAN5_TXT += gitignore.txt
MAN5_TXT += gitmailmap.txt
MAN5_TXT += gitmodules.txt
MAN5_TXT += gitrepository-layout.txt
MAN5_TXT += gitweb.conf.txt

View File

@ -664,7 +664,7 @@ mention the right animal somewhere:
----
test_expect_success 'runs correctly with no args and good output' '
git psuh >actual &&
grep Pony actual
test_i18ngrep Pony actual
'
----

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -1,327 +0,0 @@
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.
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.
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).
* 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).

View File

@ -1,6 +1,6 @@
-b::
Show blank SHA-1 for boundary commits. This can also
be controlled via the `blame.blankBoundary` config option.
be controlled via the `blame.blankboundary` config option.
--root::
Do not treat root commits as boundaries. This can also be

View File

@ -398,8 +398,6 @@ include::config/interactive.txt[]
include::config/log.txt[]
include::config/lsrefs.txt[]
include::config/mailinfo.txt[]
include::config/mailmap.txt[]
@ -440,6 +438,8 @@ include::config/rerere.txt[]
include::config/reset.txt[]
include::config/safe.txt[]
include::config/sendemail.txt[]
include::config/sequencer.txt[]

View File

@ -625,6 +625,4 @@ core.abbrev::
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.

View File

@ -85,8 +85,6 @@ diff.ignoreSubmodules::
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

View File

@ -4,4 +4,4 @@ init.templateDir::
init.defaultBranch::
Allows overriding the default branch name e.g. when initializing
a new repository.
a new repository or when cloning an empty repository.

View File

@ -1,9 +0,0 @@
lsrefs.unborn::
May be "advertise" (the default), "allow", or "ignore". If "advertise",
the server will respond to the client sending "unborn" (as described in
protocol-v2.txt) and will advertise support for this feature during the
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".

View File

@ -15,9 +15,8 @@ maintenance.strategy::
* `none`: This default setting implies no task 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.
task, but runs the `prefetch` and `commit-graph` tasks hourly and the
`loose-objects` and `incremental-repack` tasks daily.
maintenance.<task>.enabled::
This boolean config option controls whether the maintenance task

View File

@ -13,11 +13,6 @@ mergetool.<tool>.cmd::
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
@ -45,16 +40,6 @@ mergetool.meld.useAutoMerge::
value of `false` avoids using `--auto-merge` altogether, and is the
default value.
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 overwriten 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 `true`.
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

View File

@ -133,10 +133,3 @@ pack.writeBitmapHashCache::
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.
pack.writeReverseIndex::
When true, git will write a corresponding .rev file (see:
link:../technical/pack-format.html[Documentation/technical/pack-format.txt])
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 false.

View File

@ -68,6 +68,3 @@ 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.

View File

@ -0,0 +1,28 @@
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 when specified in a system or global
config, not when it is specified in a repository config or via the command
line option `-c safe.directory=<path>`.
+
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.

View File

@ -1,7 +1,10 @@
DATE FORMATS
------------
The `GIT_AUTHOR_DATE` and `GIT_COMMITTER_DATE` environment variables
The `GIT_AUTHOR_DATE`, `GIT_COMMITTER_DATE` environment variables
ifdef::git-commit[]
and the `--date` option
endif::git-commit[]
support the following date formats:
Git internal format::
@ -23,9 +26,3 @@ ISO 8601::
+
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[]

View File

@ -81,9 +81,9 @@ 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 specific format.
linkgit:git-show[1]. Note also that you can give the `-m` option to any
of these commands to force generation of diffs with individual parents
of a merge.
A "combined diff" format looks like this:

View File

@ -33,57 +33,6 @@ endif::git-diff[]
show the patch by default, or to cancel the effect of `--patch`.
endif::git-format-patch[]
ifdef::git-log[]
--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
--no-diff-merges::
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.
+
--diff-merges=(off|none):::
--no-diff-merges:::
Disable output of diffs for merge commits. Useful to override
implied value.
+
--diff-merges=first-parent:::
--diff-merges=1:::
This option makes merge commits show the full diff with
respect to the first parent only.
+
--diff-merges=separate:::
--diff-merges=m:::
-m:::
This makes merge commits show the full diff with respect to
each of the parents. Separate log entry and diff is generated
for each parent. `-m` doesn't produce any output without `-p`.
+
--diff-merges=combined:::
--diff-merges=c:::
-c:::
With this option, diff output for a merge commit 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. Furthermore, it lists
only files which were modified from all parents. `-c` implies
`-p`.
+
--diff-merges=dense-combined:::
--diff-merges=cc:::
--cc:::
With this option the output produced by
`--diff-merges=combined` is further compressed by omitting
uninteresting hunks whose contents in the parents have only
two variants and the merge result picks one of them without
modification. `--cc` implies `-p`.
--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 `--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
@ -700,14 +649,6 @@ 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 were invented primarily for 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

View File

@ -7,10 +7,6 @@
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

View File

@ -79,7 +79,7 @@ OPTIONS
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 project's
`i18n.commitencoding` can be used to specify project's
preferred encoding if it is not UTF-8).
+
This was optional in prior versions of git, but now it is the

View File

@ -226,7 +226,7 @@ commit commentary), a blame viewer will not care.
MAPPING AUTHORS
---------------
See linkgit:gitmailmap[5].
include::mailmap.txt[]
SEE ALSO

View File

@ -78,8 +78,8 @@ 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.
`-M`, except instead of the branch being renamed it along with its
config and reflog will be copied to a new name.
With a `-d` or `-D` option, `<branchname>` will be deleted. You may
specify more than one branch for deletion. If the branch currently
@ -153,7 +153,7 @@ OPTIONS
--column[=<options>]::
--no-column::
Display branch listing in columns. See configuration variable
`column.branch` for option syntax. `--column` and `--no-column`
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.

View File

@ -36,17 +36,10 @@ 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].
include::mailmap.txt[]
GIT

View File

@ -346,22 +346,6 @@ GIT_CONFIG_NOSYSTEM::
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.
[[EXAMPLES]]
EXAMPLES

View File

@ -34,14 +34,6 @@ OPTIONS
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 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

View File

@ -117,14 +117,12 @@ 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.
objects referenced by the index, remote-tracking branches, notes saved
by 'git notes' under refs/notes/, reflogs (which may reference commits
in branches that were later amended or rewound), and anything else in
the refs/* namespace. 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

View File

@ -9,18 +9,17 @@ 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' [-v] [-o <index-file>] <pack-file>
'git index-pack' --stdin [--fix-thin] [--keep] [-v] [-o <index-file>]
[--[no-]rev-index] [<pack-file>]
[<pack-file>]
DESCRIPTION
-----------
Reads a packed archive (.pack) from the specified file, and
builds a pack index file (.idx) for it. 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.
builds a pack index file (.idx) for it. The packed archive
together with the pack index can then be placed in the
objects/pack/ directory of a Git repository.
OPTIONS
@ -36,13 +35,6 @@ OPTIONS
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

View File

@ -107,15 +107,47 @@ 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`, and `--cc` 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.
Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
will never 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 merges are treated like normal
single-parent commits (this can be overridden by providing a
combined-diff option or with `--no-diff-merges`).
-c::
With this option, diff output for a merge commit
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. Furthermore, it lists only files
which were modified from all parents.
--cc::
This flag implies the `-c` option 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.
--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).
-m::
This flag makes the merge commits show the full diff like
regular commits; for each merge parent, a separate log entry
and diff is generated. An exception is that only diff against
the first parent is shown when `--first-parent` option is given;
in that case, the output represents the changes the merge
brought _into_ the then-current branch.
--diff-merges=off::
--no-diff-merges::
Disable output of diffs for merge commits (default). Useful to
override `-m`, `-c`, or `--cc`.
:git-log: 1
:diff-merges-default: `off`
include::diff-options.txt[]
include::diff-generate-patch.txt[]

View File

@ -13,7 +13,6 @@ SYNOPSIS
(--[cached|deleted|others|ignored|stage|unmerged|killed|modified])*
(-[c|d|o|i|s|u|k|m])*
[--eol]
[--deduplicate]
[-x <pattern>|--exclude=<pattern>]
[-X <file>|--exclude-from=<file>]
[--exclude-per-directory=<file>]
@ -81,13 +80,6 @@ OPTIONS
\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.

View File

@ -53,7 +53,7 @@ character.
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
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
@ -61,7 +61,7 @@ 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.
used instead of the one specified by i18n.commitencoding or UTF-8.
-n::
Disable all charset re-coding of the metadata.

View File

@ -145,12 +145,6 @@ incremental-repack::
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::
@ -224,122 +218,6 @@ Further, the `git gc` command should not be combined with
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 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.
GIT
---

View File

@ -38,10 +38,6 @@ get_merge_tool_cmd::
get_merge_tool_path::
returns the custom path for a merge tool.
initialize_merge_tool::
bring 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.

View File

@ -3,7 +3,7 @@ git-mktag(1)
NAME
----
git-mktag - Creates a tag object with extra validation
git-mktag - Creates a tag object
SYNOPSIS
@ -11,52 +11,25 @@ SYNOPSIS
[verse]
'git mktag'
OPTIONS
-------
--strict::
By default mktag turns on the equivalent of
linkgit:git-fsck[1] `--strict` mode. Use `--no-strict` to
disable it.
DESCRIPTION
-----------
Reads a tag contents on standard input and creates a tag object
that can also be used to sign other objects.
Reads a tag 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 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>` varible:
git -c fsck.extraHeaderEntry=ignore mktag <my-tag-with-headers
The output is the new tag's <object> identifier.
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>
object <sha1>
type <typename>
tag <tagname>
tagger <tagger>
followed by some 'optional' free-form message (some tags created
by older Git may not have `tagger` line). The message, when it
by older Git may not have `tagger` line). The message, when
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.

View File

@ -400,17 +400,6 @@ 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]

View File

@ -10,7 +10,6 @@ SYNOPSIS
[verse]
'git range-diff' [--color=[<when>]] [--no-color] [<diff-options>]
[--no-dual-color] [--creation-factor=<factor>]
[--left-only | --right-only]
( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
DESCRIPTION
@ -29,17 +28,6 @@ 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
-------
@ -69,14 +57,6 @@ to revert to color all lines according to the outer diff markers
See the ``Algorithm`` section below for an explanation 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).
--[no-]notes[=<ref>]::
This flag is passed to the `git log` program
(see linkgit:git-log[1]) that generates the patches.

View File

@ -165,12 +165,9 @@ depth is 4095.
Pass the `--delta-islands` option to `git-pack-objects`, see
linkgit:git-pack-objects[1].
CONFIGURATION
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
@ -181,10 +178,6 @@ need to set the configuration variable `repack.UseDeltaBaseOffset` to
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]

View File

@ -31,99 +31,6 @@ include::rev-list-options.txt[]
include::pretty-formats.txt[]
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@example.com --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

View File

@ -212,18 +212,6 @@ Options for Files
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
@ -233,42 +221,13 @@ 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.
--git-common-dir::
Show `$GIT_COMMON_DIR` if defined, else `$GIT_DIR`.
--is-inside-git-dir::
When the current working directory is below the repository
directory print "true", otherwise "false".
@ -283,6 +242,19 @@ The following options are unaffected by `--path-format`:
--is-shallow-repository::
When the repository is shallow print "true", otherwise "false".
--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-cdup::
When the command is invoked from a subdirectory, show the
path of the top-level directory relative to the current
@ -293,6 +265,20 @@ The following options are unaffected by `--path-format`:
path of the current directory relative to the top-level
directory.
--show-toplevel::
Show the 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.
--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

View File

@ -111,11 +111,11 @@ include::rev-list-options.txt[]
MAPPING AUTHORS
---------------
See linkgit:gitmailmap[5].
The `.mailmap` feature is used to coalesce together commits by the same
person in the shortlog, where their name and/or email address was
spelled differently.
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.
include::mailmap.txt[]
GIT
---

View File

@ -45,13 +45,10 @@ include::pretty-options.txt[]
include::pretty-formats.txt[]
DIFF FORMATTING
---------------
The options below can be used to change the way `git show` generates
diff output.
COMMON DIFF OPTIONS
-------------------
:git-log: 1
:diff-merges-default: `dense-combined`
include::diff-options.txt[]
include::diff-generate-patch.txt[]

View File

@ -8,8 +8,8 @@ git-stash - Stash the changes in a dirty working directory away
SYNOPSIS
--------
[verse]
'git stash' list [<log-options>]
'git stash' show [<diff-options>] [<stash>]
'git stash' list [<options>]
'git stash' show [<options>] [<stash>]
'git stash' drop [-q|--quiet] [<stash>]
'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
'git stash' branch <branchname> [<stash>]
@ -67,7 +67,7 @@ save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q
Instead, all non-option arguments are concatenated to form the stash
message.
list [<log-options>]::
list [<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
@ -83,7 +83,7 @@ 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 [<diff-options>] [<stash>]::
show [<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

View File

@ -130,7 +130,7 @@ ignored, then the directory is not shown, but all contents are shown.
--column[=<options>]::
--no-column::
Display untracked files in columns. See configuration variable
`column.status` for option syntax. `--column` and `--no-column`
column.status for option syntax.`--column` and `--no-column`
without options are equivalent to 'always' and 'never'
respectively.

View File

@ -134,7 +134,7 @@ options for details.
--column[=<options>]::
--no-column::
Display tag listing in columns. See configuration variable
`column.tag` for option syntax. `--column` and `--no-column`
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.

View File

@ -97,9 +97,8 @@ list::
List details of each working tree. The main working tree is listed first,
followed by each of the linked working trees. The output details include
whether the working tree 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 `prune`
command.
branch currently checked out (or "detached HEAD" if none), and "locked" if
the worktree is locked.
lock::
@ -144,11 +143,6 @@ locate it. Running `repair` within the recently-moved working tree will
reestablish the connection. If multiple linked working trees are moved,
running `repair` from any working tree with each tree's new `<path>` as
an argument, will reestablish the connection to all the specified paths.
+
If both the main working tree and linked working trees have been moved
manually, then running `repair` in the main working tree and specifying the
new `<path>` of each linked working tree will reestablish all connections
in both directions.
unlock::
@ -232,14 +226,9 @@ This can also be set up as the default behaviour by using the
-v::
--verbose::
With `prune`, report all removals.
+
With `list`, output additional information about worktrees (see below).
--expire <time>::
With `prune`, only expire unused working trees older than `<time>`.
+
With `list`, annotate missing working trees as prunable if they are
older than `<time>`.
--reason <string>::
With `lock`, an explanation why the working tree is locked.
@ -378,46 +367,13 @@ $ git worktree list
/path/to/other-linked-worktree 1234abc (detached HEAD)
------------
The command also shows annotations for each working tree, according to its state.
These annotations are:
* `locked`, if the working tree is locked.
* `prunable`, if the working tree can be pruned via `git worktree prune`.
------------
$ git worktree list
/path/to/linked-worktree abcd1234 [master]
/path/to/locked-worktreee 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: working tree 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
working tree itself.
Porcelain Format
~~~~~~~~~~~~~~~~
The porcelain format has a line per attribute. 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 working tree is always `worktree`, an empty line indicates the
end of the record. For example:
if the value is true. The first attribute of a working tree is always
`worktree`, an empty line indicates the end of the record. For example:
------------
$ git worktree list --porcelain
@ -432,33 +388,6 @@ 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
------------
If the lock reason contains "unusual" characters such as newline, they
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

View File

@ -13,7 +13,7 @@ SYNOPSIS
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
[--super-prefix=<path>] [--config-env <name>=<envvar>]
[--super-prefix=<path>]
<command> [<args>]
DESCRIPTION
@ -80,28 +80,6 @@ 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 OS's where
other processes might be able to read your cmdline
(e.g. `/proc/self/cmdline`), but not your environ
(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

View File

@ -74,7 +74,6 @@ into another list. There are currently 5 such transformations:
- 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
@ -277,26 +276,6 @@ Documentation
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],

View File

@ -1,123 +0,0 @@
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@email.xx>
--
The more complex forms are:
--
<proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace only the email part of a commit, and:
--
Proper Name <proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace both the name and the email of a
commit matching the specified commit email address, and:
--
Proper Name <proper@email.xx> Commit Name <commit@email.xx>
--
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@email.xx> CoMmIt NaMe <CoMmIt@EmAiL.xX>
--
EXAMPLES
--------
Your history contains commits by two authors, Jane
and Joe, whose names appear in the repository under several forms:
------------
Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
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@example.com>
Jane Doe <jane@example.com>
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@example.com>
Jane Doe <jane@example.com> <jane@laptop.(none)>
Jane Doe <jane@example.com> <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@example.com>
Jane <bugs@example.com>
------------
A full `.mailmap` file which also handles those cases (an addition of
two lines to the above example) would be:
------------
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com> <jane@laptop.(none)>
Jane Doe <jane@example.com> <jane@desktop.(none)>
Joe R. Developer <joe@example.com> Joe <bugs@example.com>
Jane Doe <jane@example.com> Jane <bugs@example.com>
------------
SEE ALSO
--------
linkgit:git-check-mailmap[1]
GIT
---
Part of the linkgit:git[1] suite

View File

@ -38,7 +38,7 @@ mind.
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:
have i18n.commitencoding in `.git/config` file, like this:
+
------------
[i18n]

75
Documentation/mailmap.txt Normal file
View File

@ -0,0 +1,75 @@
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, it
is used to map author and committer names and email addresses to
canonical real names and email addresses.
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@email.xx>
--
The more complex forms are:
--
<proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace only the email part of a commit, and:
--
Proper Name <proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace both the name and the email of a
commit matching the specified commit email address, and:
--
Proper Name <proper@email.xx> Commit Name <commit@email.xx>
--
which allows mailmap to replace both the name and the email of a
commit matching both the specified commit name and email address.
Example 1: Your history contains commits by two authors, Jane
and Joe, whose names appear in the repository under several forms:
------------
Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
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 proper `.mailmap` file
would look like:
------------
Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com>
------------
Note how there is no need for an entry for `<jane@laptop.(none)>`, because the
real name of that author is already correct.
Example 2: Your repository contains commits from the following
authors:
------------
nick1 <bugs@company.xx>
nick2 <bugs@company.xx>
nick2 <nick2@company.xx>
santa <me@company.xx>
claus <me@company.xx>
CTO <cto@coompany.xx>
------------
Then you might want a `.mailmap` file that looks like:
------------
<cto@company.xx> <cto@coompany.xx>
Some Dude <some@dude.xx> nick1 <bugs@company.xx>
Other Author <other@author.xx> nick2 <bugs@company.xx>
Other Author <other@author.xx> <nick2@company.xx>
Santa Claus <santa.claus@northpole.xx> <me@company.xx>
------------
Use hash '#' for comments that are either on their own line, or after
the email address.

View File

@ -252,15 +252,7 @@ endif::git-rev-list[]
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 occurance wins.
+
The boolean options accept an optional value `[=<BOOL>]`. 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.
+
and zero or more comma-separated options:
** 'key=<K>': 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
@ -269,25 +261,27 @@ option is given with no value, it's enabled.
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.
** 'only[=val]': select whether non-trailer lines from the trailer
block should be included. The `only` keyword may optionally be
followed by an equal sign and one of `true`, `on`, `yes` to omit or
`false`, `off`, `no` to show the non-trailer lines. If option is
given without value it is enabled. If given multiple times the last
value is used.
** 'separator=<SEP>': specify a separator inserted between trailer
lines. When this option is not given each trailer line is
terminated with 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 )`
next option. If separator option is given multiple times only the
last one is used. 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.,
** 'unfold[=val]': make it behave as if interpret-trailer's `--unfold`
option was given. In same way as to for `only` it can be followed
by an equal sign and explicit value. 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 a separator inserted between
trailer lines. When this option is not given each trailer key-value
pair is separated by ": ". Otherwise it shares the same semantics
as 'separator=<SEP>' above.
** 'valueonly[=val]': skip over the key part of the trailer line and only
show the value part. Also this optionally allows explicit value.
NOTE: Some placeholders may depend on other options given to the
revision traversal engine. For example, the `%g*` reflog options will

View File

@ -129,11 +129,6 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
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[]
--not::
Reverses the meaning of the '{caret}' prefix (or lack thereof)
@ -227,15 +222,6 @@ ifdef::git-rev-list[]
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::
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.
endif::git-rev-list[]
--cherry-mark::

View File

@ -4,7 +4,11 @@ Git commit graph format
The Git commit graph stores a list of commit OIDs and some associated
metadata, including:
- The generation number of the commit.
- The generation number of the commit. Commits with no parents have
generation number 1; commits with parents have generation number
one more than the maximum generation number of its parents. We
reserve zero as special, and can be used to mark a generation
number invalid or as "not computed".
- The root tree OID.
@ -82,33 +86,13 @@ CHUNK DATA:
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 next 8 bytes store the generation number 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', 'T' }) (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', 'V' }) [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 atleast 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

View File

@ -38,31 +38,14 @@ A consumer may load the following info for a commit from the graph:
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 nummber v1)
Define the "generation number" of a commit recursively as follows:
Define "corrected committer date" of a commit recursively as follows:
* A commit with no parents (a root commit) has generation number one.
* 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 generation number one more than
the largest generation number among its parents.
* A commit with at least one parent has corrected committer date equal to
the maximum of its commiter 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
Equivalently, the generation number 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:
@ -77,9 +60,6 @@ is easier to use for computation and observing the following property:
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:
@ -87,9 +67,7 @@ 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
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").
@ -99,7 +77,7 @@ 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
We use the macro GENERATION_NUMBER_INFINITY = 0xFFFFFFFF 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.
@ -115,12 +93,12 @@ 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.
We use the macro GENERATION_NUMBER_MAX = 0x3FFFFFFF to for commits whose
generation numbers 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 generation numbers. This
presents another case where a commit can have generation number equal to
that of a parent.
Design Details
--------------
@ -289,35 +267,6 @@ 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

View File

@ -33,9 +33,16 @@ researchers. On 23 February 2017 the SHAttered attack
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.
attack.
Thus it's considered prudent to move past any variant of SHA-1
Thus Git has in effect already migrated to a new hash that isn't SHA-1
and doesn't share its vulnerabilities, its new hash function just
happens to produce exactly the same output for all known inputs,
except two PDFs published by the SHAttered researchers, and the new
implementation (written by those researchers) claims to detect future
cryptanalytic collision attacks.
Regardless, 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.
@ -50,38 +57,6 @@ 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@genre.crustytoothpaste.net/
for more information.
Goals
-----
1. The transition to SHA-256 can be done one local repository at a time.
@ -119,7 +94,7 @@ 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
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.
@ -132,7 +107,7 @@ 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
in its sha1 form and write an object given its sha1 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).
@ -140,7 +115,7 @@ object database so that they can be named using the appropriate name
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
objects being pushed into sha1 form so the server does not have to be
aware of the hash function the client is using.
Detailed Design
@ -176,38 +151,38 @@ 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
Objects can be named by their 40 hexadecimal digit sha1-name or 64
hexadecimal digit sha256-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
The sha1-name of an object is the SHA-1 of the concatenation of its
type, length, a nul byte, and the object's sha1-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.
The sha256-name of an object is the SHA-256 of the concatenation of its
type, length, a nul byte, and the object's sha256-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.
by sha1 and sha256 differ because an object named by sha256-name refers to
other objects by their sha256-names and an object named by sha1-name
refers to other objects by their sha1-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 sha256-content of an object is the same as its sha1-content, except
that objects referenced by the object are named using their sha256-names
instead of sha1-names. Because a blob object does not refer to any
other object, its sha1-content and sha256-content are the same.
The format allows round-trip conversion between SHA-256 content and
SHA-1 content.
The format allows round-trip conversion between sha256-content and
sha1-content.
Object storage
~~~~~~~~~~~~~~
Loose objects use zlib compression and packed objects use the packed
format described in Documentation/technical/pack-format.txt, just like
today. The content that is compressed and stored uses SHA-256 content
instead of SHA-1 content.
today. The content that is compressed and stored uses sha256-content
instead of sha1-content.
Pack index
~~~~~~~~~~
@ -216,21 +191,21 @@ 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
- 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
- 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
- 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
- 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
@ -238,36 +213,37 @@ network byte order):
- 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
- 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 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.
- 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
- 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
- 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
- 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.
@ -276,10 +252,10 @@ network byte order):
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
- 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.
- 20-byte SHA-256 checksum of all of the above.
Loose object index
~~~~~~~~~~~~~~~~~~
@ -312,18 +288,18 @@ To remove entries (e.g. in "git pack-refs" or "git-prune"):
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:
The index files support a bidirectional mapping between sha1-names
and sha256-names. The lookup proceeds similarly to ordinary object
lookups. For example, to convert a sha1-name to a sha256-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
idx's sorted list of truncated sha1-names, then:
a. Read the corresponding entry in the sha1-name order to pack
name order mapping.
b. Read the corresponding entry in the full SHA-1 name table to
b. Read the corresponding entry in the full sha1-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.
c. Read the corresponding entry in the full sha256-name table.
That is the object's sha256-name.
2. Check for a loose object. Read lines from loose-object-idx until
we find a match.
@ -337,10 +313,10 @@ 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.
Reading an object's sha1-content
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The sha1-content of an object can be read by converting all sha256-names
its sha256-content references to sha1-names using the translation table.
Fetch
~~~~~
@ -363,7 +339,7 @@ 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
using the translation table and their sha1-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,
@ -372,12 +348,12 @@ the following steps:
(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
3. convert to sha256: open a new (sha256) 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.
sha1-content, convert to sha256-content, and write it to the sha256
pack. Record the new sha1<->sha256 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
in the pack the server generated and include blobs. Write a sha256 idx
file
5. clean up: remove the SHA-1 based pack file, index, and
topologically sorted list obtained from the server in steps 1
@ -402,20 +378,19 @@ 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
pushed objects are already in the translation table. The sha1-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
an object's sha1-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
existing "gpgsig" field. Its signed payload is the sha256-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.
@ -429,11 +404,10 @@ 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
sha256-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.
@ -441,11 +415,11 @@ This means tags can be signed
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 sha1-content of a commit contains the
sha1-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.
The mergetag field in the sha256-content of the same commit contains the
sha256-content of the same tag.
Submodules
~~~~~~~~~~
@ -520,7 +494,7 @@ Caveats
-------
Invalid objects
~~~~~~~~~~~~~~~
The conversion from SHA-1 content to SHA-256 content retains any
The conversion from sha1-content to sha256-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
@ -539,15 +513,15 @@ 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
For the same reason, a sha256 repository cannot borrow objects from a
sha1 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.
The "git notes" tool annotates objects using their sha1-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
sha256-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).
@ -581,7 +555,7 @@ unclear:
Git 2.12
Does this mean Git v2.12.0 is the commit with SHA-1 name
Does this mean Git v2.12.0 is the commit with sha1-name
e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7 or the commit with
new-40-digit-hash-name e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7?
@ -624,12 +598,44 @@ 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}
git --output-format=sha1 log abac87a^{sha1}..f787cac^{sha256}
Choice of Hash
--------------
In early 2005, around the time that Git was written, Xiaoyun Wang,
Yiqun Lisa Yin, and Hongbo Yu announced an attack finding SHA-1
collisions in 2^69 operations. In August they published details.
Luckily, no practical demonstrations of a collision in full SHA-1 were
published until 10 years later, in 2017.
Git v2.13.0 and later subsequently moved to a hardened SHA-1
implementation by default that mitigates the SHAttered attack, but
SHA-1 is still believed to be weak.
The hash to replace this 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).
We choose SHA-256.
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"
@ -641,9 +647,9 @@ Some initial steps can be implemented independently of one another:
- 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
@ -651,7 +657,6 @@ extension (without compatObjectFormat). This requires:
repository
Next comes introduction of compatObjectFormat:
- implementing the loose-object-idx
- translating object names between object formats
- translating object content between object formats
@ -664,11 +669,10 @@ Next comes introduction of compatObjectFormat:
"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
- convert the fetched packfile to sha256 format and generate an idx
file
- re-sort to match the order of objects in the fetched packfile
@ -730,7 +734,6 @@ Using hash functions in parallel
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
@ -740,38 +743,36 @@ using the old hash function.
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.
for sha256-content based signatures, an earlier version of this design
added "hash sha256 <sha256-name>" fields to strengthen the existing
sha1-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.
attest to the sha1-name and sha256-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
* Verifying a signed object requires access to the sha1-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
this, the design added fields such as "hash sha1 tree <sha1-name>"
and "hash sha1 parent <sha1-name>" to the sha256-content of a signed
commit, complicating the conversion process.
* Allowing signed objects without a SHA-1 (for after the transition is
* Allowing signed objects without a sha1 (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
field to suppress including "hash sha1" fields in the sha256-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
Calculating the sha1-name at object creation time at the same time it is
being streamed to disk and having its sha256-name calculated should be
an acceptable cost.
Document History
@ -781,19 +782,18 @@ Document History
bmwill@google.com, jonathantanmy@google.com, jrnieder@gmail.com,
sbeller@google.com
* Initial version sent to https://lore.kernel.org/git/20170304011251.GA26789@aiede.mtv.corp.google.com
Initial version sent to
http://lore.kernel.org/git/20170304011251.GA26789@aiede.mtv.corp.google.com
2017-03-03 jrnieder@gmail.com
Incorporated suggestions from jonathantanmy and sbeller:
* Describe purpose of signed objects with each hash type
* Redefine signed object verification using object content under the
* 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@gmail.com
* 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
* 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).
@ -805,26 +805,23 @@ Incorporated suggestions from jonathantanmy and sbeller:
especially Junio).
2017-09-27 jrnieder@gmail.com, sbeller@google.com
* Use placeholder NewHash instead of SHA3-256
* Describe criteria for picking a hash function.
* Include a transition plan (thanks especially to Brandon Williams
* 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
* define the translation table (thanks, Shawn Pearce[5], Jonathan
Tan, and Masaya Suzuki)
* Avoid loose object overhead by packing more aggressively in
* 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
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@mail.gmail.com/
[2] https://lore.kernel.org/git/CA+55aFz+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@mail.gmail.com/
[3] https://lore.kernel.org/git/20170306084353.nrns455dvkdsfgo5@sigill.intra.peff.net/
[4] https://lore.kernel.org/git/20170304224936.rqqtkdvfjgyezsht@genre.crustytoothpaste.net
[5] https://lore.kernel.org/git/CAJo=hJtoX9=AyLHHpUJS7fueV9ciZ_MNpnEPHUz8Whui6g9F0A@mail.gmail.com/
[1] http://lore.kernel.org/git/CA+55aFzJtejiCjV0e43+9oR3QuJK2PiFiLQemytoLpyJWe6P9w@mail.gmail.com/
[2] http://lore.kernel.org/git/CA+55aFz+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@mail.gmail.com/
[3] http://lore.kernel.org/git/20170306084353.nrns455dvkdsfgo5@sigill.intra.peff.net/
[4] http://lore.kernel.org/git/20170304224936.rqqtkdvfjgyezsht@genre.crustytoothpaste.net
[5] https://lore.kernel.org/git/CAJo=hJtoX9=AyLHHpUJS7fueV9ciZ_MNpnEPHUz8Whui6g9F0A@mail.gmail.com/

View File

@ -26,7 +26,7 @@ Git index format
Extensions are identified by signature. Optional extensions can
be ignored if Git does not understand them.
Git currently supports cache tree and resolve undo extensions.
Git currently supports cached tree and resolve undo extensions.
4-byte extension signature. If the first byte is 'A'..'Z' the
extension is optional and can be ignored.
@ -136,35 +136,14 @@ Git index format
== Extensions
=== Cache tree
=== Cached 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.
Cached tree extension contains pre-computed hashes for trees that can
be derived from the index. It helps speed up tree object generation
from index for a new commit.
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.
When a path is updated in index, the path must be invalidated and
removed from tree cache.
The signature for this extension is { 'T', 'R', 'E', 'E' }.
@ -195,8 +174,7 @@ Git index format
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.
its name relative to A), ...
=== Resolve undo
@ -273,14 +251,14 @@ Git index format
- Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
ctime field until "file size".
- Stat data of core.excludesFile
- 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
- Hash of core.excludesfile. A null hash means the file does
not exist.
- NUL-terminated string of per-dir exclude file name. This usually

View File

@ -274,26 +274,6 @@ Pack file entry: <+
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.
== multi-pack-index (MIDX) files have the following format:
The multi-pack-index files refer to multiple pack-files and loose objects.

View File

@ -33,8 +33,8 @@ 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
* '0002' Message Packet (response-end-pkt) - indicates the end of a response
for stateless connections
Initial Client Request
----------------------
@ -192,20 +192,11 @@ ls-refs takes in the following arguments:
When specified, only references having a prefix matching one of
the provided prefixes are displayed.
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 = PKT-LINE(obj-id SP refname *(SP ref-attribute) LF)
ref-attribute = (symref | peeled)
symref = "symref-target:" symref-target
peeled = "peeled:" obj-id

View File

@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v2.31.0-rc0
DEF_VER=v2.30.4
LF='
'

View File

@ -29,11 +29,18 @@ all::
# 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.
# USE_LIBPCRE is a synonym for USE_LIBPCRE2, define USE_LIBPCRE1
# instead if you'd like to use the legacy version 1 of the PCRE
# library. Support for version 1 will likely be removed in some future
# release of Git, as upstream has all but abandoned it.
#
# When using USE_LIBPCRE1, define NO_LIBPCRE1_JIT if you want to
# disable JIT even if supported by your library.
#
# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are
# in /foo/bar/include and /foo/bar/lib directories.
# in /foo/bar/include and /foo/bar/lib directories. Which version of
# PCRE this points to determined by the USE_LIBPCRE1 and USE_LIBPCRE2
# variables.
#
# Define HAVE_ALLOCA_H if you have working alloca(3) defined in that header.
#
@ -715,7 +722,6 @@ TEST_BUILTINS_OBJS += test-online-cpus.o
TEST_BUILTINS_OBJS += test-parse-options.o
TEST_BUILTINS_OBJS += test-parse-pathspec-file.o
TEST_BUILTINS_OBJS += test-path-utils.o
TEST_BUILTINS_OBJS += test-pcre2-config.o
TEST_BUILTINS_OBJS += test-pkt-line.o
TEST_BUILTINS_OBJS += test-prio-queue.o
TEST_BUILTINS_OBJS += test-proc-receive.o
@ -854,7 +860,6 @@ LIB_OBJS += date.o
LIB_OBJS += decorate.o
LIB_OBJS += delta-islands.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
@ -863,7 +868,6 @@ 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
@ -883,7 +887,6 @@ LIB_OBJS += gettext.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
@ -920,8 +923,6 @@ LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
LIB_OBJS += notes-utils.o
LIB_OBJS += notes.o
LIB_OBJS += object-file.o
LIB_OBJS += object-name.o
LIB_OBJS += object.o
LIB_OBJS += oid-array.o
LIB_OBJS += oidmap.o
@ -978,6 +979,9 @@ LIB_OBJS += sequencer.o
LIB_OBJS += serve.o
LIB_OBJS += server-info.o
LIB_OBJS += setup.o
LIB_OBJS += sha1-file.o
LIB_OBJS += sha1-lookup.o
LIB_OBJS += sha1-name.o
LIB_OBJS += shallow.o
LIB_OBJS += sideband.o
LIB_OBJS += sigchain.o
@ -1355,17 +1359,26 @@ ifdef NO_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))
ifdef USE_LIBPCRE1
$(error Only set USE_LIBPCRE2 (or its alias USE_LIBPCRE) or USE_LIBPCRE1, not both!)
endif
BASIC_CFLAGS += -DUSE_LIBPCRE2
EXTLIBS += -lpcre2-8
endif
ifdef USE_LIBPCRE1
BASIC_CFLAGS += -DUSE_LIBPCRE1
EXTLIBS += -lpcre
ifdef NO_LIBPCRE1_JIT
BASIC_CFLAGS += -DNO_LIBPCRE1_JIT
endif
endif
ifdef LIBPCREDIR
BASIC_CFLAGS += -I$(LIBPCREDIR)/include
EXTLIBS += -L$(LIBPCREDIR)/$(lib) $(CC_LD_DYNPATH)$(LIBPCREDIR)/$(lib)
@ -2713,7 +2726,9 @@ GIT-BUILD-OPTIONS: FORCE
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@+
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@+
@echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@+
@echo USE_LIBPCRE1=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE1)))'\' >>$@+
@echo USE_LIBPCRE2=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE2)))'\' >>$@+
@echo NO_LIBPCRE1_JIT=\''$(subst ','\'',$(subst ','\'',$(NO_LIBPCRE1_JIT)))'\' >>$@+
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
@echo NO_PTHREADS=\''$(subst ','\'',$(subst ','\'',$(NO_PTHREADS)))'\' >>$@+
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+

View File

@ -1 +1 @@
Documentation/RelNotes/2.31.0.txt
Documentation/RelNotes/2.30.4.txt

View File

@ -67,15 +67,19 @@ static void get_root_part(struct strbuf *resolved, struct strbuf *remaining)
#endif
/*
* If set, any number of trailing components may be missing; otherwise, only one
* may be.
* 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).
*/
#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)
char *strbuf_realpath(struct strbuf *resolved, const char *path,
int die_on_error)
{
struct strbuf remaining = STRBUF_INIT;
struct strbuf next = STRBUF_INIT;
@ -85,7 +89,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
struct stat st;
if (!*path) {
if (flags & REALPATH_DIE_ON_ERROR)
if (die_on_error)
die("The empty string is not a valid path");
else
goto error_out;
@ -97,7 +101,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
if (!resolved->len) {
/* relative path; can use CWD as the initial resolved path */
if (strbuf_getcwd(resolved)) {
if (flags & REALPATH_DIE_ON_ERROR)
if (die_on_error)
die_errno("unable to get current working directory");
else
goto error_out;
@ -125,9 +129,8 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
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)
if (errno != ENOENT || remaining.len) {
if (die_on_error)
die_errno("Invalid path '%s'",
resolved->buf);
else
@ -140,7 +143,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
if (num_symlinks++ > MAXSYMLINKS) {
errno = ELOOP;
if (flags & REALPATH_DIE_ON_ERROR)
if (die_on_error)
die("More than %d nested symlinks "
"on path '%s'", MAXSYMLINKS, path);
else
@ -150,7 +153,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
len = strbuf_readlink(&symlink, resolved->buf,
st.st_size);
if (len < 0) {
if (flags & REALPATH_DIE_ON_ERROR)
if (die_on_error)
die_errno("Invalid symlink '%s'",
resolved->buf);
else
@ -199,37 +202,6 @@ error_out:
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;

View File

@ -6,7 +6,7 @@
#include "refs.h"
#include "list-objects.h"
#include "quote.h"
#include "hash-lookup.h"
#include "sha1-lookup.h"
#include "run-command.h"
#include "log-tree.h"
#include "bisect.h"
@ -1064,7 +1064,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
if (!all) {
fprintf(stderr, _("No testable commit found.\n"
"Maybe you started with bad path arguments?\n"));
"Maybe you started with bad path parameters?\n"));
return BISECT_NO_TESTABLE_COMMIT;
}

View File

@ -38,27 +38,19 @@ struct update_callback_data {
int add_errors;
};
static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
static void chmod_pathspec(struct pathspec *pathspec, char flip)
{
int i, ret = 0;
int i;
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
int err;
if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
continue;
if (!show_only)
err = chmod_cache_entry(ce, flip);
else
err = S_ISREG(ce->ce_mode) ? 0 : -1;
if (err < 0)
ret = error(_("cannot chmod %cx '%s'"), flip, ce->name);
if (chmod_cache_entry(ce, flip) < 0)
fprintf(stderr, "cannot chmod %cx '%s'\n", flip, ce->name);
}
return ret;
}
static int fix_unmerged_status(struct diff_filepair *p,
@ -617,7 +609,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
exit_status |= add_files(&dir, flags);
if (chmod_arg && pathspec.nr)
exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
chmod_pathspec(&pathspec, chmod_arg[0]);
unplug_bulk_checkin();
finish:

View File

@ -21,15 +21,16 @@ static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --bisect-reset [<commit>]"),
N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
N_("git bisect--helper --bisect-next"),
N_("git bisect--helper --bisect-auto-next"),
N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
N_("git bisect--helper --bisect-replay <filename>"),
N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
NULL
};
@ -903,148 +904,28 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
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.v, argv.nr);
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, const char **argv, int argc)
{
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;
init_revisions(&revs, NULL);
setup_revisions(2, argv + i - 1, &revs, NULL);
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed\n"));
while ((commit = get_revision(&revs)) != NULL)
strvec_push(&argv_state,
oid_to_hex(&commit->object.oid));
reset_revision_walk();
} else {
strvec_push(&argv_state, argv[i]);
}
}
res = bisect_state(terms, argv_state.v, argv_state.nr);
strvec_clear(&argv_state);
return res;
}
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
enum {
BISECT_RESET = 1,
BISECT_WRITE,
CHECK_AND_SET_TERMS,
BISECT_NEXT_CHECK,
BISECT_TERMS,
BISECT_START,
BISECT_AUTOSTART,
BISECT_NEXT,
BISECT_STATE,
BISECT_LOG,
BISECT_REPLAY,
BISECT_SKIP
BISECT_AUTO_NEXT,
BISECT_STATE
} cmdmode = 0;
int res = 0, nolog = 0;
struct option options[] = {
OPT_CMDMODE(0, "bisect-reset", &cmdmode,
N_("reset the bisection state"), BISECT_RESET),
OPT_CMDMODE(0, "bisect-write", &cmdmode,
N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS),
OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
OPT_CMDMODE(0, "bisect-terms", &cmdmode,
@ -1053,14 +934,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
N_("start the bisect session"), BISECT_START),
OPT_CMDMODE(0, "bisect-next", &cmdmode,
N_("find the next bisection commit"), BISECT_NEXT),
OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
OPT_CMDMODE(0, "bisect-state", &cmdmode,
N_("mark the state of ref (or refs)"), BISECT_STATE),
OPT_CMDMODE(0, "bisect-log", &cmdmode,
N_("list the bisection steps so far"), BISECT_LOG),
OPT_CMDMODE(0, "bisect-replay", &cmdmode,
N_("replay the bisection process from the given file"), BISECT_REPLAY),
OPT_CMDMODE(0, "bisect-skip", &cmdmode,
N_("skip some commits for checkout"), BISECT_SKIP),
OPT_BOOL(0, "no-log", &nolog,
N_("no log for BISECT_WRITE")),
OPT_END()
@ -1078,7 +955,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
case BISECT_RESET:
if (argc > 1)
return error(_("--bisect-reset requires either no argument or a commit"));
res = bisect_reset(argc ? argv[0] : NULL);
return !!bisect_reset(argc ? argv[0] : NULL);
case BISECT_WRITE:
if (argc != 4 && argc != 5)
return error(_("--bisect-write requires either 4 or 5 arguments"));
set_terms(&terms, argv[3], argv[2]);
res = bisect_write(argv[0], argv[1], &terms, nolog);
break;
case CHECK_AND_SET_TERMS:
if (argc != 3)
return error(_("--check-and-set-terms requires 3 arguments"));
set_terms(&terms, argv[2], argv[1]);
res = check_and_set_terms(&terms, argv[0]);
break;
case BISECT_NEXT_CHECK:
if (argc != 2 && argc != 3)
@ -1101,26 +989,17 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
get_terms(&terms);
res = bisect_next(&terms, prefix);
break;
case BISECT_AUTO_NEXT:
if (argc)
return error(_("--bisect-auto-next requires 0 arguments"));
get_terms(&terms);
res = bisect_auto_next(&terms, prefix);
break;
case BISECT_STATE:
set_terms(&terms, "bad", "good");
get_terms(&terms);
res = bisect_state(&terms, argv, argc);
break;
case BISECT_LOG:
if (argc)
return error(_("--bisect-log requires 0 arguments"));
res = bisect_log();
break;
case BISECT_REPLAY:
if (argc != 1)
return error(_("no logfile given"));
set_terms(&terms, "bad", "good");
res = bisect_replay(&terms, argv[0]);
break;
case BISECT_SKIP:
set_terms(&terms, "bad", "good");
res = bisect_skip(&terms, argv, argc);
break;
default:
BUG("unknown subcommand %d", cmdmode);
}

View File

@ -425,11 +425,13 @@ 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)
static void determine_line_heat(struct blame_entry *ent, const char **dest_color)
{
int i = 0;
struct commit_info ci;
get_commit_info(ent->suspect->commit, &ci, 1);
while (i < colorfield_nr && ci->author_time > colorfield[i].hop)
while (i < colorfield_nr && ci.author_time > colorfield[i].hop)
i++;
*dest_color = colorfield[i].col;
@ -451,7 +453,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
cp = blame_nth_line(sb, ent->lno);
if (opt & OUTPUT_SHOW_AGE_WITH_COLOR) {
determine_line_heat(&ci, &default_color);
determine_line_heat(ent, &default_color);
color = default_color;
reset = GIT_COLOR_RESET;
}
@ -1149,7 +1151,7 @@ parse_done:
sb.xdl_opts = xdl_opts;
sb.no_whole_file_rename = no_whole_file_rename;
read_mailmap(&mailmap);
read_mailmap(&mailmap, NULL);
sb.found_guilty_entry = &found_guilty_entry;
sb.found_guilty_entry_data = &pi;

View File

@ -202,9 +202,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
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;
switch (kinds) {
case FILTER_REFS_REMOTES:
@ -222,7 +219,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
default:
die(_("cannot use -a with -d"));
}
branch_name_pos = strcspn(fmt, "%");
if (!force) {
head_rev = lookup_commit_reference(the_repository, &head_oid);
@ -269,35 +265,30 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
goto next;
}
item = string_list_append(&refs_to_delete, name);
item->util = xstrdup((flags & REF_ISBROKEN) ? "broken"
: (flags & REF_ISSYMREF) ? target
: find_unique_abbrev(&oid, DEFAULT_ABBREV));
if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid,
REF_NO_DEREF)) {
error(remote_branch
? _("Error deleting remote-tracking branch '%s'")
: _("Error deleting branch '%s'"),
bname.buf);
ret = 1;
goto next;
}
if (!quiet) {
printf(remote_branch
? _("Deleted remote-tracking branch %s (was %s).\n")
: _("Deleted branch %s (was %s).\n"),
bname.buf,
(flags & REF_ISBROKEN) ? "broken"
: (flags & REF_ISSYMREF) ? target
: find_unique_abbrev(&oid, DEFAULT_ABBREV));
}
delete_branch_config(bname.buf);
next:
free(target);
}
if (delete_refs(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 (!ref_exists(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);

View File

@ -47,7 +47,7 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
if (argc == 0 && !use_stdin)
die(_("no contacts specified"));
read_mailmap(&mailmap);
read_mailmap(&mailmap, NULL);
for (i = 0; i < argc; ++i)
check_mailmap(&mailmap, argv[i]);

View File

@ -23,35 +23,22 @@ 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('.');
}
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;
} else
fputs(topath[checkout_stage], stdout);
}
if (have_tempname) {
putchar('\t');
write_name_quoted_relative(name, prefix, stdout,
nul_term_line ? '\0' : '\n');
}
putchar('\t');
write_name_quoted_relative(name, prefix, stdout,
nul_term_line ? '\0' : '\n');
for (i = 0; i < 4; i++) {
topath[i][0] = 0;

View File

@ -821,6 +821,9 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
}
if (!active_cache_tree)
active_cache_tree = cache_tree();
if (!cache_tree_fully_valid(active_cache_tree))
cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);

View File

@ -979,8 +979,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
struct strvec ref_prefixes = STRVEC_INIT;
packet_trace_identity("clone");
@ -1258,17 +1257,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
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);
strvec_push(&ref_prefixes, "HEAD");
refspec_ref_prefixes(&remote->fetch, &ref_prefixes);
if (option_branch)
expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
option_branch);
expand_ref_prefix(&ref_prefixes, option_branch);
if (!option_no_tags)
strvec_push(&transport_ls_refs_options.ref_prefixes,
"refs/tags/");
strvec_push(&ref_prefixes, "refs/tags/");
refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
refs = transport_get_remote_refs(transport, &ref_prefixes);
if (refs) {
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
@ -1330,19 +1326,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head = NULL;
option_no_checkout = 1;
if (!option_bare) {
const char *branch;
char *ref;
if (transport_ls_refs_options.unborn_head_target &&
skip_prefix(transport_ls_refs_options.unborn_head_target,
"refs/heads/", &branch)) {
ref = transport_ls_refs_options.unborn_head_target;
transport_ls_refs_options.unborn_head_target = NULL;
create_symref("HEAD", ref, reflog_msg.buf);
} else {
branch = git_default_branch_name(0);
ref = xstrfmt("refs/heads/%s", branch);
}
const char *branch = git_default_branch_name(0);
char *ref = xstrfmt("refs/heads/%s", branch);
install_branch_config(0, branch, remote_name, ref);
free(ref);
@ -1395,7 +1380,6 @@ cleanup:
strbuf_release(&key);
junk_mode = JUNK_LEAVE_ALL;
strvec_clear(&transport_ls_refs_options.ref_prefixes);
free(transport_ls_refs_options.unborn_head_target);
strvec_clear(&ref_prefixes);
return err;
}

View File

@ -1039,7 +1039,7 @@ static const char *find_author_by_nickname(const char *name)
av[++ac] = NULL;
setup_revisions(ac, av, &revs, NULL);
revs.mailmap = &mailmap;
read_mailmap(revs.mailmap);
read_mailmap(revs.mailmap, NULL);
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));

View File

@ -194,7 +194,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
}
/* Is it annotated? */
if (!peel_iterated_oid(oid, &peeled)) {
if (!peel_ref(path, &peeled)) {
is_annotated = !oideq(oid, &peeled);
} else {
oidcpy(&peeled, oid);

View File

@ -7,7 +7,6 @@
#include "cache.h"
#include "config.h"
#include "diff.h"
#include "diff-merges.h"
#include "commit.h"
#include "revision.h"
#include "builtin.h"
@ -36,7 +35,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
*/
rev.diffopt.ita_invisible_in_index = 1;
prefix = precompose_argv_prefix(argc, argv, prefix);
precompose_argv(argc, argv);
argc = setup_revisions(argc, argv, &rev, NULL);
while (1 < argc && argv[1][0] == '-') {
@ -54,7 +53,6 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
}
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,
@ -71,9 +69,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
* 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 &&
if (rev.max_count == -1 && !rev.combine_merges &&
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
diff_merges_set_dense_combined_if_unset(&rev);
rev.combine_merges = rev.dense_combined_merges = 1;
if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");

View File

@ -25,7 +25,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
prefix = precompose_argv_prefix(argc, argv, prefix);
precompose_argv(argc, argv);
argc = setup_revisions(argc, argv, &rev, NULL);
for (i = 1; i < argc; i++) {
@ -41,8 +41,6 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
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.

View File

@ -126,7 +126,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.tweak = diff_tree_tweak_rev;
prefix = precompose_argv_prefix(argc, argv, prefix);
precompose_argv(argc, argv);
argc = setup_revisions(argc, argv, opt, &s_r_opt);
memset(&w, 0, sizeof(w));
@ -156,8 +156,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
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",
@ -194,7 +192,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int saved_nrl = 0;
int saved_dcctc = 0;
opt->diffopt.rotate_to_strict = 0;
if (opt->diffopt.detect_rename) {
if (!the_index.cache)
repo_read_index(the_repository);

View File

@ -13,7 +13,6 @@
#include "blob.h"
#include "tag.h"
#include "diff.h"
#include "diff-merges.h"
#include "diffcore.h"
#include "revision.h"
#include "log-tree.h"
@ -217,8 +216,8 @@ static int builtin_diff_combined(struct rev_info *revs,
if (argc > 1)
usage(builtin_diff_usage);
diff_merges_set_dense_combined_if_unset(revs);
if (!revs->dense_combined_merges && !revs->combine_merges)
revs->dense_combined_merges = revs->combine_merges = 1;
for (i = 1; i < ents; i++)
oid_array_append(&parents, &ent[i].item->oid);
diff_tree_combined(&ent[0].item->oid, &parents, revs);
@ -266,9 +265,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
* dense one, --cc can be explicitly asked for, or just rely
* on the default).
*/
if (revs->max_count == -1 &&
if (revs->max_count == -1 && !revs->combine_merges &&
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
diff_merges_set_dense_combined_if_unset(revs);
revs->combine_merges = revs->dense_combined_merges = 1;
setup_work_tree();
if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
@ -453,7 +452,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL);
prefix = precompose_argv_prefix(argc, argv, prefix);
precompose_argv(argc, argv);
repo_init_revisions(the_repository, &rev, prefix);
@ -491,7 +490,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
}
rev.diffopt.flags.recursive = 1;
rev.diffopt.rotate_to_strict = 1;
setup_diff_pager(&rev.diffopt);

View File

@ -220,8 +220,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
version = discover_version(&reader);
switch (version) {
case protocol_v2:
get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL,
args.stateless_rpc);
get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL, args.stateless_rpc);
break;
case protocol_v1:
case protocol_v0:

View File

@ -63,7 +63,6 @@ static int enable_auto_gc = 1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
static int max_jobs = -1, submodule_fetch_jobs_config = -1;
static int fetch_parallel_config = 1;
static int atomic_fetch;
static enum transport_family family;
static const char *depth;
static const char *deepen_since;
@ -145,8 +144,6 @@ static struct option builtin_fetch_options[] = {
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),
@ -586,14 +583,13 @@ static struct ref *get_ref_map(struct remote *remote,
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 ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
int ret;
int ret, df_conflict = 0;
if (dry_run)
return 0;
@ -601,47 +597,31 @@ static int s_update_ref(const char *action,
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_transaction_begin(&err);
if (!transaction) {
ret = STORE_REF_ERROR_OTHER;
goto out;
}
}
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref->name,
&ref->new_oid,
check_old ? &ref->old_oid : NULL,
0, msg, &err))
goto fail;
ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
check_old ? &ref->old_oid : NULL,
0, msg, &err);
ret = ref_transaction_commit(transaction, &err);
if (ret) {
ret = STORE_REF_ERROR_OTHER;
goto out;
df_conflict = (ret == TRANSACTION_NAME_CONFLICT);
goto fail;
}
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);
ref_transaction_free(transaction);
strbuf_release(&err);
free(msg);
return ret;
return 0;
fail:
ref_transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&err);
free(msg);
return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
: STORE_REF_ERROR_OTHER;
}
static int refcol_width = 10;
@ -779,7 +759,6 @@ static void format_display(struct strbuf *display, char code,
}
static int update_local_ref(struct ref *ref,
struct ref_transaction *transaction,
const char *remote,
const struct ref *remote_ref,
struct strbuf *display,
@ -820,7 +799,7 @@ static int update_local_ref(struct ref *ref,
starts_with(ref->name, "refs/tags/")) {
if (force || ref->force) {
int r;
r = s_update_ref("updating tag", ref, transaction, 0);
r = s_update_ref("updating tag", ref, 0);
format_display(display, r ? '!' : 't', _("[tag update]"),
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@ -857,7 +836,7 @@ static int update_local_ref(struct ref *ref,
what = _("[new ref]");
}
r = s_update_ref(msg, ref, transaction, 0);
r = s_update_ref(msg, ref, 0);
format_display(display, r ? '!' : '*', what,
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@ -879,7 +858,7 @@ static int update_local_ref(struct ref *ref,
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);
r = s_update_ref("fast-forward", ref, 1);
format_display(display, r ? '!' : ' ', quickref.buf,
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@ -891,7 +870,7 @@ static int update_local_ref(struct ref *ref,
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);
r = s_update_ref("forced-update", ref, 1);
format_display(display, r ? '!' : '+', quickref.buf,
r ? _("unable to update local ref") : _("forced update"),
remote, pretty_ref, summary_width);
@ -918,89 +897,6 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
return 0;
}
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"
@ -1013,20 +909,22 @@ N_("It took %.2f seconds to check forced updates. You can use\n"
static int store_updated_refs(const char *raw_url, const char *remote_name,
int connectivity_checked, struct ref *ref_map)
{
struct fetch_head fetch_head;
FILE *fp;
struct commit *commit;
int url_len, i, rc = 0;
struct strbuf note = STRBUF_INIT, err = STRBUF_INIT;
struct ref_transaction *transaction = NULL;
struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
char *url;
const char *filename = (!write_fetch_head
? "/dev/null"
: git_path_fetch_head(the_repository));
int want_status;
int summary_width = transport_summary_width(ref_map);
rc = open_fetch_head(&fetch_head);
if (rc)
return -1;
fp = fopen(filename, "a");
if (!fp)
return error_errno(_("cannot open %s"), filename);
if (raw_url)
url = transport_anonymize_url(raw_url);
@ -1043,14 +941,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
}
if (atomic_fetch) {
transaction = ref_transaction_begin(&err);
if (!transaction) {
error("%s", err.buf);
goto abort;
}
}
prepare_format_display(ref_map);
/*
@ -1063,6 +953,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
want_status++) {
for (rm = ref_map; rm; rm = rm->next) {
struct ref *ref = NULL;
const char *merge_status_marker = "";
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
if (want_status == FETCH_HEAD_MERGE)
@ -1120,15 +1011,31 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
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, url, url_len);
switch (rm->fetch_head_status) {
case FETCH_HEAD_NOT_FOR_MERGE:
merge_status_marker = "not-for-merge";
/* fall-through */
case FETCH_HEAD_MERGE:
fprintf(fp, "%s\t%s\t%s",
oid_to_hex(&rm->old_oid),
merge_status_marker,
note.buf);
for (i = 0; i < url_len; ++i)
if ('\n' == url[i])
fputs("\\n", fp);
else
fputc(url[i], fp);
fputc('\n', fp);
break;
default:
/* do not write anything to FETCH_HEAD */
break;
}
strbuf_reset(&note);
if (ref) {
rc |= update_local_ref(ref, transaction, what,
rm, &note, summary_width);
rc |= update_local_ref(ref, what, rm, &note,
summary_width);
free(ref);
} else if (write_fetch_head || dry_run) {
/*
@ -1153,17 +1060,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
}
if (!rc && transaction) {
rc = ref_transaction_commit(transaction, &err);
if (rc) {
error("%s", err.buf);
goto abort;
}
}
if (!rc)
commit_fetch_head(&fetch_head);
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 "
@ -1180,10 +1076,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
abort:
strbuf_release(&note);
strbuf_release(&err);
ref_transaction_free(transaction);
free(url);
close_fetch_head(&fetch_head);
fclose(fp);
return rc;
}
@ -1455,8 +1349,7 @@ static int do_fetch(struct transport *transport,
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;
struct strvec ref_prefixes = STRVEC_INIT;
int must_list_refs = 1;
if (tags == TAGS_DEFAULT) {
@ -1476,7 +1369,7 @@ static int do_fetch(struct transport *transport,
if (rs->nr) {
int i;
refspec_ref_prefixes(rs, &transport_ls_refs_options.ref_prefixes);
refspec_ref_prefixes(rs, &ref_prefixes);
/*
* We can avoid listing refs if all of them are exact
@ -1490,25 +1383,22 @@ static int do_fetch(struct transport *transport,
}
}
} else if (transport->remote && transport->remote->fetch.nr)
refspec_ref_prefixes(&transport->remote->fetch,
&transport_ls_refs_options.ref_prefixes);
refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
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 (ref_prefixes.nr)
strvec_push(&ref_prefixes, "refs/tags/");
}
if (must_list_refs) {
trace2_region_enter("fetch", "remote_refs", the_repository);
remote_refs = transport_get_remote_refs(transport,
&transport_ls_refs_options);
remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
trace2_region_leave("fetch", "remote_refs", the_repository);
} else
remote_refs = NULL;
strvec_clear(&transport_ls_refs_options.ref_prefixes);
strvec_clear(&ref_prefixes);
ref_map = get_ref_map(transport->remote, remote_refs, rs,
tags, &autotags);
@ -1997,10 +1887,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
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"));

View File

@ -73,7 +73,25 @@ static const char *printable_type(const struct object_id *oid,
static int fsck_config(const char *var, const char *value, void *cb)
{
return fsck_config_internal(var, value, cb, &fsck_obj_options);
if (strcmp(var, "fsck.skiplist") == 0) {
const char *path;
struct strbuf sb = STRBUF_INIT;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&sb, "skiplist=%s", path);
free((char *)path);
fsck_set_msg_types(&fsck_obj_options, sb.buf);
strbuf_release(&sb);
return 0;
}
if (skip_prefix(var, "fsck.", &var)) {
fsck_set_msg_type(&fsck_obj_options, var, value);
return 0;
}
return git_default_config(var, value, cb);
}
static int objerror(struct object *obj, const char *err)

View File

@ -54,6 +54,7 @@ static const char *prune_worktrees_expire = "3.months.ago";
static unsigned long big_pack_threshold;
static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
static struct strvec pack_refs_cmd = STRVEC_INIT;
static struct strvec reflog = STRVEC_INIT;
static struct strvec repack = STRVEC_INIT;
static struct strvec prune = STRVEC_INIT;
@ -162,15 +163,6 @@ static void gc_config(void)
git_config(git_default_config, NULL);
}
struct maintenance_run_opts;
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
{
struct strvec pack_refs_cmd = STRVEC_INIT;
strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
return run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD);
}
static int too_many_loose_objects(void)
{
/*
@ -309,7 +301,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
/* 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;
heap += sizeof(struct revindex_entry) * nr_objects;
/*
* read_sha1_file() (either at delta calculation phase, or
* writing phase) also fills up the delta base cache
@ -526,8 +518,8 @@ static void gc_before_repack(void)
if (done++)
return;
if (pack_refs && maintenance_task_pack_refs(NULL))
die(FAILED_RUN, "pack-refs");
if (pack_refs && run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD))
die(FAILED_RUN, pack_refs_cmd.v[0]);
if (prune_reflogs && run_command_v_opt(reflog.v, RUN_GIT_CMD))
die(FAILED_RUN, reflog.v[0]);
@ -564,6 +556,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_gc_usage, builtin_gc_options);
strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
strvec_pushl(&reflog, "reflog", "expire", "--all", NULL);
strvec_pushl(&repack, "repack", "-d", "-l", NULL);
strvec_pushl(&prune, "prune", "--expire", NULL);
@ -776,7 +769,7 @@ static int dfs_on_ref(const char *refname,
struct commit_list *stack = NULL;
struct commit *commit;
if (!peel_iterated_oid(oid, &peeled))
if (!peel_ref(refname, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
return 0;
@ -904,12 +897,6 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
struct string_list_item *item;
struct string_list remotes = STRING_LIST_INIT_DUP;
git_config_set_multivar_gently("log.excludedecoration",
"refs/prefetch/",
"refs/prefetch/",
CONFIG_FLAGS_FIXED_VALUE |
CONFIG_FLAGS_MULTI_REPLACE);
if (for_each_remote(append_remote, &remotes)) {
error(_("failed to fill remotes"));
result = 1;
@ -1231,7 +1218,6 @@ enum maintenance_task_label {
TASK_INCREMENTAL_REPACK,
TASK_GC,
TASK_COMMIT_GRAPH,
TASK_PACK_REFS,
/* Leave as final value */
TASK__COUNT
@ -1263,11 +1249,6 @@ static struct maintenance_task tasks[] = {
maintenance_task_commit_graph,
should_write_commit_graph,
},
[TASK_PACK_REFS] = {
"pack-refs",
maintenance_task_pack_refs,
NULL,
},
};
static int compare_tasks_by_selection(const void *a_, const void *b_)
@ -1352,8 +1333,6 @@ static void initialize_maintenance_strategy(void)
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;
}
}
@ -1461,23 +1440,11 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
return maintenance_run_tasks(&opts);
}
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 int maintenance_register(void)
{
int rc;
char *config_value;
struct child_process config_set = CHILD_PROCESS_INIT;
struct child_process config_get = CHILD_PROCESS_INIT;
char *maintpath = get_maintpath();
/* Disable foreground maintenance */
git_config_set("maintenance.auto", "false");
@ -1490,408 +1457,74 @@ static int maintenance_register(void)
config_get.git_cmd = 1;
strvec_pushl(&config_get.args, "config", "--global", "--get",
"--fixed-value", "maintenance.repo", maintpath, NULL);
"--fixed-value", "maintenance.repo",
the_repository->worktree ? the_repository->worktree
: the_repository->gitdir,
NULL);
config_get.out = -1;
if (start_command(&config_get)) {
rc = error(_("failed to run 'git config'"));
goto done;
}
if (start_command(&config_get))
return error(_("failed to run 'git config'"));
/* We already have this value in our config! */
if (!finish_command(&config_get)) {
rc = 0;
goto done;
}
if (!finish_command(&config_get))
return 0;
config_set.git_cmd = 1;
strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo",
maintpath, NULL);
the_repository->worktree ? the_repository->worktree
: the_repository->gitdir,
NULL);
rc = run_command(&config_set);
done:
free(maintpath);
return rc;
return run_command(&config_set);
}
static int maintenance_unregister(void)
{
int rc;
struct child_process config_unset = CHILD_PROCESS_INIT;
char *maintpath = get_maintpath();
config_unset.git_cmd = 1;
strvec_pushl(&config_unset.args, "config", "--global", "--unset",
"--fixed-value", "maintenance.repo", maintpath, NULL);
"--fixed-value", "maintenance.repo",
the_repository->worktree ? the_repository->worktree
: the_repository->gitdir,
NULL);
rc = run_command(&config_unset);
free(maintpath);
return rc;
}
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 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 = expand_user_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, const char *cmd)
{
int result;
struct child_process child = CHILD_PROCESS_INIT;
char *uid = launchctl_get_uid();
strvec_split(&child.args, cmd);
if (enable)
strvec_push(&child.args, "bootstrap");
else
strvec_push(&child.args, "bootout");
strvec_push(&child.args, uid);
strvec_push(&child.args, filename);
child.no_stderr = 1;
child.no_stdout = 1;
if (start_command(&child))
die(_("failed to start launchctl"));
result = finish_command(&child);
free(uid);
return result;
}
static int launchctl_remove_plist(enum schedule_priority schedule, const char *cmd)
{
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, cmd);
unlink(filename);
free(filename);
free(name);
return result;
}
static int launchctl_remove_plists(const char *cmd)
{
return launchctl_remove_plist(SCHEDULE_HOURLY, cmd) ||
launchctl_remove_plist(SCHEDULE_DAILY, cmd) ||
launchctl_remove_plist(SCHEDULE_WEEKLY, cmd);
}
static int launchctl_schedule_plist(const char *exec_path, enum schedule_priority schedule, const char *cmd)
{
FILE *plist;
int i;
const char *preamble, *repeat;
const char *frequency = get_frequency(schedule);
char *name = launchctl_service_name(frequency);
char *filename = launchctl_service_filename(name);
if (safe_create_leading_directories(filename))
die(_("failed to create directories for '%s'"), filename);
plist = xfopen(filename, "w");
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"
"<string>for-each-repo</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";
fprintf(plist, preamble, name, exec_path, exec_path, frequency);
switch (schedule) {
case SCHEDULE_HOURLY:
repeat = "<dict>\n"
"<key>Hour</key><integer>%d</integer>\n"
"<key>Minute</key><integer>0</integer>\n"
"</dict>\n";
for (i = 1; i <= 23; i++)
fprintf(plist, repeat, i);
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>0</integer>\n"
"</dict>\n";
for (i = 1; i <= 6; i++)
fprintf(plist, repeat, i);
break;
case SCHEDULE_WEEKLY:
fprintf(plist,
"<dict>\n"
"<key>Day</key><integer>0</integer>\n"
"<key>Hour</key><integer>0</integer>\n"
"<key>Minute</key><integer>0</integer>\n"
"</dict>\n");
break;
default:
/* unreachable */
break;
}
fprintf(plist, "</array>\n</dict>\n</plist>\n");
fclose(plist);
/* bootout might fail if not already running, so ignore */
launchctl_boot_plist(0, filename, cmd);
if (launchctl_boot_plist(1, filename, cmd))
die(_("failed to bootstrap service %s"), filename);
free(filename);
free(name);
return 0;
}
static int launchctl_add_plists(const char *cmd)
{
const char *exec_path = git_exec_path();
return launchctl_schedule_plist(exec_path, SCHEDULE_HOURLY, cmd) ||
launchctl_schedule_plist(exec_path, SCHEDULE_DAILY, cmd) ||
launchctl_schedule_plist(exec_path, SCHEDULE_WEEKLY, cmd);
}
static int launchctl_update_schedule(int run_maintenance, int fd, const char *cmd)
{
if (run_maintenance)
return launchctl_add_plists(cmd);
else
return launchctl_remove_plists(cmd);
}
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, const char *cmd)
{
int result;
struct strvec args = STRVEC_INIT;
const char *frequency = get_frequency(schedule);
char *name = schtasks_task_name(frequency);
strvec_split(&args, cmd);
strvec_pushl(&args, "/delete", "/tn", name, "/f", NULL);
result = run_command_v_opt(args.v, 0);
strvec_clear(&args);
free(name);
return result;
}
static int schtasks_remove_tasks(const char *cmd)
{
return schtasks_remove_task(SCHEDULE_HOURLY, cmd) ||
schtasks_remove_task(SCHEDULE_DAILY, cmd) ||
schtasks_remove_task(SCHEDULE_WEEKLY, cmd);
}
static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule, const 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;
strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX",
get_git_common_dir(), 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:00: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");
break;
case SCHEDULE_DAILY:
fprintf(tfile->fp,
"<StartBoundary>2020-01-01T00:00: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");
break;
case SCHEDULE_WEEKLY:
fprintf(tfile->fp,
"<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByWeek>\n"
"<DaysOfWeek>\n"
"<Sunday />\n"
"</DaysOfWeek>\n"
"<WeeksInterval>1</WeeksInterval>\n"
"</ScheduleByWeek>\n");
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\\git.exe\"</Command>\n"
"<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
"</Exec>\n"
"</Actions>\n"
"</Task>\n";
fprintf(tfile->fp, xml, exec_path, exec_path, 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);
return result;
}
static int schtasks_schedule_tasks(const char *cmd)
{
const char *exec_path = git_exec_path();
return schtasks_schedule_task(exec_path, SCHEDULE_HOURLY, cmd) ||
schtasks_schedule_task(exec_path, SCHEDULE_DAILY, cmd) ||
schtasks_schedule_task(exec_path, SCHEDULE_WEEKLY, cmd);
}
static int schtasks_update_schedule(int run_maintenance, int fd, const char *cmd)
{
if (run_maintenance)
return schtasks_schedule_tasks(cmd);
else
return schtasks_remove_tasks(cmd);
return run_command(&config_unset);
}
#define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE"
#define END_LINE "# END GIT MAINTENANCE SCHEDULE"
static int crontab_update_schedule(int run_maintenance, int fd, const char *cmd)
static int update_background_schedule(int run_maintenance)
{
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;
const char *crontab_name;
struct strbuf line = STRBUF_INIT;
struct lock_file lk;
char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
strvec_split(&crontab_list.args, cmd);
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0)
return error(_("another process is scheduling background maintenance"));
crontab_name = getenv("GIT_TEST_CRONTAB");
if (!crontab_name)
crontab_name = "crontab";
strvec_split(&crontab_list.args, crontab_name);
strvec_push(&crontab_list.args, "-l");
crontab_list.in = -1;
crontab_list.out = dup(fd);
crontab_list.out = dup(get_lock_file_fd(&lk));
crontab_list.git_cmd = 0;
if (start_command(&crontab_list))
return error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
if (start_command(&crontab_list)) {
result = error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
goto cleanup;
}
/* Ignore exit code, as an empty crontab will return error. */
finish_command(&crontab_list);
@ -1900,15 +1533,17 @@ static int crontab_update_schedule(int run_maintenance, int fd, const char *cmd)
* Read from the .lock file, filtering out the old
* schedule while appending the new schedule.
*/
cron_list = fdopen(fd, "r");
cron_list = fdopen(get_lock_file_fd(&lk), "r");
rewind(cron_list);
strvec_split(&crontab_edit.args, cmd);
strvec_split(&crontab_edit.args, crontab_name);
crontab_edit.in = -1;
crontab_edit.git_cmd = 0;
if (start_command(&crontab_edit))
return error(_("failed to run 'crontab'; your system might not support 'cron'"));
if (start_command(&crontab_edit)) {
result = error(_("failed to run 'crontab'; your system might not support 'cron'"));
goto cleanup;
}
cron_in = fdopen(crontab_edit.in, "w");
if (!cron_in) {
@ -1952,54 +1587,14 @@ static int crontab_update_schedule(int run_maintenance, int fd, const char *cmd)
close(crontab_edit.in);
done_editing:
if (finish_command(&crontab_edit))
if (finish_command(&crontab_edit)) {
result = error(_("'crontab' died"));
else
fclose(cron_list);
return result;
}
#if defined(__APPLE__)
static const char platform_scheduler[] = "launchctl";
#elif defined(GIT_WINDOWS_NATIVE)
static const char platform_scheduler[] = "schtasks";
#else
static const char platform_scheduler[] = "crontab";
#endif
static int update_background_schedule(int enable)
{
int result;
const char *scheduler = platform_scheduler;
const char *cmd = scheduler;
char *testing;
struct lock_file lk;
char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER"));
if (testing) {
char *sep = strchr(testing, ':');
if (!sep)
die("GIT_TEST_MAINT_SCHEDULER unparseable: %s", testing);
*sep = '\0';
scheduler = testing;
cmd = sep + 1;
goto cleanup;
}
fclose(cron_list);
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0)
return error(_("another process is scheduling background maintenance"));
if (!strcmp(scheduler, "launchctl"))
result = launchctl_update_schedule(enable, get_lock_file_fd(&lk), cmd);
else if (!strcmp(scheduler, "schtasks"))
result = schtasks_update_schedule(enable, get_lock_file_fd(&lk), cmd);
else if (!strcmp(scheduler, "crontab"))
result = crontab_update_schedule(enable, get_lock_file_fd(&lk), cmd);
else
die("unknown background scheduler: %s", scheduler);
cleanup:
rollback_lock_file(&lk);
free(testing);
return result;
}

View File

@ -216,6 +216,8 @@ static void start_threads(struct grep_opt *opt)
int err;
struct grep_opt *o = grep_opt_dup(opt);
o->output = strbuf_out;
if (i)
o->debug = 0;
compile_grep_patterns(o);
err = pthread_create(&threads[i], NULL, run, o);
@ -506,10 +508,6 @@ static int grep_cache(struct grep_opt *opt,
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);
@ -522,7 +520,8 @@ static int grep_cache(struct grep_opt *opt,
* cache entry are identical, even if worktree file has
* been modified, so use cache version instead
*/
if (cached || (ce->ce_flags & CE_VALID)) {
if (cached || (ce->ce_flags & CE_VALID) ||
ce_skip_worktree(ce)) {
if (ce_stage(ce) || ce_intent_to_add(ce))
continue;
hit |= grep_oid(opt, &ce->oid, name.buf,
@ -937,6 +936,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
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_SET_INT_F(0, "debug", &opt.debug,
N_("show parse tree for grep expression"),
1, PARSE_OPT_HIDDEN),
OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
N_("pager"), N_("show matching files in the pager"),
@ -1155,9 +1157,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!use_index && (untracked || cached))
die(_("--cached or --untracked cannot be used with --no-index"));
if (untracked && cached)
die(_("--untracked cannot be used with --cached"));
if (!use_index || untracked) {
int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
hit = grep_directory(&opt, &pathspec, use_exclude, use_index);

Some files were not shown because too many files have changed in this diff Show More