Compare commits
40 Commits
v2.31.0-rc
...
v2.30.4
Author | SHA1 | Date | |
---|---|---|---|
17083c79ae | |||
0f85c4a30b | |||
bb50ec3cc3 | |||
e47363e5a8 | |||
cb95038137 | |||
fdcad5a53e | |||
8959555cee | |||
bdc77d1d68 | |||
2a9a5862e5 | |||
6e7ad1e4c2 | |||
94f6e3e283 | |||
e4e68081bb | |||
0628636d0c | |||
d7bdabe52f | |||
e4f4299859 | |||
3f01e56686 | |||
6ff7f46039 | |||
2d1142a3e8 | |||
a79fd20c71 | |||
8f80393c14 | |||
42ce4c7930 | |||
97d1dcb1ef | |||
06214d171b | |||
92ac04b8ee | |||
d60b6a96f0 | |||
4bd06fd490 | |||
c753e2a7a8 | |||
bcf08f33d8 | |||
c735d7470e | |||
b1726b1a38 | |||
8b1a5f33d3 | |||
804963848e | |||
9fb2a1fb08 | |||
fb049fd85b | |||
6eed462c8f | |||
9b77cec89b | |||
6b82d3eea6 | |||
22539ec3b5 | |||
0d58fef58a | |||
684dd4c2b4 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -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
|
||||
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -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:
|
||||
|
@ -16,7 +16,7 @@ compiler:
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: jobname=linux-gcc-default
|
||||
- env: jobname=GETTEXT_POISON
|
||||
os: linux
|
||||
compiler:
|
||||
addons:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
'
|
||||
----
|
||||
|
||||
|
16
Documentation/RelNotes/2.17.6.txt
Normal file
16
Documentation/RelNotes/2.17.6.txt
Normal 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.
|
6
Documentation/RelNotes/2.18.5.txt
Normal file
6
Documentation/RelNotes/2.18.5.txt
Normal 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.
|
6
Documentation/RelNotes/2.19.6.txt
Normal file
6
Documentation/RelNotes/2.19.6.txt
Normal 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.
|
6
Documentation/RelNotes/2.20.5.txt
Normal file
6
Documentation/RelNotes/2.20.5.txt
Normal 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.
|
6
Documentation/RelNotes/2.21.4.txt
Normal file
6
Documentation/RelNotes/2.21.4.txt
Normal 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.
|
7
Documentation/RelNotes/2.22.5.txt
Normal file
7
Documentation/RelNotes/2.22.5.txt
Normal 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.
|
7
Documentation/RelNotes/2.23.4.txt
Normal file
7
Documentation/RelNotes/2.23.4.txt
Normal 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.
|
7
Documentation/RelNotes/2.24.4.txt
Normal file
7
Documentation/RelNotes/2.24.4.txt
Normal 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.
|
7
Documentation/RelNotes/2.25.5.txt
Normal file
7
Documentation/RelNotes/2.25.5.txt
Normal 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.
|
7
Documentation/RelNotes/2.26.3.txt
Normal file
7
Documentation/RelNotes/2.26.3.txt
Normal 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.
|
7
Documentation/RelNotes/2.27.1.txt
Normal file
7
Documentation/RelNotes/2.27.1.txt
Normal 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.
|
7
Documentation/RelNotes/2.28.1.txt
Normal file
7
Documentation/RelNotes/2.28.1.txt
Normal 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.
|
8
Documentation/RelNotes/2.29.3.txt
Normal file
8
Documentation/RelNotes/2.29.3.txt
Normal 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.
|
8
Documentation/RelNotes/2.30.2.txt
Normal file
8
Documentation/RelNotes/2.30.2.txt
Normal 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.
|
24
Documentation/RelNotes/2.30.3.txt
Normal file
24
Documentation/RelNotes/2.30.3.txt
Normal 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.
|
21
Documentation/RelNotes/2.30.4.txt
Normal file
21
Documentation/RelNotes/2.30.4.txt
Normal 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
|
@ -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).
|
@ -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
|
||||
|
@ -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[]
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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".
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
28
Documentation/config/safe.txt
Normal file
28
Documentation/config/safe.txt
Normal 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.
|
@ -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[]
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -226,7 +226,7 @@ commit commentary), a blame viewer will not care.
|
||||
MAPPING AUTHORS
|
||||
---------------
|
||||
|
||||
See linkgit:gitmailmap[5].
|
||||
include::mailmap.txt[]
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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[]
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
---
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
---
|
||||
|
@ -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[]
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
|
@ -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@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@laptop.(none)>' to
|
||||
only correct the names. However, leaving the obviously broken
|
||||
'<jane@laptop.(none)>' and '<jane@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
|
@ -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
75
Documentation/mailmap.txt
Normal 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.
|
@ -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
|
||||
|
@ -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::
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v2.31.0-rc0
|
||||
DEF_VER=v2.30.4
|
||||
|
||||
LF='
|
||||
'
|
||||
|
41
Makefile
41
Makefile
@ -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)))'\' >>$@+
|
||||
|
64
abspath.c
64
abspath.c
@ -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;
|
||||
|
4
bisect.c
4
bisect.c
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 = π
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"));
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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:
|
||||
|
242
builtin/fetch.c
242
builtin/fetch.c
@ -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, ¤t->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, ¤t->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(¬e, "%s ", kind);
|
||||
strbuf_addf(¬e, "'%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(¬e);
|
||||
if (ref) {
|
||||
rc |= update_local_ref(ref, transaction, what,
|
||||
rm, ¬e, summary_width);
|
||||
rc |= update_local_ref(ref, what, rm, ¬e,
|
||||
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(¬e);
|
||||
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"));
|
||||
|
@ -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)
|
||||
|
505
builtin/gc.c
505
builtin/gc.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
Reference in New Issue
Block a user