Merge branch 'debian-sid' into debian-experimental
* debian-sid:
debian: new upstream point release
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Change-Id: I658425b7f3a7c6a9ad49fc6546bebcbbb9afbf34
diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml
index a241a63..d0a78fc 100644
--- a/.github/workflows/check-whitespace.yml
+++ b/.github/workflows/check-whitespace.yml
@@ -26,66 +26,7 @@
- name: git log --check
id: check_out
run: |
- baseSha=${{github.event.pull_request.base.sha}}
- problems=()
- commit=
- commitText=
- commitTextmd=
- goodparent=
- while read dash sha etc
- do
- case "${dash}" in
- "---")
- if test -z "${commit}"
- then
- goodparent=${sha}
- fi
- commit="${sha}"
- commitText="${sha} ${etc}"
- commitTextmd="[${sha}](https://github.com/${{ github.repository }}/commit/${sha}) ${etc}"
- ;;
- "")
- ;;
- *)
- if test -n "${commit}"
- then
- problems+=("1) --- ${commitTextmd}")
- echo ""
- echo "--- ${commitText}"
- commit=
- fi
- case "${dash}" in
- *:[1-9]*:) # contains file and line number information
- dashend=${dash#*:}
- problems+=("[${dash}](https://github.com/${{ github.repository }}/blob/${{github.event.pull_request.head.ref}}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}")
- ;;
- *)
- problems+=("\`${dash} ${sha} ${etc}\`")
- ;;
- esac
- echo "${dash} ${sha} ${etc}"
- ;;
- esac
- done <<< $(git log --check --pretty=format:"---% h% s" ${baseSha}..)
-
- if test ${#problems[*]} -gt 0
- then
- if test -z "${commit}"
- then
- goodparent=${baseSha: 0:7}
- fi
- echo "🛑 Please review the Summary output for further information."
- echo "### :x: A whitespace issue was found in one or more of the commits." >$GITHUB_STEP_SUMMARY
- echo "" >>$GITHUB_STEP_SUMMARY
- echo "Run these commands to correct the problem:" >>$GITHUB_STEP_SUMMARY
- echo "1. \`git rebase --whitespace=fix ${goodparent}\`" >>$GITHUB_STEP_SUMMARY
- echo "1. \`git push --force\`" >>$GITHUB_STEP_SUMMARY
- echo " " >>$GITHUB_STEP_SUMMARY
- echo "Errors:" >>$GITHUB_STEP_SUMMARY
- for i in "${problems[@]}"
- do
- echo "${i}" >>$GITHUB_STEP_SUMMARY
- done
-
- exit 2
- fi
+ ./ci/check-whitespace.sh \
+ "${{github.event.pull_request.base.sha}}" \
+ "$GITHUB_STEP_SUMMARY" \
+ "https://github.com/${{github.repository}}"
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
index 53cf12f..48341e8 100644
--- a/.github/workflows/coverity.yml
+++ b/.github/workflows/coverity.yml
@@ -45,7 +45,7 @@
- run: ci/install-dependencies.sh
if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos')
env:
- runs_on_pool: ${{ matrix.os }}
+ distro: ${{ matrix.os }}
# The Coverity site says the tool is usually updated twice yearly, so the
# MD5 of download can be used to determine whether there's been an update.
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 8922bd7..13cc0fe 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -302,7 +302,7 @@
CC: ${{matrix.vector.cc}}
CC_PACKAGE: ${{matrix.vector.cc_package}}
jobname: ${{matrix.vector.jobname}}
- runs_on_pool: ${{matrix.vector.pool}}
+ distro: ${{matrix.vector.pool}}
runs-on: ${{matrix.vector.pool}}
steps:
- uses: actions/checkout@v4
@@ -341,12 +341,16 @@
vector:
- jobname: linux-musl
image: alpine
+ distro: alpine-latest
- jobname: linux32
image: daald/ubuntu32:xenial
+ distro: ubuntu32-16.04
- jobname: pedantic
image: fedora
+ distro: fedora-latest
env:
jobname: ${{matrix.vector.jobname}}
+ distro: ${{matrix.vector.distro}}
runs-on: ubuntu-latest
container: ${{matrix.vector.image}}
steps:
@@ -354,7 +358,7 @@
if: matrix.vector.jobname != 'linux32'
- uses: actions/checkout@v1 # cannot be upgraded because Node.js Actions aren't supported in this container
if: matrix.vector.jobname == 'linux32'
- - run: ci/install-docker-dependencies.sh
+ - run: ci/install-dependencies.sh
- run: ci/run-build-and-tests.sh
- name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
diff --git a/.gitignore b/.gitignore
index 612c0f6..8caf370 100644
--- a/.gitignore
+++ b/.gitignore
@@ -126,6 +126,7 @@
/git-rebase
/git-receive-pack
/git-reflog
+/git-refs
/git-remote
/git-remote-http
/git-remote-https
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c0fa2fe..37b991e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,8 +9,10 @@
test:linux:
image: $image
+ variables:
+ CUSTOM_PATH: "/custom"
before_script:
- - ./ci/install-docker-dependencies.sh
+ - ./ci/install-dependencies.sh
script:
- useradd builder --create-home
- chown -R builder "${CI_PROJECT_DIR}"
@@ -93,12 +95,39 @@
- t/failed-test-artifacts
when: on_failure
+test:fuzz-smoke-tests:
+ image: ubuntu:latest
+ variables:
+ CC: clang
+ before_script:
+ - ./ci/install-dependencies.sh
+ script:
+ - ./ci/run-build-and-minimal-fuzzers.sh
+
static-analysis:
image: ubuntu:22.04
variables:
jobname: StaticAnalysis
before_script:
- - ./ci/install-docker-dependencies.sh
+ - ./ci/install-dependencies.sh
script:
- ./ci/run-static-analysis.sh
- ./ci/check-directional-formatting.bash
+
+check-whitespace:
+ image: ubuntu:latest
+ before_script:
+ - ./ci/install-dependencies.sh
+ script:
+ - ./ci/check-whitespace.sh "$CI_MERGE_REQUEST_TARGET_BRANCH_SHA"
+ rules:
+ - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+
+documentation:
+ image: ubuntu:latest
+ variables:
+ jobname: Documentation
+ before_script:
+ - ./ci/install-dependencies.sh
+ script:
+ - ./ci/test-documentation.sh
diff --git a/Documentation/BreakingChanges.txt b/Documentation/BreakingChanges.txt
new file mode 100644
index 0000000..0532bfc
--- /dev/null
+++ b/Documentation/BreakingChanges.txt
@@ -0,0 +1,135 @@
+= Upcoming breaking changes
+
+The Git project aims to ensure backwards compatibility to the best extent
+possible. Minor releases will not break backwards compatibility unless there is
+a very strong reason to do so, like for example a security vulnerability.
+
+Regardless of that, due to the age of the Git project, it is only natural to
+accumulate a backlog of backwards-incompatible changes that will eventually be
+required to keep the project aligned with a changing world. These changes fall
+into several categories:
+
+* Changes to long established defaults.
+* Concepts that have been replaced with a superior design.
+* Concepts, commands, configuration or options that have been lacking in major
+ ways and that cannot be fixed and which will thus be removed without any
+ replacement.
+
+Explicitly not included in this list are fixes to minor bugs that may cause a
+change in user-visible behavior.
+
+The Git project irregularly releases breaking versions that deliberately break
+backwards compatibility with older versions. This is done to ensure that Git
+remains relevant, safe and maintainable going forward. The release cadence of
+breaking versions is typically measured in multiple years. We had the following
+major breaking releases in the past:
+
+* Git 1.6.0, released in August 2008.
+* Git 2.0, released in May 2014.
+
+We use <major>.<minor> release numbers these days, starting from Git 2.0. For
+future releases, our plan is to increment <major> in the release number when we
+make the next breaking release. Before Git 2.0, the release numbers were
+1.<major>.<minor> with the intention to increment <major> for "usual" breaking
+releases, reserving the jump to Git 2.0 for really large backward-compatibility
+breaking changes.
+
+The intent of this document is to track upcoming deprecations for future
+breaking releases. Furthermore, this document also tracks what will _not_ be
+deprecated. This is done such that the outcome of discussions document both
+when the discussion favors deprecation, but also when it rejects a deprecation.
+
+Items should have a clear summary of the reasons why we do or do not want to
+make the described change that can be easily understood without having to read
+the mailing list discussions. If there are alternatives to the changed feature,
+those alternatives should be pointed out to our users.
+
+All items should be accompanied by references to relevant mailing list threads
+where the deprecation was discussed. These references use message-IDs, which
+can visited via
+
+ https://lore.kernel.org/git/$message_id/
+
+to see the message and its surrounding discussion. Such a reference is there to
+make it easier for you to find how the project reached consensus on the
+described item back then.
+
+This is a living document as the environment surrounding the project changes
+over time. If circumstances change, an earlier decision to deprecate or change
+something may need to be revisited from time to time. So do not take items on
+this list to mean "it is settled, do not waste our time bringing it up again".
+
+== Git 3.0
+
+The following subsections document upcoming breaking changes for Git 3.0. There
+is no planned release date for this breaking version yet.
+
+Proposed changes and removals only include items which are "ready" to be done.
+In other words, this is not supposed to be a wishlist of features that should
+be changed to or replaced in case the alternative was implemented already.
+
+=== Changes
+
+* The default hash function for new repositories will be changed from "sha1"
+ to "sha256". SHA-1 has been deprecated by NIST in 2011 and is nowadays
+ recommended against in FIPS 140-2 and similar certifications. Furthermore,
+ there are practical attacks on SHA-1 that weaken its cryptographic properties:
++
+ ** The SHAppening (2015). The first demonstration of a practical attack
+ against SHA-1 with 2^57 operations.
+ ** SHAttered (2017). Generation of two valid PDF files with 2^63 operations.
+ ** Birthday-Near-Collision (2019). This attack allows for chosen prefix
+ attacks with 2^68 operations.
+ ** Shambles (2020). This attack allows for chosen prefix attacks with 2^63
+ operations.
++
+While we have protections in place against known attacks, it is expected
+that more attacks against SHA-1 will be found by future research. Paired
+with the ever-growing capability of hardware, it is only a matter of time
+before SHA-1 will be considered broken completely. We want to be prepared
+and will thus change the default hash algorithm to "sha256" for newly
+initialized repositories.
++
+An important requirement for this change is that the ecosystem is ready to
+support the "sha256" object format. This includes popular Git libraries,
+applications and forges.
++
+There is no plan to deprecate the "sha1" object format at this point in time.
++
+Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@zombino.com>,
+<20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>,
+<CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>.
+
+=== Removals
+
+* Support for grafting commits has long been superseded by git-replace(1).
+ Grafts are inferior to replacement refs:
++
+ ** Grafts are a local-only mechanism and cannot be shared across
+ repositories.
+ ** Grafts can lead to hard-to-diagnose problems when transferring objects
+ between repositories.
++
+The grafting mechanism has been marked as outdated since e650d0643b (docs: mark
+info/grafts as outdated, 2014-03-05) and will be removed.
++
+Cf. <20140304174806.GA11561@sigill.intra.peff.net>.
+
+== Superseded features that will not be deprecated
+
+Some features have gained newer replacements that aim to improve the design in
+certain ways. The fact that there is a replacement does not automatically mean
+that the old way of doing things will eventually be removed. This section tracks
+those features with newer alternatives.
+
+* The features git-checkout(1) offers are covered by the pair of commands
+ git-restore(1) and git-switch(1). Because the use of git-checkout(1) is still
+ widespread, and it is not expected that this will change anytime soon, all
+ three commands will stay.
++
+This decision may get revisited in case we ever figure out that there are
+almost no users of any of the commands anymore.
++
+Cf. <xmqqttjazwwa.fsf@gitster.g>,
+<xmqqleeubork.fsf@gitster.g>,
+<112b6568912a6de6672bf5592c3a718e@manjaro.org>.
diff --git a/Documentation/DecisionMaking.txt b/Documentation/DecisionMaking.txt
new file mode 100644
index 0000000..dbb4c1f
--- /dev/null
+++ b/Documentation/DecisionMaking.txt
@@ -0,0 +1,74 @@
+Decision-Making Process in the Git Project
+==========================================
+
+Introduction
+------------
+This document describes the current decision-making process in the Git
+project. It is a descriptive rather than prescriptive doc; that is, we want to
+describe how things work in practice rather than explicitly recommending any
+particular process or changes to the current process.
+
+Here we document how the project makes decisions for discussions
+(with or without patches), in scale larger than an individual patch
+series (which is fully covered by the SubmittingPatches document).
+
+
+Larger Discussions (with patches)
+---------------------------------
+As with discussions on an individual patch series, starting a larger-scale
+discussion often begins by sending a patch or series to the list. This might
+take the form of an initial design doc, with implementation following in later
+iterations of the series (for example,
+link:https://lore.kernel.org/git/0169ce6fb9ccafc089b74ae406db0d1a8ff8ac65.1688165272.git.steadmon@google.com/[adding unit tests] or
+link:https://lore.kernel.org/git/20200420235310.94493-1-emilyshaffer@google.com/[config-based hooks]),
+or it might include a full implementation from the beginning.
+In either case, discussion progresses the same way for an individual patch series,
+until consensus is reached or the topic is dropped.
+
+
+Larger Discussions (without patches)
+------------------------------------
+Occasionally, larger discussions might occur without an associated patch series.
+These may be very large-scale technical decisions that are beyond the scope of
+even a single large patch series, or they may be more open-ended,
+policy-oriented discussions (examples:
+link:https://lore.kernel.org/git/ZZ77NQkSuiRxRDwt@nand.local/[introducing Rust]
+or link:https://lore.kernel.org/git/YHofmWcIAidkvJiD@google.com/[improving submodule UX]).
+In either case, discussion progresses as described above for general patch series.
+
+For larger discussions without a patch series or other concrete implementation,
+it may be hard to judge when consensus has been reached, as there are not any
+official guidelines. If discussion stalls at this point, it may be helpful to
+restart discussion with an RFC patch series (such as a partial, unfinished
+implementation or proof of concept) that can be more easily debated.
+
+When consensus is reached that it is a good idea, the original
+proposer is expected to coordinate the effort to make it happen,
+with help from others who were involved in the discussion, as
+needed.
+
+For decisions that require code changes, it is often the case that the original
+proposer will follow up with a patch series, although it is also common for
+other interested parties to provide an implementation (or parts of the
+implementation, for very large changes).
+
+For non-technical decisions such as community norms or processes, it is up to
+the community as a whole to implement and sustain agreed-upon changes.
+The project leadership committe (PLC) may help the implementation of
+policy decisions.
+
+
+Other Discussion Venues
+-----------------------
+Occasionally decision proposals are presented off-list, e.g. at the semi-regular
+Contributors' Summit. While higher-bandwidth face-to-face discussion is often
+useful for quickly reaching consensus among attendees, generally we expect to
+summarize the discussion in notes that can later be presented on-list. For an
+example, see the thread
+link:https://lore.kernel.org/git/AC2EB721-2979-43FD-922D-C5076A57F24B@jramsay.com.au/[Notes
+from Git Contributor Summit, Los Angeles (April 5, 2020)] by James Ramsay.
+
+We prefer that "official" discussion happens on the list so that the full
+community has opportunity to engage in discussion. This also means that the
+mailing list archives contain a more-or-less complete history of project
+discussions and decisions.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 3f2383a..dc65759 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -51,6 +51,7 @@
MAN7_TXT += giteveryday.txt
MAN7_TXT += gitfaq.txt
MAN7_TXT += gitglossary.txt
+MAN7_TXT += gitpacking.txt
MAN7_TXT += gitnamespaces.txt
MAN7_TXT += gitremote-helpers.txt
MAN7_TXT += gitrevisions.txt
@@ -103,6 +104,7 @@
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
SP_ARTICLES += $(API_DOCS)
+TECH_DOCS += DecisionMaking
TECH_DOCS += ReviewingGuidelines
TECH_DOCS += MyFirstContribution
TECH_DOCS += MyFirstObjectWalk
@@ -484,12 +486,16 @@
lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS)
+lint-docs-manpages:
+ $(QUIET_GEN)./lint-manpages.sh
+
## Lint: list of targets above
.PHONY: lint-docs
lint-docs: lint-docs-fsck-msgids
lint-docs: lint-docs-gitlink
lint-docs: lint-docs-man-end-blurb
lint-docs: lint-docs-man-section-order
+lint-docs: lint-docs-manpages
ifeq ($(wildcard po/Makefile),po/Makefile)
doc-l10n install-l10n::
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index f06563e..e41654c 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -1116,6 +1116,15 @@
NOTE: Check `git help send-email` for some other options which you may find
valuable, such as changing the Reply-to address or adding more CC and BCC lines.
+:contrib-scripts: footnoteref:[contrib-scripts,Scripts under `contrib/` are +
+not part of the core `git` binary and must be called directly. Clone the Git +
+codebase and run `perl contrib/contacts/git-contacts`.]
+
+NOTE: If you're not sure whom to CC, running `contrib/contacts/git-contacts` can
+list potential reviewers. In addition, you can do `git send-email
+--cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch`{contrib-scripts} to
+automatically pass this list of emails to `send-email`.
+
NOTE: When you are sending a real patch, it will go to git@vger.kernel.org - but
please don't send your patchset from the tutorial to the real mailing list! For
now, you can send it to yourself, to make sure you understand how it will look.
diff --git a/Documentation/RelNotes/2.46.0.txt b/Documentation/RelNotes/2.46.0.txt
new file mode 100644
index 0000000..6321ddc
--- /dev/null
+++ b/Documentation/RelNotes/2.46.0.txt
@@ -0,0 +1,248 @@
+Git v2.46 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+ (None at this moment)
+
+UI, Workflows & Features
+
+ * The "--rfc" option of "git format-patch" learned to take an
+ optional string value to be used in place of "RFC" to tweak the
+ "[PATCH]" on the subject header.
+
+ * The credential helper protocol, together with the HTTP layer, have
+ been enhanced to support authentication schemes different from
+ username & password pair, like Bearer and NTLM.
+
+ * Command line completion script (in contrib/) learned to complete
+ "git symbolic-ref" a bit better (you need to enable plumbing
+ commands to be completed with GIT_COMPLETION_SHOW_ALL_COMMANDS).
+
+ * When the user responds to a prompt given by "git add -p" with an
+ unsupported command, list of available commands were given, which
+ was too much if the user knew what they wanted to type but merely
+ made a typo. Now the user gets a much shorter error message.
+
+ * The color parsing code learned to handle 12-bit RGB colors, spelled
+ as "#RGB" (in addition to "#RRGGBB" that is already supported).
+
+ * The operation mode options (like "--get") the "git config" command
+ uses have been deprecated and replaced with subcommands (like "git
+ config get").
+
+ * "git tag" learned the "--trailer" option to futz with the trailers
+ in the same way as "git commit" does.
+
+ * A new global "--no-advice" option can be used to disable all advice
+ messages, which is meant to be used only in scripts.
+
+ * Updates to symbolic refs can now be made as a part of ref
+ transaction.
+
+ * The trailer API has been reshuffled a bit.
+
+ * Terminology to call various ref-like things are getting
+ straightened out.
+
+ * The command line completion script (in contrib/) has been adjusted
+ to the recent update to "git config" that adopted subcommand based
+ UI.
+
+ * The knobs to tweak how reftable files are written have been made
+ available as configuration variables.
+
+ * When "git push" notices that the commit at the tip of the ref on
+ the other side it is about to overwrite does not exist locally, it
+ used to first try fetching it if the local repository is a partial
+ clone. The command has been taught not to do so and immediately
+ fail instead.
+
+ * The promisor.quiet configuration knob can be set to true to make
+ lazy fetching from promisor remotes silent.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Advertise "git contacts", a tool for newcomers to find people to
+ ask review for their patches, a bit more in our developer
+ documentation.
+
+ * In addition to building the objects needed, try to link the objects
+ that are used in fuzzer tests, to make sure at least they build
+ without bitrot, in Linux CI runs.
+
+ * Code to write out reftable has seen some optimization and
+ simplification.
+
+ * Tests to ensure interoperability between reftable written by jgit
+ and our code have been added and enabled in CI.
+
+ * The singleton index_state instance "the_index" has been eliminated
+ by always instantiating "the_repository" and replacing references
+ to "the_index" with references to its .index member.
+
+ * Git-GUI has a new maintainer, Johannes Sixt.
+
+ * The "test-tool" has been taught to run testsuite tests in parallel,
+ bypassing the need to use the "prove" tool.
+
+ * The "whitespace check" task that was enabled for GitHub Actions CI
+ has been ported to GitLab CI.
+
+ * The refs API lost functions that implicitly assumes to work on the
+ primary ref_store by forcing the callers to pass a ref_store as an
+ argument.
+
+ * Code clean-up to reduce inter-function communication inside
+ builtin/config.c done via the use of global variables.
+
+ * The pack bitmap code saw some clean-up to prepare for a follow-up topic.
+
+ * Preliminary code clean-up for "git send-email".
+
+ * The default "creation-factor" used by "git format-patch" has been
+ raised to make it more aggressively find matching commits.
+
+ * Before discovering the repository details, We used to assume SHA-1
+ as the "default" hash function, which has been corrected. Hopefully
+ this will smoke out codepaths that rely on such an unwarranted
+ assumptions.
+
+ * The project decision making policy has been documented.
+
+ * The strcmp-offset tests have been rewritten using the unit test
+ framework.
+
+ * "git add -p" learned to complain when an answer with more than one
+ letter is given to a prompt that expects a single letter answer.
+
+ * The alias-expanded command lines are logged to the trace output.
+
+ * A new test was added to ensure git commands that are designed to
+ run outside repositories do work.
+
+ * Basic unit tests for reftable have been reimplemented under the
+ unit test framework.
+
+ * A pair of test helpers that essentially are unit tests on hash
+ algorithms have been rewritten using the unit-tests framework.
+
+ * A test helper that essentially is unit tests on the "decorate"
+ logic has been rewritten using the unit-tests framework.
+
+ * Many memory leaks in the sparse-checkout code paths have been
+ plugged.
+
+
+Fixes since v2.45
+-----------------
+
+ * "git rebase --signoff" used to forget that it needs to add a
+ sign-off to the resulting commit when told to continue after a
+ conflict stops its operation.
+ (merge a6c2654f83 pw/rebase-m-signoff-fix later to maint).
+
+ * The procedure to build multi-pack-index got confused by the
+ replace-refs mechanism, which has been corrected by disabling the
+ latter.
+ (merge 93e2ae1c95 xx/disable-replace-when-building-midx later to maint).
+
+ * The "-k" and "--rfc" options of "format-patch" will now error out
+ when used together, as one tells us not to add anything to the
+ title of the commit, and the other one tells us to add "RFC" in
+ addition to "PATCH".
+ (merge cadcf58085 ds/format-patch-rfc-and-k later to maint).
+
+ * "git stash -S" did not handle binary files correctly, which has
+ been corrected.
+ (merge 5fb7686409 aj/stash-staged-fix later to maint).
+
+ * A scheduled "git maintenance" job is expected to work on all
+ repositories it knows about, but it stopped at the first one that
+ errored out. Now it keeps going.
+ (merge c75662bfc9 js/for-each-repo-keep-going later to maint).
+
+ * zsh can pretend to be a normal shell pretty well except for some
+ glitches that we tickle in some of our scripts. Work them around
+ so that "vimdiff" and our test suite works well enough with it.
+ (merge fedd5c79ff bc/zsh-compatibility later to maint).
+
+ * Command line completion support for zsh (in contrib/) has been
+ updated to stop exposing internal state to end-user shell
+ interaction.
+ (merge 3c20acdf46 dk/zsh-git-repo-path-fix later to maint).
+
+ * Tests that try to corrupt in-repository files in chunked format did
+ not work well on macOS due to its broken "mv", which has been
+ worked around.
+
+ * The maximum size of attribute files is enforced more consistently.
+ (merge c793f9cb08 tb/attr-limits later to maint).
+
+ * Unbreak CI jobs so that we do not attempt to use Python 2 that has
+ been removed from the platform.
+
+ * Git 2.43 started using the tree of HEAD as the source of attributes
+ in a bare repository, which has severe performance implications.
+ For now, revert the change, without ripping out a more explicit
+ support for the attr.tree configuration variable.
+
+ * The "--exit-code" option of "git diff" command learned to work with
+ the "--ext-diff" option.
+ (merge 11be65cfa4 rs/external-diff-with-exit-code later to maint).
+
+ * Windows CI running in GitHub Actions started complaining about the
+ order of arguments given to calloc(); the imported regex code uses
+ the wrong order almost consistently, which has been corrected.
+
+ * Expose "name conflict" error when a ref creation fails due to D/F
+ conflict in the ref namespace, to improve an error message given by
+ "git fetch".
+ (merge 9339fca23e it/refs-name-conflict later to maint).
+
+ * The SubmittingPatches document now refers folks to manpages
+ translation project.
+
+ * The documentation for "git diff --name-only" has been clarified
+ that it is about showing the names in the post-image tree.
+ (merge 4986662cbc jc/doc-diff-name-only later to maint).
+
+ * The credential helper that talks with osx keychain learned to avoid
+ storing back the authentication material it just got received from
+ the keychain.
+ (merge e1ab45b2da kn/osxkeychain-skip-idempotent-store later to maint).
+
+ * The chainlint script (invoked during "make test") did nothing when
+ it failed to detect the number of available CPUs. It now falls
+ back to 1 CPU to avoid the problem.
+ (merge 2e7e9205be es/chainlint-ncores-fix later to maint).
+
+ * Revert overly aggressive "layered defence" that went into 2.45.1
+ and friends, which broke "git-lfs", "git-annex", and other use
+ cases, so that we can rebuild necessary counterparts in the open.
+
+ * "git init" in an already created directory, when the user
+ configuration has includeif.onbranch, started to fail recently,
+ which has been corrected.
+ (merge 407997c1dd ps/fix-reinit-includeif-onbranch later to maint).
+
+ * Memory leaks in "git mv" has been plugged.
+
+ * The safe.directory configuration knob has been updated to
+ optionally allow leading path matches.
+ (merge 313eec177a jc/safe-directory-leading-path later to maint).
+
+ * An overly large ".gitignore" files are now rejected silently.
+ (merge e7c3d1ddba jk/cap-exclude-file-size later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge a5a4cb7b27 rs/diff-parseopts-cleanup later to maint).
+ (merge 55702c543e fa/p4-error later to maint).
+ (merge 2566a77774 vd/doc-merge-tree-x-option later to maint).
+ (merge b64b0df9da ds/scalar-reconfigure-all-fix later to maint).
+ (merge c81ffcff83 dm/update-index-doc-fix later to maint).
+ (merge fc0202b0e9 dg/fetch-pack-code-cleanup later to maint).
+ (merge 7150f140f9 mt/t0211-typofix later to maint).
+ (merge d424488901 jc/rev-parse-fatal-doc later to maint).
+ (merge 36d900d2b0 rs/difftool-env-simplify later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index c647c7e..d8a8caa 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -7,6 +7,73 @@
project. There is also a link:MyFirstContribution.html[step-by-step tutorial]
available which covers many of these same guidelines.
+[[patch-flow]]
+=== A typical life cycle of a patch series
+
+To help us understand the reason behind various guidelines given later
+in the document, first let's understand how the life cycle of a
+typical patch series for this project goes.
+
+. You come up with an itch. You code it up. You do not need any
+ pre-authorization from the project to do so.
++
+Your patches will be reviewed by other contributors on the mailing
+list, and the reviews will be done to assess the merit of various
+things, like the general idea behind your patch (including "is it
+solving a problem worth solving in the first place?"), the reason
+behind the design of the solution, and the actual implementation.
+The guidelines given here are there to help your patches by making
+them easier to understand by the reviewers.
+
+. You send the patches to the list and cc people who may need to know
+ about the change. Your goal is *not* necessarily to convince others
+ that what you are building is good. Your goal is to get help in
+ coming up with a solution for the "itch" that is better than what
+ you can build alone.
++
+The people who may need to know are the ones who worked on the code
+you are touching. These people happen to be the ones who are
+most likely to be knowledgeable enough to help you, but
+they have no obligation to help you (i.e. you ask them for help,
+you don't demand). +git log -p {litdd} _$area_you_are_modifying_+ would
+help you find out who they are.
+
+. You get comments and suggestions for improvements. You may even get
+ them in an "on top of your change" patch form. You are expected to
+ respond to them with "Reply-All" on the mailing list, while taking
+ them into account while preparing an updated set of patches.
+
+. Polish, refine, and re-send your patches to the list and to the people
+ who spent their time to improve your patch. Go back to step (2).
+
+. While the above iterations improve your patches, the maintainer may
+ pick the patches up from the list and queue them to the `seen`
+ branch, in order to make it easier for people to play with it
+ without having to pick up and apply the patches to their trees
+ themselves. Being in `seen` has no other meaning. Specifically, it
+ does not mean the patch was "accepted" in any way.
+
+. When the discussion reaches a consensus that the latest iteration of
+ the patches are in good enough shape, the maintainer includes the
+ topic in the "What's cooking" report that are sent out a few times a
+ week to the mailing list, marked as "Will merge to 'next'." This
+ decision is primarily made by the maintainer with help from those
+ who participated in the review discussion.
+
+. After the patches are merged to the 'next' branch, the discussion
+ can still continue to further improve them by adding more patches on
+ top, but by the time a topic gets merged to 'next', it is expected
+ that everybody agrees that the scope and the basic direction of the
+ topic are appropriate, so such an incremental updates are limited to
+ small corrections and polishing. After a topic cooks for some time
+ (like 7 calendar days) in 'next' without needing further tweaks on
+ top, it gets merged to the 'master' branch and wait to become part
+ of the next major release.
+
+In the following sections, many techniques and conventions are listed
+to help your patches get reviewed effectively in such a life cycle.
+
+
[[choose-starting-point]]
=== Choose a starting point.
@@ -192,8 +259,9 @@
which case, they can explain why they extend your code to cover
files, too).
-The goal of your log message is to convey the _why_ behind your
-change to help future developers.
+The goal of your log message is to convey the _why_ behind your change
+to help future developers. The reviewers will also make sure that
+your proposed log message will serve this purpose well.
The first line of the commit message should be a short description (50
characters is the soft limit, see DISCUSSION in linkgit:git-commit[1]),
@@ -397,17 +465,57 @@
[[send-patches]]
=== Sending your patches.
+==== Choosing your reviewers
+
:security-ml: footnoteref:[security-ml,The Git Security mailing list: git-security@googlegroups.com]
-Before sending any patches, please note that patches that may be
+NOTE: Patches that may be
security relevant should be submitted privately to the Git Security
mailing list{security-ml}, instead of the public mailing list.
-Learn to use format-patch and send-email if possible. These commands
+:contrib-scripts: footnoteref:[contrib-scripts,Scripts under `contrib/` are +
+not part of the core `git` binary and must be called directly. Clone the Git +
+codebase and run `perl contrib/contacts/git-contacts`.]
+
+Send your patch with "To:" set to the mailing list, with "cc:" listing
+people who are involved in the area you are touching (the `git-contacts`
+script in `contrib/contacts/`{contrib-scripts} can help to
+identify them), to solicit comments and reviews. Also, when you made
+trial merges of your topic to `next` and `seen`, you may have noticed
+work by others conflicting with your changes. There is a good possibility
+that these people may know the area you are touching well.
+
+If you are using `send-email`, you can feed it the output of `git-contacts` like
+this:
+
+....
+ git send-email --cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch
+....
+
+:current-maintainer: footnote:[The current maintainer: gitster@pobox.com]
+:git-ml: footnote:[The mailing list: git@vger.kernel.org]
+
+After the list reached a consensus that it is a good idea to apply the
+patch, re-send it with "To:" set to the maintainer{current-maintainer}
+and "cc:" the list{git-ml} for inclusion. This is especially relevant
+when the maintainer did not heavily participate in the discussion and
+instead left the review to trusted others.
+
+Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
+`Tested-by:` lines as necessary to credit people who helped your
+patch, and "cc:" them when sending such a final version for inclusion.
+
+==== `format-patch` and `send-email`
+
+Learn to use `format-patch` and `send-email` if possible. These commands
are optimized for the workflow of sending patches, avoiding many ways
your existing e-mail client (often optimized for "multipart/*" MIME
type e-mails) might render your patches unusable.
+NOTE: Here we outline the procedure using `format-patch` and
+`send-email`, but you can instead use GitGitGadget to send in your
+patches (see link:MyFirstContribution.html[MyFirstContribution]).
+
People on the Git mailing list need to be able to read and
comment on the changes you are submitting. It is important for
a developer to be able to "quote" your changes, using standard
@@ -415,10 +523,12 @@
your code. For this reason, each patch should be submitted
"inline" in a separate message.
-Multiple related patches should be grouped into their own e-mail
-thread to help readers find all parts of the series. To that end,
-send them as replies to either an additional "cover letter" message
-(see below), the first patch, or the respective preceding patch.
+All subsequent versions of a patch series and other related patches should be
+grouped into their own e-mail thread to help readers find all parts of the
+series. To that end, send them as replies to either an additional "cover
+letter" message (see below), the first patch, or the respective preceding patch.
+Here is a link:MyFirstContribution.html#v2-git-send-email[step-by-step guide] on
+how to submit updated versions of a patch series.
If your log message (including your name on the
`Signed-off-by` trailer) is not writable in ASCII, make sure that
@@ -498,42 +608,93 @@
that starts with `-----BEGIN PGP SIGNED MESSAGE-----`. That is
not a text/plain, it's something else.
-:security-ml-ref: footnoteref:[security-ml]
+=== Handling Conflicts and Iterating Patches
-As mentioned at the beginning of the section, patches that may be
-security relevant should not be submitted to the public mailing list
-mentioned below, but should instead be sent privately to the Git
-Security mailing list{security-ml-ref}.
+When revising changes made to your patches, it's important to
+acknowledge the possibility of conflicts with other ongoing topics. To
+navigate these potential conflicts effectively, follow the recommended
+steps outlined below:
-Send your patch with "To:" set to the mailing list, with "cc:" listing
-people who are involved in the area you are touching (the `git
-contacts` command in `contrib/contacts/` can help to
-identify them), to solicit comments and reviews. Also, when you made
-trial merges of your topic to `next` and `seen`, you may have noticed
-work by others conflicting with your changes. There is a good possibility
-that these people may know the area you are touching well.
+. Build on a suitable base branch, see the <<choose-starting-point, section above>>,
+and format-patch the series. If you are doing "rebase -i" in-place to
+update from the previous round, this will reuse the previous base so
+(2) and (3) may become trivial.
-:current-maintainer: footnote:[The current maintainer: gitster@pobox.com]
-:git-ml: footnote:[The mailing list: git@vger.kernel.org]
+. Find the base of where the last round was queued
++
+ $ mine='kn/ref-transaction-symref'
+ $ git checkout "origin/seen^{/^Merge branch '$mine'}...master"
-After the list reached a consensus that it is a good idea to apply the
-patch, re-send it with "To:" set to the maintainer{current-maintainer}
-and "cc:" the list{git-ml} for inclusion. This is especially relevant
-when the maintainer did not heavily participate in the discussion and
-instead left the review to trusted others.
+. Apply your format-patch result. There are two cases
+.. Things apply cleanly and tests fine. Go to (4).
+.. Things apply cleanly but does not build or test fails, or things do
+not apply cleanly.
++
+In the latter case, you have textual or semantic conflicts coming from
+the difference between the old base and the base you used to build in
+(1). Identify what caused the breakages (e.g., a topic or two may have
+merged since the base used by (2) until the base used by (1)).
++
+Check out the latest 'origin/master' (which may be newer than the base
+used by (2)), "merge --no-ff" the topics you newly depend on in there,
+and use the result of the merge(s) as the base, rebuild the series and
+test again. Run format-patch from the last such merges to the tip of
+your topic. If you did
++
+ $ git checkout origin/master
+ $ git merge --no-ff --into-name kn/ref-transaction-symref fo/obar
+ $ git merge --no-ff --into-name kn/ref-transaction-symref ba/zqux
+ ... rebuild the topic ...
++
+Then you'd just format your topic above these "preparing the ground"
+merges, e.g.
++
+ $ git format-patch "HEAD^{/^Merge branch 'ba/zqux'}"..HEAD
++
+Do not forget to write in the cover letter you did this, including the
+topics you have in your base on top of 'master'. Then go to (4).
-Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
-`Tested-by:` lines as necessary to credit people who helped your
-patch, and "cc:" them when sending such a final version for inclusion.
+. Make a trial merge of your topic into 'next' and 'seen', e.g.
++
+ $ git checkout --detach 'origin/seen'
+ $ git revert -m 1 <the merge of the previous iteration into seen>
+ $ git merge kn/ref-transaction-symref
++
+The "revert" is needed if the previous iteration of your topic is
+already in 'seen' (like in this case). You could choose to rebuild
+master..origin/seen from scratch while excluding your previous
+iteration, which may emulate what happens on the maintainers end more
+closely.
++
+This trial merge may conflict. It is primarily to see what conflicts
+_other_ topics may have with your topic. In other words, you do not
+have to depend on it to make your topic work on 'master'. It may
+become the job of the other topic owners to resolve conflicts if your
+topic goes to 'next' before theirs.
++
+Make a note on what conflict you saw in the cover letter. You do not
+necessarily have to resolve them, but it would be a good opportunity to
+learn what others are doing in related areas.
++
+ $ git checkout --detach 'origin/next'
+ $ git merge kn/ref-transaction-symref
++
+This is to see what conflicts your topic has with other topics that are
+already cooking. This should not conflict if (3)-2 prepared a base on
+top of updated master plus dependent topics taken from 'next'. Unless
+the context is severe (one way to tell is try the same trial merge with
+your old iteration, which may conflict in a similar way), expect that it
+will be handled on maintainers end (if it gets unmanageable, I'll ask to
+rebase when I receive your patches).
== Subsystems with dedicated maintainers
Some parts of the system have dedicated maintainers with their own
repositories.
-- `git-gui/` comes from git-gui project, maintained by Pratyush Yadav:
+- `git-gui/` comes from git-gui project, maintained by Johannes Sixt:
- https://github.com/prati0100/git-gui.git
+ https://github.com/j6t/git-gui
- `gitk-git/` comes from Paul Mackerras's gitk project:
@@ -548,54 +709,12 @@
Patches to these parts should be based on their trees.
-[[patch-flow]]
-== An ideal patch flow
+- The "Git documentation translations" project, led by Jean-Noël
+ Avila, translates our documentation pages. Their work products are
+ maintained separately from this project, not as part of our tree:
-Here is an ideal patch flow for this project the current maintainer
-suggests to the contributors:
+ https://github.com/jnavila/git-manpages-l10n/
-. You come up with an itch. You code it up.
-
-. Send it to the list and cc people who may need to know about
- the change.
-+
-The people who may need to know are the ones whose code you
-are butchering. These people happen to be the ones who are
-most likely to be knowledgeable enough to help you, but
-they have no obligation to help you (i.e. you ask for help,
-don't demand). +git log -p {litdd} _$area_you_are_modifying_+ would
-help you find out who they are.
-
-. You get comments and suggestions for improvements. You may
- even get them in an "on top of your change" patch form.
-
-. Polish, refine, and re-send to the list and the people who
- spend their time to improve your patch. Go back to step (2).
-
-. The list forms consensus that the last round of your patch is
- good. Send it to the maintainer and cc the list.
-
-. A topic branch is created with the patch and is merged to `next`,
- and cooked further and eventually graduates to `master`.
-
-In any time between the (2)-(3) cycle, the maintainer may pick it up
-from the list and queue it to `seen`, in order to make it easier for
-people to play with it without having to pick up and apply the patch to
-their trees themselves.
-
-[[patch-status]]
-== Know the status of your patch after submission
-
-* You can use Git itself to find out when your patch is merged in
- master. `git pull --rebase` will automatically skip already-applied
- patches, and will let you know. This works only if you rebase on top
- of the branch in which your patch has been merged (i.e. it will not
- tell you if your patch is merged in `seen` if you rebase on top of
- master).
-
-* Read the Git mailing list, the maintainer regularly posts messages
- entitled "What's cooking in git.git" giving
- the status of various proposed changes.
== GitHub CI[[GHCI]]
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 70b448b..8c0b3ed 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -316,7 +316,8 @@
Colors may also be given as numbers between 0 and 255; these use ANSI
256-color mode (but note that not all terminals may support this). If
your terminal supports it, you may also specify 24-bit RGB values as
-hex, like `#ff0ab3`.
+hex, like `#ff0ab3`, or 12-bit RGB values like `#f1b`, which is
+equivalent to the 24-bit color `#ff11bb`.
+
The accepted attributes are `bold`, `dim`, `ul`, `blink`, `reverse`,
`italic`, and `strike` (for crossed-out or "strikethrough" letters).
@@ -383,6 +384,8 @@
include::config/attr.txt[]
+include::config/bitmap-pseudo-merge.txt[]
+
include::config/blame.txt[]
include::config/branch.txt[]
@@ -487,6 +490,8 @@
include::config/pretty.txt[]
+include::config/promisor.txt[]
+
include::config/protocol.txt[]
include::config/pull.txt[]
@@ -497,6 +502,8 @@
include::config/receive.txt[]
+include::config/reftable.txt[]
+
include::config/remote.txt[]
include::config/remotes.txt[]
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index 0e35ae5..fa61241 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -96,6 +96,8 @@
`pushNonFFCurrent`, `pushNonFFMatching`, `pushAlreadyExists`,
`pushFetchFirst`, `pushNeedsForce`, and `pushRefNeedsUpdate`
simultaneously.
+ rebaseTodoError::
+ Shown when there is an error after editing the rebase todo list.
refSyntax::
Shown when the user provides an illegal ref name, to
tell the user about the ref syntax documentation.
diff --git a/Documentation/config/alias.txt b/Documentation/config/alias.txt
index 01df96f..2c5db0a 100644
--- a/Documentation/config/alias.txt
+++ b/Documentation/config/alias.txt
@@ -21,8 +21,23 @@
it will be treated as a shell command. For example, defining
`alias.new = !gitk --all --not ORIG_HEAD`, the invocation
`git new` is equivalent to running the shell command
-`gitk --all --not ORIG_HEAD`. Note that shell commands will be
-executed from the top-level directory of a repository, which may
-not necessarily be the current directory.
-`GIT_PREFIX` is set as returned by running `git rev-parse --show-prefix`
-from the original current directory. See linkgit:git-rev-parse[1].
+`gitk --all --not ORIG_HEAD`. Note:
++
+* Shell commands will be executed from the top-level directory of a
+ repository, which may not necessarily be the current directory.
+* `GIT_PREFIX` is set as returned by running `git rev-parse --show-prefix`
+ from the original current directory. See linkgit:git-rev-parse[1].
+* Shell command aliases always receive any extra arguments provided to
+ the Git command-line as positional arguments.
+** Care should be taken if your shell alias is a "one-liner" script
+ with multiple commands (e.g. in a pipeline), references multiple
+ arguments, or is otherwise not able to handle positional arguments
+ added at the end. For example: `alias.cmd = "!echo $1 | grep $2"`
+ called as `git cmd 1 2` will be executed as 'echo $1 | grep $2
+ 1 2', which is not what you want.
+** A convenient way to deal with this is to write your script
+ operations in an inline function that is then called with any
+ arguments from the command-line. For example `alias.cmd = "!c() {
+ echo $1 | grep $2 ; }; c" will correctly execute the prior example.
+** Setting `GIT_TRACE=1` can help you debug the command being run for
+ your alias.
diff --git a/Documentation/config/bitmap-pseudo-merge.txt b/Documentation/config/bitmap-pseudo-merge.txt
new file mode 100644
index 0000000..1f264ec
--- /dev/null
+++ b/Documentation/config/bitmap-pseudo-merge.txt
@@ -0,0 +1,91 @@
+NOTE: The configuration options in `bitmapPseudoMerge.*` are considered
+EXPERIMENTAL and may be subject to change or be removed entirely in the
+future. For more information about the pseudo-merge bitmap feature, see
+the "Pseudo-merge bitmaps" section of linkgit:gitpacking[7].
+
+bitmapPseudoMerge.<name>.pattern::
+ Regular expression used to match reference names. Commits
+ pointed to by references matching this pattern (and meeting
+ the below criteria, like `bitmapPseudoMerge.<name>.sampleRate`
+ and `bitmapPseudoMerge.<name>.threshold`) will be considered
+ for inclusion in a pseudo-merge bitmap.
++
+Commits are grouped into pseudo-merge groups based on whether or not
+any reference(s) that point at a given commit match the pattern, which
+is an extended regular expression.
++
+Within a pseudo-merge group, commits may be further grouped into
+sub-groups based on the capture groups in the pattern. These
+sub-groupings are formed from the regular expressions by concatenating
+any capture groups from the regular expression, with a '-' dash in
+between.
++
+For example, if the pattern is `refs/tags/`, then all tags (provided
+they meet the below criteria) will be considered candidates for the
+same pseudo-merge group. However, if the pattern is instead
+`refs/remotes/([0-9])+/tags/`, then tags from different remotes will
+be grouped into separate pseudo-merge groups, based on the remote
+number.
+
+bitmapPseudoMerge.<name>.decay::
+ Determines the rate at which consecutive pseudo-merge bitmap
+ groups decrease in size. Must be non-negative. This parameter
+ can be thought of as `k` in the function `f(n) = C * n^-k`,
+ where `f(n)` is the size of the `n`th group.
++
+Setting the decay rate equal to `0` will cause all groups to be the
+same size. Setting the decay rate equal to `1` will cause the `n`th
+group to be `1/n` the size of the initial group. Higher values of the
+decay rate cause consecutive groups to shrink at an increasing rate.
+The default is `1`.
++
+If all groups are the same size, it is possible that groups containing
+newer commits will be able to be used less often than earlier groups,
+since it is more likely that the references pointing at newer commits
+will be updated more often than a reference pointing at an old commit.
+
+bitmapPseudoMerge.<name>.sampleRate::
+ Determines the proportion of non-bitmapped commits (among
+ reference tips) which are selected for inclusion in an
+ unstable pseudo-merge bitmap. Must be between `0` and `1`
+ (inclusive). The default is `1`.
+
+bitmapPseudoMerge.<name>.threshold::
+ Determines the minimum age of non-bitmapped commits (among
+ reference tips, as above) which are candidates for inclusion
+ in an unstable pseudo-merge bitmap. The default is
+ `1.week.ago`.
+
+bitmapPseudoMerge.<name>.maxMerges::
+ Determines the maximum number of pseudo-merge commits among
+ which commits may be distributed.
++
+For pseudo-merge groups whose pattern does not contain any capture
+groups, this setting is applied for all commits matching the regular
+expression. For patterns that have one or more capture groups, this
+setting is applied for each distinct capture group.
++
+For example, if your capture group is `refs/tags/`, then this setting
+will distribute all tags into a maximum of `maxMerges` pseudo-merge
+commits. However, if your capture group is, say,
+`refs/remotes/([0-9]+)/tags/`, then this setting will be applied to
+each remote's set of tags individually.
++
+Must be non-negative. The default value is 64.
+
+bitmapPseudoMerge.<name>.stableThreshold::
+ Determines the minimum age of commits (among reference tips,
+ as above, however stable commits are still considered
+ candidates even when they have been covered by a bitmap) which
+ are candidates for a stable a pseudo-merge bitmap. The default
+ is `1.month.ago`.
++
+Setting this threshold to a smaller value (e.g., 1.week.ago) will cause
+more stable groups to be generated (which impose a one-time generation
+cost) but those groups will likely become stale over time. Using a
+larger value incurs the opposite penalty (fewer stable groups which are
+more useful).
+
+bitmapPseudoMerge.<name>.stableSize::
+ Determines the size (in number of commits) of a stable
+ psuedo-merge bitmap. The default is `512`.
diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt
index 5ce7b91..190bda1 100644
--- a/Documentation/config/diff.txt
+++ b/Documentation/config/diff.txt
@@ -79,6 +79,15 @@
you want to use an external diff program only on a subset of
your files, you might want to use linkgit:gitattributes[5] instead.
+diff.trustExitCode::
+ If this boolean value is set to true then the
+ `diff.external` command is expected to return exit code
+ 0 if it considers the input files to be equal or 1 if it
+ considers them to be different, like `diff(1)`.
+ If it is set to false, which is the default, then the command
+ is expected to return exit code 0 regardless of equality.
+ Any other exit code causes Git to report a fatal error.
+
diff.ignoreSubmodules::
Sets the default value of --ignore-submodules. Note that this
affects only 'git diff' Porcelain, and not lower level 'diff'
@@ -164,6 +173,15 @@
The custom diff driver command. See linkgit:gitattributes[5]
for details.
+diff.<driver>.trustExitCode::
+ If this boolean value is set to true then the
+ `diff.<driver>.command` command is expected to return exit code
+ 0 if it considers the input files to be equal or 1 if it
+ considers them to be different, like `diff(1)`.
+ If it is set to false, which is the default, then the command
+ is expected to return exit code 0 regardless of equality.
+ Any other exit code causes Git to report a fatal error.
+
diff.<driver>.xfuncname::
The regular expression that the diff driver should use to
recognize the hunk header. A built-in pattern may also be used.
diff --git a/Documentation/config/interactive.txt b/Documentation/config/interactive.txt
index 5cc2655..8b876cb 100644
--- a/Documentation/config/interactive.txt
+++ b/Documentation/config/interactive.txt
@@ -1,8 +1,8 @@
interactive.singleKey::
- In interactive commands, allow the user to provide one-letter
- input with a single key (i.e., without hitting enter).
- Currently this is used by the `--patch` mode of
- linkgit:git-add[1], linkgit:git-checkout[1],
+ When set to true, allow the user to provide one-letter input
+ with a single key (i.e., without hitting the Enter key) in
+ interactive commands. This is currently used by the `--patch`
+ mode of linkgit:git-add[1], linkgit:git-checkout[1],
linkgit:git-restore[1], linkgit:git-commit[1],
linkgit:git-reset[1], and linkgit:git-stash[1].
diff --git a/Documentation/config/promisor.txt b/Documentation/config/promisor.txt
new file mode 100644
index 0000000..98c5cb2
--- /dev/null
+++ b/Documentation/config/promisor.txt
@@ -0,0 +1,3 @@
+promisor.quiet::
+ If set to "true" assume `--quiet` when fetching additional
+ objects for a partial clone.
diff --git a/Documentation/config/reftable.txt b/Documentation/config/reftable.txt
new file mode 100644
index 0000000..0515727
--- /dev/null
+++ b/Documentation/config/reftable.txt
@@ -0,0 +1,48 @@
+reftable.blockSize::
+ The size in bytes used by the reftable backend when writing blocks.
+ The block size is determined by the writer, and does not have to be a
+ power of 2. The block size must be larger than the longest reference
+ name or log entry used in the repository, as references cannot span
+ blocks.
++
+Powers of two that are friendly to the virtual memory system or
+filesystem (such as 4kB or 8kB) are recommended. Larger sizes (64kB) can
+yield better compression, with a possible increased cost incurred by
+readers during access.
++
+The largest block size is `16777215` bytes (15.99 MiB). The default value is
+`4096` bytes (4kB). A value of `0` will use the default value.
+
+reftable.restartInterval::
+ The interval at which to create restart points. The reftable backend
+ determines the restart points at file creation. Every 16 may be
+ more suitable for smaller block sizes (4k or 8k), every 64 for larger
+ block sizes (64k).
++
+More frequent restart points reduces prefix compression and increases
+space consumed by the restart table, both of which increase file size.
++
+Less frequent restart points makes prefix compression more effective,
+decreasing overall file size, with increased penalties for readers
+walking through more records after the binary search step.
++
+A maximum of `65535` restart points per block is supported.
++
+The default value is to create restart points every 16 records. A value of `0`
+will use the default value.
+
+reftable.indexObjects::
+ Whether the reftable backend shall write object blocks. Object blocks
+ are a reverse mapping of object ID to the references pointing to them.
++
+The default value is `true`.
+
+reftable.geometricFactor::
+ Whenever the reftable backend appends a new table to the stack, it
+ performs auto compaction to ensure that there is only a handful of
+ tables. The backend does this by ensuring that tables form a geometric
+ sequence regarding the respective sizes of each table.
++
+By default, the geometric sequence uses a factor of 2, meaning that for any
+table, the next-biggest table must at least be twice as big. A maximum factor
+of 256 is supported.
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt
index 577df40..2d45c98 100644
--- a/Documentation/config/safe.txt
+++ b/Documentation/config/safe.txt
@@ -44,7 +44,8 @@
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.
+that you deem safe. Giving a directory with `/*` appended to it will
+allow access to all repositories under the named directory.
+
As explained, Git only allows you to access repositories owned by
yourself, i.e. the user who is running Git, by default. When Git
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 0e94569..cd0b81a 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -329,12 +329,13 @@
linkgit:git-config[1]).
--name-only::
- Show only names of changed files. The file names are often encoded in UTF-8.
+ Show only the name of each changed file in the post-image tree.
+ The file names are often encoded in UTF-8.
For more information see the discussion about encoding in the linkgit:git-log[1]
manual page.
--name-status::
- Show only names and status of changed files. See the description
+ Show only the name(s) and status of each changed file. See the description
of the `--diff-filter` option on what the status letters mean.
Just like `--name-only` the file names are often encoded in UTF-8.
@@ -819,6 +820,11 @@
--quiet::
Disable all output of the program. Implies `--exit-code`.
+ Disables execution of external diff helpers whose exit code
+ is not trusted, i.e. their respective configuration option
+ `diff.trustExitCode` or `diff.<driver>.trustExitCode` or
+ environment variable `GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE` is
+ false.
endif::git-log[]
endif::git-format-patch[]
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 624a6e6..69d5cc9 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -18,7 +18,7 @@
[--quoted-cr=<action>]
[--empty=(stop|drop|keep)]
[(<mbox> | <Maildir>)...]
-'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)] | --allow-empty)
+'git am' (--continue | --skip | --abort | --quit | --retry | --show-current-patch[=(diff|raw)] | --allow-empty)
DESCRIPTION
-----------
@@ -208,6 +208,12 @@
Abort the patching operation but keep HEAD and the index
untouched.
+--retry::
+ Try to apply the last conflicting patch again. This is generally
+ only useful for passing extra options to the retry attempt
+ (e.g., `--3way`), since otherwise you'll just see the same
+ failure again.
+
--show-current-patch[=(diff|raw)]::
Show the message at which `git am` has stopped due to
conflicts. If `raw` is specified, show the raw contents of
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index ac61113..65c645d 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -9,21 +9,14 @@
SYNOPSIS
--------
[verse]
-'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] <name> [<value> [<value-pattern>]]
-'git config' [<file-option>] [--type=<type>] [--comment=<message>] --add <name> <value>
-'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] --replace-all <name> <value> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get <name> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get-all <name> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] [--name-only] --get-regexp <name-regex> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch <name> <URL>
-'git config' [<file-option>] [--fixed-value] --unset <name> [<value-pattern>]
-'git config' [<file-option>] [--fixed-value] --unset-all <name> [<value-pattern>]
-'git config' [<file-option>] --rename-section <old-name> <new-name>
-'git config' [<file-option>] --remove-section <name>
-'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
-'git config' [<file-option>] --get-color <name> [<default>]
+'git config list' [<file-option>] [<display-option>] [--includes]
+'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>
+'git config set' [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>
+'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>
+'git config rename-section' [<file-option>] <old-name> <new-name>
+'git config remove-section' [<file-option>] <name>
+'git config edit' [<file-option>]
'git config' [<file-option>] --get-colorbool <name> [<stdout-is-tty>]
-'git config' [<file-option>] -e | --edit
DESCRIPTION
-----------
@@ -31,7 +24,7 @@
actually the section and the key separated by a dot, and the value will be
escaped.
-Multiple lines can be added to an option by using the `--add` option.
+Multiple lines can be added to an option by using the `--append` option.
If you want to update or unset an option which can occur on multiple
lines, a `value-pattern` (which is an extended regular expression,
unless the `--fixed-value` option is given) needs to be given. Only the
@@ -74,6 +67,42 @@
A list of all available configuration variables can be obtained using the
`git help --config` command.
+COMMANDS
+--------
+
+list::
+ List all variables set in config file, along with their values.
+
+get::
+ Emits the value of the specified key. If key is present multiple times
+ in the configuration, emits the last value. If `--all` is specified,
+ emits all values associated with key. Returns error code 1 if key is
+ not present.
+
+set::
+ Set value for one or more config options. By default, this command
+ refuses to write multi-valued config options. Passing `--all` will
+ replace all multi-valued config options with the new value, whereas
+ `--value=` will replace all config options whose values match the given
+ pattern.
+
+unset::
+ Unset value for one or more config options. By default, this command
+ refuses to unset multi-valued keys. Passing `--all` will unset all
+ multi-valued config options, whereas `--value` will unset all config
+ options whose values match the given pattern.
+
+rename-section::
+ Rename the given section to a new name.
+
+remove-section::
+ Remove the given section from the configuration file.
+
+edit::
+ Opens an editor to modify the specified config file; either
+ `--system`, `--global`, `--local` (default), `--worktree`, or
+ `--file <config-file>`.
+
[[OPTIONS]]
OPTIONS
-------
@@ -82,10 +111,9 @@
Default behavior is to replace at most one line. This replaces
all lines matching the key (and optionally the `value-pattern`).
---add::
+--append::
Adds a new line to the option without altering any existing
- values. This is the same as providing '^$' as the `value-pattern`
- in `--replace-all`.
+ values. This is the same as providing '--value=^$' in `set`.
--comment <message>::
Append a comment at the end of new or modified lines.
@@ -99,22 +127,16 @@
not contain linefeed characters (no multi-line comments are
permitted).
---get::
- Get the value for a given key (optionally filtered by a regex
- matching the value). Returns error code 1 if the key was not
- found and the last value if multiple key values were found.
+--all::
+ With `get`, return all values for a multi-valued key.
---get-all::
- Like get, but returns all values for a multi-valued key.
+---regexp::
+ With `get`, interpret the name as a regular expression. Regular
+ expression matching is currently case-sensitive and done against a
+ canonicalized version of the key in which section and variable names
+ are lowercased, but subsection names are not.
---get-regexp::
- Like --get-all, but interprets the name as a regular expression and
- writes out the key names. Regular expression matching is currently
- case-sensitive and done against a canonicalized version of the key
- in which section and variable names are lowercased, but subsection
- names are not.
-
---get-urlmatch <name> <URL>::
+--url=<URL>::
When given a two-part <name> as <section>.<key>, the value for
<section>.<URL>.<key> whose <URL> part matches the best to the
given URL is returned (if no such key exists, the value for
@@ -178,22 +200,6 @@
section in linkgit:gitrevisions[7] for a more complete list of
ways to spell blob names.
---remove-section::
- Remove the given section from the configuration file.
-
---rename-section::
- Rename the given section to a new name.
-
---unset::
- Remove the line matching the key from config file.
-
---unset-all::
- Remove all lines matching the key from config file.
-
--l::
---list::
- List all variables set in config file, along with their values.
-
--fixed-value::
When used with the `value-pattern` argument, treat `value-pattern` as
an exact string instead of a regular expression. This will restrict
@@ -248,8 +254,8 @@
contain line breaks.
--name-only::
- Output only the names of config variables for `--list` or
- `--get-regexp`.
+ Output only the names of config variables for `list` or
+ `get`.
--show-origin::
Augment the output of all queried config options with the
@@ -273,23 +279,6 @@
When the color setting for `name` is undefined, the command uses
`color.ui` as fallback.
---get-color <name> [<default>]::
-
- Find the color configured for `name` (e.g. `color.diff.new`) and
- output it as the ANSI color escape sequence to the standard
- output. The optional `default` parameter is used instead, if
- there is no color configured for `name`.
-+
-`--type=color [--default=<default>]` is preferred over `--get-color`
-(but note that `--get-color` will omit the trailing newline printed by
-`--type=color`).
-
--e::
---edit::
- Opens an editor to modify the specified config file; either
- `--system`, `--global`, `--local` (default), `--worktree`, or
- `--file <config-file>`.
-
--[no-]includes::
Respect `include.*` directives in config files when looking up
values. Defaults to `off` when a specific file is given (e.g.,
@@ -297,14 +286,64 @@
config files.
--default <value>::
- When using `--get`, and the requested variable is not found, behave as if
+ When using `get`, and the requested variable is not found, behave as if
<value> were the value assigned to that variable.
+DEPRECATED MODES
+----------------
+
+The following modes have been deprecated in favor of subcommands. It is
+recommended to migrate to the new syntax.
+
+'git config <name>'::
+ Replaced by `git config get <name>`.
+
+'git config <name> <value> [<value-pattern>]'::
+ Replaced by `git config set [--value=<pattern>] <name> <value>`.
+
+-l::
+--list::
+ Replaced by `git config list`.
+
+--get <name> [<value-pattern>]::
+ Replaced by `git config get [--value=<pattern>] <name>`.
+
+--get-all <name> [<value-pattern>]::
+ Replaced by `git config get [--value=<pattern>] --all --show-names <name>`.
+
+--get-regexp <name-regexp>::
+ Replaced by `git config get --all --show-names --regexp <name-regexp>`.
+
+--get-urlmatch <name> <URL>::
+ Replaced by `git config get --all --show-names --url=<URL> <name>`.
+
+--get-color <name> [<default>]::
+ Replaced by `git config get --type=color [--default=<default>] <name>`.
+
+--add <name> <value>::
+ Replaced by `git config set --append <name> <value>`.
+
+--unset <name> [<value-pattern>]::
+ Replaced by `git config unset [--value=<pattern>] <name>`.
+
+--unset-all <name> [<value-pattern>]::
+ Replaced by `git config unset [--value=<pattern>] --all <name>`.
+
+--rename-section <old-name> <new-name>::
+ Replaced by `git config rename-section <old-name> <new-name>`.
+
+--remove-section <name>::
+ Replaced by `git config remove-section <name>`.
+
+-e::
+--edit::
+ Replaced by `git config edit`.
+
CONFIGURATION
-------------
`pager.config` is only respected when listing configuration, i.e., when
-using `--list` or any of the `--get-*` which may return multiple results.
-The default is to use a pager.
+using `list` or `get` which may return multiple results. The default is to use
+a pager.
[[FILES]]
FILES
@@ -346,8 +385,8 @@
values of a key from all files will be used.
By default, options are only written to the repository specific
-configuration file. Note that this also affects options like `--replace-all`
-and `--unset`. *'git config' will only ever change one file at a time*.
+configuration file. Note that this also affects options like `set`
+and `unset`. *'git config' will only ever change one file at a time*.
You can limit which configuration sources are read from or written to by
specifying the path of a file with the `--file` option, or by specifying a
@@ -482,7 +521,7 @@
you can set the filemode to true with
------------
-% git config core.filemode true
+% git config set core.filemode true
------------
The hypothetical proxy command entries actually have a postfix to discern
@@ -490,7 +529,7 @@
to "ssh".
------------
-% git config core.gitproxy '"ssh" for kernel.org' 'for kernel.org$'
+% git config set --value='for kernel.org$' core.gitproxy '"ssh" for kernel.org'
------------
This makes sure that only the key/value pair for kernel.org is replaced.
@@ -498,7 +537,7 @@
To delete the entry for renames, do
------------
-% git config --unset diff.renames
+% git config unset diff.renames
------------
If you want to delete an entry for a multivar (like core.gitproxy above),
@@ -507,51 +546,45 @@
To query the value for a given key, do
------------
-% git config --get core.filemode
-------------
-
-or
-
-------------
-% git config core.filemode
+% git config get core.filemode
------------
or, to query a multivar:
------------
-% git config --get core.gitproxy "for kernel.org$"
+% git config get --value="for kernel.org$" core.gitproxy
------------
If you want to know all the values for a multivar, do:
------------
-% git config --get-all core.gitproxy
+% git config get --all --show-names core.gitproxy
------------
If you like to live dangerously, you can replace *all* core.gitproxy by a
new one with
------------
-% git config --replace-all core.gitproxy ssh
+% git config set --all core.gitproxy ssh
------------
However, if you really only want to replace the line for the default proxy,
i.e. the one without a "for ..." postfix, do something like this:
------------
-% git config core.gitproxy ssh '! for '
+% git config set --value='! for ' core.gitproxy ssh
------------
To actually match only values with an exclamation mark, you have to
------------
-% git config section.key value '[!]'
+% git config set --value='[!]' section.key value
------------
To add a new proxy, without altering any of the existing ones, use
------------
-% git config --add core.gitproxy '"proxy-command" for example.com'
+% git config set --append core.gitproxy '"proxy-command" for example.com'
------------
An example to use customized color from the configuration in your
@@ -559,8 +592,8 @@
------------
#!/bin/sh
-WS=$(git config --get-color color.diff.whitespace "blue reverse")
-RESET=$(git config --get-color "" "reset")
+WS=$(git config get --type=color --default="blue reverse" color.diff.whitespace)
+RESET=$(git config get --type=color --default="reset" "")
echo "${WS}your whitespace color or blue reverse${RESET}"
------------
@@ -568,11 +601,11 @@
false, while it is set to `true` for all others:
------------
-% git config --type=bool --get-urlmatch http.sslverify https://good.example.com
+% git config get --type=bool --url=https://good.example.com http.sslverify
true
-% git config --type=bool --get-urlmatch http.sslverify https://weak.example.com
+% git config get --type=bool --url=https://weak.example.com http.sslverify
false
-% git config --get-urlmatch http https://weak.example.com
+% git config get --url=https://weak.example.com http
http.cookieFile /tmp/cookie.txt
http.sslverify false
------------
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index 918a0aa..e414932 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -8,7 +8,7 @@
SYNOPSIS
--------
------------------
-'git credential' (fill|approve|reject)
+'git credential' (fill|approve|reject|capability)
------------------
DESCRIPTION
@@ -41,6 +41,9 @@
any configured credential helpers, which may erase any stored
credentials matching the description.
+If the action is `capability`, git-credential will announce any capabilities
+it supports to standard output.
+
If the action is `approve` or `reject`, no output should be emitted.
TYPICAL USE OF GIT CREDENTIAL
@@ -111,7 +114,9 @@
separated by an `=` (equals) sign, followed by a newline.
The key may contain any bytes except `=`, newline, or NUL. The value may
-contain any bytes except newline or NUL.
+contain any bytes except newline or NUL. A line, including the trailing
+newline, may not exceed 65535 bytes in order to allow implementations to
+parse efficiently.
Attributes with keys that end with C-style array brackets `[]` can have
multiple values. Each instance of a multi-valued attribute forms an
@@ -178,6 +183,61 @@
Components which are missing from the URL (e.g., there is no
username in the example above) will be left unset.
+`authtype`::
+ This indicates that the authentication scheme in question should be used.
+ Common values for HTTP and HTTPS include `basic`, `bearer`, and `digest`,
+ although the latter is insecure and should not be used. If `credential`
+ is used, this may be set to an arbitrary string suitable for the protocol in
+ question (usually HTTP).
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`credential`::
+ The pre-encoded credential, suitable for the protocol in question (usually
+ HTTP). If this key is sent, `authtype` is mandatory, and `username` and
+ `password` are not used. For HTTP, Git concatenates the `authtype` value and
+ this value with a single space to determine the `Authorization` header.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`ephemeral`::
+ This boolean value indicates, if true, that the value in the `credential`
+ field should not be saved by the credential helper because its usefulness is
+ limited in time. For example, an HTTP Digest `credential` value is computed
+ using a nonce and reusing it will not result in successful authentication.
+ This may also be used for situations with short duration (e.g., 24-hour)
+ credentials. The default value is false.
++
+The credential helper will still be invoked with `store` or `erase` so that it
+can determine whether the operation was successful.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`state[]`::
+ This value provides an opaque state that will be passed back to this helper
+ if it is called again. Each different credential helper may specify this
+ once. The value should include a prefix unique to the credential helper and
+ should ignore values that don't match its prefix.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`continue`::
+ This is a boolean value, which, if enabled, indicates that this
+ authentication is a non-final part of a multistage authentication step. This
+ is common in protocols such as NTLM and Kerberos, where two rounds of client
+ authentication are required, and setting this flag allows the credential
+ helper to implement the multistage authentication step. This flag should
+ only be sent if a further stage is required; that is, if another round of
+ authentication is expected.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input. This attribute is 'one-way' from a credential helper to
+pass information to Git (or other programs invoking `git credential`).
+
`wwwauth[]`::
When an HTTP response is received by Git that includes one or more
@@ -189,7 +249,45 @@
they appear in the HTTP response. This attribute is 'one-way' from Git
to pass additional information to credential helpers.
-Unrecognised attributes are silently discarded.
+`capability[]`::
+ This signals that Git, or the helper, as appropriate, supports the capability
+ in question. This can be used to provide better, more specific data as part
+ of the protocol. A `capability[]` directive must precede any value depending
+ on it and these directives _should_ be the first item announced in the
+ protocol.
++
+There are two currently supported capabilities. The first is `authtype`, which
+indicates that the `authtype`, `credential`, and `ephemeral` values are
+understood. The second is `state`, which indicates that the `state[]` and
+`continue` values are understood.
++
+It is not obligatory to use the additional features just because the capability
+is supported, but they should not be provided without the capability.
+
+Unrecognised attributes and capabilities are silently discarded.
+
+[[CAPA-IOFMT]]
+CAPABILITY INPUT/OUTPUT FORMAT
+------------------------------
+
+For `git credential capability`, the format is slightly different. First, a
+`version 0` announcement is made to indicate the current version of the
+protocol, and then each capability is announced with a line like `capability
+authtype`. Credential helpers may also implement this format, again with the
+`capability` argument. Additional lines may be added in the future; callers
+should ignore lines which they don't understand.
+
+Because this is a new part of the credential helper protocol, older versions of
+Git, as well as some credential helpers, may not support it. If a non-zero
+exit status is received, or if the first line doesn't start with the word
+`version` and a space, callers should assume that no capabilities are supported.
+
+The intention of this format is to differentiate it from the credential output
+in an unambiguous way. It is possible to use very simple credential helpers
+(e.g., inline shell scripts) which always produce identical output. Using a
+distinct format allows users to continue to use this syntax without having to
+worry about correctly implementing capability advertisements or accidentally
+confusing callers querying for capabilities.
GIT
---
diff --git a/Documentation/git-for-each-repo.txt b/Documentation/git-for-each-repo.txt
index 94bd19d..abe3527 100644
--- a/Documentation/git-for-each-repo.txt
+++ b/Documentation/git-for-each-repo.txt
@@ -42,6 +42,15 @@
as available. If `git for-each-repo` is run in a directory that is not a
Git repository, then only the system and global config is used.
+--keep-going::
+ Continue with the remaining repositories if the command failed
+ on a repository. The exit code will still indicate that the
+ overall operation was not successful.
++
+Note that the exact exit code of the failing command is not passed
+through as the exit code of the `for-each-repo` command: If the command
+failed in any of the specified repositories, the overall exit code will
+be 1.
SUBPROCESS BEHAVIOR
-------------------
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 728bb38..8708b31 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -20,7 +20,7 @@
[--in-reply-to=<message-id>] [--suffix=.<sfx>]
[--ignore-if-in-upstream] [--always]
[--cover-from-description=<mode>]
- [--rfc] [--subject-prefix=<subject-prefix>]
+ [--rfc[=<rfc>]] [--subject-prefix=<subject-prefix>]
[(--reroll-count|-v) <n>]
[--to=<email>] [--cc=<email>]
[--[no-]cover-letter] [--quiet]
@@ -238,10 +238,21 @@
value of the `format.filenameMaxLength` configuration
variable, or 64 if unconfigured.
---rfc::
- Prepends "RFC" to the subject prefix (producing "RFC PATCH" by
- default). RFC means "Request For Comments"; use this when sending
- an experimental patch for discussion rather than application.
+--rfc[=<rfc>]::
+ Prepends the string _<rfc>_ (defaults to "RFC") to
+ the subject prefix. As the subject prefix defaults to
+ "PATCH", you'll get "RFC PATCH" by default.
++
+RFC means "Request For Comments"; use this when sending
+an experimental patch for discussion rather than application.
+"--rfc=WIP" may also be a useful way to indicate that a patch
+is not complete yet ("WIP" stands for "Work In Progress").
++
+If the convention of the receiving community for a particular extra
+string is to have it _after_ the subject prefix, the string _<rfc>_
+can be prefixed with a dash ("`-`") to signal that the the rest of
+the _<rfc>_ string should be appended to the subject prefix instead,
+e.g., `--rfc='-(WIP)'` results in "PATCH (WIP)".
-v <n>::
--reroll-count=<n>::
@@ -346,6 +357,11 @@
between the previous and current series of patches by adjusting the
creation/deletion cost fudge factor. See linkgit:git-range-diff[1])
for details.
++
+Defaults to 999 (the linkgit:git-range-diff[1] uses 60), as the use
+case is to show comparison with an older iteration of the same
+topic and the tool should find more correspondence between the two
+sets of patches.
--notes[=<ref>]::
--no-notes::
diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt
index e8f3ccb..f5b02ef 100644
--- a/Documentation/git-gui.txt
+++ b/Documentation/git-gui.txt
@@ -114,7 +114,7 @@
The official repository of the 'git gui' project can be found at:
- https://github.com/prati0100/git-gui.git/
+ https://github.com/j6t/git-gui
GIT
---
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 1c4f696..76c86c3 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -9,7 +9,7 @@
SYNOPSIS
--------
[verse]
-'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]
+'git ls-remote' [--branches] [--tags] [--refs] [--upload-pack=<exec>]
[-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
[--symref] [<repository> [<patterns>...]]
@@ -21,14 +21,16 @@
OPTIONS
-------
--h::
---heads::
+-b::
+--branches::
-t::
--tags::
- Limit to only refs/heads and refs/tags, respectively.
+ Limit to only local branches and local tags, respectively.
These options are _not_ mutually exclusive; when given
both, references stored in refs/heads and refs/tags are
- displayed. Note that `git ls-remote -h` used without
+ displayed. Note that `--heads` and `-h` are deprecated
+ synonyms for `--branches` and `-b` and may be removed in
+ the future. Also note that `git ls-remote -h` used without
anything else on the command line gives help, consistent
with other git subcommands.
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index dd388fa..84cb2ed 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -72,6 +72,11 @@
As the merge-base is provided directly, <branch1> and <branch2> do not need
to specify commits; trees are enough.
+-X<option>::
+--strategy-option=<option>::
+ Pass the merge strategy-specific option through to the merge strategy.
+ See linkgit:git-merge[1] for details.
+
[[OUTPUT]]
OUTPUT
------
diff --git a/Documentation/git-refs.txt b/Documentation/git-refs.txt
new file mode 100644
index 0000000..5b99e04
--- /dev/null
+++ b/Documentation/git-refs.txt
@@ -0,0 +1,61 @@
+git-refs(1)
+===========
+
+NAME
+----
+git-refs - Low-level access to refs
+
+
+SYNOPSIS
+--------
+[verse]
+'git refs migrate' --ref-format=<format> [--dry-run]
+
+DESCRIPTION
+-----------
+
+This command provides low-level access to refs.
+
+COMMANDS
+--------
+
+migrate::
+ Migrate ref store between different formats.
+
+OPTIONS
+-------
+
+The following options are specific to 'git refs migrate':
+
+--ref-format=<format>::
+ The ref format to migrate the ref store to. Can be one of:
++
+include::ref-storage-format.txt[]
+
+--dry-run::
+ Perform the migration, but do not modify the repository. The migrated
+ refs will be written into a separate directory that can be inspected
+ separately. The name of the directory will be reported on stdout. This
+ can be used to double check that the migration works as expected before
+ performing the actual migration.
+
+KNOWN LIMITATIONS
+-----------------
+
+The ref format migration has several known limitations in its current form:
+
+* It is not possible to migrate repositories that have reflogs.
+
+* It is not possible to migrate repositories that have worktrees.
+
+* There is no way to block concurrent writes to the repository during an
+ ongoing migration. Concurrent writes can lead to an inconsistent migrated
+ state. Users are expected to block writes on a higher level. If your
+ repository is registered for scheduled maintenance, it is recommended to
+ unregister it first with git-maintenance(1).
+
+These limitations may eventually be lifted.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index f9d5a35..dc12d38 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -18,8 +18,15 @@
(i.e. parameters that begin with a dash '-') and parameters
meant for the underlying 'git rev-list' command they use internally
and flags and parameters for the other commands they use
-downstream of 'git rev-list'. This command is used to
-distinguish between them.
+downstream of 'git rev-list'. The primary purpose of this command
+is to allow calling programs to distinguish between them. There are
+a few other operation modes that have nothing to do with the above
+"help parse command line options".
+
+Unless otherwise specified, most of the options and operation modes
+require you to run this command inside a git repository or a working
+tree that is under the control of a git repository, and will give you
+a fatal error otherwise.
OPTIONS
@@ -32,11 +39,15 @@
--parseopt::
Use 'git rev-parse' in option parsing mode (see PARSEOPT section below).
+ The command in this mode can be used outside a repository or
+ a working tree controlled by a repository.
--sq-quote::
Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
section below). In contrast to the `--sq` option below, this
mode only does quoting. Nothing else is done to command input.
+ The command in this mode can be used outside a repository or
+ a working tree controlled by a repository.
Options for --parseopt
~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index ba75747..616d919 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -9,8 +9,8 @@
--------
[verse]
'git show-ref' [--head] [-d | --dereference]
- [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]
- [--heads] [--] [<pattern>...]
+ [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]
+ [--] [<pattern>...]
'git show-ref' --verify [-q | --quiet] [-d | --dereference]
[-s | --hash[=<n>]] [--abbrev[=<n>]]
[--] [<ref>...]
@@ -45,12 +45,14 @@
Show the HEAD reference, even if it would normally be filtered out.
---heads::
+--branches::
--tags::
- Limit to "refs/heads" and "refs/tags", respectively. These options
+ Limit to local branches and local tags, respectively. These options
are not mutually exclusive; when given both, references stored in
- "refs/heads" and "refs/tags" are displayed.
+ "refs/heads" and "refs/tags" are displayed. Note that `--heads`
+ is a deprecated synonym for `--branches` and may be removed
+ in the future.
-d::
--dereference::
@@ -139,7 +141,7 @@
For example,
-----------------------------------------------------------------------------
-$ git show-ref --heads --hash
+$ git show-ref --branches --hash
2e3ba0114a1f52b47df29743d6915d056be13278
185008ae97960c8d551adcd9e23565194651b5d1
03adf42c988195b50e1a1935ba5fcbc39b2b029b
@@ -183,8 +185,8 @@
actually want to show any results, and we want to use the full refname for it
in order to not trigger the problem with ambiguous partial matches).
-To show only tags, or only proper branch heads, use `--tags` and/or `--heads`
-respectively (using both means that it shows tags and heads, but not other
+To show only tags, or only proper branch heads, use `--tags` and/or `--branches`
+respectively (using both means that it shows tags and branches, but not other
random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the `-d` or `--dereference`
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 5fe519c..4494729 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -10,6 +10,7 @@
--------
[verse]
'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]
+ [(--trailer <token>[(=|:)<value>])...]
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
'git tag' [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
@@ -31,8 +32,8 @@
`-m <msg>` or `-F <file>` is given, an editor is started for the user to type
in the tag message.
-If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <key-id>`
-are absent, `-a` is implied.
+If `-m <msg>` or `-F <file>` or `--trailer <token>[=<value>]` is given
+and `-a`, `-s`, and `-u <key-id>` are absent, `-a` is implied.
Otherwise, a tag reference that points directly at the given object
(i.e., a lightweight tag) is created.
@@ -178,6 +179,17 @@
Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
is given.
+--trailer <token>[(=|:)<value>]::
+ Specify a (<token>, <value>) pair that should be applied as a
+ trailer. (e.g. `git tag --trailer "Custom-Key: value"`
+ will add a "Custom-Key" trailer to the tag message.)
+ The `trailer.*` configuration variables
+ (linkgit:git-interpret-trailers[1]) can be used to define if
+ a duplicated trailer is omitted, where in the run of trailers
+ each trailer would appear, and other details.
+ The trailers can be extracted in `git tag --list`, using
+ `--format="%(trailers)"` placeholder.
+
-e::
--edit::
The message taken from file with `-F` and command line with
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 8c47890..7128aed 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -25,6 +25,7 @@
[--really-refresh] [--unresolve] [--again | -g]
[--info-only] [--index-info]
[-z] [--stdin] [--index-version <n>]
+ [--show-index-version]
[--verbose]
[--] [<file>...]
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 374a2eb..afcf33c 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -65,6 +65,10 @@
create SP <ref> SP <new-oid> LF
delete SP <ref> [SP <old-oid>] LF
verify SP <ref> [SP <old-oid>] LF
+ symref-update SP <ref> SP <new-target> [SP (ref SP <old-target> | oid SP <old-oid>)] LF
+ symref-create SP <ref> SP <new-target> LF
+ symref-delete SP <ref> [SP <old-target>] LF
+ symref-verify SP <ref> [SP <old-target>] LF
option SP <opt> LF
start LF
prepare LF
@@ -86,6 +90,10 @@
create SP <ref> NUL <new-oid> NUL
delete SP <ref> NUL [<old-oid>] NUL
verify SP <ref> NUL [<old-oid>] NUL
+ symref-update SP <ref> NUL <new-target> [NUL (ref NUL <old-target> | oid NUL <old-oid>)] NUL
+ symref-create SP <ref> NUL <new-target> NUL
+ symref-delete SP <ref> [NUL <old-target>] NUL
+ symref-verify SP <ref> [NUL <old-target>] NUL
option SP <opt> NUL
start NUL
prepare NUL
@@ -113,10 +121,27 @@
Delete <ref> after verifying it exists with <old-oid>, if
given. If given, <old-oid> may not be zero.
+symref-update::
+ Set <ref> to <new-target> after verifying <old-target> or <old-oid>,
+ if given. Specify a zero <old-oid> to ensure that the ref does not
+ exist before the update.
+
verify::
Verify <ref> against <old-oid> but do not change it. If
<old-oid> is zero or missing, the ref must not exist.
+symref-create:
+ Create symbolic ref <ref> with <new-target> after verifying
+ it does not exist.
+
+symref-delete::
+ Delete <ref> after verifying it exists with <old-target>, if given.
+
+symref-verify::
+ Verify symbolic <ref> against <old-target> but do not change it.
+ If <old-target> is missing, the ref must not exist. Can only be
+ used in `no-deref` mode.
+
option::
Modify the behavior of the next command naming a <ref>.
The only valid option is `no-deref` to avoid dereferencing
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 024a01d..4489e22 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -11,9 +11,10 @@
[verse]
'git' [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
- [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
- [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
- [--config-env=<name>=<envvar>] <command> [<args>]
+ [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]
+ [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]
+ [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]
+ <command> [<args>]
DESCRIPTION
-----------
@@ -186,6 +187,13 @@
This is equivalent to setting the `GIT_NO_LAZY_FETCH`
environment variable to `1`.
+--no-optional-locks::
+ Do not perform optional operations that require locks. This is
+ equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`.
+
+--no-advice::
+ Disable all advice hints from being printed.
+
--literal-pathspecs::
Treat pathspecs literally (i.e. no globbing, no pathspec magic).
This is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
@@ -207,10 +215,6 @@
Add "icase" magic to all pathspec. This is equivalent to setting
the `GIT_ICASE_PATHSPECS` environment variable to `1`.
---no-optional-locks::
- Do not perform optional operations that require locks. This is
- equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`.
-
--list-cmds=<group>[,<group>...]::
List commands by group. This is an internal/experimental
option and may change or be removed in the future. Supported
@@ -640,6 +644,16 @@
For each path `GIT_EXTERNAL_DIFF` is called, two environment variables,
`GIT_DIFF_PATH_COUNTER` and `GIT_DIFF_PATH_TOTAL` are set.
+`GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE`::
+ If this Boolean environment variable is set to true then the
+ `GIT_EXTERNAL_DIFF` command is expected to return exit code
+ 0 if it considers the input files to be equal or 1 if it
+ considers them to be different, like `diff(1)`.
+ If it is set to false, which is the default, then the command
+ is expected to return exit code 0 regardless of equality.
+ Any other exit code causes Git to report a fatal error.
+
+
`GIT_DIFF_PATH_COUNTER`::
A 1-based counter incremented by one for every path.
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 4338d02..80cae17 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -776,6 +776,11 @@
parameters, just like `GIT_EXTERNAL_DIFF` program is called.
See linkgit:git[1] for details.
+If the program is able to ignore certain changes (similar to
+`git diff --ignore-space-change`), then also set the option
+`trustExitCode` to true. It is then expected to return exit code 1 if
+it finds significant changes and 0 if it doesn't.
+
Setting the internal diff algorithm
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index ee9b92c..06e9971 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -486,7 +486,7 @@
This hook is invoked by any Git command that performs reference
updates. It executes whenever a reference transaction is prepared,
committed or aborted and may thus get called multiple times. The hook
-does not cover symbolic references (but that may change in the future).
+also supports symbolic reference updates.
The hook takes exactly one argument, which is the current state the
given reference transaction is in:
@@ -503,16 +503,20 @@
For each reference update that was added to the transaction, the hook
receives on standard input a line of the format:
- <old-oid> SP <new-oid> SP <ref-name> LF
+ <old-value> SP <new-value> SP <ref-name> LF
-where `<old-oid>` is the old object name passed into the reference
-transaction, `<new-oid>` is the new object name to be stored in the
+where `<old-value>` is the old object name passed into the reference
+transaction, `<new-value>` is the new object name to be stored in the
ref and `<ref-name>` is the full name of the ref. When force updating
the reference regardless of its current value or when the reference is
-to be created anew, `<old-oid>` is the all-zeroes object name. To
+to be created anew, `<old-value>` is the all-zeroes object name. To
distinguish these cases, you can inspect the current value of
`<ref-name>` via `git rev-parse`.
+For symbolic reference updates the `<old_value>` and `<new-value>`
+fields could denote references instead of objects. A reference will be
+denoted with a 'ref:' prefix, like `ref:<ref-target>`.
+
The exit status of the hook is ignored for any state except for the
"prepared" state. In the "prepared" state, a non-zero exit status will
cause the transaction to be aborted. The hook will not be called with
diff --git a/Documentation/gitpacking.txt b/Documentation/gitpacking.txt
new file mode 100644
index 0000000..4a6fcba
--- /dev/null
+++ b/Documentation/gitpacking.txt
@@ -0,0 +1,189 @@
+gitpacking(7)
+=============
+
+NAME
+----
+gitpacking - Advanced concepts related to packing in Git
+
+SYNOPSIS
+--------
+gitpacking
+
+DESCRIPTION
+-----------
+
+This document aims to describe some advanced concepts related to packing
+in Git.
+
+Many concepts are currently described scattered between manual pages of
+various Git commands, including linkgit:git-pack-objects[1],
+linkgit:git-repack[1], and others, as well as linkgit:gitformat-pack[5],
+and parts of the `Documentation/technical` tree.
+
+There are many aspects of packing in Git that are not covered in this
+document that instead live in the aforementioned areas. Over time, those
+scattered bits may coalesce into this document.
+
+== Pseudo-merge bitmaps
+
+NOTE: Pseudo-merge bitmaps are considered an experimental feature, so
+the configuration and many of the ideas are subject to change.
+
+=== Background
+
+Reachability bitmaps are most efficient when we have on-disk stored
+bitmaps for one or more of the starting points of a traversal. For this
+reason, Git prefers storing bitmaps for commits at the tips of refs,
+because traversals tend to start with those points.
+
+But if you have a large number of refs, it's not feasible to store a
+bitmap for _every_ ref tip. It takes up space, and just OR-ing all of
+those bitmaps together is expensive.
+
+One way we can deal with that is to create bitmaps that represent
+_groups_ of refs. When a traversal asks about the entire group, then we
+can use this single bitmap instead of considering each ref individually.
+Because these bitmaps represent the set of objects which would be
+reachable in a hypothetical merge of all of the commits, we call them
+pseudo-merge bitmaps.
+
+=== Overview
+
+A "pseudo-merge bitmap" is used to refer to a pair of bitmaps, as
+follows:
+
+Commit bitmap::
+
+ A bitmap whose set bits describe the set of commits included in the
+ pseudo-merge's "merge" bitmap (as below).
+
+Merge bitmap::
+
+ A bitmap whose set bits describe the reachability closure over the set
+ of commits in the pseudo-merge's "commits" bitmap (as above). An
+ identical bitmap would be generated for an octopus merge with the same
+ set of parents as described in the commits bitmap.
+
+Pseudo-merge bitmaps can accelerate bitmap traversals when all commits
+for a given pseudo-merge are listed on either side of the traversal,
+either directly (by explicitly asking for them as part of the `HAVES`
+or `WANTS`) or indirectly (by encountering them during a fill-in
+traversal).
+
+=== Use-cases
+
+For example, suppose there exists a pseudo-merge bitmap with a large
+number of commits, all of which are listed in the `WANTS` section of
+some bitmap traversal query. When pseudo-merge bitmaps are enabled, the
+bitmap machinery can quickly determine there is a pseudo-merge which
+satisfies some subset of the wanted objects on either side of the query.
+Then, we can inflate the EWAH-compressed bitmap, and `OR` it in to the
+resulting bitmap. By contrast, without pseudo-merge bitmaps, we would
+have to repeat the decompression and `OR`-ing step over a potentially
+large number of individual bitmaps, which can take proportionally more
+time.
+
+Another benefit of pseudo-merges arises when there is some combination
+of (a) a large number of references, with (b) poor bitmap coverage, and
+(c) deep, nested trees, making fill-in traversal relatively expensive.
+For example, suppose that there are a large enough number of tags where
+bitmapping each of the tags individually is infeasible. Without
+pseudo-merge bitmaps, computing the result of, say, `git rev-list
+--use-bitmap-index --count --objects --tags` would likely require a
+large amount of fill-in traversal. But when a large quantity of those
+tags are stored together in a pseudo-merge bitmap, the bitmap machinery
+can take advantage of the fact that we only care about the union of
+objects reachable from all of those tags, and answer the query much
+faster.
+
+=== Configuration
+
+Reference tips are grouped into different pseudo-merge groups according
+to two criteria. A reference name matches one or more of the defined
+pseudo-merge patterns, and optionally one or more capture groups within
+that pattern which further partition the group.
+
+Within a group, commits may be considered "stable", or "unstable"
+depending on their age. These are adjusted by setting the
+`bitmapPseudoMerge.<name>.stableThreshold` and
+`bitmapPseudoMerge.<name>.threshold` configuration values, respectively.
+
+All stable commits are grouped into pseudo-merges of equal size
+(`bitmapPseudoMerge.<name>.stableSize`). If the `stableSize`
+configuration is set to, say, 100, then the first 100 commits (ordered
+by committer date) which are older than the `stableThreshold` value will
+form one group, the next 100 commits will form another group, and so on.
+
+Among unstable commits, the pseudo-merge machinery will attempt to
+combine older commits into large groups as opposed to newer commits
+which will appear in smaller groups. This is based on the heuristic that
+references whose tip commit is older are less likely to be modified to
+point at a different commit than a reference whose tip commit is newer.
+
+The size of groups is determined by a power-law decay function, and the
+decay parameter roughly corresponds to "k" in `f(n) = C*n^(-k/100)`,
+where `f(n)` describes the size of the `n`-th pseudo-merge group. The
+sample rate controls what percentage of eligible commits are considered
+as candidates. The threshold parameter indicates the minimum age (so as
+to avoid including too-recent commits in a pseudo-merge group, making it
+less likely to be valid). The "maxMerges" parameter sets an upper-bound
+on the number of pseudo-merge commits an individual group
+
+The "stable"-related parameters control "stable" pseudo-merge groups,
+comprised of a fixed number of commits which are older than the
+configured "stable threshold" value and may be grouped together in
+chunks of "stableSize" in order of age.
+
+The exact configuration for pseudo-merges is as follows:
+
+include::config/bitmap-pseudo-merge.txt[]
+
+=== Examples
+
+Suppose that you have a repository with a large number of references,
+and you want a bare-bones configuration of pseudo-merge bitmaps that
+will enhance bitmap coverage of the `refs/` namespace. You may start
+wiht a configuration like so:
+
+ [bitmapPseudoMerge "all"]
+ pattern = "refs/"
+ threshold = now
+ stableThreshold = never
+ sampleRate = 100
+ maxMerges = 64
+
+This will create pseudo-merge bitmaps for all references, regardless of
+their age, and group them into 64 pseudo-merge commits.
+
+If you wanted to separate tags from branches when generating
+pseudo-merge commits, you would instead define the pattern with a
+capture group, like so:
+
+ [bitmapPseudoMerge "all"]
+ pattern = "refs/(heads/tags)/"
+
+Suppose instead that you are working in a fork-network repository, with
+each fork specified by some numeric ID, and whose refs reside in
+`refs/virtual/NNN/` (where `NNN` is the numeric ID corresponding to some
+fork) in the network. In this instance, you may instead write something
+like:
+
+ [bitmapPseudoMerge "all"]
+ pattern = "refs/virtual/([0-9]+)/(heads|tags)/"
+ threshold = now
+ stableThreshold = never
+ sampleRate = 100
+ maxMerges = 64
+
+Which would generate pseudo-merge group identifiers like "1234-heads",
+and "5678-tags" (for branches in fork "1234", and tags in remote "5678",
+respectively).
+
+SEE ALSO
+--------
+linkgit:git-pack-objects[1]
+linkgit:git-repack[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index d71b199..30b394a 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -497,20 +497,18 @@
unusual refs.
[[def_pseudoref]]pseudoref::
- Pseudorefs are a class of files under `$GIT_DIR` which behave
- like refs for the purposes of rev-parse, but which are treated
- specially by git. Pseudorefs both have names that are all-caps,
- and always start with a line consisting of a
- <<def_SHA1,SHA-1>> followed by whitespace. So, HEAD is not a
- pseudoref, because it is sometimes a symbolic ref. They might
- optionally contain some additional data. `MERGE_HEAD` and
- `CHERRY_PICK_HEAD` are examples. Unlike
- <<def_per_worktree_ref,per-worktree refs>>, these files cannot
- be symbolic refs, and never have reflogs. They also cannot be
- updated through the normal ref update machinery. Instead,
- they are updated by directly writing to the files. However,
- they can be read as if they were refs, so `git rev-parse
- MERGE_HEAD` will work.
+ A ref that has different semantics than normal refs. These refs can be
+ read via normal Git commands, but cannot be written to by commands like
+ linkgit:git-update-ref[1].
++
+The following pseudorefs are known to Git:
+
+ - `FETCH_HEAD` is written by linkgit:git-fetch[1] or linkgit:git-pull[1]. It
+ may refer to multiple object IDs. Each object ID is annotated with metadata
+ indicating where it was fetched from and its fetch status.
+
+ - `MERGE_HEAD` is written by linkgit:git-merge[1] when resolving merge
+ conflicts. It contains all commit IDs which are being merged.
[[def_pull]]pull::
Pulling a <<def_branch,branch>> means to <<def_fetch,fetch>> it and
@@ -552,20 +550,38 @@
to the result.
[[def_ref]]ref::
- A name that begins with `refs/` (e.g. `refs/heads/master`)
- that points to an <<def_object_name,object name>> or another
- ref (the latter is called a <<def_symref,symbolic ref>>).
+ A name that that points to an <<def_object_name,object name>> or
+ another ref (the latter is called a <<def_symref,symbolic ref>>).
For convenience, a ref can sometimes be abbreviated when used
as an argument to a Git command; see linkgit:gitrevisions[7]
for details.
Refs are stored in the <<def_repository,repository>>.
+
The ref namespace is hierarchical.
-Different subhierarchies are used for different purposes (e.g. the
-`refs/heads/` hierarchy is used to represent local branches).
+Ref names must either start with `refs/` or be located in the root of
+the hierarchy. For the latter, their name must follow these rules:
+
-There are a few special-purpose refs that do not begin with `refs/`.
-The most notable example is `HEAD`.
+ - The name consists of only upper-case characters or underscores.
+
+ - The name ends with "`_HEAD`" or is equal to "`HEAD`".
++
+There are some irregular refs in the root of the hierarchy that do not
+match these rules. The following list is exhaustive and shall not be
+extended in the future:
++
+ - `AUTO_MERGE`
+
+ - `BISECT_EXPECTED_REV`
+
+ - `NOTES_MERGE_PARTIAL`
+
+ - `NOTES_MERGE_REF`
+
+ - `MERGE_AUTOSTASH`
++
+Different subhierarchies are used for different purposes. For example,
+the `refs/heads/` hierarchy is used to represent local branches whereas
+the `refs/tags/` hierarchy is used to represent local tags..
[[def_reflog]]reflog::
A reflog shows the local "history" of a ref. In other words,
@@ -576,7 +592,8 @@
[[def_refspec]]refspec::
A "refspec" is used by <<def_fetch,fetch>> and
<<def_push,push>> to describe the mapping between remote
- <<def_ref,ref>> and local ref.
+ <<def_ref,ref>> and local ref. See linkgit:git-fetch[1] or
+ linkgit:git-push[1] for details.
[[def_remote]]remote repository::
A <<def_repository,repository>> which is used to track the same
@@ -638,20 +655,6 @@
An <<def_object,object>> used to temporarily store the contents of a
<<def_dirty,dirty>> working directory and the index for future reuse.
-[[def_special_ref]]special ref::
- A ref that has different semantics than normal refs. These refs can be
- accessed via normal Git commands but may not behave the same as a
- normal ref in some cases.
-+
-The following special refs are known to Git:
-
- - "`FETCH_HEAD`" is written by linkgit:git-fetch[1] or linkgit:git-pull[1]. It
- may refer to multiple object IDs. Each object ID is annotated with metadata
- indicating where it was fetched from and its fetch status.
-
- - "`MERGE_HEAD`" is written by linkgit:git-merge[1] when resolving merge
- conflicts. It contains all commit IDs which are being merged.
-
[[def_submodule]]submodule::
A <<def_repository,repository>> that holds the history of a
separate project inside another repository (the latter of
diff --git a/Documentation/lint-manpages.sh b/Documentation/lint-manpages.sh
new file mode 100755
index 0000000..92cfc0a
--- /dev/null
+++ b/Documentation/lint-manpages.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+extract_variable () {
+ (
+ cat ../Makefile
+ cat <<EOF
+print_variable:
+ @\$(foreach b,\$($1),echo XXX \$(b:\$X=) YYY;)
+EOF
+ ) |
+ make -C .. -f - print_variable 2>/dev/null |
+ sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p'
+}
+
+check_missing_docs () (
+ ret=0
+
+ for v in $ALL_COMMANDS
+ do
+ case "$v" in
+ git-merge-octopus) continue;;
+ git-merge-ours) continue;;
+ git-merge-recursive) continue;;
+ git-merge-resolve) continue;;
+ git-merge-subtree) continue;;
+ git-fsck-objects) continue;;
+ git-init-db) continue;;
+ git-remote-*) continue;;
+ git-stage) continue;;
+ git-legacy-*) continue;;
+ git-?*--?* ) continue ;;
+ esac
+
+ if ! test -f "$v.txt"
+ then
+ echo "no doc: $v"
+ ret=1
+ fi
+
+ if ! sed -e '1,/^### command list/d' -e '/^#/d' ../command-list.txt |
+ grep -q "^$v[ ]"
+ then
+ case "$v" in
+ git)
+ ;;
+ *)
+ echo "no link: $v"
+ ret=1
+ ;;
+ esac
+ fi
+ done
+
+ exit $ret
+)
+
+check_extraneous_docs () {
+ (
+ sed -e '1,/^### command list/d' \
+ -e '/^#/d' \
+ -e '/guide$/d' \
+ -e '/interfaces$/d' \
+ -e 's/[ ].*//' \
+ -e 's/^/listed /' ../command-list.txt
+ make print-man1 |
+ grep '\.txt$' |
+ sed -e 's|^|documented |' \
+ -e 's/\.txt//'
+ ) | (
+ all_commands="$(printf "%s " "$ALL_COMMANDS" "$BUILT_INS" "$EXCLUDED_PROGRAMS" | tr '\n' ' ')"
+ ret=0
+
+ while read how cmd
+ do
+ case " $all_commands " in
+ *" $cmd "*) ;;
+ *)
+ echo "removed but $how: $cmd"
+ ret=1;;
+ esac
+ done
+
+ exit $ret
+ )
+}
+
+BUILT_INS="$(extract_variable BUILT_INS)"
+ALL_COMMANDS="$(extract_variable ALL_COMMANDS)"
+EXCLUDED_PROGRAMS="$(extract_variable EXCLUDED_PROGRAMS)"
+
+findings=$(
+ if ! check_missing_docs
+ then
+ ret=1
+ fi
+
+ if ! check_extraneous_docs
+ then
+ ret=1
+ fi
+
+ exit $ret
+)
+ret=$?
+
+printf "%s" "$findings" | sort
+
+exit $ret
diff --git a/Documentation/technical/bitmap-format.txt b/Documentation/technical/bitmap-format.txt
index f5d2009..bfb0ec7 100644
--- a/Documentation/technical/bitmap-format.txt
+++ b/Documentation/technical/bitmap-format.txt
@@ -255,3 +255,144 @@
xor_row (4 byte integer, network byte order): ::
The position of the triplet whose bitmap is used to compress
this one, or `0xffffffff` if no such bitmap exists.
+
+Pseudo-merge bitmaps
+--------------------
+
+If the `BITMAP_OPT_PSEUDO_MERGES` flag is set, a variable number of
+bytes (preceding the name-hash cache, commit lookup table, and trailing
+checksum) of the `.bitmap` file is used to store pseudo-merge bitmaps.
+
+For more information on what pseudo-merges are, why they are useful, and
+how to configure them, see the information in linkgit:gitpacking[7].
+
+=== File format
+
+If enabled, pseudo-merge bitmaps are stored in an optional section at
+the end of a `.bitmap` file. The format is as follows:
+
+....
++-------------------------------------------+
+| .bitmap File |
++-------------------------------------------+
+| |
+| Pseudo-merge bitmaps (Variable Length) |
+| +---------------------------+ |
+| | commits_bitmap (EWAH) | |
+| +---------------------------+ |
+| | merge_bitmap (EWAH) | |
+| +---------------------------+ |
+| |
++-------------------------------------------+
+| |
+| Lookup Table |
+| +---------------------------+ |
+| | commit_pos (4 bytes) | |
+| +---------------------------+ |
+| | offset (8 bytes) | |
+| +------------+--------------+ |
+| |
+| Offset Cases: |
+| ------------- |
+| |
+| 1. MSB Unset: single pseudo-merge bitmap |
+| + offset to pseudo-merge bitmap |
+| |
+| 2. MSB Set: multiple pseudo-merges |
+| + offset to extended lookup table |
+| |
++-------------------------------------------+
+| |
+| Extended Lookup Table (Optional) |
+| +----+----------+----------+----------+ |
+| | N | Offset 1 | .... | Offset N | |
+| +----+----------+----------+----------+ |
+| | | 8 bytes | .... | 8 bytes | |
+| +----+----------+----------+----------+ |
+| |
++-------------------------------------------+
+| |
+| Pseudo-merge position table |
+| +----+----------+----------+----------+ |
+| | N | Offset 1 | .... | Offset N | |
+| +----+----------+----------+----------+ |
+| | | 8 bytes | .... | 8 bytes | |
+| +----+----------+----------+----------+ |
+| |
++-------------------------------------------+
+| |
+| Pseudo-merge Metadata |
+| +-----------------------------------+ |
+| | # pseudo-merges (4 bytes) | |
+| +-----------------------------------+ |
+| | # commits (4 bytes) | |
+| +-----------------------------------+ |
+| | Lookup offset (8 bytes) | |
+| +-----------------------------------+ |
+| | Extension size (8 bytes) | |
+| +-----------------------------------+ |
+| |
++-------------------------------------------+
+....
+
+* One or more pseudo-merge bitmaps, each containing:
+
+ ** `commits_bitmap`, an EWAH-compressed bitmap describing the set of
+ commits included in the this psuedo-merge.
+
+ ** `merge_bitmap`, an EWAH-compressed bitmap describing the union of
+ the set of objects reachable from all commits listed in the
+ `commits_bitmap`.
+
+* A lookup table, mapping pseudo-merged commits to the pseudo-merges
+ they belong to. Entries appear in increasing order of each commit's
+ bit position. Each entry is 12 bytes wide, and is comprised of the
+ following:
+
+ ** `commit_pos`, a 4-byte unsigned value (in network byte-order)
+ containing the bit position for this commit.
+
+ ** `offset`, an 8-byte unsigned value (also in network byte-order)
+ containing either one of two possible offsets, depending on whether or
+ not the most-significant bit is set.
+
+ *** If unset (i.e. `offset & ((uint64_t)1<<63) == 0`), the offset
+ (relative to the beginning of the `.bitmap` file) at which the
+ pseudo-merge bitmap for this commit can be read. This indicates
+ only a single pseudo-merge bitmap contains this commit.
+
+ *** If set (i.e. `offset & ((uint64_t)1<<63) != 0`), the offset
+ (again relative to the beginning of the `.bitmap` file) at which
+ the extended offset table can be located describing the set of
+ pseudo-merge bitmaps which contain this commit. This indicates
+ that multiple pseudo-merge bitmaps contain this commit.
+
+* An (optional) extended lookup table (written if and only if there is
+ at least one commit which appears in more than one pseudo-merge).
+ There are as many entries as commits which appear in multiple
+ pseudo-merges. Each entry contains the following:
+
+ ** `N`, a 4-byte unsigned value equal to the number of pseudo-merges
+ which contain a given commit.
+
+ ** An array of `N` 8-byte unsigned values, each of which is
+ interpreted as an offset (relative to the beginning of the
+ `.bitmap` file) at which a pseudo-merge bitmap for this commit can
+ be read. These values occur in no particular order.
+
+* Positions for all pseudo-merges, each stored as an 8-byte unsigned
+ value (in network byte-order) containing the offset (relative to the
+ beginning of the `.bitmap` file) of each consecutive pseudo-merge.
+
+* A 4-byte unsigned value (in network byte-order) equal to the number of
+ pseudo-merges.
+
+* A 4-byte unsigned value (in network byte-order) equal to the number of
+ unique commits which appear in any pseudo-merge.
+
+* An 8-byte unsigned value (in network byte-order) equal to the number
+ of bytes between the start of the pseudo-merge section and the
+ beginning of the lookup table.
+
+* An 8-byte unsigned value (in network byte-order) equal to the number
+ of bytes in the pseudo-merge section (including this field).
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index eb53b0e..814cdcf 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.45.2
+DEF_VER=v2.45.GIT
LF='
'
diff --git a/Makefile b/Makefile
index 1e31acc..3eab701 100644
--- a/Makefile
+++ b/Makefile
@@ -409,6 +409,9 @@
# to the "<name>" of the corresponding `compat/fsmonitor/fsm-settings-<name>.c`
# that implements the `fsm_os_settings__*()` routines.
#
+# Define LINK_FUZZ_PROGRAMS if you want `make all` to also build the fuzz test
+# programs in oss-fuzz/.
+#
# === Optional library: libintl ===
#
# Define NO_GETTEXT if you don't want Git output to be translated.
@@ -752,23 +755,6 @@
ETAGS_TARGET = TAGS
-# If you add a new fuzzer, please also make sure to run it in
-# ci/run-build-and-minimal-fuzzers.sh so that we make sure it still links and
-# runs in the future.
-FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o
-FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
-FUZZ_OBJS += oss-fuzz/fuzz-config.o
-FUZZ_OBJS += oss-fuzz/fuzz-date.o
-FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
-FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
-.PHONY: fuzz-objs
-fuzz-objs: $(FUZZ_OBJS)
-
-# Always build fuzz objects even if not testing, to prevent bit-rot.
-all:: $(FUZZ_OBJS)
-
-FUZZ_PROGRAMS += $(patsubst %.o,%,$(filter-out %dummy-cmd-main.o,$(FUZZ_OBJS)))
-
# Empty...
EXTRA_PROGRAMS =
@@ -807,7 +793,7 @@
TEST_BUILTINS_OBJS += test-dump-split-index.o
TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
TEST_BUILTINS_OBJS += test-env-helper.o
-TEST_BUILTINS_OBJS += test-example-decorate.o
+TEST_BUILTINS_OBJS += test-example-tap.o
TEST_BUILTINS_OBJS += test-find-pack.o
TEST_BUILTINS_OBJS += test-fsmonitor-client.o
TEST_BUILTINS_OBJS += test-genrandom.o
@@ -824,7 +810,6 @@
TEST_BUILTINS_OBJS += test-mktemp.o
TEST_BUILTINS_OBJS += test-oid-array.o
TEST_BUILTINS_OBJS += test-oidmap.o
-TEST_BUILTINS_OBJS += test-oidtree.o
TEST_BUILTINS_OBJS += test-online-cpus.o
TEST_BUILTINS_OBJS += test-pack-mtimes.o
TEST_BUILTINS_OBJS += test-parse-options.o
@@ -852,7 +837,6 @@
TEST_BUILTINS_OBJS += test-sha256.o
TEST_BUILTINS_OBJS += test-sigchain.o
TEST_BUILTINS_OBJS += test-simple-ipc.o
-TEST_BUILTINS_OBJS += test-strcmp-offset.o
TEST_BUILTINS_OBJS += test-string-list.o
TEST_BUILTINS_OBJS += test-submodule-config.o
TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
@@ -1119,6 +1103,7 @@
LIB_OBJS += protocol.o
LIB_OBJS += protocol-caps.o
LIB_OBJS += prune-packed.o
+LIB_OBJS += pseudo-merge.o
LIB_OBJS += quote.o
LIB_OBJS += range-diff.o
LIB_OBJS += reachable.o
@@ -1296,6 +1281,7 @@
BUILTIN_OBJS += builtin/rebase.o
BUILTIN_OBJS += builtin/receive-pack.o
BUILTIN_OBJS += builtin/reflog.o
+BUILTIN_OBJS += builtin/refs.o
BUILTIN_OBJS += builtin/remote-ext.o
BUILTIN_OBJS += builtin/remote-fd.o
BUILTIN_OBJS += builtin/remote.o
@@ -1347,14 +1333,21 @@
THIRD_PARTY_SOURCES += sha1collisiondetection/%
THIRD_PARTY_SOURCES += sha1dc/%
-UNIT_TEST_PROGRAMS += t-basic
-UNIT_TEST_PROGRAMS += t-mem-pool
-UNIT_TEST_PROGRAMS += t-strbuf
UNIT_TEST_PROGRAMS += t-ctype
+UNIT_TEST_PROGRAMS += t-example-decorate
+UNIT_TEST_PROGRAMS += t-hash
+UNIT_TEST_PROGRAMS += t-mem-pool
+UNIT_TEST_PROGRAMS += t-oidtree
UNIT_TEST_PROGRAMS += t-prio-queue
+UNIT_TEST_PROGRAMS += t-reftable-basics
+UNIT_TEST_PROGRAMS += t-strbuf
+UNIT_TEST_PROGRAMS += t-strcmp-offset
+UNIT_TEST_PROGRAMS += t-strvec
+UNIT_TEST_PROGRAMS += t-trailer
UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
+UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o
# xdiff and reftable libs may in turn depend on what is in libgit.a
GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
@@ -1458,8 +1451,8 @@
ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
endif
-ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS)
-ALL_LDFLAGS = $(LDFLAGS)
+ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_APPEND)
+ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
ifdef SANITIZE
SANITIZERS := $(foreach flag,$(subst $(comma),$(space),$(SANITIZE)),$(flag))
@@ -2373,6 +2366,29 @@
endif
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
+# If you add a new fuzzer, please also make sure to run it in
+# ci/run-build-and-minimal-fuzzers.sh so that we make sure it still links and
+# runs in the future.
+FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o
+FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
+FUZZ_OBJS += oss-fuzz/fuzz-config.o
+FUZZ_OBJS += oss-fuzz/fuzz-date.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
+.PHONY: fuzz-objs
+fuzz-objs: $(FUZZ_OBJS)
+
+# Always build fuzz objects even if not testing, to prevent bit-rot.
+all:: $(FUZZ_OBJS)
+
+FUZZ_PROGRAMS += $(patsubst %.o,%,$(filter-out %dummy-cmd-main.o,$(FUZZ_OBJS)))
+
+# Build fuzz programs when possible, even without the necessary fuzzing support,
+# to prevent bit-rot.
+ifdef LINK_FUZZ_PROGRAMS
+all:: $(FUZZ_PROGRAMS)
+endif
+
please_set_SHELL_PATH_to_a_more_modern_shell:
@$$(:)
@@ -2656,20 +2672,17 @@
REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o
-REFTABLE_OBJS += reftable/refname.o
REFTABLE_OBJS += reftable/generic.o
REFTABLE_OBJS += reftable/stack.o
REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o
-REFTABLE_TEST_OBJS += reftable/basics_test.o
REFTABLE_TEST_OBJS += reftable/block_test.o
REFTABLE_TEST_OBJS += reftable/dump.o
REFTABLE_TEST_OBJS += reftable/merged_test.o
REFTABLE_TEST_OBJS += reftable/pq_test.o
REFTABLE_TEST_OBJS += reftable/record_test.o
REFTABLE_TEST_OBJS += reftable/readwrite_test.o
-REFTABLE_TEST_OBJS += reftable/refname_test.o
REFTABLE_TEST_OBJS += reftable/stack_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
REFTABLE_TEST_OBJS += reftable/tree_test.o
@@ -3228,7 +3241,7 @@
.PRECIOUS: $(TEST_OBJS)
-t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
+t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) $(UNIT_TEST_DIR)/test-lib.o
t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(REFTABLE_TEST_LIB)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
@@ -3749,42 +3762,6 @@
.PHONY: check-docs
check-docs::
$(MAKE) -C Documentation lint-docs
- @(for v in $(patsubst %$X,%,$(ALL_COMMANDS)); \
- do \
- case "$$v" in \
- git-merge-octopus | git-merge-ours | git-merge-recursive | \
- git-merge-resolve | git-merge-subtree | \
- git-fsck-objects | git-init-db | \
- git-remote-* | git-stage | git-legacy-* | \
- git-?*--?* ) continue ;; \
- esac ; \
- test -f "Documentation/$$v.txt" || \
- echo "no doc: $$v"; \
- sed -e '1,/^### command list/d' -e '/^#/d' command-list.txt | \
- grep -q "^$$v[ ]" || \
- case "$$v" in \
- git) ;; \
- *) echo "no link: $$v";; \
- esac ; \
- done; \
- ( \
- sed -e '1,/^### command list/d' \
- -e '/^#/d' \
- -e '/guide$$/d' \
- -e '/interfaces$$/d' \
- -e 's/[ ].*//' \
- -e 's/^/listed /' command-list.txt; \
- $(MAKE) -C Documentation print-man1 | \
- grep '\.txt$$' | \
- sed -e 's|^|documented |' \
- -e 's/\.txt//'; \
- ) | while read how cmd; \
- do \
- case " $(patsubst %$X,%,$(ALL_COMMANDS) $(BUILT_INS) $(EXCLUDED_PROGRAMS)) " in \
- *" $$cmd "*) ;; \
- *) echo "removed but $$how: $$cmd" ;; \
- esac; \
- done ) | sort
### Make sure built-ins do not have dups and listed in git.c
#
@@ -3858,28 +3835,31 @@
#
# An example command to build against libFuzzer from LLVM 11.0.0:
#
-# make CC=clang CXX=clang++ \
+# make CC=clang FUZZ_CXX=clang++ \
# CFLAGS="-fsanitize=fuzzer-no-link,address" \
# LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \
# fuzz-all
#
+FUZZ_CXX ?= $(CC)
FUZZ_CXXFLAGS ?= $(ALL_CFLAGS)
.PHONY: fuzz-all
+fuzz-all: $(FUZZ_PROGRAMS)
$(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) GIT-LDFLAGS
- $(QUIET_LINK)$(CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) \
+ $(QUIET_LINK)$(FUZZ_CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) \
-Wl,--allow-multiple-definition \
$(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE)
-fuzz-all: $(FUZZ_PROGRAMS)
-
-$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o $(UNIT_TEST_DIR)/test-lib.o $(GITLIBS) GIT-LDFLAGS
+$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o \
+ $(UNIT_TEST_DIR)/test-lib.o \
+ $(UNIT_TEST_DIR)/lib-oid.o \
+ $(GITLIBS) GIT-LDFLAGS
$(call mkdir_p_parent_template)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(filter %.a,$^) $(LIBS)
.PHONY: build-unit-tests unit-tests
build-unit-tests: $(UNIT_TEST_PROGS)
-unit-tests: $(UNIT_TEST_PROGS)
+unit-tests: $(UNIT_TEST_PROGS) t/helper/test-tool$X
$(MAKE) -C t/ unit-tests
diff --git a/RelNotes b/RelNotes
index 2079120..cc696fc 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.45.2.txt
\ No newline at end of file
+Documentation/RelNotes/2.46.0.txt
\ No newline at end of file
diff --git a/add-interactive.c b/add-interactive.c
index e17602b..b5d6cd6 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -532,8 +532,9 @@
size_t *binary_count)
{
struct object_id head_oid;
- int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- &head_oid, NULL);
+ int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING,
+ &head_oid, NULL);
struct collection_status s = { 0 };
int i;
@@ -761,8 +762,10 @@
size_t count, i, j;
struct object_id oid;
- int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
- NULL);
+ int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING,
+ &oid,
+ NULL);
struct lock_file index_lock;
const char **paths;
struct tree *tree;
@@ -990,8 +993,10 @@
ssize_t count, i;
struct object_id oid;
- int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
- NULL);
+ int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING,
+ &oid,
+ NULL);
if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
return -1;
diff --git a/add-patch.c b/add-patch.c
index 0997d4a..d8ea05f 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -293,13 +293,13 @@
va_list args;
va_start(args, fmt);
- fputs(s->s.error_color, stderr);
- vfprintf(stderr, fmt, args);
- fputs(s->s.reset_color, stderr);
- fputc('\n', stderr);
+ fputs(s->s.error_color, stdout);
+ vprintf(fmt, args);
+ puts(s->s.reset_color);
va_end(args);
}
+LAST_ARG_MUST_BE_NULL
static void setup_child_process(struct add_p_state *s,
struct child_process *cp, ...)
{
@@ -1228,6 +1228,7 @@
fflush(stdout);
if (read_single_character(s) == EOF)
return -1;
+ /* do not limit to 1-byte input to allow 'no' etc. */
switch (tolower(s->answer.buf[0])) {
case 'n': return 0;
case 'y': return 1;
@@ -1326,7 +1327,7 @@
err(s, _("Nothing was applied.\n"));
} else
/* As a last resort, show the diff to the user */
- fwrite(diff->buf, diff->len, 1, stderr);
+ fwrite(diff->buf, diff->len, 1, stdout);
return 0;
}
@@ -1511,6 +1512,12 @@
if (!s->answer.len)
continue;
ch = tolower(s->answer.buf[0]);
+
+ /* 'g' takes a hunk number and '/' takes a regexp */
+ if (s->answer.len != 1 && (ch != 'g' && ch != '/')) {
+ err(s, _("Only one letter is expected, got '%s'"), s->answer.buf);
+ continue;
+ }
if (ch == 'y') {
hunk->use = USE_HUNK;
soft_increment:
@@ -1668,7 +1675,7 @@
}
} else if (s->answer.buf[0] == 'p') {
rendered_hunk_index = -1;
- } else {
+ } else if (s->answer.buf[0] == '?') {
const char *p = _(help_patch_remainder), *eol = p;
color_fprintf(stdout, s->s.help_color, "%s",
@@ -1692,6 +1699,9 @@
color_fprintf_ln(stdout, s->s.help_color,
"%.*s", (int)(eol - p), p);
}
+ } else {
+ err(s, _("Unknown command '%s' (use '?' for help)"),
+ s->answer.buf);
}
}
@@ -1778,9 +1788,9 @@
break;
if (s.file_diff_nr == 0)
- fprintf(stderr, _("No changes.\n"));
+ err(&s, _("No changes."));
else if (binary_count == s.file_diff_nr)
- fprintf(stderr, _("Only binary files changed.\n"));
+ err(&s, _("Only binary files changed."));
add_p_state_clear(&s);
return 0;
diff --git a/advice.c b/advice.c
index 7511119..558a46f 100644
--- a/advice.c
+++ b/advice.c
@@ -2,6 +2,7 @@
#include "advice.h"
#include "config.h"
#include "color.h"
+#include "environment.h"
#include "gettext.h"
#include "help.h"
#include "string-list.h"
@@ -69,6 +70,7 @@
[ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
[ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
[ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
+ [ADVICE_REBASE_TODO_ERROR] = { "rebaseTodoError" },
[ADVICE_REF_SYNTAX] = { "refSyntax" },
[ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" },
[ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" },
@@ -127,6 +129,12 @@
int advice_enabled(enum advice_type type)
{
int enabled = advice_setting[type].level != ADVICE_LEVEL_DISABLED;
+ static int globally_enabled = -1;
+
+ if (globally_enabled < 0)
+ globally_enabled = git_env_bool(GIT_ADVICE_ENVIRONMENT, 1);
+ if (!globally_enabled)
+ return 0;
if (type == ADVICE_PUSH_UPDATE_REJECTED)
return enabled &&
diff --git a/advice.h b/advice.h
index c8d29f9..5105d90 100644
--- a/advice.h
+++ b/advice.h
@@ -37,6 +37,7 @@
ADVICE_PUSH_UNQUALIFIED_REF_NAME,
ADVICE_PUSH_UPDATE_REJECTED,
ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
+ ADVICE_REBASE_TODO_ERROR,
ADVICE_REF_SYNTAX,
ADVICE_RESET_NO_REFRESH_WARNING,
ADVICE_RESOLVE_CONFLICT,
diff --git a/alias.c b/alias.c
index 5a238f2..4daafd9 100644
--- a/alias.c
+++ b/alias.c
@@ -21,9 +21,11 @@
return 0;
if (data->alias) {
- if (!strcasecmp(p, data->alias))
- return git_config_string((const char **)&data->v,
+ if (!strcasecmp(p, data->alias)) {
+ FREE_AND_NULL(data->v);
+ return git_config_string(&data->v,
key, value);
+ }
} else if (data->list) {
string_list_append(data->list, p);
}
diff --git a/attr.c b/attr.c
index 679e422..300f994 100644
--- a/attr.c
+++ b/attr.c
@@ -25,7 +25,7 @@
#include "tree-walk.h"
#include "object-name.h"
-const char *git_attr_tree;
+char *git_attr_tree;
const char git_attr__true[] = "(builtin)true";
const char git_attr__false[] = "\0(builtin)false";
@@ -765,8 +765,8 @@
return res;
}
-static struct attr_stack *read_attr_from_buf(char *buf, const char *path,
- unsigned flags)
+static struct attr_stack *read_attr_from_buf(char *buf, size_t length,
+ const char *path, unsigned flags)
{
struct attr_stack *res;
char *sp;
@@ -774,6 +774,11 @@
if (!buf)
return NULL;
+ if (length >= ATTR_MAX_FILE_SIZE) {
+ warning(_("ignoring overly large gitattributes blob '%s'"), path);
+ free(buf);
+ return NULL;
+ }
CALLOC_ARRAY(res, 1);
for (sp = buf; *sp;) {
@@ -813,7 +818,7 @@
return NULL;
}
- return read_attr_from_buf(buf, path, flags);
+ return read_attr_from_buf(buf, sz, path, flags);
}
static struct attr_stack *read_attr_from_index(struct index_state *istate,
@@ -860,13 +865,7 @@
stack = read_attr_from_blob(istate, &istate->cache[sparse_dir_pos]->oid, relative_path, flags);
} else {
buf = read_blob_data_from_index(istate, path, &size);
- if (!buf)
- return NULL;
- if (size >= ATTR_MAX_FILE_SIZE) {
- warning(_("ignoring overly large gitattributes blob '%s'"), path);
- return NULL;
- }
- stack = read_attr_from_buf(buf, path, flags);
+ stack = read_attr_from_buf(buf, size, path, flags);
}
return stack;
}
@@ -1206,15 +1205,16 @@
}
static const char *default_attr_source_tree_object_name;
-static int ignore_bad_attr_tree;
void set_git_attr_source(const char *tree_object_name)
{
default_attr_source_tree_object_name = xstrdup(tree_object_name);
}
-static void compute_default_attr_source(struct object_id *attr_source)
+static int compute_default_attr_source(struct object_id *attr_source)
{
+ int ignore_bad_attr_tree = 0;
+
if (!default_attr_source_tree_object_name)
default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT);
@@ -1223,29 +1223,34 @@
ignore_bad_attr_tree = 1;
}
- if (!default_attr_source_tree_object_name &&
- startup_info->have_repository &&
- is_bare_repository()) {
- default_attr_source_tree_object_name = "HEAD";
- ignore_bad_attr_tree = 1;
- }
+ if (!default_attr_source_tree_object_name)
+ return 0;
- if (!default_attr_source_tree_object_name || !is_null_oid(attr_source))
- return;
+ if (!startup_info->have_repository) {
+ if (!ignore_bad_attr_tree)
+ die(_("cannot use --attr-source or GIT_ATTR_SOURCE without repo"));
+ return 0;
+ }
if (repo_get_oid_treeish(the_repository,
default_attr_source_tree_object_name,
- attr_source) && !ignore_bad_attr_tree)
- die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+ attr_source)) {
+ if (!ignore_bad_attr_tree)
+ die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+ return 0;
+ }
+
+ return 1;
}
static struct object_id *default_attr_source(void)
{
static struct object_id attr_source;
+ static int has_attr_source = -1;
- if (is_null_oid(&attr_source))
- compute_default_attr_source(&attr_source);
- if (is_null_oid(&attr_source))
+ if (has_attr_source < 0)
+ has_attr_source = compute_default_attr_source(&attr_source);
+ if (!has_attr_source)
return NULL;
return &attr_source;
}
@@ -1296,7 +1301,8 @@
if (pos >= 0) {
if (S_ISGITLINK(istate->cache[pos]->ce_mode))
mode = istate->cache[pos]->ce_mode;
- } else if (resolve_gitlink_ref(path, "HEAD", &oid) == 0) {
+ } else if (repo_resolve_gitlink_ref(the_repository, path,
+ "HEAD", &oid) == 0) {
mode = S_IFGITLINK;
}
}
diff --git a/attr.h b/attr.h
index 127998a..bb33b60 100644
--- a/attr.h
+++ b/attr.h
@@ -190,6 +190,8 @@
};
struct attr_check *attr_check_alloc(void);
+
+LAST_ARG_MUST_BE_NULL
struct attr_check *attr_check_initl(const char *, ...);
struct attr_check *attr_check_dup(const struct attr_check *check);
@@ -236,6 +238,6 @@
/* Return whether the system gitattributes file is enabled and should be used. */
int git_attr_system_is_enabled(void);
-extern const char *git_attr_tree;
+extern char *git_attr_tree;
#endif /* ATTR_H */
diff --git a/bisect.c b/bisect.c
index 29aae87..4ea703b 100644
--- a/bisect.c
+++ b/bisect.c
@@ -469,7 +469,8 @@
static int read_bisect_refs(void)
{
- return for_each_ref_in("refs/bisect/", register_ref, NULL);
+ return refs_for_each_ref_in(get_main_ref_store(the_repository),
+ "refs/bisect/", register_ref, NULL);
}
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
@@ -709,7 +710,7 @@
static int is_expected_rev(const struct object_id *oid)
{
struct object_id expected_oid;
- if (read_ref("BISECT_EXPECTED_REV", &expected_oid))
+ if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected_oid))
return 0;
return oideq(oid, &expected_oid);
}
@@ -721,11 +722,14 @@
struct pretty_print_context pp = {0};
struct strbuf commit_msg = STRBUF_INIT;
- update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), NULL,
+ "BISECT_EXPECTED_REV", bisect_rev, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (no_checkout) {
- update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), NULL,
+ "BISECT_HEAD", bisect_rev, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
} else {
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -1027,7 +1031,8 @@
* If no_checkout is non-zero, the bisection process does not
* checkout the trial commit but instead simply updates BISECT_HEAD.
*/
- int no_checkout = ref_exists("BISECT_HEAD");
+ int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
+ "BISECT_HEAD");
unsigned bisect_flags = 0;
read_bisect_terms(&term_bad, &term_good);
@@ -1178,10 +1183,14 @@
/* There may be some refs packed during bisection */
struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
- for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ "refs/bisect", mark_for_removal,
+ (void *) &refs_for_removal);
string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
string_list_append(&refs_for_removal, xstrdup("BISECT_EXPECTED_REV"));
- result = delete_refs("bisect: remove", &refs_for_removal, REF_NO_DEREF);
+ result = refs_delete_refs(get_main_ref_store(the_repository),
+ "bisect: remove", &refs_for_removal,
+ REF_NO_DEREF);
refs_for_removal.strdup_strings = 1;
string_list_clear(&refs_for_removal, 0);
unlink_or_warn(git_path_bisect_ancestors_ok());
diff --git a/blame.c b/blame.c
index 1a16d4e..33586b9 100644
--- a/blame.c
+++ b/blame.c
@@ -2700,7 +2700,7 @@
return NULL;
/* Do we have HEAD? */
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING, &head_oid, NULL))
return NULL;
head_commit = lookup_commit_reference_gently(revs->repo,
&head_oid, 1);
@@ -2803,7 +2803,7 @@
if (sb->final) {
parent_oid = &sb->final->object.oid;
} else {
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING, &head_oid, NULL))
die("no such ref: HEAD");
parent_oid = &head_oid;
}
diff --git a/branch.c b/branch.c
index e4a738f..df5d24f 100644
--- a/branch.c
+++ b/branch.c
@@ -377,7 +377,7 @@
exit(code);
}
- return ref_exists(ref->buf);
+ return refs_ref_exists(get_main_ref_store(the_repository), ref->buf);
}
static int initialized_checked_out_branches;
@@ -623,11 +623,12 @@
msg = xstrfmt("branch: Reset to %s", start_name);
else
msg = xstrfmt("branch: Created from %s", start_name);
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf,
&oid, forcing ? NULL : null_oid(),
- 0, msg, &err) ||
+ NULL, NULL, 0, msg, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
diff --git a/builtin.h b/builtin.h
index 2828063..7eda9b2 100644
--- a/builtin.h
+++ b/builtin.h
@@ -207,6 +207,7 @@
int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);
int cmd_receive_pack(int argc, const char **argv, const char *prefix);
int cmd_reflog(int argc, const char **argv, const char *prefix);
+int cmd_refs(int argc, const char **argv, const char *prefix);
int cmd_remote(int argc, const char **argv, const char *prefix);
int cmd_remote_ext(int argc, const char **argv, const char *prefix);
int cmd_remote_fd(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index b7d3ff1..3dfcfc5 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2006 Linus Torvalds
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -40,20 +40,20 @@
{
int i, ret = 0;
- for (i = 0; i < the_index.cache_nr; i++) {
- struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ struct cache_entry *ce = the_repository->index->cache[i];
int err;
if (!include_sparse &&
(ce_skip_worktree(ce) ||
- !path_in_sparse_checkout(ce->name, &the_index)))
+ !path_in_sparse_checkout(ce->name, the_repository->index)))
continue;
- if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
+ if (pathspec && !ce_path_match(the_repository->index, ce, pathspec, NULL))
continue;
if (!show_only)
- err = chmod_index_entry(&the_index, ce, flip);
+ err = chmod_index_entry(the_repository->index, ce, flip);
else
err = S_ISREG(ce->ce_mode) ? 0 : -1;
@@ -68,20 +68,20 @@
{
int i, retval = 0;
- for (i = 0; i < the_index.cache_nr; i++) {
- struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ struct cache_entry *ce = the_repository->index->cache[i];
if (!include_sparse &&
(ce_skip_worktree(ce) ||
- !path_in_sparse_checkout(ce->name, &the_index)))
+ !path_in_sparse_checkout(ce->name, the_repository->index)))
continue;
if (ce_stage(ce))
continue; /* do not touch unmerged paths */
if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
continue; /* do not touch non blobs */
- if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
+ if (pathspec && !ce_path_match(the_repository->index, ce, pathspec, NULL))
continue;
- retval |= add_file_to_index(&the_index, ce->name,
+ retval |= add_file_to_index(the_repository->index, ce->name,
flags | ADD_CACHE_RENORMALIZE);
}
@@ -100,11 +100,11 @@
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
- if (dir_path_match(&the_index, entry, pathspec, prefix, seen))
+ if (dir_path_match(the_repository->index, entry, pathspec, prefix, seen))
*dst++ = entry;
}
dir->nr = dst - dir->entries;
- add_pathspec_matches_against_index(pathspec, &the_index, seen,
+ add_pathspec_matches_against_index(pathspec, the_repository->index, seen,
PS_IGNORE_SKIP_WORKTREE);
return seen;
}
@@ -119,14 +119,14 @@
(verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
seen = xcalloc(pathspec->nr, 1);
- refresh_index(&the_index, flags, pathspec, seen,
+ refresh_index(the_repository->index, flags, pathspec, seen,
_("Unstaged changes after refreshing the index:"));
for (i = 0; i < pathspec->nr; i++) {
if (!seen[i]) {
const char *path = pathspec->items[i].original;
if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
- !path_in_sparse_checkout(path, &the_index)) {
+ !path_in_sparse_checkout(path, the_repository->index)) {
string_list_append(&only_match_skip_worktree,
pathspec->items[i].original);
} else {
@@ -338,12 +338,12 @@
for (i = 0; i < dir->nr; i++) {
if (!include_sparse &&
- !path_in_sparse_checkout(dir->entries[i]->name, &the_index)) {
+ !path_in_sparse_checkout(dir->entries[i]->name, the_repository->index)) {
string_list_append(&matched_sparse_paths,
dir->entries[i]->name);
continue;
}
- if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
+ if (add_file_to_index(the_repository->index, dir->entries[i]->name, flags)) {
if (!ignore_add_errors)
die(_("adding files failed"));
exit_status = 1;
@@ -461,8 +461,8 @@
if (repo_read_index_preload(the_repository, &pathspec, 0) < 0)
die(_("index file corrupt"));
- die_in_unpopulated_submodule(&the_index, prefix);
- die_path_inside_submodule(&the_index, &pathspec);
+ die_in_unpopulated_submodule(the_repository->index, prefix);
+ die_path_inside_submodule(the_repository->index, &pathspec);
if (add_new_files) {
int baselen;
@@ -474,7 +474,7 @@
}
/* This picks up the paths that are not tracked */
- baselen = fill_directory(&dir, &the_index, &pathspec);
+ baselen = fill_directory(&dir, the_repository->index, &pathspec);
if (pathspec.nr)
seen = prune_directory(&dir, &pathspec, baselen);
}
@@ -491,7 +491,7 @@
if (!seen)
seen = find_pathspecs_matching_against_index(&pathspec,
- &the_index, PS_IGNORE_SKIP_WORKTREE);
+ the_repository->index, PS_IGNORE_SKIP_WORKTREE);
/*
* file_exists() assumes exact match
@@ -527,8 +527,8 @@
!file_exists(path)) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
- if (is_excluded(&dir, &the_index, path, &dtype))
- dir_add_ignored(&dir, &the_index,
+ if (is_excluded(&dir, the_repository->index, path, &dtype))
+ dir_add_ignored(&dir, the_repository->index,
path, pathspec.items[i].len);
} else
die(_("pathspec '%s' did not match any files"),
@@ -569,7 +569,7 @@
end_odb_transaction();
finish:
- if (write_locked_index(&the_index, &lock_file,
+ if (write_locked_index(the_repository->index, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write new index file"));
diff --git a/builtin/am.c b/builtin/am.c
index 022cae2..9265926 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -3,7 +3,7 @@
*
* Based on git-am.sh by Junio C Hamano.
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "abspath.h"
#include "advice.h"
@@ -1001,7 +1001,8 @@
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
- delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "REBASE_HEAD", NULL, REF_NO_DEREF);
if (split_mail(state, patch_format, paths, keep_cr) < 0) {
am_destroy(state);
@@ -1081,12 +1082,15 @@
if (!repo_get_oid(the_repository, "HEAD", &curr_head)) {
write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
if (!state->rebasing)
- update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "am", "ORIG_HEAD", &curr_head, NULL,
+ 0,
+ UPDATE_REFS_DIE_ON_ERR);
} else {
write_state_text(state, "abort-safety", "");
if (!state->rebasing)
- delete_ref(NULL, "ORIG_HEAD", NULL, 0);
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, "ORIG_HEAD", NULL, 0);
}
/*
@@ -1119,7 +1123,8 @@
oidclr(&state->orig_commit);
unlink(am_path(state, "original-commit"));
- delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "REBASE_HEAD", NULL, REF_NO_DEREF);
if (!repo_get_oid(the_repository, "HEAD", &head))
write_state_text(state, "abort-safety", oid_to_hex(&head));
@@ -1466,8 +1471,9 @@
oidcpy(&state->orig_commit, &commit_oid);
write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
- update_ref("am", "REBASE_HEAD", &commit_oid,
- NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), "am",
+ "REBASE_HEAD", &commit_oid,
+ NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
return 0;
}
@@ -1536,8 +1542,8 @@
if (index_file) {
/* Reload index as apply_all_patches() will have modified it. */
- discard_index(&the_index);
- read_index_from(&the_index, index_file, get_git_dir());
+ discard_index(the_repository->index);
+ read_index_from(the_repository->index, index_file, get_git_dir());
}
return 0;
@@ -1579,10 +1585,10 @@
if (build_fake_ancestor(state, index_path))
return error("could not build fake ancestor");
- discard_index(&the_index);
- read_index_from(&the_index, index_path, get_git_dir());
+ discard_index(the_repository->index);
+ read_index_from(the_repository->index, index_path, get_git_dir());
- if (write_index_as_tree(&orig_tree, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(&orig_tree, the_repository->index, index_path, 0, NULL))
return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
say(state, stdout, _("Using index info to reconstruct a base tree..."));
@@ -1608,12 +1614,12 @@
return error(_("Did you hand edit your patch?\n"
"It does not apply to blobs recorded in its index."));
- if (write_index_as_tree(&their_tree, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(&their_tree, the_repository->index, index_path, 0, NULL))
return error("could not write tree");
say(state, stdout, _("Falling back to patching base and 3-way merge..."));
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
/*
@@ -1660,7 +1666,7 @@
if (!state->no_verify && run_hooks("pre-applypatch"))
exit(1);
- if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(&tree, the_repository->index, get_index_file(), 0, NULL))
die(_("git write-tree failed to write a tree"));
if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) {
@@ -1697,8 +1703,9 @@
strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
state->msg);
- update_ref(sb.buf, "HEAD", &commit, old_oid, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), sb.buf, "HEAD",
+ &commit, old_oid, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (state->rebasing) {
FILE *fp = xfopen(am_path(state, "rewritten"), "a");
@@ -1948,7 +1955,7 @@
}
}
- if (unmerged_index(&the_index)) {
+ if (unmerged_index(the_repository->index)) {
printf_ln(_("You still have unmerged paths in your index.\n"
"You should 'git add' each file with resolved conflicts to mark them as such.\n"
"You might run `git rm` on a file to accept \"deleted by them\" for it."));
@@ -1987,12 +1994,12 @@
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.update = 1;
opts.merge = 1;
opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
@@ -2006,7 +2013,7 @@
return -1;
}
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
@@ -2029,8 +2036,8 @@
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.merge = 1;
opts.fn = oneway_merge;
init_tree_desc(&t[0], &tree->object.oid, tree->buffer, tree->size);
@@ -2040,7 +2047,7 @@
return -1;
}
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
@@ -2068,7 +2075,7 @@
if (fast_forward_to(head_tree, head_tree, 1))
return -1;
- if (write_index_as_tree(&index, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(&index, the_repository->index, get_index_file(), 0, NULL))
return -1;
index_tree = parse_tree_indirect(&index);
@@ -2175,7 +2182,8 @@
am_rerere_clear();
- curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
+ curr_branch = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, &curr_head, NULL);
has_curr_head = curr_branch && !is_null_oid(&curr_head);
if (!has_curr_head)
oidcpy(&curr_head, the_hash_algo->empty_tree);
@@ -2188,11 +2196,13 @@
die(_("failed to clean index"));
if (has_orig_head)
- update_ref("am --abort", "HEAD", &orig_head,
- has_curr_head ? &curr_head : NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "am --abort", "HEAD", &orig_head,
+ has_curr_head ? &curr_head : NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else if (curr_branch)
- delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ curr_branch, NULL, REF_NO_DEREF);
free(curr_branch);
am_destroy(state);
@@ -2383,6 +2393,9 @@
N_("show the patch being applied"),
PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW },
+ OPT_CMDMODE(0, "retry", &resume_mode,
+ N_("try to apply current patch again"),
+ RESUME_APPLY),
OPT_CMDMODE(0, "allow-empty", &resume_mode,
N_("record the empty patch as an empty commit"),
RESUME_ALLOW_EMPTY),
diff --git a/builtin/apply.c b/builtin/apply.c
index 861a019..d623c52 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "gettext.h"
#include "repository.h"
+#include "hash.h"
#include "apply.h"
static const char * const apply_usage[] = {
@@ -18,6 +19,15 @@
if (init_apply_state(&state, the_repository, prefix))
exit(128);
+ /*
+ * We could to redo the "apply.c" machinery to make this
+ * arbitrary fallback unnecessary, but it is dubious that it
+ * is worth the effort.
+ * cf. https://lore.kernel.org/git/xmqqcypfcmn4.fsf@gitster.g/
+ */
+ if (!the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
argc = apply_parse_options(argc, argv,
&state, &force_apply, &options,
apply_usage);
diff --git a/builtin/bisect.c b/builtin/bisect.c
index f69c3f7..dabce9b 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -243,7 +243,7 @@
strbuf_addstr(&branch, commit);
}
- if (branch.len && !ref_exists("BISECT_HEAD")) {
+ if (branch.len && !refs_ref_exists(get_main_ref_store(the_repository), "BISECT_HEAD")) {
struct child_process cmd = CHILD_PROCESS_INIT;
cmd.git_cmd = 1;
@@ -262,7 +262,8 @@
return bisect_clean_state();
}
-static void log_commit(FILE *fp, char *fmt, const char *state,
+static void log_commit(FILE *fp,
+ const char *fmt, const char *state,
struct commit *commit)
{
struct pretty_print_context pp = {0};
@@ -302,8 +303,8 @@
goto finish;
}
- if (update_ref(NULL, tag.buf, &oid, NULL, 0,
- UPDATE_REFS_MSG_ON_ERR)) {
+ if (refs_update_ref(get_main_ref_store(the_repository), NULL, tag.buf, &oid, NULL, 0,
+ UPDATE_REFS_MSG_ON_ERR)) {
res = -1;
goto finish;
}
@@ -416,11 +417,12 @@
char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
char *good_glob = xstrfmt("%s-*", terms->term_good);
- if (ref_exists(bad_ref))
+ if (refs_ref_exists(get_main_ref_store(the_repository), bad_ref))
state->nr_bad = 1;
- for_each_glob_ref_in(inc_nr, good_glob, "refs/bisect/",
- (void *) &state->nr_good);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository), inc_nr,
+ good_glob, "refs/bisect/",
+ (void *) &state->nr_good);
free(good_glob);
free(bad_ref);
@@ -574,9 +576,11 @@
reset_revision_walk();
repo_init_revisions(the_repository, revs, NULL);
setup_revisions(0, NULL, revs, NULL);
- for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ add_bisect_ref, bad, "refs/bisect/", &cb);
cb.object_flags = UNINTERESTING;
- for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ add_bisect_ref, good, "refs/bisect/", &cb);
if (prepare_revision_walk(revs))
res = error(_("revision walk setup failed\n"));
@@ -636,7 +640,7 @@
char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
int res;
- read_ref(bad_ref, &oid);
+ refs_read_ref(get_main_ref_store(the_repository), bad_ref, &oid);
commit = lookup_commit_reference_by_name(bad_ref);
repo_format_commit_message(the_repository, commit, "%s", &commit_name,
&pp);
@@ -779,7 +783,8 @@
/*
* Verify HEAD
*/
- head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
+ head = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, &head_oid, &flags);
if (!head)
if (repo_get_oid(the_repository, "HEAD", &head_oid))
return error(_("bad HEAD - I need a HEAD"));
@@ -838,8 +843,8 @@
res = error(_("invalid ref: '%s'"), start_head.buf);
goto finish;
}
- if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
- UPDATE_REFS_MSG_ON_ERR)) {
+ if (refs_update_ref(get_main_ref_store(the_repository), NULL, "BISECT_HEAD", &oid, NULL, 0,
+ UPDATE_REFS_MSG_ON_ERR)) {
res = BISECT_FAILED;
goto finish;
}
@@ -972,7 +977,7 @@
oid_array_append(&revs, &commit->object.oid);
}
- if (read_ref("BISECT_EXPECTED_REV", &expected))
+ if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected))
verify_expected = 0; /* Ignore invalid file contents */
for (i = 0; i < revs.nr; i++) {
@@ -982,7 +987,9 @@
}
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
unlink_or_warn(git_path_bisect_ancestors_ok());
- delete_ref(NULL, "BISECT_EXPECTED_REV", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, "BISECT_EXPECTED_REV", NULL,
+ REF_NO_DEREF);
verify_expected = 0;
}
}
@@ -1179,13 +1186,15 @@
struct object_id good_rev;
struct object_id current_rev;
char *good_glob = xstrfmt("%s-*", terms->term_good);
- int no_checkout = ref_exists("BISECT_HEAD");
+ int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
+ "BISECT_HEAD");
- for_each_glob_ref_in(get_first_good, good_glob, "refs/bisect/",
- &good_rev);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ get_first_good, good_glob, "refs/bisect/",
+ &good_rev);
free(good_glob);
- if (read_ref(no_checkout ? "BISECT_HEAD" : "HEAD", ¤t_rev))
+ if (refs_read_ref(get_main_ref_store(the_repository), no_checkout ? "BISECT_HEAD" : "HEAD", ¤t_rev))
return -1;
res = bisect_checkout(&good_rev, no_checkout);
diff --git a/builtin/blame.c b/builtin/blame.c
index 9aa7468..9ca1a7c 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -134,7 +134,7 @@
{
struct ident_split ident;
size_t len, maillen, namelen;
- char *tmp, *endp;
+ const char *tmp, *endp;
const char *namebuf, *mailbuf;
tmp = strstr(inbuf, what);
@@ -718,7 +718,7 @@
return 0;
}
if (!strcmp(var, "blame.ignorerevsfile")) {
- const char *str;
+ char *str;
int ret;
ret = git_config_pathname(&str, var, value);
@@ -915,7 +915,6 @@
struct range_set ranges;
unsigned int range_i;
long anchor;
- const int hexsz = the_hash_algo->hexsz;
long num_lines = 0;
const char *str_usage = cmd_is_annotate ? annotate_usage : blame_usage;
const char **opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
@@ -973,11 +972,11 @@
} else if (show_progress < 0)
show_progress = isatty(2);
- if (0 < abbrev && abbrev < hexsz)
+ if (0 < abbrev && abbrev < (int)the_hash_algo->hexsz)
/* one more abbrev length is needed for the boundary commit */
abbrev++;
else if (!abbrev)
- abbrev = hexsz;
+ abbrev = the_hash_algo->hexsz;
if (revs_file && read_ancestry(revs_file))
die_errno("reading graft file '%s' failed", revs_file);
@@ -1093,8 +1092,8 @@
struct commit *head_commit;
struct object_id head_oid;
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- &head_oid, NULL) ||
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING,
+ &head_oid, NULL) ||
!(head_commit = lookup_commit_reference_gently(revs.repo,
&head_oid, 1)))
die("no such ref: HEAD");
diff --git a/builtin/branch.c b/builtin/branch.c
index dd3e3a7..48cac74 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -148,8 +148,8 @@
if (upstream &&
(reference_name = reference_name_to_free =
- resolve_refdup(upstream, RESOLVE_REF_READING,
- &oid, NULL)) != NULL)
+ refs_resolve_refdup(get_main_ref_store(the_repository), upstream, RESOLVE_REF_READING,
+ &oid, NULL)) != NULL)
reference_rev = lookup_commit_reference(the_repository,
&oid);
}
@@ -272,21 +272,24 @@
}
}
- target = resolve_refdup(name,
- RESOLVE_REF_READING
- | RESOLVE_REF_NO_RECURSE
- | RESOLVE_REF_ALLOW_BAD_NAME,
- &oid, &flags);
+ target = refs_resolve_refdup(get_main_ref_store(the_repository),
+ name,
+ RESOLVE_REF_READING
+ | RESOLVE_REF_NO_RECURSE
+ | RESOLVE_REF_ALLOW_BAD_NAME,
+ &oid, &flags);
if (!target) {
if (remote_branch) {
error(_("remote-tracking branch '%s' not found"), bname.buf);
} else {
char *virtual_name = mkpathdup(fmt_remotes, bname.buf);
- char *virtual_target = resolve_refdup(virtual_name,
- RESOLVE_REF_READING
- | RESOLVE_REF_NO_RECURSE
- | RESOLVE_REF_ALLOW_BAD_NAME,
- &oid, &flags);
+ char *virtual_target = refs_resolve_refdup(get_main_ref_store(the_repository),
+ virtual_name,
+ RESOLVE_REF_READING
+ | RESOLVE_REF_NO_RECURSE
+ | RESOLVE_REF_ALLOW_BAD_NAME,
+ &oid,
+ &flags);
FREE_AND_NULL(virtual_name);
if (virtual_target)
@@ -317,13 +320,13 @@
free(target);
}
- if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
+ if (refs_delete_refs(get_main_ref_store(the_repository), NULL, &refs_to_delete, REF_NO_DEREF))
ret = 1;
for_each_string_list_item(item, &refs_to_delete) {
char *describe_ref = item->util;
char *name = item->string;
- if (!ref_exists(name)) {
+ if (!refs_ref_exists(get_main_ref_store(the_repository), name)) {
char *refname = name + branch_name_pos;
if (!quiet)
printf(remote_branch
@@ -499,7 +502,8 @@
static void print_current_branch_name(void)
{
int flags;
- const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
+ const char *refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &flags);
const char *shortname;
if (!refname)
die(_("could not resolve HEAD"));
@@ -555,7 +559,7 @@
continue;
refs = get_worktree_ref_store(worktrees[i]);
- if (refs_create_symref(refs, "HEAD", newref, logmsg))
+ if (refs_update_symref(refs, "HEAD", newref, logmsg))
ret = error(_("HEAD of working tree %s is not updated"),
worktrees[i]->path);
}
@@ -580,7 +584,7 @@
* Bad name --- this could be an attempt to rename a
* ref that we used to allow to be created by accident.
*/
- if (ref_exists(oldref.buf))
+ if (refs_ref_exists(get_main_ref_store(the_repository), oldref.buf))
recovery = 1;
else {
int code = die_message(_("invalid branch name: '%s'"), oldname);
@@ -601,7 +605,7 @@
}
}
- if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
+ if ((copy || !(oldref_usage & IS_HEAD)) && !refs_ref_exists(get_main_ref_store(the_repository), oldref.buf)) {
if (oldref_usage & IS_HEAD)
die(_("no commit on branch '%s' yet"), oldname);
else
@@ -632,9 +636,9 @@
oldref.buf, newref.buf);
if (!copy && !(oldref_usage & IS_ORPHAN) &&
- rename_ref(oldref.buf, newref.buf, logmsg.buf))
+ refs_rename_ref(get_main_ref_store(the_repository), oldref.buf, newref.buf, logmsg.buf))
die(_("branch rename failed"));
- if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
+ if (copy && refs_copy_existing_ref(get_main_ref_store(the_repository), oldref.buf, newref.buf, logmsg.buf))
die(_("branch copy failed"));
if (recovery) {
@@ -786,7 +790,8 @@
track = git_branch_track;
- head = resolve_refdup("HEAD", 0, &head_oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ 0, &head_oid, NULL);
if (!head)
die(_("failed to resolve HEAD as a valid ref"));
if (!strcmp(head, "HEAD"))
@@ -891,7 +896,7 @@
}
strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
- if (!ref_exists(branch_ref.buf))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), branch_ref.buf))
error((!argc || branch_checked_out(branch_ref.buf))
? _("no commit on branch '%s' yet")
: _("no branch named '%s'"),
@@ -936,7 +941,7 @@
die(_("no such branch '%s'"), argv[0]);
}
- if (!ref_exists(branch->refname)) {
+ if (!refs_ref_exists(get_main_ref_store(the_repository), branch->refname)) {
if (!argc || branch_checked_out(branch->refname))
die(_("no commit on branch '%s' yet"), branch->name);
die(_("branch '%s' does not exist"), branch->name);
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 25f860a..b3cc77a 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -107,7 +107,7 @@
struct tm tm;
enum diagnose_mode diagnose = DIAGNOSE_NONE;
char *option_output = NULL;
- char *option_suffix = "%Y-%m-%d-%H%M";
+ const char *option_suffix = "%Y-%m-%d-%H%M";
const char *user_relative_path = NULL;
char *prefixed_filename;
size_t output_path_len;
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 3ad11dc..d5d41a8 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -140,6 +140,11 @@
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
+ if (!startup_info->have_repository) {
+ ret = error(_("need a repository to verify a bundle"));
+ goto cleanup;
+ }
+
if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
ret = 1;
goto cleanup;
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 0c948f4..43a1d7a 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "config.h"
#include "convert.h"
@@ -77,7 +77,7 @@
struct checkout_metadata meta;
init_checkout_metadata(&meta, NULL, NULL, oid);
- if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf, &meta)) {
+ if (convert_to_working_tree(the_repository->index, path, *buf, *size, &strbuf, &meta)) {
free(*buf);
*size = strbuf.len;
*buf = strbuf_detach(&strbuf, NULL);
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index c1da1d1..9376810 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
#include "attr.h"
@@ -71,9 +70,9 @@
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
if (collect_all) {
- git_all_attrs(&the_index, full_path, check);
+ git_all_attrs(the_repository->index, full_path, check);
} else {
- git_check_attr(&the_index, full_path, check);
+ git_check_attr(the_repository->index, full_path, check);
}
output_attr(check, file);
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 906cd96..2bda6a1 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
#include "dir.h"
@@ -36,8 +35,8 @@
static void output_pattern(const char *path, struct path_pattern *pattern)
{
- char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : "";
- char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
+ const char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : "";
+ const char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
if (!nul_term_line) {
if (!verbose) {
write_name_quoted(path, stdout, '\n');
@@ -95,21 +94,21 @@
PATHSPEC_KEEP_ORDER,
prefix, argv);
- die_path_inside_submodule(&the_index, &pathspec);
+ die_path_inside_submodule(the_repository->index, &pathspec);
/*
* look for pathspecs matching entries in the index, since these
* should not be ignored, in order to be consistent with
* 'git status', 'git add' etc.
*/
- seen = find_pathspecs_matching_against_index(&pathspec, &the_index,
+ seen = find_pathspecs_matching_against_index(&pathspec, the_repository->index,
PS_HEED_SKIP_WORKTREE);
for (i = 0; i < pathspec.nr; i++) {
full_path = pathspec.items[i].match;
pattern = NULL;
if (!seen[i]) {
int dtype = DT_UNKNOWN;
- pattern = last_matching_pattern(dir, &the_index,
+ pattern = last_matching_pattern(dir, the_repository->index,
full_path, &dtype);
if (!verbose && pattern &&
pattern->flags & PATTERN_FLAG_NEGATIVE)
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 2e086a2..29e744d 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -4,7 +4,7 @@
* Copyright (C) 2005 Linus Torvalds
*
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -69,7 +69,7 @@
static int checkout_file(const char *name, const char *prefix)
{
int namelen = strlen(name);
- int pos = index_name_pos(&the_index, name, namelen);
+ int pos = index_name_pos(the_repository->index, name, namelen);
int has_same_name = 0;
int is_file = 0;
int is_skipped = 1;
@@ -79,8 +79,8 @@
if (pos < 0)
pos = -pos - 1;
- while (pos < the_index.cache_nr) {
- struct cache_entry *ce = the_index.cache[pos];
+ while (pos <the_repository->index->cache_nr) {
+ struct cache_entry *ce =the_repository->index->cache[pos];
if (ce_namelen(ce) != namelen ||
memcmp(ce->name, name, namelen))
break;
@@ -140,8 +140,8 @@
int i, errs = 0;
struct cache_entry *last_ce = NULL;
- for (i = 0; i < the_index.cache_nr ; i++) {
- struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr ; i++) {
+ struct cache_entry *ce = the_repository->index->cache[i];
if (S_ISSPARSEDIR(ce->ce_mode)) {
if (!ce_skip_worktree(ce))
@@ -154,8 +154,8 @@
* first entry inside the expanded sparse directory).
*/
if (ignore_skip_worktree) {
- ensure_full_index(&the_index);
- ce = the_index.cache[i];
+ ensure_full_index(the_repository->index);
+ ce = the_repository->index->cache[i];
}
}
@@ -260,7 +260,7 @@
argc = parse_options(argc, argv, prefix, builtin_checkout_index_options,
builtin_checkout_index_usage, 0);
- state.istate = &the_index;
+ state.istate = the_repository->index;
state.force = force;
state.quiet = quiet;
state.not_new = not_new;
@@ -280,7 +280,7 @@
*/
if (index_opt && !state.base_dir_len && !to_tempfile) {
state.refresh_cache = 1;
- state.istate = &the_index;
+ state.istate = the_repository->index;
repo_hold_locked_index(the_repository, &lock_file,
LOCK_DIE_ON_ERROR);
}
@@ -339,7 +339,7 @@
return 1;
if (is_lock_file_locked(&lock_file) &&
- write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
return 0;
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 71e6036..3cf44b4 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "branch.h"
@@ -146,7 +145,7 @@
return READ_TREE_RECURSIVE;
len = base->len + strlen(pathname);
- ce = make_empty_cache_entry(&the_index, len);
+ ce = make_empty_cache_entry(the_repository->index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, base->buf, base->len);
memcpy(ce->name + base->len, pathname, len - base->len);
@@ -159,9 +158,9 @@
* entry in place. Whether it is UPTODATE or not, checkout_entry will
* do the right thing.
*/
- pos = index_name_pos(&the_index, ce->name, ce->ce_namelen);
+ pos = index_name_pos(the_repository->index, ce->name, ce->ce_namelen);
if (pos >= 0) {
- struct cache_entry *old = the_index.cache[pos];
+ struct cache_entry *old = the_repository->index->cache[pos];
if (ce->ce_mode == old->ce_mode &&
!ce_intent_to_add(old) &&
oideq(&ce->oid, &old->oid)) {
@@ -171,7 +170,7 @@
}
}
- add_index_entry(&the_index, ce,
+ add_index_entry(the_repository->index, ce,
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
return 0;
}
@@ -190,8 +189,8 @@
static int skip_same_name(const struct cache_entry *ce, int pos)
{
- while (++pos < the_index.cache_nr &&
- !strcmp(the_index.cache[pos]->name, ce->name))
+ while (++pos < the_repository->index->cache_nr &&
+ !strcmp(the_repository->index->cache[pos]->name, ce->name))
; /* skip */
return pos;
}
@@ -199,9 +198,9 @@
static int check_stage(int stage, const struct cache_entry *ce, int pos,
int overlay_mode)
{
- while (pos < the_index.cache_nr &&
- !strcmp(the_index.cache[pos]->name, ce->name)) {
- if (ce_stage(the_index.cache[pos]) == stage)
+ while (pos < the_repository->index->cache_nr &&
+ !strcmp(the_repository->index->cache[pos]->name, ce->name)) {
+ if (ce_stage(the_repository->index->cache[pos]) == stage)
return 0;
pos++;
}
@@ -218,8 +217,8 @@
unsigned seen = 0;
const char *name = ce->name;
- while (pos < the_index.cache_nr) {
- ce = the_index.cache[pos];
+ while (pos < the_repository->index->cache_nr) {
+ ce = the_repository->index->cache[pos];
if (strcmp(name, ce->name))
break;
seen |= (1 << ce_stage(ce));
@@ -235,10 +234,10 @@
const struct checkout *state, int *nr_checkouts,
int overlay_mode)
{
- while (pos < the_index.cache_nr &&
- !strcmp(the_index.cache[pos]->name, ce->name)) {
- if (ce_stage(the_index.cache[pos]) == stage)
- return checkout_entry(the_index.cache[pos], state,
+ while (pos < the_repository->index->cache_nr &&
+ !strcmp(the_repository->index->cache[pos]->name, ce->name)) {
+ if (ce_stage(the_repository->index->cache[pos]) == stage)
+ return checkout_entry(the_repository->index->cache[pos], state,
NULL, nr_checkouts);
pos++;
}
@@ -256,7 +255,7 @@
int *nr_checkouts, struct mem_pool *ce_mem_pool,
int conflict_style)
{
- struct cache_entry *ce = the_index.cache[pos];
+ struct cache_entry *ce = the_repository->index->cache[pos];
const char *path = ce->name;
mmfile_t ancestor, ours, theirs;
enum ll_merge_result merge_status;
@@ -269,7 +268,7 @@
int renormalize = 0;
memset(threeway, 0, sizeof(threeway));
- while (pos < the_index.cache_nr) {
+ while (pos < the_repository->index->cache_nr) {
int stage;
stage = ce_stage(ce);
if (!stage || strcmp(path, ce->name))
@@ -278,7 +277,7 @@
if (stage == 2)
mode = create_ce_mode(ce->ce_mode);
pos++;
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
}
if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2]))
return error(_("path '%s' does not have necessary versions"), path);
@@ -356,7 +355,7 @@
* match_pathspec() for _all_ entries when
* opts->source_tree != NULL.
*/
- if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))
+ if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched))
ce->ce_flags |= CE_MATCHED;
}
@@ -367,7 +366,7 @@
ce->ce_flags &= ~CE_MATCHED;
if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
return;
- if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {
+ if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched)) {
ce->ce_flags |= CE_MATCHED;
if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
/*
@@ -391,7 +390,7 @@
state.force = 1;
state.refresh_cache = 1;
- state.istate = &the_index;
+ state.istate = the_repository->index;
mem_pool_init(&ce_mem_pool, 0);
get_parallel_checkout_configs(&pc_workers, &pc_threshold);
@@ -404,8 +403,8 @@
if (pc_workers > 1)
init_parallel_checkout();
- for (pos = 0; pos < the_index.cache_nr; pos++) {
- struct cache_entry *ce = the_index.cache[pos];
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+ struct cache_entry *ce = the_repository->index->cache[pos];
if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state,
@@ -429,7 +428,7 @@
errs |= run_parallel_checkout(&state, pc_workers, pc_threshold,
NULL, NULL);
mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
- remove_marked_cache_entries(&the_index, 1);
+ remove_marked_cache_entries(the_repository->index, 1);
remove_scheduled_dirs();
errs |= finish_delayed_checkout(&state, opts->show_progress);
@@ -571,7 +570,7 @@
if (opts->source_tree)
read_tree_some(opts->source_tree, &opts->pathspec);
if (opts->merge)
- unmerge_index(&the_index, &opts->pathspec, CE_MATCHED);
+ unmerge_index(the_repository->index, &opts->pathspec, CE_MATCHED);
ps_matched = xcalloc(opts->pathspec.nr, 1);
@@ -579,13 +578,13 @@
* Make sure all pathspecs participated in locating the paths
* to be checked out.
*/
- for (pos = 0; pos < the_index.cache_nr; pos++)
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++)
if (opts->overlay_mode)
- mark_ce_for_checkout_overlay(the_index.cache[pos],
+ mark_ce_for_checkout_overlay(the_repository->index->cache[pos],
ps_matched,
opts);
else
- mark_ce_for_checkout_no_overlay(the_index.cache[pos],
+ mark_ce_for_checkout_no_overlay(the_repository->index->cache[pos],
ps_matched,
opts);
@@ -596,8 +595,8 @@
free(ps_matched);
/* Any unmerged paths? */
- for (pos = 0; pos < the_index.cache_nr; pos++) {
- const struct cache_entry *ce = the_index.cache[pos];
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+ const struct cache_entry *ce = the_repository->index->cache[pos];
if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce))
continue;
@@ -622,7 +621,7 @@
if (opts->checkout_worktree)
errs |= checkout_worktree(opts, new_branch_info);
else
- remove_marked_cache_entries(&the_index, 1);
+ remove_marked_cache_entries(the_repository->index, 1);
/*
* Allow updating the index when checking out from the index.
@@ -634,7 +633,7 @@
checkout_index = opts->checkout_index;
if (checkout_index) {
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
} else {
/*
@@ -646,7 +645,8 @@
rollback_lock_file(&lock_file);
}
- read_ref_full("HEAD", 0, &rev, NULL);
+ refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0,
+ &rev, NULL);
head = lookup_commit_reference_gently(the_repository, &rev, 1);
errs |= post_checkout_hook(head, head, 0);
@@ -703,8 +703,8 @@
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = o->show_progress;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
init_checkout_metadata(&opts.meta, info->refname,
info->commit ? &info->commit->object.oid : null_oid(),
NULL);
@@ -756,12 +756,12 @@
{
memset(topts, 0, sizeof(*topts));
topts->head_idx = -1;
- topts->src_index = &the_index;
- topts->dst_index = &the_index;
+ topts->src_index = the_repository->index;
+ topts->dst_index = the_repository->index;
setup_unpack_trees_porcelain(topts, "checkout");
- topts->initial_checkout = is_index_unborn(&the_index);
+ topts->initial_checkout = is_index_unborn(the_repository->index);
topts->update = 1;
topts->merge = 1;
topts->quiet = merge && old_commit;
@@ -783,7 +783,7 @@
if (repo_read_index_preload(the_repository, NULL, 0) < 0)
return error(_("index file corrupt"));
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
if (new_branch_info->commit)
BUG("'switch --orphan' should never accept a commit as starting point");
@@ -807,9 +807,9 @@
struct unpack_trees_options topts;
const struct object_id *old_commit_oid;
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
- if (unmerged_index(&the_index)) {
+ if (unmerged_index(the_repository->index)) {
error(_("you need to resolve your current index first"));
return 1;
}
@@ -919,10 +919,10 @@
}
}
- if (!cache_tree_fully_valid(the_index.cache_tree))
- cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+ if (!cache_tree_fully_valid(the_repository->index->cache_tree))
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
if (!opts->discard_changes && !opts->quiet && new_branch_info->commit)
@@ -958,7 +958,8 @@
int ret;
struct strbuf err = STRBUF_INIT;
- ret = safe_create_reflog(refname, &err);
+ ret = refs_create_reflog(get_main_ref_store(the_repository),
+ refname, &err);
if (ret) {
fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
opts->new_orphan_branch, err.buf);
@@ -999,8 +1000,10 @@
if (!strcmp(new_branch_info->name, "HEAD") && !new_branch_info->path && !opts->force_detach) {
/* Nothing to do. */
} else if (opts->force_detach || !new_branch_info->path) { /* No longer on any branch. */
- update_ref(msg.buf, "HEAD", &new_branch_info->commit->object.oid, NULL,
- REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ "HEAD", &new_branch_info->commit->object.oid,
+ NULL,
+ REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
if (!opts->quiet) {
if (old_branch_info->path &&
advice_enabled(ADVICE_DETACHED_HEAD) && !opts->force_detach)
@@ -1008,7 +1011,7 @@
describe_detached_head(_("HEAD is now at"), new_branch_info->commit);
}
} else if (new_branch_info->path) { /* Switch branches. */
- if (create_symref("HEAD", new_branch_info->path, msg.buf) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, msg.buf) < 0)
die(_("unable to update HEAD"));
if (!opts->quiet) {
if (old_branch_info->path && !strcmp(new_branch_info->path, old_branch_info->path)) {
@@ -1029,8 +1032,9 @@
}
}
if (old_branch_info->path && old_branch_info->name) {
- if (!ref_exists(old_branch_info->path) && reflog_exists(old_branch_info->path))
- delete_reflog(old_branch_info->path);
+ if (!refs_ref_exists(get_main_ref_store(the_repository), old_branch_info->path) && refs_reflog_exists(get_main_ref_store(the_repository), old_branch_info->path))
+ refs_delete_reflog(get_main_ref_store(the_repository),
+ old_branch_info->path);
}
}
remove_branch_state(the_repository, !opts->quiet);
@@ -1129,7 +1133,8 @@
object->flags &= ~UNINTERESTING;
add_pending_object(&revs, object, oid_to_hex(&object->oid));
- for_each_ref(add_pending_uninteresting_ref, &revs);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ add_pending_uninteresting_ref, &revs);
if (new_commit)
add_pending_oid(&revs, "HEAD",
&new_commit->object.oid,
@@ -1159,7 +1164,8 @@
trace2_cmd_mode("branch");
memset(&old_branch_info, 0, sizeof(old_branch_info));
- old_branch_info.path = resolve_refdup("HEAD", 0, &rev, &flag);
+ old_branch_info.path = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, &rev, &flag);
if (old_branch_info.path)
old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
if (!(flag & REF_ISSYMREF))
@@ -1247,7 +1253,7 @@
setup_branch_path(new_branch_info);
if (!check_refname_format(new_branch_info->path, 0) &&
- !read_ref(new_branch_info->path, &branch_rev))
+ !refs_read_ref(get_main_ref_store(the_repository), new_branch_info->path, &branch_rev))
oidcpy(rev, &branch_rev);
else
/* not an existing branch */
@@ -1269,12 +1275,12 @@
}
}
-static const char *parse_remote_branch(const char *arg,
- struct object_id *rev,
- int could_be_checkout_paths)
+static char *parse_remote_branch(const char *arg,
+ struct object_id *rev,
+ int could_be_checkout_paths)
{
int num_matches = 0;
- const char *remote = unique_tracking_name(arg, rev, &num_matches);
+ char *remote = unique_tracking_name(arg, rev, &num_matches);
if (remote && could_be_checkout_paths) {
die(_("'%s' could be both a local file and a tracking branch.\n"
@@ -1310,6 +1316,7 @@
const char **new_branch = &opts->new_branch;
int argcount = 0;
const char *arg;
+ char *remote = NULL;
int dash_dash_pos;
int has_dash_dash = 0;
int i;
@@ -1410,8 +1417,8 @@
recover_with_dwim = 0;
if (recover_with_dwim) {
- const char *remote = parse_remote_branch(arg, rev,
- could_be_checkout_paths);
+ remote = parse_remote_branch(arg, rev,
+ could_be_checkout_paths);
if (remote) {
*new_branch = arg;
arg = remote;
@@ -1453,6 +1460,7 @@
argc--;
}
+ free(remote);
return argcount;
}
@@ -1466,7 +1474,8 @@
if (!opts->new_branch)
die(_("You are on a branch yet to be born"));
strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
- status = create_symref("HEAD", branch_ref.buf, "checkout -b");
+ status = refs_update_symref(get_main_ref_store(the_repository),
+ "HEAD", branch_ref.buf, "checkout -b");
strbuf_release(&branch_ref);
if (!opts->quiet)
fprintf(stderr, _("Switched to a new branch '%s'\n"),
@@ -1553,7 +1562,8 @@
if (opts->ignore_other_worktrees)
return;
- head_ref = resolve_refdup("HEAD", 0, NULL, &flags);
+ head_ref = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &flags);
if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref, full_ref)))
die_if_checked_out(full_ref, 1);
free(head_ref);
@@ -1634,7 +1644,7 @@
struct object_id rev;
int flag;
- if (!read_ref_full("HEAD", 0, &rev, &flag) &&
+ if (!refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0, &rev, &flag) &&
(flag & REF_ISSYMREF) && is_null_oid(&rev))
return switch_unborn_to_new_branch(opts);
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 29efe84..ded5a91 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -6,7 +6,6 @@
* Based on git-clean.sh by Pavel Roskin
*/
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "config.h"
@@ -714,7 +713,7 @@
for_each_string_list_item(item, &del_list) {
int dtype = DT_UNKNOWN;
- if (is_excluded(&dir, &the_index, item->string, &dtype)) {
+ if (is_excluded(&dir, the_repository->index, item->string, &dtype)) {
*item->string = '\0';
changed++;
}
@@ -1021,7 +1020,7 @@
PATHSPEC_PREFER_CWD,
prefix, argv);
- fill_directory(&dir, &the_index, &pathspec);
+ fill_directory(&dir, the_repository->index, &pathspec);
correct_untracked_entries(&dir);
for (i = 0; i < dir.nr; i++) {
@@ -1029,7 +1028,7 @@
struct stat st;
const char *rel;
- if (!index_name_is_other(&the_index, ent->name, ent->len))
+ if (!index_name_is_other(the_repository->index, ent->name, ent->len))
continue;
if (lstat(ent->name, &st))
diff --git a/builtin/clone.c b/builtin/clone.c
index 5fbe39f..b28f88e 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -8,7 +8,6 @@
* Clone a repository into a different directory that does not yet exist.
*/
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "advice.h"
@@ -72,7 +71,7 @@
static struct string_list option_not = STRING_LIST_INIT_NODUP;
static const char *real_git_dir;
static const char *ref_format;
-static char *option_upload_pack = "git-upload-pack";
+static const char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
static int option_sparse_checkout;
@@ -178,8 +177,8 @@
static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
{
- static char *suffix[] = { "/.git", "", ".git/.git", ".git" };
- static char *bundle_suffix[] = { ".bundle", "" };
+ static const char *suffix[] = { "/.git", "", ".git/.git", ".git" };
+ static const char *bundle_suffix[] = { ".bundle", "" };
size_t baselen = path->len;
struct stat st;
int i;
@@ -524,6 +523,9 @@
struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
struct ref *local_refs = head;
struct ref **tail = head ? &head->next : &local_refs;
+ struct refspec_item tag_refspec;
+
+ refspec_item_init(&tag_refspec, TAG_REFSPEC, 0);
if (option_single_branch) {
struct ref *remote_head = NULL;
@@ -546,7 +548,7 @@
&tail, 0);
/* if --branch=tag, pull the requested tag explicitly */
- get_fetch_map(remote_head, tag_refspec, &tail, 0);
+ get_fetch_map(remote_head, &tag_refspec, &tail, 0);
}
free_refs(remote_head);
} else {
@@ -556,8 +558,9 @@
}
if (!option_mirror && !option_single_branch && !option_no_tags)
- get_fetch_map(refs, tag_refspec, &tail, 0);
+ get_fetch_map(refs, &tag_refspec, &tail, 0);
+ refspec_item_clear(&tag_refspec);
return local_refs;
}
@@ -568,7 +571,8 @@
struct ref_transaction *t;
struct strbuf err = STRBUF_INIT;
- t = ref_transaction_begin(&err);
+ t = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!t)
die("%s", err.buf);
@@ -576,7 +580,7 @@
if (!r->peer_ref)
continue;
if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
- 0, NULL, &err))
+ NULL, 0, NULL, &err))
die("%s", err.buf);
}
@@ -599,8 +603,9 @@
OBJECT_INFO_QUICK |
OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
- update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg,
+ ref->name, &ref->old_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
}
}
@@ -652,9 +657,9 @@
struct strbuf head_ref = STRBUF_INIT;
strbuf_addstr(&head_ref, branch_top);
strbuf_addstr(&head_ref, "HEAD");
- if (create_symref(head_ref.buf,
- remote_head_points_at->peer_ref->name,
- msg) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), head_ref.buf,
+ remote_head_points_at->peer_ref->name,
+ msg) < 0)
die(_("unable to update %s"), head_ref.buf);
strbuf_release(&head_ref);
}
@@ -666,33 +671,36 @@
const char *head;
if (our && skip_prefix(our->name, "refs/heads/", &head)) {
/* Local default branch link */
- if (create_symref("HEAD", our->name, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL) < 0)
die(_("unable to update HEAD"));
if (!option_bare) {
- update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ msg, "HEAD", &our->old_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
install_branch_config(0, head, remote_name, our->name);
}
} else if (our) {
struct commit *c = lookup_commit_reference(the_repository,
&our->old_oid);
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
- update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg,
+ "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
} else if (remote) {
/*
* We know remote HEAD points to a non-branch, or
* HEAD points to a branch but we don't know which one.
* Detach HEAD in all these cases.
*/
- update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg,
+ "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
} else if (unborn && skip_prefix(unborn, "refs/heads/", &head)) {
/*
* Unborn head from remote; same as "our" case above except
* that we have no ref to update.
*/
- if (create_symref("HEAD", unborn, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn, NULL) < 0)
die(_("unable to update HEAD"));
if (!option_bare)
install_branch_config(0, head, remote_name, unborn);
@@ -733,7 +741,8 @@
if (option_no_checkout)
return 0;
- head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ RESOLVE_REF_READING, &oid, NULL);
if (!head) {
warning(_("remote HEAD refers to nonexistent ref, "
"unable to checkout"));
@@ -760,8 +769,8 @@
opts.preserve_ignored = 0;
opts.fn = oneway_merge;
opts.verbose_update = (option_verbosity >= 0);
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
init_checkout_metadata(&opts.meta, head, &oid, NULL);
tree = parse_tree_indirect(&oid);
@@ -775,7 +784,7 @@
free(head);
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
@@ -965,7 +974,7 @@
int submodule_progress;
int filter_submodules = 0;
int hash_algo;
- unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
+ enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
const int do_not_override_repo_unix_permissions = -1;
struct transport_ls_refs_options transport_ls_refs_options =
@@ -1454,6 +1463,7 @@
} else if (remote_head) {
our_head_points_at = NULL;
} else {
+ char *to_free = NULL;
const char *branch;
if (!mapped_refs) {
@@ -1466,7 +1476,7 @@
"refs/heads/", &branch)) {
unborn_head = xstrdup(transport_ls_refs_options.unborn_head_target);
} else {
- branch = git_default_branch_name(0);
+ branch = to_free = repo_default_branch_name(the_repository, 0);
unborn_head = xstrfmt("refs/heads/%s", branch);
}
@@ -1482,6 +1492,8 @@
* a match.
*/
our_head_points_at = find_remote_branch(mapped_refs, branch);
+
+ free(to_free);
}
write_refspec_config(src_ref_prefix, our_head_points_at,
diff --git a/builtin/commit.c b/builtin/commit.c
index 6e14844..75c7411 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -5,7 +5,6 @@
* Based on git-commit.sh by Junio C Hamano and Linus Torvalds
*/
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -38,6 +37,7 @@
#include "commit-reach.h"
#include "commit-graph.h"
#include "pretty.h"
+#include "trailer.h"
static const char * const builtin_commit_usage[] = {
N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
@@ -107,13 +107,13 @@
} commit_style;
static const char *logfile, *force_author;
-static const char *template_file;
+static char *template_file;
/*
* The _message variables are commit names from which to take
* the commit message and/or authorship.
*/
static const char *author_message, *author_message_buffer;
-static char *edit_message, *use_message;
+static const char *edit_message, *use_message;
static char *fixup_message, *fixup_commit, *squash_message;
static const char *fixup_prefix;
static int all, also, interactive, patch_interactive, only, amend, signoff;
@@ -121,8 +121,8 @@
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int config_commit_verbose = -1; /* unspecified */
static int no_post_rewrite, allow_empty_message, pathspec_file_nul;
-static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
-static char *sign_commit, *pathspec_from_file;
+static const char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
+static const char *sign_commit, *pathspec_from_file;
static struct strvec trailer_args = STRVEC_INIT;
/*
@@ -133,7 +133,7 @@
* is specified explicitly.
*/
static enum commit_msg_cleanup_mode cleanup_mode;
-static const char *cleanup_arg;
+static char *cleanup_arg;
static enum commit_whence whence;
static int use_editor = 1, include_status = 1;
@@ -142,14 +142,6 @@
static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
-static int opt_pass_trailer(const struct option *opt, const char *arg, int unset)
-{
- BUG_ON_OPT_NEG(unset);
-
- strvec_pushl(opt->value, "--trailer", arg, NULL);
- return 0;
-}
-
static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)
{
enum wt_status_format *value = (enum wt_status_format *)opt->value;
@@ -266,19 +258,19 @@
if (with_tree) {
char *max_prefix = common_prefix(pattern);
- overlay_tree_on_index(&the_index, with_tree, max_prefix);
+ overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
free(max_prefix);
}
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
struct string_list_item *item;
if (ce->ce_flags & CE_UPDATE)
continue;
- if (!ce_path_match(&the_index, ce, pattern, m))
+ if (!ce_path_match(the_repository->index, ce, pattern, m))
continue;
item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
@@ -302,10 +294,10 @@
continue;
if (!lstat(p->string, &st)) {
- if (add_to_index(&the_index, p->string, &st, 0))
+ if (add_to_index(the_repository->index, p->string, &st, 0))
die(_("updating files failed"));
} else
- remove_file_from_index(&the_index, p->string);
+ remove_file_from_index(the_repository->index, p->string);
}
}
@@ -316,7 +308,7 @@
struct tree_desc t;
if (!current_head) {
- discard_index(&the_index);
+ discard_index(the_repository->index);
return;
}
@@ -324,8 +316,8 @@
opts.head_idx = 1;
opts.index_only = 1;
opts.merge = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.fn = oneway_merge;
tree = parse_tree_indirect(¤t_head->object.oid);
@@ -344,7 +336,7 @@
* refresh_flags contains REFRESH_QUIET, so the only errors
* are for unmerged entries.
*/
- if (refresh_index(&the_index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL))
+ if (refresh_index(the_repository->index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL))
die_resolve_conflict("commit");
}
@@ -393,7 +385,7 @@
refresh_cache_or_die(refresh_flags);
- if (write_locked_index(&the_index, &index_lock, 0))
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to create temporary index"));
old_repo_index_file = the_repository->index_file;
@@ -412,13 +404,13 @@
unsetenv(INDEX_ENVIRONMENT);
FREE_AND_NULL(old_index_env);
- discard_index(&the_index);
- read_index_from(&the_index, get_lock_file_path(&index_lock),
+ discard_index(the_repository->index);
+ read_index_from(the_repository->index, get_lock_file_path(&index_lock),
get_git_dir());
- if (cache_tree_update(&the_index, WRITE_TREE_SILENT) == 0) {
+ if (cache_tree_update(the_repository->index, WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
- if (write_locked_index(&the_index, &index_lock, 0))
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to update temporary index"));
} else
warning(_("Failed to update main cache tree"));
@@ -450,8 +442,8 @@
exit(128);
refresh_cache_or_die(refresh_flags);
- cache_tree_update(&the_index, WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, 0))
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to write new index file"));
commit_style = COMMIT_NORMAL;
ret = get_lock_file_path(&index_lock);
@@ -472,10 +464,10 @@
repo_hold_locked_index(the_repository, &index_lock,
LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags);
- if (the_index.cache_changed
- || !cache_tree_fully_valid(the_index.cache_tree))
- cache_tree_update(&the_index, WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock,
+ if (the_repository->index->cache_changed
+ || !cache_tree_fully_valid(the_repository->index->cache_tree))
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+ if (write_locked_index(the_repository->index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write new index file"));
commit_style = COMMIT_AS_IS;
@@ -516,15 +508,15 @@
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
exit(1);
- discard_index(&the_index);
+ discard_index(the_repository->index);
if (repo_read_index(the_repository) < 0)
die(_("cannot read the index"));
repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
add_remove_files(&partial);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
- cache_tree_update(&the_index, WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, 0))
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to write new index file"));
hold_lock_file_for_update(&false_lock,
@@ -534,14 +526,14 @@
create_base_index(current_head);
add_remove_files(&partial);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
- if (write_locked_index(&the_index, &false_lock, 0))
+ if (write_locked_index(the_repository->index, &false_lock, 0))
die(_("unable to write temporary index file"));
- discard_index(&the_index);
+ discard_index(the_repository->index);
ret = get_lock_file_path(&false_lock);
- read_index_from(&the_index, ret, get_git_dir());
+ read_index_from(the_repository->index, ret, get_git_dir());
out:
string_list_clear(&partial, 0);
clear_pathspec(&pathspec);
@@ -999,7 +991,7 @@
struct object_id oid;
const char *parent = "HEAD";
- if (!the_index.initialized && repo_read_index(the_repository) < 0)
+ if (!the_repository->index->initialized && repo_read_index(the_repository) < 0)
die(_("Cannot read index"));
if (amend)
@@ -1009,11 +1001,11 @@
int i, ita_nr = 0;
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++)
- if (ce_intent_to_add(the_index.cache[i]))
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++)
+ if (ce_intent_to_add(the_repository->index->cache[i]))
ita_nr++;
- committable = the_index.cache_nr - ita_nr > 0;
+ committable = the_repository->index->cache_nr - ita_nr > 0;
} else {
/*
* Unless the user did explicitly request a submodule
@@ -1038,14 +1030,7 @@
fclose(s->fp);
if (trailer_args.nr) {
- struct child_process run_trailer = CHILD_PROCESS_INIT;
-
- strvec_pushl(&run_trailer.args, "interpret-trailers",
- "--in-place", "--no-divider",
- git_path_commit_editmsg(), NULL);
- strvec_pushv(&run_trailer.args, trailer_args.v);
- run_trailer.git_cmd = 1;
- if (run_command(&run_trailer))
+ if (amend_file_with_trailers(git_path_commit_editmsg(), &trailer_args))
die(_("unable to pass trailers to --trailers"));
strvec_clear(&trailer_args);
}
@@ -1081,11 +1066,11 @@
* and could have updated it. We must do this before we invoke
* the editor and after we invoke run_status above.
*/
- discard_index(&the_index);
+ discard_index(the_repository->index);
}
- read_index_from(&the_index, index_file, get_git_dir());
+ read_index_from(the_repository->index, index_file, get_git_dir());
- if (cache_tree_update(&the_index, 0)) {
+ if (cache_tree_update(the_repository->index, 0)) {
error(_("Error building trees"));
return 0;
}
@@ -1586,7 +1571,7 @@
status_format != STATUS_FORMAT_PORCELAIN_V2)
progress_flag = REFRESH_PROGRESS;
repo_read_index(the_repository);
- refresh_index(&the_index,
+ refresh_index(the_repository->index,
REFRESH_QUIET|REFRESH_UNMERGED|progress_flag,
&s.pathspec, NULL, NULL);
@@ -1673,7 +1658,7 @@
OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword specified commit")),
OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
- OPT_CALLBACK_F(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG, opt_pass_trailer),
+ OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG),
OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),
OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
@@ -1856,7 +1841,7 @@
append_merge_tag_headers(parents, &tail);
}
- if (commit_tree_extended(sb.buf, sb.len, &the_index.cache_tree->oid,
+ if (commit_tree_extended(sb.buf, sb.len, &the_repository->index->cache_tree->oid,
parents, &oid, author_ident.buf, NULL,
sign_commit, extra)) {
rollback_index_files();
diff --git a/builtin/config.c b/builtin/config.c
index 0015620..20a0b64 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -16,59 +16,112 @@
#include "worktree.h"
static const char *const builtin_config_usage[] = {
- N_("git config [<options>]"),
+ N_("git config list [<file-option>] [<display-option>] [--includes]"),
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+ N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ N_("git config rename-section [<file-option>] <old-name> <new-name>"),
+ N_("git config remove-section [<file-option>] <name>"),
+ N_("git config edit [<file-option>]"),
+ N_("git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"),
NULL
};
-static char *key;
-static regex_t *key_regexp;
-static const char *value_pattern;
-static regex_t *regexp;
-static int show_keys;
-static int omit_values;
-static int use_key_regexp;
-static int do_all;
-static int do_not_match;
-static char delim = '=';
-static char key_delim = ' ';
-static char term = '\n';
+static const char *const builtin_config_list_usage[] = {
+ N_("git config list [<file-option>] [<display-option>] [--includes]"),
+ NULL
+};
-static int use_global_config, use_system_config, use_local_config;
-static int use_worktree_config;
-static struct git_config_source given_config_source;
-static int actions, type;
-static char *default_value;
-static int end_nul;
-static int respect_includes_opt = -1;
-static struct config_options config_options;
-static int show_origin;
-static int show_scope;
-static int fixed_value;
-static const char *comment;
+static const char *const builtin_config_get_usage[] = {
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+ NULL
+};
-#define ACTION_GET (1<<0)
-#define ACTION_GET_ALL (1<<1)
-#define ACTION_GET_REGEXP (1<<2)
-#define ACTION_REPLACE_ALL (1<<3)
-#define ACTION_ADD (1<<4)
-#define ACTION_UNSET (1<<5)
-#define ACTION_UNSET_ALL (1<<6)
-#define ACTION_RENAME_SECTION (1<<7)
-#define ACTION_REMOVE_SECTION (1<<8)
-#define ACTION_LIST (1<<9)
-#define ACTION_EDIT (1<<10)
-#define ACTION_SET (1<<11)
-#define ACTION_SET_ALL (1<<12)
-#define ACTION_GET_COLOR (1<<13)
-#define ACTION_GET_COLORBOOL (1<<14)
-#define ACTION_GET_URLMATCH (1<<15)
+static const char *const builtin_config_set_usage[] = {
+ N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ NULL
+};
-/*
- * The actions "ACTION_LIST | ACTION_GET_*" which may produce more than
- * one line of output and which should therefore be paged.
- */
-#define PAGING_ACTIONS (ACTION_LIST | ACTION_GET_ALL | \
- ACTION_GET_REGEXP | ACTION_GET_URLMATCH)
+static const char *const builtin_config_unset_usage[] = {
+ N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ NULL
+};
+
+static const char *const builtin_config_rename_section_usage[] = {
+ N_("git config rename-section [<file-option>] <old-name> <new-name>"),
+ NULL
+};
+
+static const char *const builtin_config_remove_section_usage[] = {
+ N_("git config remove-section [<file-option>] <name>"),
+ NULL
+};
+
+static const char *const builtin_config_edit_usage[] = {
+ N_("git config edit [<file-option>]"),
+ NULL
+};
+
+#define CONFIG_LOCATION_OPTIONS(opts) \
+ OPT_GROUP(N_("Config file location")), \
+ OPT_BOOL(0, "global", &opts.use_global_config, N_("use global config file")), \
+ OPT_BOOL(0, "system", &opts.use_system_config, N_("use system config file")), \
+ OPT_BOOL(0, "local", &opts.use_local_config, N_("use repository config file")), \
+ OPT_BOOL(0, "worktree", &opts.use_worktree_config, N_("use per-worktree config file")), \
+ OPT_STRING('f', "file", &opts.source.file, N_("file"), N_("use given config file")), \
+ OPT_STRING(0, "blob", &opts.source.blob, N_("blob-id"), N_("read config from given blob object"))
+
+struct config_location_options {
+ struct git_config_source source;
+ struct config_options options;
+ char *file_to_free;
+ int use_global_config;
+ int use_system_config;
+ int use_local_config;
+ int use_worktree_config;
+ int respect_includes_opt;
+};
+#define CONFIG_LOCATION_OPTIONS_INIT { \
+ .respect_includes_opt = -1, \
+}
+
+#define CONFIG_TYPE_OPTIONS(type) \
+ OPT_GROUP(N_("Type")), \
+ OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \
+ OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), \
+ OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), \
+ OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), \
+ OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), \
+ OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH), \
+ OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE)
+
+#define CONFIG_DISPLAY_OPTIONS(opts) \
+ OPT_GROUP(N_("Display options")), \
+ OPT_BOOL('z', "null", &opts.end_nul, N_("terminate values with NUL byte")), \
+ OPT_BOOL(0, "name-only", &opts.omit_values, N_("show variable names only")), \
+ OPT_BOOL(0, "show-origin", &opts.show_origin, N_("show origin of config (file, standard input, blob, command line)")), \
+ OPT_BOOL(0, "show-scope", &opts.show_scope, N_("show scope of config (worktree, local, global, system, command)")), \
+ OPT_BOOL(0, "show-names", &opts.show_keys, N_("show config keys in addition to their values")), \
+ CONFIG_TYPE_OPTIONS(opts.type)
+
+struct config_display_options {
+ int end_nul;
+ int omit_values;
+ int show_origin;
+ int show_scope;
+ int show_keys;
+ int type;
+ char *default_value;
+ /* Populated via `display_options_init()`. */
+ int term;
+ int delim;
+ int key_delim;
+};
+#define CONFIG_DISPLAY_OPTIONS_INIT { \
+ .term = '\n', \
+ .delim = '=', \
+ .key_delim = ' ', \
+}
#define TYPE_BOOL 1
#define TYPE_INT 2
@@ -82,8 +135,6 @@
{ OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
PARSE_OPT_NONEG, option_parse_type, (i) }
-static NORETURN void usage_builtin_config(void);
-
static int option_parse_type(const struct option *opt, const char *arg,
int unset)
{
@@ -128,61 +179,13 @@
* --type=int'.
*/
error(_("only one type at a time"));
- usage_builtin_config();
+ exit(129);
}
*to_type = new_type;
return 0;
}
-static struct option builtin_config_options[] = {
- OPT_GROUP(N_("Config file location")),
- OPT_BOOL(0, "global", &use_global_config, N_("use global config file")),
- OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
- OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")),
- OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")),
- OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")),
- OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")),
- OPT_GROUP(N_("Action")),
- OPT_BIT(0, "get", &actions, N_("get value: name [value-pattern]"), ACTION_GET),
- OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-pattern]"), ACTION_GET_ALL),
- OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-pattern]"), ACTION_GET_REGEXP),
- OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
- OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value-pattern]"), ACTION_REPLACE_ALL),
- OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
- OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-pattern]"), ACTION_UNSET),
- OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-pattern]"), ACTION_UNSET_ALL),
- OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
- OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
- OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
- OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")),
- OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
- OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
- OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL),
- OPT_GROUP(N_("Type")),
- OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type),
- OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
- OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT),
- OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
- OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR),
- OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
- OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
- OPT_GROUP(N_("Other")),
- OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
- OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
- OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
- OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
- OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
- OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
- OPT_STRING(0, "comment", &comment, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
- OPT_END(),
-};
-
-static NORETURN void usage_builtin_config(void)
-{
- usage_with_options(builtin_config_usage, builtin_config_options);
-}
-
static void check_argc(int argc, int min, int max)
{
if (argc >= min && argc <= max)
@@ -192,27 +195,29 @@
else
error(_("wrong number of arguments, should be from %d to %d"),
min, max);
- usage_builtin_config();
+ exit(129);
}
-static void show_config_origin(const struct key_value_info *kvi,
+static void show_config_origin(const struct config_display_options *opts,
+ const struct key_value_info *kvi,
struct strbuf *buf)
{
- const char term = end_nul ? '\0' : '\t';
+ const char term = opts->end_nul ? '\0' : '\t';
strbuf_addstr(buf, config_origin_type_name(kvi->origin_type));
strbuf_addch(buf, ':');
- if (end_nul)
+ if (opts->end_nul)
strbuf_addstr(buf, kvi->filename ? kvi->filename : "");
else
quote_c_style(kvi->filename ? kvi->filename : "", buf, NULL, 0);
strbuf_addch(buf, term);
}
-static void show_config_scope(const struct key_value_info *kvi,
+static void show_config_scope(const struct config_display_options *opts,
+ const struct key_value_info *kvi,
struct strbuf *buf)
{
- const char term = end_nul ? '\0' : '\t';
+ const char term = opts->end_nul ? '\0' : '\t';
const char *scope = config_scope_name(kvi->scope);
strbuf_addstr(buf, N_(scope));
@@ -221,24 +226,25 @@
static int show_all_config(const char *key_, const char *value_,
const struct config_context *ctx,
- void *cb UNUSED)
+ void *cb)
{
+ const struct config_display_options *opts = cb;
const struct key_value_info *kvi = ctx->kvi;
- if (show_origin || show_scope) {
+ if (opts->show_origin || opts->show_scope) {
struct strbuf buf = STRBUF_INIT;
- if (show_scope)
- show_config_scope(kvi, &buf);
- if (show_origin)
- show_config_origin(kvi, &buf);
+ if (opts->show_scope)
+ show_config_scope(opts, kvi, &buf);
+ if (opts->show_origin)
+ show_config_origin(opts, kvi, &buf);
/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
fwrite(buf.buf, 1, buf.len, stdout);
strbuf_release(&buf);
}
- if (!omit_values && value_)
- printf("%s%c%s%c", key_, delim, value_, term);
+ if (!opts->omit_values && value_)
+ printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
else
- printf("%s%c", key_, term);
+ printf("%s%c", key_, opts->term);
return 0;
}
@@ -248,26 +254,27 @@
int alloc;
};
-static int format_config(struct strbuf *buf, const char *key_,
+static int format_config(const struct config_display_options *opts,
+ struct strbuf *buf, const char *key_,
const char *value_, const struct key_value_info *kvi)
{
- if (show_scope)
- show_config_scope(kvi, buf);
- if (show_origin)
- show_config_origin(kvi, buf);
- if (show_keys)
+ if (opts->show_scope)
+ show_config_scope(opts, kvi, buf);
+ if (opts->show_origin)
+ show_config_origin(opts, kvi, buf);
+ if (opts->show_keys)
strbuf_addstr(buf, key_);
- if (!omit_values) {
- if (show_keys)
- strbuf_addch(buf, key_delim);
+ if (!opts->omit_values) {
+ if (opts->show_keys)
+ strbuf_addch(buf, opts->key_delim);
- if (type == TYPE_INT)
+ if (opts->type == TYPE_INT)
strbuf_addf(buf, "%"PRId64,
git_config_int64(key_, value_ ? value_ : "", kvi));
- else if (type == TYPE_BOOL)
+ else if (opts->type == TYPE_BOOL)
strbuf_addstr(buf, git_config_bool(key_, value_) ?
"true" : "false");
- else if (type == TYPE_BOOL_OR_INT) {
+ else if (opts->type == TYPE_BOOL_OR_INT) {
int is_bool, v;
v = git_config_bool_or_int(key_, value_, kvi,
&is_bool);
@@ -275,24 +282,24 @@
strbuf_addstr(buf, v ? "true" : "false");
else
strbuf_addf(buf, "%d", v);
- } else if (type == TYPE_BOOL_OR_STR) {
+ } else if (opts->type == TYPE_BOOL_OR_STR) {
int v = git_parse_maybe_bool(value_);
if (v < 0)
strbuf_addstr(buf, value_);
else
strbuf_addstr(buf, v ? "true" : "false");
- } else if (type == TYPE_PATH) {
- const char *v;
+ } else if (opts->type == TYPE_PATH) {
+ char *v;
if (git_config_pathname(&v, key_, value_) < 0)
return -1;
strbuf_addstr(buf, v);
free((char *)v);
- } else if (type == TYPE_EXPIRY_DATE) {
+ } else if (opts->type == TYPE_EXPIRY_DATE) {
timestamp_t t;
if (git_config_expiry_date(&t, key_, value_) < 0)
return -1;
strbuf_addf(buf, "%"PRItime, t);
- } else if (type == TYPE_COLOR) {
+ } else if (opts->type == TYPE_COLOR) {
char v[COLOR_MAXLEN];
if (git_config_color(v, key_, value_) < 0)
return -1;
@@ -301,43 +308,73 @@
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
- if (show_keys)
+ if (opts->show_keys)
strbuf_setlen(buf, buf->len - 1);
}
}
- strbuf_addch(buf, term);
+ strbuf_addch(buf, opts->term);
return 0;
}
+#define GET_VALUE_ALL (1 << 0)
+#define GET_VALUE_KEY_REGEXP (1 << 1)
+
+struct collect_config_data {
+ const struct config_display_options *display_opts;
+ struct strbuf_list *values;
+ const char *value_pattern;
+ const char *key;
+ regex_t *regexp;
+ regex_t *key_regexp;
+ int do_not_match;
+ unsigned get_value_flags;
+ unsigned flags;
+};
+
static int collect_config(const char *key_, const char *value_,
const struct config_context *ctx, void *cb)
{
- struct strbuf_list *values = cb;
+ struct collect_config_data *data = cb;
+ struct strbuf_list *values = data->values;
const struct key_value_info *kvi = ctx->kvi;
- if (!use_key_regexp && strcmp(key_, key))
+ if (!(data->get_value_flags & GET_VALUE_KEY_REGEXP) &&
+ strcmp(key_, data->key))
return 0;
- if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
+ if ((data->get_value_flags & GET_VALUE_KEY_REGEXP) &&
+ regexec(data->key_regexp, key_, 0, NULL, 0))
return 0;
- if (fixed_value && strcmp(value_pattern, (value_?value_:"")))
+ if ((data->flags & CONFIG_FLAGS_FIXED_VALUE) &&
+ strcmp(data->value_pattern, (value_?value_:"")))
return 0;
- if (regexp != NULL &&
- (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
+ if (data->regexp &&
+ (data->do_not_match ^ !!regexec(data->regexp, (value_?value_:""), 0, NULL, 0)))
return 0;
ALLOC_GROW(values->items, values->nr + 1, values->alloc);
strbuf_init(&values->items[values->nr], 0);
- return format_config(&values->items[values->nr++], key_, value_, kvi);
+ return format_config(data->display_opts, &values->items[values->nr++],
+ key_, value_, kvi);
}
-static int get_value(const char *key_, const char *regex_, unsigned flags)
+static int get_value(const struct config_location_options *opts,
+ const struct config_display_options *display_opts,
+ const char *key_, const char *regex_,
+ unsigned get_value_flags, unsigned flags)
{
int ret = CONFIG_GENERIC_ERROR;
struct strbuf_list values = {NULL};
+ struct collect_config_data data = {
+ .display_opts = display_opts,
+ .values = &values,
+ .get_value_flags = get_value_flags,
+ .flags = flags,
+ };
+ char *key = NULL;
int i;
- if (use_key_regexp) {
+ if (get_value_flags & GET_VALUE_KEY_REGEXP) {
char *tl;
/*
@@ -354,10 +391,10 @@
for (tl = key; *tl && *tl != '.'; tl++)
*tl = tolower(*tl);
- key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
- if (regcomp(key_regexp, key, REG_EXTENDED)) {
+ data.key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
+ if (regcomp(data.key_regexp, key, REG_EXTENDED)) {
error(_("invalid key pattern: %s"), key_);
- FREE_AND_NULL(key_regexp);
+ FREE_AND_NULL(data.key_regexp);
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
@@ -366,30 +403,32 @@
ret = CONFIG_INVALID_KEY;
goto free_strings;
}
+
+ data.key = key;
}
if (regex_ && (flags & CONFIG_FLAGS_FIXED_VALUE))
- value_pattern = regex_;
+ data.value_pattern = regex_;
else if (regex_) {
if (regex_[0] == '!') {
- do_not_match = 1;
+ data.do_not_match = 1;
regex_++;
}
- regexp = (regex_t*)xmalloc(sizeof(regex_t));
- if (regcomp(regexp, regex_, REG_EXTENDED)) {
+ data.regexp = (regex_t*)xmalloc(sizeof(regex_t));
+ if (regcomp(data.regexp, regex_, REG_EXTENDED)) {
error(_("invalid pattern: %s"), regex_);
- FREE_AND_NULL(regexp);
+ FREE_AND_NULL(data.regexp);
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
}
- config_with_options(collect_config, &values,
- &given_config_source, the_repository,
- &config_options);
+ config_with_options(collect_config, &data,
+ &opts->source, the_repository,
+ &opts->options);
- if (!values.nr && default_value) {
+ if (!values.nr && display_opts->default_value) {
struct key_value_info kvi = KVI_INIT;
struct strbuf *item;
@@ -397,16 +436,17 @@
ALLOC_GROW(values.items, values.nr + 1, values.alloc);
item = &values.items[values.nr++];
strbuf_init(item, 0);
- if (format_config(item, key_, default_value, &kvi) < 0)
+ if (format_config(display_opts, item, key_,
+ display_opts->default_value, &kvi) < 0)
die(_("failed to format default config value: %s"),
- default_value);
+ display_opts->default_value);
}
ret = !values.nr;
for (i = 0; i < values.nr; i++) {
struct strbuf *buf = values.items + i;
- if (do_all || i == values.nr - 1)
+ if ((get_value_flags & GET_VALUE_ALL) || i == values.nr - 1)
fwrite(buf->buf, 1, buf->len, stdout);
strbuf_release(buf);
}
@@ -414,20 +454,20 @@
free_strings:
free(key);
- if (key_regexp) {
- regfree(key_regexp);
- free(key_regexp);
+ if (data.key_regexp) {
+ regfree(data.key_regexp);
+ free(data.key_regexp);
}
- if (regexp) {
- regfree(regexp);
- free(regexp);
+ if (data.regexp) {
+ regfree(data.regexp);
+ free(data.regexp);
}
return ret;
}
static char *normalize_value(const char *key, const char *value,
- struct key_value_info *kvi)
+ int type, struct key_value_info *kvi)
{
if (!value)
return NULL;
@@ -478,97 +518,113 @@
BUG("cannot normalize type %d", type);
}
-static int get_color_found;
-static const char *get_color_slot;
-static const char *get_colorbool_slot;
-static char parsed_color[COLOR_MAXLEN];
+struct get_color_config_data {
+ int get_color_found;
+ const char *get_color_slot;
+ char parsed_color[COLOR_MAXLEN];
+};
static int git_get_color_config(const char *var, const char *value,
const struct config_context *ctx UNUSED,
- void *cb UNUSED)
+ void *cb)
{
- if (!strcmp(var, get_color_slot)) {
+ struct get_color_config_data *data = cb;
+
+ if (!strcmp(var, data->get_color_slot)) {
if (!value)
config_error_nonbool(var);
- if (color_parse(value, parsed_color) < 0)
+ if (color_parse(value, data->parsed_color) < 0)
return -1;
- get_color_found = 1;
+ data->get_color_found = 1;
}
return 0;
}
-static void get_color(const char *var, const char *def_color)
+static void get_color(const struct config_location_options *opts,
+ const char *var, const char *def_color)
{
- get_color_slot = var;
- get_color_found = 0;
- parsed_color[0] = '\0';
- config_with_options(git_get_color_config, NULL,
- &given_config_source, the_repository,
- &config_options);
+ struct get_color_config_data data = {
+ .get_color_slot = var,
+ .parsed_color[0] = '\0',
+ };
- if (!get_color_found && def_color) {
- if (color_parse(def_color, parsed_color) < 0)
+ config_with_options(git_get_color_config, &data,
+ &opts->source, the_repository,
+ &opts->options);
+
+ if (!data.get_color_found && def_color) {
+ if (color_parse(def_color, data.parsed_color) < 0)
die(_("unable to parse default color value"));
}
- fputs(parsed_color, stdout);
+ fputs(data.parsed_color, stdout);
}
-static int get_colorbool_found;
-static int get_diff_color_found;
-static int get_color_ui_found;
+struct get_colorbool_config_data {
+ int get_colorbool_found;
+ int get_diff_color_found;
+ int get_color_ui_found;
+ const char *get_colorbool_slot;
+};
+
static int git_get_colorbool_config(const char *var, const char *value,
const struct config_context *ctx UNUSED,
- void *data UNUSED)
+ void *cb)
{
- if (!strcmp(var, get_colorbool_slot))
- get_colorbool_found = git_config_colorbool(var, value);
+ struct get_colorbool_config_data *data = cb;
+
+ if (!strcmp(var, data->get_colorbool_slot))
+ data->get_colorbool_found = git_config_colorbool(var, value);
else if (!strcmp(var, "diff.color"))
- get_diff_color_found = git_config_colorbool(var, value);
+ data->get_diff_color_found = git_config_colorbool(var, value);
else if (!strcmp(var, "color.ui"))
- get_color_ui_found = git_config_colorbool(var, value);
+ data->get_color_ui_found = git_config_colorbool(var, value);
return 0;
}
-static int get_colorbool(const char *var, int print)
+static int get_colorbool(const struct config_location_options *opts,
+ const char *var, int print)
{
- get_colorbool_slot = var;
- get_colorbool_found = -1;
- get_diff_color_found = -1;
- get_color_ui_found = -1;
- config_with_options(git_get_colorbool_config, NULL,
- &given_config_source, the_repository,
- &config_options);
+ struct get_colorbool_config_data data = {
+ .get_colorbool_slot = var,
+ .get_colorbool_found = -1,
+ .get_diff_color_found = -1,
+ .get_color_ui_found = -1,
+ };
- if (get_colorbool_found < 0) {
- if (!strcmp(get_colorbool_slot, "color.diff"))
- get_colorbool_found = get_diff_color_found;
- if (get_colorbool_found < 0)
- get_colorbool_found = get_color_ui_found;
+ config_with_options(git_get_colorbool_config, &data,
+ &opts->source, the_repository,
+ &opts->options);
+
+ if (data.get_colorbool_found < 0) {
+ if (!strcmp(data.get_colorbool_slot, "color.diff"))
+ data.get_colorbool_found = data.get_diff_color_found;
+ if (data.get_colorbool_found < 0)
+ data.get_colorbool_found = data.get_color_ui_found;
}
- if (get_colorbool_found < 0)
+ if (data.get_colorbool_found < 0)
/* default value if none found in config */
- get_colorbool_found = GIT_COLOR_AUTO;
+ data.get_colorbool_found = GIT_COLOR_AUTO;
- get_colorbool_found = want_color(get_colorbool_found);
+ data.get_colorbool_found = want_color(data.get_colorbool_found);
if (print) {
- printf("%s\n", get_colorbool_found ? "true" : "false");
+ printf("%s\n", data.get_colorbool_found ? "true" : "false");
return 0;
} else
- return get_colorbool_found ? 0 : 1;
+ return data.get_colorbool_found ? 0 : 1;
}
-static void check_write(void)
+static void check_write(const struct git_config_source *source)
{
- if (!given_config_source.file && !startup_info->have_repository)
+ if (!source->file && !startup_info->have_repository)
die(_("not in a git directory"));
- if (given_config_source.use_stdin)
+ if (source->use_stdin)
die(_("writing to stdin is not supported"));
- if (given_config_source.blob)
+ if (source->blob)
die(_("writing config blobs is not supported"));
}
@@ -605,10 +661,13 @@
return 0;
}
-static int get_urlmatch(const char *var, const char *url)
+static int get_urlmatch(const struct config_location_options *opts,
+ const struct config_display_options *_display_opts,
+ const char *var, const char *url)
{
int ret;
char *section_tail;
+ struct config_display_options display_opts = *_display_opts;
struct string_list_item *item;
struct urlmatch_config config = URLMATCH_CONFIG_INIT;
struct string_list values = STRING_LIST_INIT_DUP;
@@ -625,15 +684,15 @@
if (section_tail) {
*section_tail = '\0';
config.key = section_tail + 1;
- show_keys = 0;
+ display_opts.show_keys = 0;
} else {
config.key = NULL;
- show_keys = 1;
+ display_opts.show_keys = 1;
}
config_with_options(urlmatch_config_entry, &config,
- &given_config_source, the_repository,
- &config_options);
+ &opts->source, the_repository,
+ &opts->options);
ret = !values.nr;
@@ -641,7 +700,7 @@
struct urlmatch_current_candidate_value *matched = item->util;
struct strbuf buf = STRBUF_INIT;
- format_config(&buf, item->string,
+ format_config(&display_opts, &buf, item->string,
matched->value_is_null ? NULL : matched->value.buf,
&matched->kvi);
fwrite(buf.buf, 1, buf.len, stdout);
@@ -671,47 +730,39 @@
return strbuf_detach(&buf, NULL);
}
-int cmd_config(int argc, const char **argv, const char *prefix)
+static void location_options_init(struct config_location_options *opts,
+ const char *prefix)
{
- int nongit = !startup_info->have_repository;
- char *value = NULL;
- int flags = 0;
- int ret = 0;
- struct key_value_info default_kvi = KVI_INIT;
+ if (!opts->source.file)
+ opts->source.file = opts->file_to_free =
+ xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
- given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
-
- argc = parse_options(argc, argv, prefix, builtin_config_options,
- builtin_config_usage,
- PARSE_OPT_STOP_AT_NON_OPTION);
-
- if (use_global_config + use_system_config + use_local_config +
- use_worktree_config +
- !!given_config_source.file + !!given_config_source.blob > 1) {
+ if (opts->use_global_config + opts->use_system_config +
+ opts->use_local_config + opts->use_worktree_config +
+ !!opts->source.file + !!opts->source.blob > 1) {
error(_("only one config file at a time"));
- usage_builtin_config();
+ exit(129);
}
- if (nongit) {
- if (use_local_config)
+ if (!startup_info->have_repository) {
+ if (opts->use_local_config)
die(_("--local can only be used inside a git repository"));
- if (given_config_source.blob)
+ if (opts->source.blob)
die(_("--blob can only be used inside a git repository"));
- if (use_worktree_config)
+ if (opts->use_worktree_config)
die(_("--worktree can only be used inside a git repository"));
-
}
- if (given_config_source.file &&
- !strcmp(given_config_source.file, "-")) {
- given_config_source.file = NULL;
- given_config_source.use_stdin = 1;
- given_config_source.scope = CONFIG_SCOPE_COMMAND;
+ if (opts->source.file &&
+ !strcmp(opts->source.file, "-")) {
+ opts->source.file = NULL;
+ opts->source.use_stdin = 1;
+ opts->source.scope = CONFIG_SCOPE_COMMAND;
}
- if (use_global_config) {
- given_config_source.file = git_global_config();
- if (!given_config_source.file)
+ if (opts->use_global_config) {
+ opts->source.file = opts->file_to_free = git_global_config();
+ if (!opts->source.file)
/*
* It is unknown if HOME/.gitconfig exists, so
* we do not know if we should write to XDG
@@ -719,17 +770,18 @@
* is set and points at a sane location.
*/
die(_("$HOME not set"));
- given_config_source.scope = CONFIG_SCOPE_GLOBAL;
- } else if (use_system_config) {
- given_config_source.file = git_system_config();
- given_config_source.scope = CONFIG_SCOPE_SYSTEM;
- } else if (use_local_config) {
- given_config_source.file = git_pathdup("config");
- given_config_source.scope = CONFIG_SCOPE_LOCAL;
- } else if (use_worktree_config) {
+ opts->source.scope = CONFIG_SCOPE_GLOBAL;
+ } else if (opts->use_system_config) {
+ opts->source.file = opts->file_to_free = git_system_config();
+ opts->source.scope = CONFIG_SCOPE_SYSTEM;
+ } else if (opts->use_local_config) {
+ opts->source.file = opts->file_to_free = git_pathdup("config");
+ opts->source.scope = CONFIG_SCOPE_LOCAL;
+ } else if (opts->use_worktree_config) {
struct worktree **worktrees = get_worktrees();
if (the_repository->repository_format_worktree_config)
- given_config_source.file = git_pathdup("config.worktree");
+ opts->source.file = opts->file_to_free =
+ git_pathdup("config.worktree");
else if (worktrees[0] && worktrees[1])
die(_("--worktree cannot be used with multiple "
"working trees unless the config\n"
@@ -737,76 +789,439 @@
"Please read \"CONFIGURATION FILE\"\n"
"section in \"git help worktree\" for details"));
else
- given_config_source.file = git_pathdup("config");
- given_config_source.scope = CONFIG_SCOPE_LOCAL;
+ opts->source.file = opts->file_to_free =
+ git_pathdup("config");
+ opts->source.scope = CONFIG_SCOPE_LOCAL;
free_worktrees(worktrees);
- } else if (given_config_source.file) {
- if (!is_absolute_path(given_config_source.file) && prefix)
- given_config_source.file =
- prefix_filename(prefix, given_config_source.file);
- given_config_source.scope = CONFIG_SCOPE_COMMAND;
- } else if (given_config_source.blob) {
- given_config_source.scope = CONFIG_SCOPE_COMMAND;
+ } else if (opts->source.file) {
+ if (!is_absolute_path(opts->source.file) && prefix)
+ opts->source.file = opts->file_to_free =
+ prefix_filename(prefix, opts->source.file);
+ opts->source.scope = CONFIG_SCOPE_COMMAND;
+ } else if (opts->source.blob) {
+ opts->source.scope = CONFIG_SCOPE_COMMAND;
}
- if (respect_includes_opt == -1)
- config_options.respect_includes = !given_config_source.file;
+ if (opts->respect_includes_opt == -1)
+ opts->options.respect_includes = !opts->source.file;
else
- config_options.respect_includes = respect_includes_opt;
- if (!nongit) {
- config_options.commondir = get_git_common_dir();
- config_options.git_dir = get_git_dir();
+ opts->options.respect_includes = opts->respect_includes_opt;
+ if (startup_info->have_repository) {
+ opts->options.commondir = get_git_common_dir();
+ opts->options.git_dir = get_git_dir();
+ }
+}
+
+static void location_options_release(struct config_location_options *opts)
+{
+ free(opts->file_to_free);
+}
+
+static void display_options_init(struct config_display_options *opts)
+{
+ if (opts->end_nul) {
+ opts->term = '\0';
+ opts->delim = '\n';
+ opts->key_delim = '\n';
+ }
+}
+
+static int cmd_config_list(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ CONFIG_DISPLAY_OPTIONS(display_opts),
+ OPT_GROUP(N_("Other")),
+ OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+ N_("respect include directives on lookup")),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_list_usage, 0);
+ check_argc(argc, 0, 0);
+
+ location_options_init(&location_opts, prefix);
+ display_options_init(&display_opts);
+
+ setup_auto_pager("config", 1);
+
+ if (config_with_options(show_all_config, &display_opts,
+ &location_opts.source, the_repository,
+ &location_opts.options) < 0) {
+ if (location_opts.source.file)
+ die_errno(_("unable to read config file '%s'"),
+ location_opts.source.file);
+ else
+ die(_("error processing config file(s)"));
}
- if (end_nul) {
- term = '\0';
- delim = '\n';
- key_delim = '\n';
+ location_options_release(&location_opts);
+ return 0;
+}
+
+static int cmd_config_get(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+ const char *value_pattern = NULL, *url = NULL;
+ int flags = 0;
+ unsigned get_value_flags = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_GROUP(N_("Filter options")),
+ OPT_BIT(0, "all", &get_value_flags, N_("return all values for multi-valued config options"), GET_VALUE_ALL),
+ OPT_BIT(0, "regexp", &get_value_flags, N_("interpret the name as a regular expression"), GET_VALUE_KEY_REGEXP),
+ OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_STRING(0, "url", &url, N_("URL"), N_("show config matching the given URL")),
+ CONFIG_DISPLAY_OPTIONS(display_opts),
+ OPT_GROUP(N_("Other")),
+ OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+ N_("respect include directives on lookup")),
+ OPT_STRING(0, "default", &display_opts.default_value,
+ N_("value"), N_("use default value when missing entry")),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_get_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 1, 1);
+
+ if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+ die(_("--fixed-value only applies with 'value-pattern'"));
+ if (display_opts.default_value &&
+ ((get_value_flags & GET_VALUE_ALL) || url))
+ die(_("--default= cannot be used with --all or --url="));
+ if (url && ((get_value_flags & GET_VALUE_ALL) ||
+ (get_value_flags & GET_VALUE_KEY_REGEXP) ||
+ value_pattern))
+ die(_("--url= cannot be used with --all, --regexp or --value"));
+
+ location_options_init(&location_opts, prefix);
+ display_options_init(&display_opts);
+
+ setup_auto_pager("config", 1);
+
+ if (url)
+ ret = get_urlmatch(&location_opts, &display_opts, argv[0], url);
+ else
+ ret = get_value(&location_opts, &display_opts, argv[0], value_pattern,
+ get_value_flags, flags);
+
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_set(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ const char *value_pattern = NULL, *comment_arg = NULL;
+ char *comment = NULL;
+ int flags = 0, append = 0, type = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ CONFIG_TYPE_OPTIONS(type),
+ OPT_GROUP(N_("Filter")),
+ OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
+ OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_GROUP(N_("Other")),
+ OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
+ OPT_BOOL(0, "append", &append, N_("add a new line without altering any existing values")),
+ OPT_END(),
+ };
+ struct key_value_info default_kvi = KVI_INIT;
+ char *value;
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_set_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 2, 2);
+
+ if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+ die(_("--fixed-value only applies with --value=<pattern>"));
+ if (append && value_pattern)
+ die(_("--append cannot be used with --value=<pattern>"));
+ if (append)
+ value_pattern = CONFIG_REGEX_NONE;
+
+ comment = git_config_prepare_comment_string(comment_arg);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ value = normalize_value(argv[0], argv[1], type, &default_kvi);
+
+ if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) {
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], value, value_pattern,
+ comment, flags);
+ } else {
+ ret = git_config_set_in_file_gently(location_opts.source.file,
+ argv[0], comment, value);
+ if (ret == CONFIG_NOTHING_SET)
+ error(_("cannot overwrite multiple values with a single value\n"
+ " Use a regexp, --add or --replace-all to change %s."), argv[0]);
}
- if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
+ location_options_release(&location_opts);
+ free(comment);
+ free(value);
+ return ret;
+}
+
+static int cmd_config_unset(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ const char *value_pattern = NULL;
+ int flags = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_GROUP(N_("Filter")),
+ OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
+ OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_unset_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 1, 1);
+
+ if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+ die(_("--fixed-value only applies with 'value-pattern'"));
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern)
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], NULL, value_pattern,
+ NULL, flags);
+ else
+ ret = git_config_set_in_file_gently(location_opts.source.file, argv[0],
+ NULL, NULL);
+
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_rename_section(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_rename_section_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 2, 2);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ ret = git_config_rename_section_in_file(location_opts.source.file,
+ argv[0], argv[1]);
+ if (ret < 0)
+ goto out;
+ else if (!ret)
+ die(_("no such section: %s"), argv[0]);
+ ret = 0;
+
+out:
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_remove_section(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_remove_section_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 1, 1);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ ret = git_config_rename_section_in_file(location_opts.source.file,
+ argv[0], NULL);
+ if (ret < 0)
+ goto out;
+ else if (!ret)
+ die(_("no such section: %s"), argv[0]);
+ ret = 0;
+
+out:
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int show_editor(struct config_location_options *opts)
+{
+ char *config_file;
+
+ if (!opts->source.file && !startup_info->have_repository)
+ die(_("not in a git directory"));
+ if (opts->source.use_stdin)
+ die(_("editing stdin is not supported"));
+ if (opts->source.blob)
+ die(_("editing blobs is not supported"));
+ git_config(git_default_config, NULL);
+ config_file = opts->source.file ?
+ xstrdup(opts->source.file) :
+ git_pathdup("config");
+ if (opts->use_global_config) {
+ int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd >= 0) {
+ char *content = default_user_config();
+ write_str_in_full(fd, content);
+ free(content);
+ close(fd);
+ }
+ else if (errno != EEXIST)
+ die_errno(_("cannot create configuration file %s"), config_file);
+ }
+ launch_editor(config_file, NULL, NULL);
+ free(config_file);
+
+ return 0;
+}
+
+static int cmd_config_edit(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_edit_usage, 0);
+ check_argc(argc, 0, 0);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ ret = show_editor(&location_opts);
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_actions(int argc, const char **argv, const char *prefix)
+{
+ enum {
+ ACTION_GET = (1<<0),
+ ACTION_GET_ALL = (1<<1),
+ ACTION_GET_REGEXP = (1<<2),
+ ACTION_REPLACE_ALL = (1<<3),
+ ACTION_ADD = (1<<4),
+ ACTION_UNSET = (1<<5),
+ ACTION_UNSET_ALL = (1<<6),
+ ACTION_RENAME_SECTION = (1<<7),
+ ACTION_REMOVE_SECTION = (1<<8),
+ ACTION_LIST = (1<<9),
+ ACTION_EDIT = (1<<10),
+ ACTION_SET = (1<<11),
+ ACTION_SET_ALL = (1<<12),
+ ACTION_GET_COLOR = (1<<13),
+ ACTION_GET_COLORBOOL = (1<<14),
+ ACTION_GET_URLMATCH = (1<<15),
+ };
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+ const char *comment_arg = NULL;
+ int actions = 0;
+ unsigned flags = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_GROUP(N_("Action")),
+ OPT_CMDMODE(0, "get", &actions, N_("get value: name [<value-pattern>]"), ACTION_GET),
+ OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key [<value-pattern>]"), ACTION_GET_ALL),
+ OPT_CMDMODE(0, "get-regexp", &actions, N_("get values for regexp: name-regex [<value-pattern>]"), ACTION_GET_REGEXP),
+ OPT_CMDMODE(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
+ OPT_CMDMODE(0, "replace-all", &actions, N_("replace all matching variables: name value [<value-pattern>]"), ACTION_REPLACE_ALL),
+ OPT_CMDMODE(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
+ OPT_CMDMODE(0, "unset", &actions, N_("remove a variable: name [<value-pattern>]"), ACTION_UNSET),
+ OPT_CMDMODE(0, "unset-all", &actions, N_("remove all matches: name [<value-pattern>]"), ACTION_UNSET_ALL),
+ OPT_CMDMODE(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
+ OPT_CMDMODE(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
+ OPT_CMDMODE('l', "list", &actions, N_("list all"), ACTION_LIST),
+ OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
+ OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot [<default>]"), ACTION_GET_COLOR),
+ OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot [<stdout-is-tty>]"), ACTION_GET_COLORBOOL),
+ CONFIG_DISPLAY_OPTIONS(display_opts),
+ OPT_GROUP(N_("Other")),
+ OPT_STRING(0, "default", &display_opts.default_value,
+ N_("value"), N_("with --get, use default value when missing entry")),
+ OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+ N_("respect include directives on lookup")),
+ OPT_END(),
+ };
+ char *value = NULL, *comment = NULL;
+ int ret = 0;
+ struct key_value_info default_kvi = KVI_INIT;
+
+ argc = parse_options(argc, argv, prefix, opts,
+ builtin_config_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ location_options_init(&location_opts, prefix);
+ display_options_init(&display_opts);
+
+ if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && display_opts.type) {
error(_("--get-color and variable type are incoherent"));
- usage_builtin_config();
+ exit(129);
}
- if (HAS_MULTI_BITS(actions)) {
- error(_("only one action at a time"));
- usage_builtin_config();
- }
if (actions == 0)
switch (argc) {
case 1: actions = ACTION_GET; break;
case 2: actions = ACTION_SET; break;
case 3: actions = ACTION_SET_ALL; break;
default:
- usage_builtin_config();
+ error(_("no action specified"));
+ exit(129);
}
- if (omit_values &&
+ if (display_opts.omit_values &&
!(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
error(_("--name-only is only applicable to --list or --get-regexp"));
- usage_builtin_config();
+ exit(129);
}
- if (show_origin && !(actions &
+ if (display_opts.show_origin && !(actions &
(ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
error(_("--show-origin is only applicable to --get, --get-all, "
"--get-regexp, and --list"));
- usage_builtin_config();
+ exit(129);
}
- if (default_value && !(actions & ACTION_GET)) {
+ if (display_opts.default_value && !(actions & ACTION_GET)) {
error(_("--default is only applicable to --get"));
- usage_builtin_config();
+ exit(129);
}
- if (comment &&
+ if (comment_arg &&
!(actions & (ACTION_ADD|ACTION_SET|ACTION_SET_ALL|ACTION_REPLACE_ALL))) {
error(_("--comment is only applicable to add/set/replace operations"));
- usage_builtin_config();
+ exit(129);
}
/* check usage of --fixed-value */
- if (fixed_value) {
+ if (flags & CONFIG_FLAGS_FIXED_VALUE) {
int allowed_usage = 0;
switch (actions) {
@@ -835,148 +1250,125 @@
if (!allowed_usage) {
error(_("--fixed-value only applies with 'value-pattern'"));
- usage_builtin_config();
+ exit(129);
}
-
- flags |= CONFIG_FLAGS_FIXED_VALUE;
}
- comment = git_config_prepare_comment_string(comment);
+ comment = git_config_prepare_comment_string(comment_arg);
- if (actions & PAGING_ACTIONS)
+ /*
+ * The following actions may produce more than one line of output and
+ * should therefore be paged.
+ */
+ if (actions & (ACTION_LIST | ACTION_GET_ALL | ACTION_GET_REGEXP | ACTION_GET_URLMATCH))
setup_auto_pager("config", 1);
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
- if (config_with_options(show_all_config, NULL,
- &given_config_source, the_repository,
- &config_options) < 0) {
- if (given_config_source.file)
+ if (config_with_options(show_all_config, &display_opts,
+ &location_opts.source, the_repository,
+ &location_opts.options) < 0) {
+ if (location_opts.source.file)
die_errno(_("unable to read config file '%s'"),
- given_config_source.file);
+ location_opts.source.file);
else
die(_("error processing config file(s)"));
}
}
else if (actions == ACTION_EDIT) {
- char *config_file;
-
- check_argc(argc, 0, 0);
- if (!given_config_source.file && nongit)
- die(_("not in a git directory"));
- if (given_config_source.use_stdin)
- die(_("editing stdin is not supported"));
- if (given_config_source.blob)
- die(_("editing blobs is not supported"));
- git_config(git_default_config, NULL);
- config_file = given_config_source.file ?
- xstrdup(given_config_source.file) :
- git_pathdup("config");
- if (use_global_config) {
- int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
- if (fd >= 0) {
- char *content = default_user_config();
- write_str_in_full(fd, content);
- free(content);
- close(fd);
- }
- else if (errno != EEXIST)
- die_errno(_("cannot create configuration file %s"), config_file);
- }
- launch_editor(config_file, NULL, NULL);
- free(config_file);
+ ret = show_editor(&location_opts);
}
else if (actions == ACTION_SET) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 2);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_in_file_gently(given_config_source.file, argv[0], comment, value);
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], comment, value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
}
else if (actions == ACTION_SET_ALL) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 3);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
argv[0], value, argv[2],
comment, flags);
}
else if (actions == ACTION_ADD) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 2);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
argv[0], value,
CONFIG_REGEX_NONE,
comment, flags);
}
else if (actions == ACTION_REPLACE_ALL) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 3);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
argv[0], value, argv[2],
comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1], flags);
+ ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+ 0, flags);
}
else if (actions == ACTION_GET_ALL) {
- do_all = 1;
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1], flags);
+ ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+ GET_VALUE_ALL, flags);
}
else if (actions == ACTION_GET_REGEXP) {
- show_keys = 1;
- use_key_regexp = 1;
- do_all = 1;
+ display_opts.show_keys = 1;
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1], flags);
+ ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+ GET_VALUE_ALL|GET_VALUE_KEY_REGEXP, flags);
}
else if (actions == ACTION_GET_URLMATCH) {
check_argc(argc, 2, 2);
- return get_urlmatch(argv[0], argv[1]);
+ ret = get_urlmatch(&location_opts, &display_opts, argv[0], argv[1]);
}
else if (actions == ACTION_UNSET) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 1, 2);
if (argc == 2)
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], NULL, argv[1],
- NULL, flags);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags);
else
- return git_config_set_in_file_gently(given_config_source.file,
- argv[0], NULL, NULL);
+ ret = git_config_set_in_file_gently(location_opts.source.file,
+ argv[0], NULL, NULL);
}
else if (actions == ACTION_UNSET_ALL) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 1, 2);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], NULL, argv[1],
- NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 2);
- ret = git_config_rename_section_in_file(given_config_source.file,
+ ret = git_config_rename_section_in_file(location_opts.source.file,
argv[0], argv[1]);
if (ret < 0)
- return ret;
+ goto out;
else if (!ret)
die(_("no such section: %s"), argv[0]);
else
ret = 0;
}
else if (actions == ACTION_REMOVE_SECTION) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 1, 1);
- ret = git_config_rename_section_in_file(given_config_source.file,
+ ret = git_config_rename_section_in_file(location_opts.source.file,
argv[0], NULL);
if (ret < 0)
- return ret;
+ goto out;
else if (!ret)
die(_("no such section: %s"), argv[0]);
else
@@ -984,15 +1376,51 @@
}
else if (actions == ACTION_GET_COLOR) {
check_argc(argc, 1, 2);
- get_color(argv[0], argv[1]);
+ get_color(&location_opts, argv[0], argv[1]);
}
else if (actions == ACTION_GET_COLORBOOL) {
check_argc(argc, 1, 2);
if (argc == 2)
color_stdout_is_tty = git_config_bool("command line", argv[1]);
- return get_colorbool(argv[0], argc == 2);
+ ret = get_colorbool(&location_opts, argv[0], argc == 2);
}
+out:
+ location_options_release(&location_opts);
+ free(comment);
free(value);
return ret;
}
+
+int cmd_config(int argc, const char **argv, const char *prefix)
+{
+ parse_opt_subcommand_fn *subcommand = NULL;
+ struct option subcommand_opts[] = {
+ OPT_SUBCOMMAND("list", &subcommand, cmd_config_list),
+ OPT_SUBCOMMAND("get", &subcommand, cmd_config_get),
+ OPT_SUBCOMMAND("set", &subcommand, cmd_config_set),
+ OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset),
+ OPT_SUBCOMMAND("rename-section", &subcommand, cmd_config_rename_section),
+ OPT_SUBCOMMAND("remove-section", &subcommand, cmd_config_remove_section),
+ OPT_SUBCOMMAND("edit", &subcommand, cmd_config_edit),
+ OPT_END(),
+ };
+
+ /*
+ * This is somewhat hacky: we first parse the command line while
+ * keeping all args intact in order to determine whether a subcommand
+ * has been specified. If so, we re-parse it a second time, but this
+ * time we drop KEEP_ARGV0. This is so that we don't munge the command
+ * line in case no subcommand was given, which would otherwise confuse
+ * us when parsing the legacy-style modes that don't use subcommands.
+ */
+ argc = parse_options(argc, argv, prefix, subcommand_opts, builtin_config_usage,
+ PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_ARGV0|PARSE_OPT_KEEP_UNKNOWN_OPT);
+ if (subcommand) {
+ argc = parse_options(argc, argv, prefix, subcommand_opts, builtin_config_usage,
+ PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_UNKNOWN_OPT);
+ return subcommand(argc, argv, prefix);
+ }
+
+ return cmd_config_actions(argc, argv, prefix);
+}
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 17f929d..4952b22 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -115,7 +115,9 @@
return error("client sent bogus timeout line: %s", item.buf);
*timeout = atoi(p);
- if (credential_read(c, fh) < 0)
+ credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL);
+
+ if (credential_read(c, fh, CREDENTIAL_OP_HELPER) < 0)
return -1;
return 0;
}
@@ -131,8 +133,18 @@
else if (!strcmp(action.buf, "get")) {
struct credential_cache_entry *e = lookup_credential(&c);
if (e) {
- fprintf(out, "username=%s\n", e->item.username);
- fprintf(out, "password=%s\n", e->item.password);
+ e->item.capa_authtype.request_initial = 1;
+ e->item.capa_authtype.request_helper = 1;
+
+ fprintf(out, "capability[]=authtype\n");
+ if (e->item.username)
+ fprintf(out, "username=%s\n", e->item.username);
+ if (e->item.password)
+ fprintf(out, "password=%s\n", e->item.password);
+ if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.authtype)
+ fprintf(out, "authtype=%s\n", e->item.authtype);
+ if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.credential)
+ fprintf(out, "credential=%s\n", e->item.credential);
if (e->item.password_expiry_utc != TIME_MAX)
fprintf(out, "password_expiry_utc=%"PRItime"\n",
e->item.password_expiry_utc);
@@ -157,8 +169,10 @@
else if (!strcmp(action.buf, "store")) {
if (timeout < 0)
warning("cache client didn't specify a timeout");
- else if (!c.username || !c.password)
+ else if ((!c.username || !c.password) && (!c.authtype && !c.credential))
warning("cache client gave us a partial credential");
+ else if (c.ephemeral)
+ warning("not storing ephemeral credential");
else {
remove_credential(&c, 0);
cache_credential(&c, timeout);
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index bef120b..3db8df7 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -1,4 +1,5 @@
#include "builtin.h"
+#include "credential.h"
#include "gettext.h"
#include "parse-options.h"
#include "path.h"
@@ -127,6 +128,13 @@
return socket;
}
+static void announce_capabilities(void)
+{
+ struct credential c = CREDENTIAL_INIT;
+ c.capa_authtype.request_initial = 1;
+ credential_announce_capabilities(&c, stdout);
+}
+
int cmd_credential_cache(int argc, const char **argv, const char *prefix)
{
char *socket_path = NULL;
@@ -163,6 +171,8 @@
do_cache(socket_path, op, timeout, FLAG_RELAY);
else if (!strcmp(op, "store"))
do_cache(socket_path, op, timeout, FLAG_RELAY|FLAG_SPAWN);
+ else if (!strcmp(op, "capability"))
+ announce_capabilities();
else
; /* ignore unknown operation */
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index 4a49241..494c809 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -205,7 +205,7 @@
if (!fns.nr)
die("unable to set up default path; use --file");
- if (credential_read(&c, stdin) < 0)
+ if (credential_read(&c, stdin, CREDENTIAL_OP_HELPER) < 0)
die("unable to read credential");
if (!strcmp(op, "get"))
diff --git a/builtin/credential.c b/builtin/credential.c
index 7010752..b72e76d 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -17,18 +17,29 @@
usage(usage_msg);
op = argv[1];
- if (credential_read(&c, stdin) < 0)
+ if (!strcmp(op, "capability")) {
+ credential_set_all_capabilities(&c, CREDENTIAL_OP_INITIAL);
+ credential_announce_capabilities(&c, stdout);
+ return 0;
+ }
+
+ if (credential_read(&c, stdin, CREDENTIAL_OP_INITIAL) < 0)
die("unable to read credential from stdin");
if (!strcmp(op, "fill")) {
- credential_fill(&c);
- credential_write(&c, stdout);
+ credential_fill(&c, 0);
+ credential_next_state(&c);
+ credential_write(&c, stdout, CREDENTIAL_OP_RESPONSE);
} else if (!strcmp(op, "approve")) {
+ credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
credential_approve(&c);
} else if (!strcmp(op, "reject")) {
+ credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
credential_reject(&c);
} else {
usage(usage_msg);
}
+
+ credential_clear(&c);
return 0;
}
diff --git a/builtin/describe.c b/builtin/describe.c
index d6c77a7..e5287ed 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
#include "environment.h"
@@ -201,7 +200,7 @@
}
/* Is it annotated? */
- if (!peel_iterated_oid(oid, &peeled)) {
+ if (!peel_iterated_oid(the_repository, oid, &peeled)) {
is_annotated = !oideq(oid, &peeled);
} else {
oidcpy(&peeled, oid);
@@ -638,7 +637,8 @@
}
hashmap_init(&names, commit_name_neq, NULL, 0);
- for_each_rawref(get_name, NULL);
+ refs_for_each_rawref(get_main_ref_store(the_repository), get_name,
+ NULL);
if (!hashmap_get_size(&names) && !always)
die(_("No names found, cannot describe anything."));
@@ -674,7 +674,7 @@
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
repo_read_index(the_repository);
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
+ refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED,
NULL, NULL, NULL);
fd = repo_hold_locked_index(the_repository,
&index_lock, 0);
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index 4f22eb2..4857a43 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -18,7 +18,7 @@
struct tm tm;
enum diagnose_mode mode = DIAGNOSE_STATS;
char *option_output = NULL;
- char *option_suffix = "%Y-%m-%d-%H%M";
+ const char *option_suffix = "%Y-%m-%d-%H%M";
char *prefixed_filename;
const struct option diagnose_options[] = {
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index a8e68ce..0d3c611 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
#include "diff.h"
@@ -206,7 +205,7 @@
opt->diffopt.rotate_to_strict = 0;
opt->diffopt.no_free = 1;
if (opt->diffopt.detect_rename) {
- if (!the_index.cache)
+ if (the_repository->index->cache)
repo_read_index(the_repository);
opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE;
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 6e196e0..9b6cdab 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2006 Junio C Hamano
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "config.h"
#include "ewah/ewok.h"
@@ -239,9 +239,9 @@
fd = repo_hold_locked_index(the_repository, &lock_file, 0);
if (fd < 0)
return;
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL,
+ refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL,
NULL);
repo_update_index_if_able(the_repository, &lock_file);
}
@@ -465,6 +465,15 @@
no_index = DIFF_NO_INDEX_IMPLICIT;
}
+ /*
+ * When operating outside of a Git repository we need to have a hash
+ * algorithm at hand so that we can generate the blob hashes. We
+ * default to SHA1 here, but may eventually want to change this to be
+ * configurable via a command line option.
+ */
+ if (nongit)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL);
prefix = precompose_argv_prefix(argc, argv, prefix);
diff --git a/builtin/difftool.c b/builtin/difftool.c
index a3c72b8..a1794b7 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -11,7 +11,7 @@
*
* Copyright (C) 2016 Johannes Schindelin
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "abspath.h"
#include "config.h"
@@ -117,7 +117,7 @@
int fd = open(buf.buf, O_RDONLY);
if (fd >= 0 &&
- !index_fd(&the_index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
+ !index_fd(the_repository->index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
if (is_null_oid(oid)) {
oidcpy(oid, &wt_oid);
use = 1;
@@ -674,19 +674,15 @@
static int run_file_diff(int prompt, const char *prefix,
struct child_process *child)
{
- const char *env[] = {
- "GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
- NULL
- };
-
+ strvec_push(&child->env, "GIT_PAGER=");
+ strvec_push(&child->env, "GIT_EXTERNAL_DIFF=git-difftool--helper");
if (prompt > 0)
- env[2] = "GIT_DIFFTOOL_PROMPT=true";
+ strvec_push(&child->env, "GIT_DIFFTOOL_PROMPT=true");
else if (!prompt)
- env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
+ strvec_push(&child->env, "GIT_DIFFTOOL_NO_PROMPT=true");
child->git_cmd = 1;
child->dir = prefix;
- strvec_pushv(&child->env, env);
return run_command(child);
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index dc5a9d3..d1c0243 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1604,10 +1604,11 @@
if (is_null_oid(&b->oid)) {
if (b->delete)
- delete_ref(NULL, b->name, NULL, 0);
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, b->name, NULL, 0);
return 0;
}
- if (read_ref(b->name, &old_oid))
+ if (refs_read_ref(get_main_ref_store(the_repository), b->name, &old_oid))
oidclr(&old_oid);
if (!force_update && !is_null_oid(&old_oid)) {
struct commit *old_cmit, *new_cmit;
@@ -1631,10 +1632,11 @@
return -1;
}
}
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction ||
ref_transaction_update(transaction, b->name, &b->oid, &old_oid,
- 0, msg, &err) ||
+ NULL, NULL, 0, msg, &err) ||
ref_transaction_commit(transaction, &err)) {
ref_transaction_free(transaction);
error("%s", err.buf);
@@ -1665,7 +1667,8 @@
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction) {
failure |= error("%s", err.buf);
goto cleanup;
@@ -1675,7 +1678,8 @@
strbuf_addf(&ref_name, "refs/tags/%s", t->name);
if (ref_transaction_update(transaction, ref_name.buf,
- &t->oid, NULL, 0, msg, &err)) {
+ &t->oid, NULL, NULL, NULL,
+ 0, msg, &err)) {
failure |= error("%s", err.buf);
goto cleanup;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 5857d86..693f02b 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -340,7 +340,8 @@
refname_hash_init(&remote_refs);
create_fetch_oidset(head, &fetch_oids);
- for_each_ref(add_one_refname, &existing_refs);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_one_refname,
+ &existing_refs);
/*
* If we already have a transaction, then we need to filter out all
@@ -581,11 +582,16 @@
}
}
- if (tags == TAGS_SET)
+ if (tags == TAGS_SET) {
+ struct refspec_item tag_refspec;
+
/* also fetch all tags */
- get_fetch_map(remote_refs, tag_refspec, &tail, 0);
- else if (tags == TAGS_DEFAULT && *autotags)
+ refspec_item_init(&tag_refspec, TAG_REFSPEC, 0);
+ get_fetch_map(remote_refs, &tag_refspec, &tail, 0);
+ refspec_item_clear(&tag_refspec);
+ } else if (tags == TAGS_DEFAULT && *autotags) {
find_non_local_tags(remote_refs, NULL, &ref_map, &tail);
+ }
/* Now append any refs to be updated opportunistically: */
*tail = orefs;
@@ -614,7 +620,9 @@
if (!existing_refs_populated) {
refname_hash_init(&existing_refs);
- for_each_ref(add_one_refname, &existing_refs);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ add_one_refname,
+ &existing_refs);
existing_refs_populated = 1;
}
@@ -659,7 +667,8 @@
* lifecycle.
*/
if (!transaction) {
- transaction = our_transaction = ref_transaction_begin(&err);
+ transaction = our_transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction) {
ret = STORE_REF_ERROR_OTHER;
goto out;
@@ -668,7 +677,7 @@
ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
check_old ? &ref->old_oid : NULL,
- 0, msg, &err);
+ NULL, NULL, 0, msg, &err);
if (ret) {
ret = STORE_REF_ERROR_OTHER;
goto out;
@@ -1382,8 +1391,8 @@
if (!dry_run) {
if (transaction) {
for (ref = stale_refs; ref; ref = ref->next) {
- result = ref_transaction_delete(transaction, ref->name, NULL, 0,
- "fetch: prune", &err);
+ result = ref_transaction_delete(transaction, ref->name, NULL,
+ NULL, 0, "fetch: prune", &err);
if (result)
goto cleanup;
}
@@ -1393,7 +1402,9 @@
for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);
- result = delete_refs("fetch: prune", &refnames, 0);
+ result = refs_delete_refs(get_main_ref_store(the_repository),
+ "fetch: prune", &refnames,
+ 0);
string_list_clear(&refnames, 0);
}
}
@@ -1406,7 +1417,8 @@
_("(none)"), ref->name,
&ref->new_oid, &ref->old_oid,
summary_width);
- warn_dangling_symref(stderr, dangling_msg, ref->name);
+ refs_warn_dangling_symref(get_main_ref_store(the_repository),
+ stderr, dangling_msg, ref->name);
}
}
@@ -1479,7 +1491,8 @@
continue;
}
old_nr = oids->nr;
- for_each_glob_ref(add_oid, s, oids);
+ refs_for_each_glob_ref(get_main_ref_store(the_repository),
+ add_oid, s, oids);
if (old_nr == oids->nr)
warning("ignoring --negotiation-tip=%s because it does not match any refs",
s);
@@ -1655,7 +1668,8 @@
config->display_format);
if (atomic_fetch) {
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction) {
retcode = -1;
goto cleanup;
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 919282e..5517a4a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -98,7 +98,7 @@
}
if (include_root_refs)
- flags |= FILTER_REFS_ROOT_REFS;
+ flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD;
filter.match_as_path = 1;
filter_and_format_refs(&filter, flags, sorting, &format);
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index 28186b3..c4fa41f 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -32,6 +32,7 @@
int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
{
static const char *config_key = NULL;
+ int keep_going = 0;
int i, result = 0;
const struct string_list *values;
int err;
@@ -39,6 +40,8 @@
const struct option options[] = {
OPT_STRING(0, "config", &config_key, N_("config"),
N_("config key storing a list of repository paths")),
+ OPT_BOOL(0, "keep-going", &keep_going,
+ N_("keep going even if command fails in a repository")),
OPT_END()
};
@@ -55,8 +58,14 @@
else if (err)
return 0;
- for (i = 0; !result && i < values->nr; i++)
- result = run_command_on_repo(values->items[i].string, argc, argv);
+ for (i = 0; i < values->nr; i++) {
+ int ret = run_command_on_repo(values->items[i].string, argc, argv);
+ if (ret) {
+ if (!keep_going)
+ return ret;
+ result = 1;
+ }
+ }
return result;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index f892487..d13a226 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -514,7 +514,9 @@
struct strbuf refname = STRBUF_INIT;
strbuf_worktree_ref(cb_data, &refname, logname);
- for_each_reflog_ent(refname.buf, fsck_handle_reflog_ent, refname.buf);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ refname.buf, fsck_handle_reflog_ent,
+ refname.buf);
strbuf_release(&refname);
return 0;
}
@@ -563,7 +565,8 @@
const char *head_points_at;
struct object_id head_oid;
- for_each_rawref(fsck_handle_ref, NULL);
+ refs_for_each_rawref(get_main_ref_store(the_repository),
+ fsck_handle_ref, NULL);
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
@@ -712,7 +715,9 @@
if (verbose)
fprintf_ln(stderr, _("Checking %s link"), head_ref_name);
- *head_points_at = resolve_ref_unsafe(head_ref_name, 0, head_oid, NULL);
+ *head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ head_ref_name, 0, head_oid,
+ NULL);
if (!*head_points_at) {
errors_found |= ERROR_REFS;
return error(_("invalid %s"), head_ref_name);
diff --git a/builtin/gc.c b/builtin/gc.c
index d187cec..72bac25 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -846,7 +846,7 @@
struct commit_list *stack = NULL;
struct commit *commit;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
return 0;
@@ -907,7 +907,8 @@
if (data.limit < 0)
return 1;
- result = for_each_ref(dfs_on_ref, &data);
+ result = refs_for_each_ref(get_main_ref_store(the_repository),
+ dfs_on_ref, &data);
repo_clear_commit_marks(the_repository, SEEN);
@@ -1870,6 +1871,7 @@
"<string>%s/git</string>\n"
"<string>--exec-path=%s</string>\n"
"<string>for-each-repo</string>\n"
+ "<string>--keep-going</string>\n"
"<string>--config=maintenance.repo</string>\n"
"<string>maintenance</string>\n"
"<string>run</string>\n"
@@ -2112,7 +2114,7 @@
"<Actions Context=\"Author\">\n"
"<Exec>\n"
"<Command>\"%s\\headless-git.exe\"</Command>\n"
- "<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
+ "<Arguments>--exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
"</Exec>\n"
"</Actions>\n"
"</Task>\n";
@@ -2257,7 +2259,7 @@
"# replaced in the future by a Git command.\n\n");
strbuf_addf(&line_format,
- "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
+ "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n",
exec_path, exec_path);
fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
@@ -2458,7 +2460,7 @@
"\n"
"[Service]\n"
"Type=oneshot\n"
- "ExecStart=\"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%i\n"
+ "ExecStart=\"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n"
"LockPersonality=yes\n"
"MemoryDenyWriteExecute=yes\n"
"NoNewPrivileges=yes\n"
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 82ca6d2..c767414 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -123,6 +123,9 @@
else
prefix = setup_git_directory_gently(&nongit);
+ if (nongit && !the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
if (vpath && prefix) {
vpath_free = prefix_filename(prefix, vpath);
vpath = vpath_free;
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0170469..582dcf2 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -81,7 +81,7 @@
const char *ref_format = NULL;
const char *initial_branch = NULL;
int hash_algo = GIT_HASH_UNKNOWN;
- unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
+ enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
int init_shared_repository = -1;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 8768bfe..1d96949 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -141,7 +141,7 @@
LIST_HEAD(head);
struct strbuf sb = STRBUF_INIT;
struct strbuf trailer_block = STRBUF_INIT;
- struct trailer_info info;
+ struct trailer_info *info;
FILE *outfile = stdout;
trailer_config_init();
@@ -151,13 +151,13 @@
if (opts->in_place)
outfile = create_in_place_tempfile(file);
- parse_trailers(opts, &info, sb.buf, &head);
+ info = parse_trailers(opts, sb.buf, &head);
/* Print the lines before the trailers */
if (!opts->only_trailers)
- fwrite(sb.buf, 1, info.trailer_block_start, outfile);
+ fwrite(sb.buf, 1, trailer_block_start(info), outfile);
- if (!opts->only_trailers && !info.blank_line_before_trailer)
+ if (!opts->only_trailers && !blank_line_before_trailer_block(info))
fprintf(outfile, "\n");
@@ -178,8 +178,8 @@
/* Print the lines after the trailers as is */
if (!opts->only_trailers)
- fwrite(sb.buf + info.trailer_block_end, 1, sb.len - info.trailer_block_end, outfile);
- trailer_info_release(&info);
+ fwrite(sb.buf + trailer_block_end(info), 1, sb.len - trailer_block_end(info), outfile);
+ trailer_info_release(info);
if (opts->in_place)
if (rename_tempfile(&trailers_tempfile, file))
diff --git a/builtin/log.c b/builtin/log.c
index c0a8bb9..21a81c7 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -48,22 +48,8 @@
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
#define FORMAT_PATCH_NAME_MAX_DEFAULT 64
-/* Set a default date-time format for git log ("log.date" config variable) */
-static const char *default_date_mode = NULL;
-
-static int default_abbrev_commit;
-static int default_show_root = 1;
-static int default_follow;
-static int default_show_signature;
-static int default_encode_email_headers = 1;
-static int decoration_style;
-static int decoration_given;
-static int use_mailmap_config = 1;
static unsigned int force_in_body_from;
static int stdout_mboxrd;
-static const char *fmt_patch_subject_prefix = "PATCH";
-static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
-static const char *fmt_pretty;
static int format_no_prefix;
static const char * const builtin_log_usage[] = {
@@ -111,6 +97,39 @@
return -1;
}
+struct log_config {
+ int default_abbrev_commit;
+ int default_show_root;
+ int default_follow;
+ int default_show_signature;
+ int default_encode_email_headers;
+ int decoration_style;
+ int decoration_given;
+ int use_mailmap_config;
+ char *fmt_patch_subject_prefix;
+ int fmt_patch_name_max;
+ char *fmt_pretty;
+ char *default_date_mode;
+};
+
+static void log_config_init(struct log_config *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+ cfg->default_show_root = 1;
+ cfg->default_encode_email_headers = 1;
+ cfg->use_mailmap_config = 1;
+ cfg->fmt_patch_subject_prefix = xstrdup("PATCH");
+ cfg->fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
+ cfg->decoration_style = auto_decoration_style();
+}
+
+static void log_config_release(struct log_config *cfg)
+{
+ free(cfg->default_date_mode);
+ free(cfg->fmt_pretty);
+ free(cfg->fmt_patch_subject_prefix);
+}
+
static int use_default_decoration_filter = 1;
static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
@@ -127,20 +146,22 @@
return 0;
}
-static int decorate_callback(const struct option *opt UNUSED, const char *arg,
+static int decorate_callback(const struct option *opt, const char *arg,
int unset)
{
- if (unset)
- decoration_style = 0;
- else if (arg)
- decoration_style = parse_decoration_style(arg);
- else
- decoration_style = DECORATE_SHORT_REFS;
+ struct log_config *cfg = opt->value;
- if (decoration_style < 0)
+ if (unset)
+ cfg->decoration_style = 0;
+ else if (arg)
+ cfg->decoration_style = parse_decoration_style(arg);
+ else
+ cfg->decoration_style = DECORATE_SHORT_REFS;
+
+ if (cfg->decoration_style < 0)
die(_("invalid --decorate option: %s"), arg);
- decoration_given = 1;
+ cfg->decoration_given = 1;
return 0;
}
@@ -160,32 +181,26 @@
return 0;
}
-static void init_log_defaults(void)
+static void cmd_log_init_defaults(struct rev_info *rev,
+ struct log_config *cfg)
{
- init_diff_ui_defaults();
-
- decoration_style = auto_decoration_style();
-}
-
-static void cmd_log_init_defaults(struct rev_info *rev)
-{
- if (fmt_pretty)
- get_commit_format(fmt_pretty, rev);
- if (default_follow)
+ if (cfg->fmt_pretty)
+ get_commit_format(cfg->fmt_pretty, rev);
+ if (cfg->default_follow)
rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
init_diffstat_widths(&rev->diffopt);
rev->diffopt.flags.recursive = 1;
rev->diffopt.flags.allow_textconv = 1;
- rev->abbrev_commit = default_abbrev_commit;
- rev->show_root_diff = default_show_root;
- rev->subject_prefix = fmt_patch_subject_prefix;
- rev->patch_name_max = fmt_patch_name_max;
- rev->show_signature = default_show_signature;
- rev->encode_email_headers = default_encode_email_headers;
+ rev->abbrev_commit = cfg->default_abbrev_commit;
+ rev->show_root_diff = cfg->default_show_root;
+ rev->subject_prefix = cfg->fmt_patch_subject_prefix;
+ rev->patch_name_max = cfg->fmt_patch_name_max;
+ rev->show_signature = cfg->default_show_signature;
+ rev->encode_email_headers = cfg->default_encode_email_headers;
- if (default_date_mode)
- parse_date_format(default_date_mode, &rev->date_mode);
+ if (cfg->default_date_mode)
+ parse_date_format(cfg->default_date_mode, &rev->date_mode);
}
static void set_default_decoration_filter(struct decoration_filter *decoration_filter)
@@ -233,7 +248,8 @@
}
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
- struct rev_info *rev, struct setup_revision_opt *opt)
+ struct rev_info *rev, struct setup_revision_opt *opt,
+ struct log_config *cfg)
{
struct userformat_want w;
int quiet = 0, source = 0, mailmap;
@@ -258,7 +274,7 @@
N_("pattern"), N_("only decorate refs that match <pattern>")),
OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
N_("pattern"), N_("do not decorate refs that match <pattern>")),
- OPT_CALLBACK_F(0, "decorate", NULL, NULL, N_("decorate options"),
+ OPT_CALLBACK_F(0, "decorate", cfg, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback),
OPT_CALLBACK('L', NULL, &line_cb, "range:file",
N_("trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
@@ -269,7 +285,7 @@
line_cb.rev = rev;
line_cb.prefix = prefix;
- mailmap = use_mailmap_config;
+ mailmap = cfg->use_mailmap_config;
argc = parse_options(argc, argv, prefix,
builtin_log_options, builtin_log_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -314,8 +330,8 @@
* "log --pretty=raw" is special; ignore UI oriented
* configuration variables such as decoration.
*/
- if (!decoration_given)
- decoration_style = 0;
+ if (!cfg->decoration_given)
+ cfg->decoration_style = 0;
if (!rev->abbrev_commit_given)
rev->abbrev_commit = 0;
}
@@ -326,24 +342,24 @@
* Disable decoration loading if the format will not
* show them anyway.
*/
- decoration_style = 0;
- } else if (!decoration_style) {
+ cfg->decoration_style = 0;
+ } else if (!cfg->decoration_style) {
/*
* If we are going to show them, make sure we do load
* them here, but taking care not to override a
* specific style set by config or --decorate.
*/
- decoration_style = DECORATE_SHORT_REFS;
+ cfg->decoration_style = DECORATE_SHORT_REFS;
}
}
- if (decoration_style || rev->simplify_by_decoration) {
+ if (cfg->decoration_style || rev->simplify_by_decoration) {
set_default_decoration_filter(&decoration_filter);
- if (decoration_style)
+ if (cfg->decoration_style)
rev->show_decorations = 1;
- load_ref_decorations(&decoration_filter, decoration_style);
+ load_ref_decorations(&decoration_filter, cfg->decoration_style);
}
if (rev->line_level_traverse)
@@ -353,16 +369,11 @@
}
static void cmd_log_init(int argc, const char **argv, const char *prefix,
- struct rev_info *rev, struct setup_revision_opt *opt)
+ struct rev_info *rev, struct setup_revision_opt *opt,
+ struct log_config *cfg)
{
- cmd_log_init_defaults(rev);
- cmd_log_init_finish(argc, argv, prefix, rev, opt);
-}
-
-static int cmd_log_deinit(int ret, struct rev_info *rev)
-{
- release_revisions(rev);
- return ret;
+ cmd_log_init_defaults(rev, cfg);
+ cmd_log_init_finish(argc, argv, prefix, rev, opt, cfg);
}
/*
@@ -566,30 +577,37 @@
static int git_log_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ struct log_config *cfg = cb;
const char *slot_name;
- if (!strcmp(var, "format.pretty"))
- return git_config_string(&fmt_pretty, var, value);
- if (!strcmp(var, "format.subjectprefix"))
- return git_config_string(&fmt_patch_subject_prefix, var, value);
+ if (!strcmp(var, "format.pretty")) {
+ FREE_AND_NULL(cfg->fmt_pretty);
+ return git_config_string(&cfg->fmt_pretty, var, value);
+ }
+ if (!strcmp(var, "format.subjectprefix")) {
+ FREE_AND_NULL(cfg->fmt_patch_subject_prefix);
+ return git_config_string(&cfg->fmt_patch_subject_prefix, var, value);
+ }
if (!strcmp(var, "format.filenamemaxlength")) {
- fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
+ cfg->fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "format.encodeemailheaders")) {
- default_encode_email_headers = git_config_bool(var, value);
+ cfg->default_encode_email_headers = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.abbrevcommit")) {
- default_abbrev_commit = git_config_bool(var, value);
+ cfg->default_abbrev_commit = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "log.date"))
- return git_config_string(&default_date_mode, var, value);
+ if (!strcmp(var, "log.date")) {
+ FREE_AND_NULL(cfg->default_date_mode);
+ return git_config_string(&cfg->default_date_mode, var, value);
+ }
if (!strcmp(var, "log.decorate")) {
- decoration_style = parse_decoration_style(value);
- if (decoration_style < 0)
- decoration_style = 0; /* maybe warn? */
+ cfg->decoration_style = parse_decoration_style(value);
+ if (cfg->decoration_style < 0)
+ cfg->decoration_style = 0; /* maybe warn? */
return 0;
}
if (!strcmp(var, "log.diffmerges")) {
@@ -598,21 +616,21 @@
return diff_merges_config(value);
}
if (!strcmp(var, "log.showroot")) {
- default_show_root = git_config_bool(var, value);
+ cfg->default_show_root = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.follow")) {
- default_follow = git_config_bool(var, value);
+ cfg->default_follow = git_config_bool(var, value);
return 0;
}
if (skip_prefix(var, "color.decorate.", &slot_name))
return parse_decorate_color_config(var, slot_name, value);
if (!strcmp(var, "log.mailmap")) {
- use_mailmap_config = git_config_bool(var, value);
+ cfg->use_mailmap_config = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.showsignature")) {
- default_show_signature = git_config_bool(var, value);
+ cfg->default_show_signature = git_config_bool(var, value);
return 0;
}
@@ -621,11 +639,14 @@
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -635,10 +656,15 @@
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+
+ ret = cmd_log_walk(&rev);
+
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
static void show_tagger(const char *buf, struct rev_info *rev)
@@ -733,14 +759,16 @@
int cmd_show(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
unsigned int i;
struct setup_revision_opt opt;
struct pathspec match_all;
int ret = 0;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
@@ -759,10 +787,14 @@
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.tweak = show_setup_revisions_tweak;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
- if (!rev.no_walk)
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+ if (!rev.no_walk) {
+ ret = cmd_log_walk(&rev);
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
+ }
rev.diffopt.no_free = 1;
for (i = 0; i < rev.pending.nr && !ret; i++) {
@@ -832,8 +864,10 @@
rev.diffopt.no_free = 0;
diff_free(&rev.diffopt);
+ release_revisions(&rev);
+ log_config_release(&cfg);
- return cmd_log_deinit(ret, &rev);
+ return ret;
}
/*
@@ -841,11 +875,14 @@
*/
int cmd_log_reflog(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
init_reflog_walk(&rev.reflog_info);
@@ -854,14 +891,18 @@
rev.verbose_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
- cmd_log_init_defaults(&rev);
+ cmd_log_init_defaults(&rev, &cfg);
rev.abbrev_commit = 1;
rev.commit_format = CMIT_FMT_ONELINE;
rev.use_terminator = 1;
rev.always_show_header = 1;
- cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
+ cmd_log_init_finish(argc, argv, prefix, &rev, &opt, &cfg);
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+ ret = cmd_log_walk(&rev);
+
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
static void log_setup_revisions_tweak(struct rev_info *rev)
@@ -876,11 +917,14 @@
int cmd_log(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -890,42 +934,17 @@
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
opt.tweak = log_setup_revisions_tweak;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
+
+ ret = cmd_log_walk(&rev);
+
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
/* format-patch */
-static const char *fmt_patch_suffix = ".patch";
-static int numbered = 0;
-static int auto_number = 1;
-
-static char *default_attach = NULL;
-
-static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
-static struct string_list extra_to = STRING_LIST_INIT_NODUP;
-static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
-
-static void add_header(const char *value)
-{
- struct string_list_item *item;
- int len = strlen(value);
- while (len && value[len - 1] == '\n')
- len--;
-
- if (!strncasecmp(value, "to: ", 4)) {
- item = string_list_append(&extra_to, value + 4);
- len -= 4;
- } else if (!strncasecmp(value, "cc: ", 4)) {
- item = string_list_append(&extra_cc, value + 4);
- len -= 4;
- } else {
- item = string_list_append(&extra_hdr, value);
- }
-
- item->string[len] = '\0';
-}
-
enum cover_setting {
COVER_UNSET,
COVER_OFF,
@@ -952,17 +971,61 @@
AUTO_BASE_WHEN_ABLE
};
-static enum thread_level thread;
-static int do_signoff;
-static enum auto_base_setting auto_base;
-static char *from;
-static const char *signature = git_version_string;
-static const char *signature_file;
-static enum cover_setting config_cover_letter;
-static const char *config_output_directory;
-static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
-static int show_notes;
-static struct display_notes_opt notes_opt;
+struct format_config {
+ struct log_config log;
+ enum thread_level thread;
+ int do_signoff;
+ enum auto_base_setting auto_base;
+ char *base_commit;
+ char *from;
+ char *signature;
+ char *signature_file;
+ enum cover_setting config_cover_letter;
+ char *config_output_directory;
+ enum cover_from_description cover_from_description_mode;
+ int show_notes;
+ struct display_notes_opt notes_opt;
+ int numbered_cmdline_opt;
+ int numbered;
+ int auto_number;
+ char *default_attach;
+ struct string_list extra_hdr;
+ struct string_list extra_to;
+ struct string_list extra_cc;
+ int keep_subject;
+ int subject_prefix;
+ struct strbuf sprefix;
+ char *fmt_patch_suffix;
+};
+
+static void format_config_init(struct format_config *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+ log_config_init(&cfg->log);
+ cfg->cover_from_description_mode = COVER_FROM_MESSAGE;
+ cfg->auto_number = 1;
+ string_list_init_dup(&cfg->extra_hdr);
+ string_list_init_dup(&cfg->extra_to);
+ string_list_init_dup(&cfg->extra_cc);
+ strbuf_init(&cfg->sprefix, 0);
+ cfg->fmt_patch_suffix = xstrdup(".patch");
+}
+
+static void format_config_release(struct format_config *cfg)
+{
+ log_config_release(&cfg->log);
+ free(cfg->base_commit);
+ free(cfg->from);
+ free(cfg->signature);
+ free(cfg->signature_file);
+ free(cfg->config_output_directory);
+ free(cfg->default_attach);
+ string_list_clear(&cfg->extra_hdr, 0);
+ string_list_clear(&cfg->extra_to, 0);
+ string_list_clear(&cfg->extra_cc, 0);
+ strbuf_release(&cfg->sprefix);
+ free(cfg->fmt_patch_suffix);
+}
static enum cover_from_description parse_cover_from_description(const char *arg)
{
@@ -980,27 +1043,51 @@
die(_("%s: invalid cover from description mode"), arg);
}
+static void add_header(struct format_config *cfg, const char *value)
+{
+ struct string_list_item *item;
+ int len = strlen(value);
+ while (len && value[len - 1] == '\n')
+ len--;
+
+ if (!strncasecmp(value, "to: ", 4)) {
+ item = string_list_append(&cfg->extra_to, value + 4);
+ len -= 4;
+ } else if (!strncasecmp(value, "cc: ", 4)) {
+ item = string_list_append(&cfg->extra_cc, value + 4);
+ len -= 4;
+ } else {
+ item = string_list_append(&cfg->extra_hdr, value);
+ }
+
+ item->string[len] = '\0';
+}
+
static int git_format_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ struct format_config *cfg = cb;
+
if (!strcmp(var, "format.headers")) {
if (!value)
die(_("format.headers without value"));
- add_header(value);
+ add_header(cfg, value);
return 0;
}
- if (!strcmp(var, "format.suffix"))
- return git_config_string(&fmt_patch_suffix, var, value);
+ if (!strcmp(var, "format.suffix")) {
+ FREE_AND_NULL(cfg->fmt_patch_suffix);
+ return git_config_string(&cfg->fmt_patch_suffix, var, value);
+ }
if (!strcmp(var, "format.to")) {
if (!value)
return config_error_nonbool(var);
- string_list_append(&extra_to, value);
+ string_list_append(&cfg->extra_to, value);
return 0;
}
if (!strcmp(var, "format.cc")) {
if (!value)
return config_error_nonbool(var);
- string_list_append(&extra_cc, value);
+ string_list_append(&cfg->extra_cc, value);
return 0;
}
if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") ||
@@ -1009,69 +1096,76 @@
}
if (!strcmp(var, "format.numbered")) {
if (value && !strcasecmp(value, "auto")) {
- auto_number = 1;
+ cfg->auto_number = 1;
return 0;
}
- numbered = git_config_bool(var, value);
- auto_number = auto_number && numbered;
+ cfg->numbered = git_config_bool(var, value);
+ cfg->auto_number = cfg->auto_number && cfg->numbered;
return 0;
}
if (!strcmp(var, "format.attach")) {
- if (value && *value)
- default_attach = xstrdup(value);
- else if (value && !*value)
- FREE_AND_NULL(default_attach);
- else
- default_attach = xstrdup(git_version_string);
+ if (value && *value) {
+ FREE_AND_NULL(cfg->default_attach);
+ cfg->default_attach = xstrdup(value);
+ } else if (value && !*value) {
+ FREE_AND_NULL(cfg->default_attach);
+ } else {
+ FREE_AND_NULL(cfg->default_attach);
+ cfg->default_attach = xstrdup(git_version_string);
+ }
return 0;
}
if (!strcmp(var, "format.thread")) {
if (value && !strcasecmp(value, "deep")) {
- thread = THREAD_DEEP;
+ cfg->thread = THREAD_DEEP;
return 0;
}
if (value && !strcasecmp(value, "shallow")) {
- thread = THREAD_SHALLOW;
+ cfg->thread = THREAD_SHALLOW;
return 0;
}
- thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
+ cfg->thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
return 0;
}
if (!strcmp(var, "format.signoff")) {
- do_signoff = git_config_bool(var, value);
+ cfg->do_signoff = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "format.signature"))
- return git_config_string(&signature, var, value);
- if (!strcmp(var, "format.signaturefile"))
- return git_config_pathname(&signature_file, var, value);
+ if (!strcmp(var, "format.signature")) {
+ FREE_AND_NULL(cfg->signature);
+ return git_config_string(&cfg->signature, var, value);
+ }
+ if (!strcmp(var, "format.signaturefile")) {
+ FREE_AND_NULL(cfg->signature_file);
+ return git_config_pathname(&cfg->signature_file, var, value);
+ }
if (!strcmp(var, "format.coverletter")) {
if (value && !strcasecmp(value, "auto")) {
- config_cover_letter = COVER_AUTO;
+ cfg->config_cover_letter = COVER_AUTO;
return 0;
}
- config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
+ cfg->config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
return 0;
}
- if (!strcmp(var, "format.outputdirectory"))
- return git_config_string(&config_output_directory, var, value);
+ if (!strcmp(var, "format.outputdirectory")) {
+ FREE_AND_NULL(cfg->config_output_directory);
+ return git_config_string(&cfg->config_output_directory, var, value);
+ }
if (!strcmp(var, "format.useautobase")) {
if (value && !strcasecmp(value, "whenAble")) {
- auto_base = AUTO_BASE_WHEN_ABLE;
+ cfg->auto_base = AUTO_BASE_WHEN_ABLE;
return 0;
}
- auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
+ cfg->auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
return 0;
}
if (!strcmp(var, "format.from")) {
int b = git_parse_maybe_bool(value);
- free(from);
+ FREE_AND_NULL(cfg->from);
if (b < 0)
- from = xstrdup(value);
+ cfg->from = xstrdup(value);
else if (b)
- from = xstrdup(git_committer_info(IDENT_NO_DATE));
- else
- from = NULL;
+ cfg->from = xstrdup(git_committer_info(IDENT_NO_DATE));
return 0;
}
if (!strcmp(var, "format.forceinbodyfrom")) {
@@ -1081,15 +1175,15 @@
if (!strcmp(var, "format.notes")) {
int b = git_parse_maybe_bool(value);
if (b < 0)
- enable_ref_display_notes(¬es_opt, &show_notes, value);
+ enable_ref_display_notes(&cfg->notes_opt, &cfg->show_notes, value);
else if (b)
- enable_default_display_notes(¬es_opt, &show_notes);
+ enable_default_display_notes(&cfg->notes_opt, &cfg->show_notes);
else
- disable_display_notes(¬es_opt, &show_notes);
+ disable_display_notes(&cfg->notes_opt, &cfg->show_notes);
return 0;
}
if (!strcmp(var, "format.coverfromdescription")) {
- cover_from_description_mode = parse_cover_from_description(value);
+ cfg->cover_from_description_mode = parse_cover_from_description(value);
return 0;
}
if (!strcmp(var, "format.mboxrd")) {
@@ -1110,7 +1204,7 @@
if (!strcmp(var, "diff.noprefix"))
return 0;
- return git_log_config(var, value, ctx, cb);
+ return git_log_config(var, value, ctx, &cfg->log);
}
static const char *output_directory = NULL;
@@ -1189,7 +1283,7 @@
o2->flags = flags2;
}
-static void gen_message_id(struct rev_info *info, char *base)
+static void gen_message_id(struct rev_info *info, const char *base)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
@@ -1198,7 +1292,7 @@
info->message_id = strbuf_detach(&buf, NULL);
}
-static void print_signature(FILE *file)
+static void print_signature(const char *signature, FILE *file)
{
if (!signature || !*signature)
return;
@@ -1268,14 +1362,15 @@
const char *branch_name,
struct strbuf *sb,
const char *encoding,
- int need_8bit_cte)
+ int need_8bit_cte,
+ const struct format_config *cfg)
{
const char *subject = "*** SUBJECT HERE ***";
const char *body = "*** BLURB HERE ***";
struct strbuf description_sb = STRBUF_INIT;
struct strbuf subject_sb = STRBUF_INIT;
- if (cover_from_description_mode == COVER_FROM_NONE)
+ if (cfg->cover_from_description_mode == COVER_FROM_NONE)
goto do_pp;
if (description_file && *description_file)
@@ -1285,13 +1380,13 @@
if (!description_sb.len)
goto do_pp;
- if (cover_from_description_mode == COVER_FROM_SUBJECT ||
- cover_from_description_mode == COVER_FROM_AUTO)
+ if (cfg->cover_from_description_mode == COVER_FROM_SUBJECT ||
+ cfg->cover_from_description_mode == COVER_FROM_AUTO)
body = format_subject(&subject_sb, description_sb.buf, " ");
- if (cover_from_description_mode == COVER_FROM_MESSAGE ||
- (cover_from_description_mode == COVER_FROM_AUTO &&
- subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
+ if (cfg->cover_from_description_mode == COVER_FROM_MESSAGE ||
+ (cfg->cover_from_description_mode == COVER_FROM_AUTO &&
+ subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
body = description_sb.buf;
else
subject = subject_sb.buf;
@@ -1328,7 +1423,8 @@
int nr, struct commit **list,
const char *description_file,
const char *branch_name,
- int quiet)
+ int quiet,
+ const struct format_config *cfg)
{
const char *committer;
struct shortlog log;
@@ -1367,7 +1463,7 @@
pp.encode_email_headers = rev->encode_email_headers;
pp_user_info(&pp, NULL, &sb, committer, encoding);
prepare_cover_text(&pp, description_file, branch_name, &sb,
- encoding, need_8bit_cte);
+ encoding, need_8bit_cte, cfg);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
free(pp.after_subject);
@@ -1468,41 +1564,54 @@
NULL
};
-static int keep_subject = 0;
+struct keep_callback_data {
+ struct format_config *cfg;
+ struct rev_info *revs;
+};
static int keep_callback(const struct option *opt, const char *arg, int unset)
{
+ struct keep_callback_data *data = opt->value;
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- ((struct rev_info *)opt->value)->total = -1;
- keep_subject = 1;
+ data->revs->total = -1;
+ data->cfg->keep_subject = 1;
return 0;
}
-static int subject_prefix = 0;
-
static int subject_prefix_callback(const struct option *opt, const char *arg,
int unset)
{
- struct strbuf *sprefix;
+ struct format_config *cfg = opt->value;
BUG_ON_OPT_NEG(unset);
- sprefix = opt->value;
- subject_prefix = 1;
- strbuf_reset(sprefix);
- strbuf_addstr(sprefix, arg);
+ cfg->subject_prefix = 1;
+ strbuf_reset(&cfg->sprefix);
+ strbuf_addstr(&cfg->sprefix, arg);
return 0;
}
-static int numbered_cmdline_opt = 0;
+static int rfc_callback(const struct option *opt, const char *arg,
+ int unset)
+{
+ const char **rfc = opt->value;
+
+ *rfc = opt->value;
+ if (unset)
+ *rfc = NULL;
+ else
+ *rfc = arg ? arg : "RFC";
+ return 0;
+}
static int numbered_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct format_config *cfg = opt->value;
BUG_ON_OPT_ARG(arg);
- *(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1;
+ cfg->numbered = cfg->numbered_cmdline_opt = unset ? 0 : 1;
if (unset)
- auto_number = 0;
+ cfg->auto_number = 0;
return 0;
}
@@ -1526,13 +1635,14 @@
static int thread_callback(const struct option *opt, const char *arg, int unset)
{
- enum thread_level *thread = (enum thread_level *)opt->value;
+ struct format_config *cfg = opt->value;
+
if (unset)
- *thread = THREAD_UNSET;
+ cfg->thread = THREAD_UNSET;
else if (!arg || !strcmp(arg, "shallow"))
- *thread = THREAD_SHALLOW;
+ cfg->thread = THREAD_SHALLOW;
else if (!strcmp(arg, "deep"))
- *thread = THREAD_DEEP;
+ cfg->thread = THREAD_DEEP;
/*
* Please update _git_formatpatch() in git-completion.bash
* when you add new options.
@@ -1568,15 +1678,17 @@
return 0;
}
-static int header_callback(const struct option *opt UNUSED, const char *arg,
+static int header_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct format_config *cfg = opt->value;
+
if (unset) {
- string_list_clear(&extra_hdr, 0);
- string_list_clear(&extra_to, 0);
- string_list_clear(&extra_cc, 0);
+ string_list_clear(&cfg->extra_hdr, 0);
+ string_list_clear(&cfg->extra_to, 0);
+ string_list_clear(&cfg->extra_cc, 0);
} else {
- add_header(arg);
+ add_header(cfg, arg);
}
return 0;
}
@@ -1598,17 +1710,17 @@
static int base_callback(const struct option *opt, const char *arg, int unset)
{
- const char **base_commit = opt->value;
+ struct format_config *cfg = opt->value;
if (unset) {
- auto_base = AUTO_BASE_NEVER;
- *base_commit = NULL;
+ cfg->auto_base = AUTO_BASE_NEVER;
+ FREE_AND_NULL(cfg->base_commit);
} else if (!strcmp(arg, "auto")) {
- auto_base = AUTO_BASE_ALWAYS;
- *base_commit = NULL;
+ cfg->auto_base = AUTO_BASE_ALWAYS;
+ FREE_AND_NULL(cfg->base_commit);
} else {
- auto_base = AUTO_BASE_NEVER;
- *base_commit = arg;
+ cfg->auto_base = AUTO_BASE_NEVER;
+ cfg->base_commit = xstrdup(arg);
}
return 0;
}
@@ -1619,7 +1731,7 @@
struct object_id *patch_id;
};
-static struct commit *get_base_commit(const char *base_commit,
+static struct commit *get_base_commit(const struct format_config *cfg,
struct commit **list,
int total)
{
@@ -1627,9 +1739,9 @@
struct commit **rev;
int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
- switch (auto_base) {
+ switch (cfg->auto_base) {
case AUTO_BASE_NEVER:
- if (base_commit) {
+ if (cfg->base_commit) {
auto_select = 0;
die_on_failure = 1;
} else {
@@ -1639,11 +1751,11 @@
break;
case AUTO_BASE_ALWAYS:
case AUTO_BASE_WHEN_ABLE:
- if (base_commit) {
+ if (cfg->base_commit) {
BUG("requested automatic base selection but a commit was provided");
} else {
auto_select = 1;
- die_on_failure = auto_base == AUTO_BASE_ALWAYS;
+ die_on_failure = cfg->auto_base == AUTO_BASE_ALWAYS;
}
break;
default:
@@ -1651,9 +1763,9 @@
}
if (!auto_select) {
- base = lookup_commit_reference_by_name(base_commit);
+ base = lookup_commit_reference_by_name(cfg->base_commit);
if (!base)
- die(_("unknown commit %s"), base_commit);
+ die(_("unknown commit %s"), cfg->base_commit);
} else {
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
@@ -1871,6 +1983,7 @@
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
+ struct format_config cfg;
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
@@ -1895,7 +2008,6 @@
char *cover_from_description_arg = NULL;
char *description_file = NULL;
char *branch_name = NULL;
- char *base_commit = NULL;
struct base_tree_info bases;
struct commit *base;
int show_progress = 0;
@@ -1906,18 +2018,24 @@
struct strbuf rdiff1 = STRBUF_INIT;
struct strbuf rdiff2 = STRBUF_INIT;
struct strbuf rdiff_title = STRBUF_INIT;
- struct strbuf sprefix = STRBUF_INIT;
+ const char *rfc = NULL;
int creation_factor = -1;
- int rfc = 0;
+ const char *signature = git_version_string;
+ const char *signature_file_arg = NULL;
+ struct keep_callback_data keep_callback_data = {
+ .cfg = &cfg,
+ .revs = &rev,
+ };
+ const char *fmt_patch_suffix = NULL;
const struct option builtin_format_patch_options[] = {
- OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
+ OPT_CALLBACK_F('n', "numbered", &cfg, NULL,
N_("use [PATCH n/m] even with a single patch"),
PARSE_OPT_NOARG, numbered_callback),
- OPT_CALLBACK_F('N', "no-numbered", &numbered, NULL,
+ OPT_CALLBACK_F('N', "no-numbered", &cfg, NULL,
N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback),
- OPT_BOOL('s', "signoff", &do_signoff, N_("add a Signed-off-by trailer")),
+ OPT_BOOL('s', "signoff", &cfg.do_signoff, N_("add a Signed-off-by trailer")),
OPT_BOOL(0, "stdout", &use_stdout,
N_("print patches to standard out")),
OPT_BOOL(0, "cover-letter", &cover_letter,
@@ -1930,21 +2048,23 @@
N_("start numbering patches at <n> instead of 1")),
OPT_STRING('v', "reroll-count", &reroll_count, N_("reroll-count"),
N_("mark the series as Nth re-roll")),
- OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
+ OPT_INTEGER(0, "filename-max-length", &cfg.log.fmt_patch_name_max,
N_("max length of output filename")),
- OPT_BOOL(0, "rfc", &rfc, N_("use [RFC PATCH] instead of [PATCH]")),
+ OPT_CALLBACK_F(0, "rfc", &rfc, N_("rfc"),
+ N_("add <rfc> (default 'RFC') before 'PATCH'"),
+ PARSE_OPT_OPTARG, rfc_callback),
OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
N_("cover-from-description-mode"),
N_("generate parts of a cover letter based on a branch's description")),
OPT_FILENAME(0, "description-file", &description_file,
N_("use branch description from file")),
- OPT_CALLBACK_F(0, "subject-prefix", &sprefix, N_("prefix"),
+ OPT_CALLBACK_F(0, "subject-prefix", &cfg, N_("prefix"),
N_("use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback),
OPT_CALLBACK_F('o', "output-directory", &output_directory,
N_("dir"), N_("store resulting files in <dir>"),
PARSE_OPT_NONEG, output_directory_callback),
- OPT_CALLBACK_F('k', "keep-subject", &rev, NULL,
+ OPT_CALLBACK_F('k', "keep-subject", &keep_callback_data, NULL,
N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback),
OPT_BOOL(0, "no-binary", &no_binary_diff,
@@ -1957,11 +2077,11 @@
N_("show patch format instead of default (patch + stat)"),
1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Messaging")),
- OPT_CALLBACK(0, "add-header", NULL, N_("header"),
+ OPT_CALLBACK(0, "add-header", &cfg, N_("header"),
N_("add email header"), header_callback),
- OPT_STRING_LIST(0, "to", &extra_to, N_("email"), N_("add To: header")),
- OPT_STRING_LIST(0, "cc", &extra_cc, N_("email"), N_("add Cc: header")),
- OPT_CALLBACK_F(0, "from", &from, N_("ident"),
+ OPT_STRING_LIST(0, "to", &cfg.extra_to, N_("email"), N_("add To: header")),
+ OPT_STRING_LIST(0, "cc", &cfg.extra_cc, N_("email"), N_("add Cc: header")),
+ OPT_CALLBACK_F(0, "from", &cfg.from, N_("ident"),
N_("set From address to <ident> (or committer ident if absent)"),
PARSE_OPT_OPTARG, from_callback),
OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
@@ -1973,15 +2093,15 @@
N_("inline the patch"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
inline_callback),
- OPT_CALLBACK_F(0, "thread", &thread, N_("style"),
+ OPT_CALLBACK_F(0, "thread", &cfg, N_("style"),
N_("enable message threading, styles: shallow, deep"),
PARSE_OPT_OPTARG, thread_callback),
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
- OPT_CALLBACK_F(0, "base", &base_commit, N_("base-commit"),
+ OPT_CALLBACK_F(0, "base", &cfg, N_("base-commit"),
N_("add prerequisite tree info to the patch series"),
0, base_callback),
- OPT_FILENAME(0, "signature-file", &signature_file,
+ OPT_FILENAME(0, "signature-file", &signature_file_arg,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_BOOL(0, "progress", &show_progress,
@@ -1998,20 +2118,17 @@
OPT_END()
};
- extra_hdr.strdup_strings = 1;
- extra_to.strdup_strings = 1;
- extra_cc.strdup_strings = 1;
-
- init_log_defaults();
- init_display_notes(¬es_opt);
- git_config(git_format_config, NULL);
+ format_config_init(&cfg);
+ init_diff_ui_defaults();
+ init_display_notes(&cfg.notes_opt);
+ git_config(git_format_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
- rev.show_notes = show_notes;
- memcpy(&rev.notes_opt, ¬es_opt, sizeof(notes_opt));
+ rev.show_notes = cfg.show_notes;
+ memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt));
rev.commit_format = CMIT_FMT_EMAIL;
- rev.encode_email_headers = default_encode_email_headers;
+ rev.encode_email_headers = cfg.log.default_encode_email_headers;
rev.expand_tabs_in_log_default = 0;
rev.verbose_header = 1;
rev.diff = 1;
@@ -2022,12 +2139,12 @@
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
- strbuf_addstr(&sprefix, fmt_patch_subject_prefix);
+ strbuf_addstr(&cfg.sprefix, cfg.log.fmt_patch_subject_prefix);
if (format_no_prefix)
diff_set_noprefix(&rev.diffopt);
- if (default_attach) {
- rev.mime_boundary = default_attach;
+ if (cfg.default_attach) {
+ rev.mime_boundary = cfg.default_attach;
rev.no_inline = 1;
}
@@ -2043,55 +2160,63 @@
rev.force_in_body_from = force_in_body_from;
+ if (!fmt_patch_suffix)
+ fmt_patch_suffix = cfg.fmt_patch_suffix;
+
/* Make sure "0000-$sub.patch" gives non-negative length for $sub */
- if (fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
- fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
+ if (cfg.log.fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
+ cfg.log.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
if (cover_from_description_arg)
- cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+ cfg.cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
- if (rfc)
- strbuf_insertstr(&sprefix, 0, "RFC ");
+ if (rfc && rfc[0]) {
+ cfg.subject_prefix = 1;
+ if (rfc[0] == '-')
+ strbuf_addf(&cfg.sprefix, " %s", rfc + 1);
+ else
+ strbuf_insertf(&cfg.sprefix, 0, "%s ", rfc);
+ }
if (reroll_count) {
- strbuf_addf(&sprefix, " v%s", reroll_count);
+ strbuf_addf(&cfg.sprefix, " v%s", reroll_count);
rev.reroll_count = reroll_count;
}
- rev.subject_prefix = sprefix.buf;
+ rev.subject_prefix = cfg.sprefix.buf;
- for (i = 0; i < extra_hdr.nr; i++) {
- strbuf_addstr(&buf, extra_hdr.items[i].string);
+ for (i = 0; i < cfg.extra_hdr.nr; i++) {
+ strbuf_addstr(&buf, cfg.extra_hdr.items[i].string);
strbuf_addch(&buf, '\n');
}
- if (extra_to.nr)
+ if (cfg.extra_to.nr)
strbuf_addstr(&buf, "To: ");
- for (i = 0; i < extra_to.nr; i++) {
+ for (i = 0; i < cfg.extra_to.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
- strbuf_addstr(&buf, extra_to.items[i].string);
- if (i + 1 < extra_to.nr)
+ strbuf_addstr(&buf, cfg.extra_to.items[i].string);
+ if (i + 1 < cfg.extra_to.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
- if (extra_cc.nr)
+ if (cfg.extra_cc.nr)
strbuf_addstr(&buf, "Cc: ");
- for (i = 0; i < extra_cc.nr; i++) {
+ for (i = 0; i < cfg.extra_cc.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
- strbuf_addstr(&buf, extra_cc.items[i].string);
- if (i + 1 < extra_cc.nr)
+ strbuf_addstr(&buf, cfg.extra_cc.items[i].string);
+ if (i + 1 < cfg.extra_cc.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
rev.extra_headers = to_free = strbuf_detach(&buf, NULL);
- if (from) {
- if (split_ident_line(&rev.from_ident, from, strlen(from)))
- die(_("invalid ident line: %s"), from);
+ if (cfg.from) {
+ if (split_ident_line(&rev.from_ident, cfg.from, strlen(cfg.from)))
+ die(_("invalid ident line: %s"), cfg.from);
}
if (start_number < 0)
@@ -2102,14 +2227,14 @@
* and it would conflict with --keep-subject (-k) from the
* command line, reset "numbered".
*/
- if (numbered && keep_subject && !numbered_cmdline_opt)
- numbered = 0;
+ if (cfg.numbered && cfg.keep_subject && !cfg.numbered_cmdline_opt)
+ cfg.numbered = 0;
- if (numbered && keep_subject)
+ if (cfg.numbered && cfg.keep_subject)
die(_("options '%s' and '%s' cannot be used together"), "-n", "-k");
- if (keep_subject && subject_prefix)
+ if (cfg.keep_subject && cfg.subject_prefix)
die(_("options '%s' and '%s' cannot be used together"), "--subject-prefix/--rfc", "-k");
- rev.preserve_subject = keep_subject;
+ rev.preserve_subject = cfg.keep_subject;
argc = setup_revisions(argc, argv, &rev, &s_r_opt);
if (argc > 1)
@@ -2136,7 +2261,7 @@
rev.always_show_header = 1;
rev.zero_commit = zero_commit;
- rev.patch_name_max = fmt_patch_name_max;
+ rev.patch_name_max = cfg.log.fmt_patch_name_max;
if (!rev.diffopt.flags.text && !no_binary_diff)
rev.diffopt.flags.binary = 1;
@@ -2157,7 +2282,7 @@
int saved;
if (!output_directory)
- output_directory = config_output_directory;
+ output_directory = cfg.config_output_directory;
output_directory = set_outdir(prefix, output_directory);
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
@@ -2206,8 +2331,10 @@
if (check_head) {
const char *ref, *v;
- ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- NULL, NULL);
+ ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD",
+ RESOLVE_REF_READING,
+ NULL, NULL);
if (ref && skip_prefix(ref, "refs/heads/", &v))
branch_name = xstrdup(v);
else
@@ -2253,14 +2380,16 @@
goto done;
total = nr;
if (cover_letter == -1) {
- if (config_cover_letter == COVER_AUTO)
+ if (cfg.config_cover_letter == COVER_AUTO)
cover_letter = (total > 1);
+ else if ((idiff_prev.nr || rdiff_prev) && (total > 1))
+ cover_letter = (cfg.config_cover_letter != COVER_OFF);
else
- cover_letter = (config_cover_letter == COVER_ON);
+ cover_letter = (cfg.config_cover_letter == COVER_ON);
}
- if (!keep_subject && auto_number && (total > 1 || cover_letter))
- numbered = 1;
- if (numbered)
+ if (!cfg.keep_subject && cfg.auto_number && (total > 1 || cover_letter))
+ cfg.numbered = 1;
+ if (cfg.numbered)
rev.total = total + start_number - 1;
if (idiff_prev.nr) {
@@ -2274,7 +2403,7 @@
}
if (creation_factor < 0)
- creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
+ creation_factor = CREATION_FACTOR_FOR_THE_SAME_SERIES;
else if (!rdiff_prev)
die(_("the option '%s' requires '%s'"), "--creation-factor", "--range-diff");
@@ -2292,27 +2421,40 @@
_("Range-diff against v%d:"));
}
+ /*
+ * The order of precedence is:
+ *
+ * 1. The `--signature` and `--no-signature` options.
+ * 2. The `--signature-file` option.
+ * 3. The `format.signature` config.
+ * 4. The `format.signatureFile` config.
+ * 5. Default `git_version_string`.
+ */
if (!signature) {
; /* --no-signature inhibits all signatures */
} else if (signature && signature != git_version_string) {
; /* non-default signature already set */
- } else if (signature_file) {
+ } else if (signature_file_arg || (cfg.signature_file && !cfg.signature)) {
struct strbuf buf = STRBUF_INIT;
+ const char *signature_file = signature_file_arg ?
+ signature_file_arg : cfg.signature_file;
if (strbuf_read_file(&buf, signature_file, 128) < 0)
die_errno(_("unable to read signature file '%s'"), signature_file);
signature = strbuf_detach(&buf, NULL);
+ } else if (cfg.signature) {
+ signature = cfg.signature;
}
memset(&bases, 0, sizeof(bases));
- base = get_base_commit(base_commit, list, nr);
+ base = get_base_commit(&cfg, list, nr);
if (base) {
reset_revision_walk();
clear_object_flags(UNINTERESTING);
prepare_bases(&bases, base, list, nr);
}
- if (in_reply_to || thread || cover_letter) {
+ if (in_reply_to || cfg.thread || cover_letter) {
rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
string_list_init_dup(rev.ref_message_ids);
}
@@ -2323,19 +2465,19 @@
rev.numbered_files = just_numbers;
rev.patch_suffix = fmt_patch_suffix;
if (cover_letter) {
- if (thread)
+ if (cfg.thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, !!output_directory,
- origin, nr, list, description_file, branch_name, quiet);
+ origin, nr, list, description_file, branch_name, quiet, &cfg);
print_bases(&bases, rev.diffopt.file);
- print_signature(rev.diffopt.file);
+ print_signature(signature, rev.diffopt.file);
total++;
start_number--;
/* interdiff/range-diff in cover-letter; omit from patches */
rev.idiff_oid1 = NULL;
rev.rdiff1 = NULL;
}
- rev.add_signoff = do_signoff;
+ rev.add_signoff = cfg.do_signoff;
if (show_progress)
progress = start_delayed_progress(_("Generating patches"), total);
@@ -2345,7 +2487,7 @@
commit = list[nr];
rev.nr = total - nr + (start_number - 1);
/* Make the second and subsequent mails replies to the first */
- if (thread) {
+ if (cfg.thread) {
/* Have we already had a message ID? */
if (rev.message_id) {
/*
@@ -2369,7 +2511,7 @@
* letter is a reply to the
* --in-reply-to, if specified.
*/
- if (thread == THREAD_SHALLOW
+ if (cfg.thread == THREAD_SHALLOW
&& rev.ref_message_ids->nr > 0
&& (!cover_letter || rev.nr > 1))
free(rev.message_id);
@@ -2402,7 +2544,7 @@
mime_boundary_leader,
rev.mime_boundary);
else
- print_signature(rev.diffopt.file);
+ print_signature(signature, rev.diffopt.file);
}
if (output_directory)
fclose(rev.diffopt.file);
@@ -2410,9 +2552,6 @@
stop_progress(&progress);
free(list);
free(branch_name);
- string_list_clear(&extra_to, 0);
- string_list_clear(&extra_cc, 0);
- string_list_clear(&extra_hdr, 0);
if (ignore_if_in_upstream)
free_patch_ids(&ids);
@@ -2422,13 +2561,14 @@
strbuf_release(&rdiff1);
strbuf_release(&rdiff2);
strbuf_release(&rdiff_title);
- strbuf_release(&sprefix);
free(to_free);
free(rev.message_id);
if (rev.ref_message_ids)
string_list_clear(rev.ref_message_ids, 0);
free(rev.ref_message_ids);
- return cmd_log_deinit(0, &rev);
+ release_revisions(&rev);
+ format_config_release(&cfg);
+ return 0;
}
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index e8d65eb..69841ed 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -9,7 +9,7 @@
#include "wildmatch.h"
static const char * const ls_remote_usage[] = {
- N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+ N_("git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
" [--symref] [<repository> [<patterns>...]]"),
NULL
@@ -68,7 +68,10 @@
N_("path of git-upload-pack on the remote host"),
PARSE_OPT_HIDDEN },
OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS),
- OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS),
+ OPT_BIT('b', "branches", &flags, N_("limit to branches"), REF_BRANCHES),
+ OPT_BIT_F('h', "heads", &flags,
+ N_("deprecated synonym for --branches"), REF_BRANCHES,
+ PARSE_OPT_HIDDEN),
OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL),
OPT_BOOL(0, "get-url", &get_url,
N_("take url.<base>.insteadOf into account")),
@@ -100,7 +103,7 @@
if (flags & REF_TAGS)
strvec_push(&transport_options.ref_prefixes, "refs/tags/");
- if (flags & REF_HEADS)
+ if (flags & REF_BRANCHES)
strvec_push(&transport_options.ref_prefixes, "refs/heads/");
remote = remote_get(dest);
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 3af9ddb..fe6dbc5 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -113,8 +113,8 @@
DIR *dir;
struct dirent *dent;
char *name = NULL;
- char *subs[] = { "cur", "new", NULL };
- char **sub;
+ const char *subs[] = { "cur", "new", NULL };
+ const char **sub;
int ret = -1;
for (sub = subs; *sub; ++sub) {
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 270d5f6..0fabe3f 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "hex.h"
#include "read-cache-ll.h"
@@ -18,11 +17,11 @@
char ownbuf[4][60];
struct child_process cmd = CHILD_PROCESS_INIT;
- if (pos >= the_index.cache_nr)
+ if (pos >= the_repository->index->cache_nr)
die("git merge-index: %s not in the cache", path);
found = 0;
do {
- const struct cache_entry *ce = the_index.cache[pos];
+ const struct cache_entry *ce = the_repository->index->cache[pos];
int stage = ce_stage(ce);
if (strcmp(ce->name, path))
@@ -32,7 +31,7 @@
xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode);
arguments[stage] = hexbuf[stage];
arguments[stage + 4] = ownbuf[stage];
- } while (++pos < the_index.cache_nr);
+ } while (++pos < the_repository->index->cache_nr);
if (!found)
die("git merge-index: %s not in the cache", path);
@@ -51,7 +50,7 @@
static void merge_one_path(const char *path)
{
- int pos = index_name_pos(&the_index, path, strlen(path));
+ int pos = index_name_pos(the_repository->index, path, strlen(path));
/*
* If it already exists in the cache as stage0, it's
@@ -65,9 +64,9 @@
{
int i;
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
if (!ce_stage(ce))
continue;
i += merge_entry(i, ce->name)-1;
@@ -89,7 +88,7 @@
repo_read_index(the_repository);
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
i = 1;
if (!strcmp(argv[i], "-o")) {
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 8bdb439..1082d91 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
@@ -364,7 +363,7 @@
setup_traverse_info(&info, base);
info.fn = threeway_callback;
- traverse_trees(&the_index, 3, t, &info);
+ traverse_trees(the_repository->index, 3, t, &info);
}
static void *get_tree_descriptor(struct repository *r,
diff --git a/builtin/merge.c b/builtin/merge.c
index 6f4fec8..fb3eb15 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -6,7 +6,6 @@
* Based on git-merge.sh by Junio C Hamano.
*/
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "advice.h"
@@ -101,7 +100,7 @@
{ "subtree", NO_FAST_FORWARD | NO_TRIVIAL },
};
-static const char *pull_twohead, *pull_octopus;
+static char *pull_twohead, *pull_octopus;
enum ff_type {
FF_NO,
@@ -111,7 +110,7 @@
static enum ff_type fast_forward = FF_ALLOW;
-static const char *cleanup_arg;
+static char *cleanup_arg;
static enum commit_msg_cleanup_mode cleanup_mode;
static int option_parse_message(const struct option *opt,
@@ -300,7 +299,7 @@
int rc = -1;
fd = repo_hold_locked_index(the_repository, &lock_file, 0);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
repo_update_index_if_able(the_repository, &lock_file);
rollback_lock_file(&lock_file);
@@ -372,7 +371,7 @@
run_command(&cmd);
refresh_cache:
- discard_index(&the_index);
+ discard_index(the_repository->index);
if (repo_read_index(the_repository) < 0)
die(_("could not read index"));
}
@@ -449,8 +448,10 @@
if (verbosity >= 0 && !merge_msg.len)
printf(_("No merge message -- not updating HEAD\n"));
else {
- update_ref(reflog_message.buf, "HEAD", new_head, head,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ reflog_message.buf, "HEAD", new_head,
+ head,
+ 0, UPDATE_REFS_DIE_ON_ERR);
/*
* We ignore errors in 'gc --auto', since the
* user should see them.
@@ -547,7 +548,7 @@
struct strbuf truname = STRBUF_INIT;
strbuf_addf(&truname, "refs/heads/%s", remote);
strbuf_setlen(&truname, truname.len - len);
- if (ref_exists(truname.buf)) {
+ if (refs_ref_exists(get_main_ref_store(the_repository), truname.buf)) {
strbuf_addf(msg,
"%s\t\tbranch '%s'%s of .\n",
oid_to_hex(&remote_head->object.oid),
@@ -610,17 +611,19 @@
return 0;
}
- if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat"))
+ if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) {
show_diffstat = git_config_bool(k, v);
- else if (!strcmp(k, "merge.verifysignatures"))
+ } else if (!strcmp(k, "merge.verifysignatures")) {
verify_signatures = git_config_bool(k, v);
- else if (!strcmp(k, "pull.twohead"))
+ } else if (!strcmp(k, "pull.twohead")) {
+ FREE_AND_NULL(pull_twohead);
return git_config_string(&pull_twohead, k, v);
- else if (!strcmp(k, "pull.octopus"))
+ } else if (!strcmp(k, "pull.octopus")) {
+ FREE_AND_NULL(pull_octopus);
return git_config_string(&pull_octopus, k, v);
- else if (!strcmp(k, "commit.cleanup"))
+ } else if (!strcmp(k, "commit.cleanup")) {
return git_config_string(&cleanup_arg, k, v);
- else if (!strcmp(k, "merge.ff")) {
+ } else if (!strcmp(k, "merge.ff")) {
int boolval = git_parse_maybe_bool(v);
if (0 <= boolval) {
fast_forward = boolval ? FF_ALLOW : FF_NO;
@@ -657,8 +660,8 @@
memset(&opts, 0, sizeof(opts));
opts.head_idx = 2;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.update = 1;
opts.verbose_update = 1;
opts.trivial_merges_only = 1;
@@ -674,7 +677,7 @@
if (!trees[nr_trees++])
return -1;
opts.fn = threeway_merge;
- cache_tree_free(&the_index.cache_tree);
+ cache_tree_free(&the_repository->index->cache_tree);
for (i = 0; i < nr_trees; i++) {
parse_tree(trees[i]);
init_tree_desc(t+i, &trees[i]->object.oid,
@@ -687,7 +690,7 @@
static void write_tree_trivial(struct object_id *oid)
{
- if (write_index_as_tree(oid, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(oid, the_repository->index, get_index_file(), 0, NULL))
die(_("git write-tree failed to write a tree"));
}
@@ -745,7 +748,7 @@
rollback_lock_file(&lock);
return 2;
}
- if (write_locked_index(&the_index, &lock,
+ if (write_locked_index(the_repository->index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write %s"), get_index_file());
return clean ? 0 : 1;
@@ -768,8 +771,8 @@
{
int i, ret = 0;
- for (i = 0; i < the_index.cache_nr; i++)
- if (ce_stage(the_index.cache[i]))
+ for (i = 0; i < the_repository->index->cache_nr; i++)
+ if (ce_stage(the_repository->index->cache[i]))
ret++;
return ret;
@@ -843,9 +846,9 @@
* the editor and after we invoke run_status above.
*/
if (invoked_hook)
- discard_index(&the_index);
+ discard_index(the_repository->index);
}
- read_index_from(&the_index, index_file, get_git_dir());
+ read_index_from(the_repository->index, index_file, get_git_dir());
strbuf_addbuf(&msg, &merge_msg);
if (squash)
BUG("the control must not reach here under --squash");
@@ -957,7 +960,7 @@
* Thus, we will get the cleanup mode which is returned when we _are_
* using an editor.
*/
- append_conflicts_hint(&the_index, &msgbuf,
+ append_conflicts_hint(the_repository->index, &msgbuf,
get_cleanup_mode(cleanup_arg, 1));
fputs(msgbuf.buf, fp);
strbuf_release(&msgbuf);
@@ -1252,7 +1255,7 @@
*/
tag_ref = xstrfmt("refs/tags/%s",
((struct tag *)merge_remote_util(commit)->obj)->tag);
- if (!read_ref(tag_ref, &oid) &&
+ if (!refs_read_ref(get_main_ref_store(the_repository), tag_ref, &oid) &&
oideq(&oid, &merge_remote_util(commit)->obj->oid))
is_throwaway_tag = 0;
else
@@ -1284,14 +1287,16 @@
* Check if we are _not_ on a detached HEAD, i.e. if there is a
* current branch.
*/
- branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL);
+ branch = branch_to_free = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, &head_oid,
+ NULL);
if (branch)
skip_prefix(branch, "refs/heads/", &branch);
if (!pull_twohead) {
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
if (default_strategy && !strcmp(default_strategy, "ort"))
- pull_twohead = "ort";
+ pull_twohead = xstrdup("ort");
}
init_diff_ui_defaults();
@@ -1325,8 +1330,10 @@
if (!file_exists(git_path_merge_head(the_repository)))
die(_("There is no merge to abort (MERGE_HEAD missing)."));
- if (!read_ref("MERGE_AUTOSTASH", &stash_oid))
- delete_ref("", "MERGE_AUTOSTASH", &stash_oid, REF_NO_DEREF);
+ if (!refs_read_ref(get_main_ref_store(the_repository), "MERGE_AUTOSTASH", &stash_oid))
+ refs_delete_ref(get_main_ref_store(the_repository),
+ "", "MERGE_AUTOSTASH", &stash_oid,
+ REF_NO_DEREF);
/* Invoke 'git reset --merge' */
ret = cmd_reset(nargc, nargv, prefix);
@@ -1379,14 +1386,14 @@
else
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
}
- if (ref_exists("CHERRY_PICK_HEAD")) {
+ if (refs_ref_exists(get_main_ref_store(the_repository), "CHERRY_PICK_HEAD")) {
if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."));
else
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
}
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
if (option_edit < 0)
option_edit = default_edit_option();
@@ -1450,8 +1457,10 @@
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid);
- update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "initial pull", "HEAD", remote_head_oid, NULL,
+ 0,
+ UPDATE_REFS_DIE_ON_ERR);
goto done;
}
@@ -1531,8 +1540,10 @@
free(list);
}
- update_ref("updating ORIG_HEAD", "ORIG_HEAD",
- &head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "updating ORIG_HEAD", "ORIG_HEAD",
+ &head_commit->object.oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (remoteheads && !common) {
/* No common ancestors found. */
@@ -1595,7 +1606,7 @@
* We are not doing octopus, not fast-forward, and have
* only one common.
*/
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
if (allow_trivial && fast_forward != FF_ONLY) {
/*
* Must first ensure that index matches HEAD before
@@ -1784,6 +1795,8 @@
}
strbuf_release(&buf);
free(branch_to_free);
- discard_index(&the_index);
+ free(pull_twohead);
+ free(pull_octopus);
+ discard_index(the_repository->index);
return ret;
}
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index a72aebe..8360932 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -8,6 +8,7 @@
#include "strbuf.h"
#include "trace2.h"
#include "object-store-ll.h"
+#include "replace-object.h"
#define BUILTIN_MIDX_WRITE_USAGE \
N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
@@ -273,6 +274,8 @@
};
struct option *options = parse_options_concat(builtin_multi_pack_index_options, common_opts);
+ disable_replace_refs();
+
git_config(git_default_config, NULL);
if (the_repository &&
diff --git a/builtin/mv.c b/builtin/mv.c
index 22e64fc..6c69033 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2006 Johannes Schindelin
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "abspath.h"
#include "advice.h"
@@ -20,6 +20,7 @@
#include "read-cache-ll.h"
#include "repository.h"
#include "setup.h"
+#include "strvec.h"
#include "submodule.h"
#include "entry.h"
@@ -38,45 +39,35 @@
#define DUP_BASENAME 1
#define KEEP_TRAILING_SLASH 2
-static const char **internal_prefix_pathspec(const char *prefix,
- const char **pathspec,
- int count, unsigned flags)
+static void internal_prefix_pathspec(struct strvec *out,
+ const char *prefix,
+ const char **pathspec,
+ int count, unsigned flags)
{
- int i;
- const char **result;
int prefixlen = prefix ? strlen(prefix) : 0;
- ALLOC_ARRAY(result, count + 1);
/* Create an intermediate copy of the pathspec based on the flags */
- for (i = 0; i < count; i++) {
- int length = strlen(pathspec[i]);
- int to_copy = length;
- char *it;
+ for (int i = 0; i < count; i++) {
+ size_t length = strlen(pathspec[i]);
+ size_t to_copy = length;
+ const char *maybe_basename;
+ char *trimmed, *prefixed_path;
+
while (!(flags & KEEP_TRAILING_SLASH) &&
to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
to_copy--;
- it = xmemdupz(pathspec[i], to_copy);
- if (flags & DUP_BASENAME) {
- result[i] = xstrdup(basename(it));
- free(it);
- } else {
- result[i] = it;
- }
- }
- result[count] = NULL;
+ trimmed = xmemdupz(pathspec[i], to_copy);
+ maybe_basename = (flags & DUP_BASENAME) ? basename(trimmed) : trimmed;
+ prefixed_path = prefix_path(prefix, prefixlen, maybe_basename);
+ strvec_push(out, prefixed_path);
- /* Prefix the pathspec and free the old intermediate strings */
- for (i = 0; i < count; i++) {
- const char *match = prefix_path(prefix, prefixlen, result[i]);
- free((char *) result[i]);
- result[i] = match;
+ free(prefixed_path);
+ free(trimmed);
}
-
- return result;
}
-static const char *add_slash(const char *path)
+static char *add_slash(const char *path)
{
size_t len = strlen(path);
if (len && path[len - 1] != '/') {
@@ -86,46 +77,48 @@
with_slash[len] = 0;
return with_slash;
}
- return path;
+ return xstrdup(path);
}
#define SUBMODULE_WITH_GITDIR ((const char *)1)
-static void prepare_move_submodule(const char *src, int first,
- const char **submodule_gitfile)
+static const char *submodule_gitfile_path(const char *src, int first)
{
struct strbuf submodule_dotgit = STRBUF_INIT;
- if (!S_ISGITLINK(the_index.cache[first]->ce_mode))
+ const char *path;
+
+ if (!S_ISGITLINK(the_repository->index->cache[first]->ce_mode))
die(_("Directory %s is in index and no submodule?"), src);
- if (!is_staging_gitmodules_ok(&the_index))
+ if (!is_staging_gitmodules_ok(the_repository->index))
die(_("Please stage your changes to .gitmodules or stash them to proceed"));
+
strbuf_addf(&submodule_dotgit, "%s/.git", src);
- *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
- if (*submodule_gitfile)
- *submodule_gitfile = xstrdup(*submodule_gitfile);
- else
- *submodule_gitfile = SUBMODULE_WITH_GITDIR;
+
+ path = read_gitfile(submodule_dotgit.buf);
strbuf_release(&submodule_dotgit);
+ if (path)
+ return path;
+ return SUBMODULE_WITH_GITDIR;
}
static int index_range_of_same_dir(const char *src, int length,
int *first_p, int *last_p)
{
- const char *src_w_slash = add_slash(src);
+ char *src_w_slash = add_slash(src);
int first, last, len_w_slash = length + 1;
- first = index_name_pos(&the_index, src_w_slash, len_w_slash);
+ first = index_name_pos(the_repository->index, src_w_slash, len_w_slash);
if (first >= 0)
die(_("%.*s is in index"), len_w_slash, src_w_slash);
first = -1 - first;
- for (last = first; last < the_index.cache_nr; last++) {
- const char *path = the_index.cache[last]->name;
+ for (last = first; last < the_repository->index->cache_nr; last++) {
+ const char *path = the_repository->index->cache[last]->name;
if (strncmp(path, src_w_slash, len_w_slash))
break;
}
- if (src_w_slash != src)
- free((char *)src_w_slash);
+
+ free(src_w_slash);
*first_p = first;
*last_p = last;
return last - first;
@@ -141,17 +134,17 @@
static int empty_dir_has_sparse_contents(const char *name)
{
int ret = 0;
- const char *with_slash = add_slash(name);
+ char *with_slash = add_slash(name);
int length = strlen(with_slash);
- int pos = index_name_pos(&the_index, with_slash, length);
+ int pos = index_name_pos(the_repository->index, with_slash, length);
const struct cache_entry *ce;
if (pos < 0) {
pos = -pos - 1;
- if (pos >= the_index.cache_nr)
+ if (pos >= the_repository->index->cache_nr)
goto free_return;
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (strncmp(with_slash, ce->name, length))
goto free_return;
if (ce_skip_worktree(ce))
@@ -159,11 +152,32 @@
}
free_return:
- if (with_slash != name)
- free((char *)with_slash);
+ free(with_slash);
return ret;
}
+static void remove_empty_src_dirs(const char **src_dir, size_t src_dir_nr)
+{
+ size_t i;
+ struct strbuf a_src_dir = STRBUF_INIT;
+
+ for (i = 0; i < src_dir_nr; i++) {
+ int dummy;
+ strbuf_addstr(&a_src_dir, src_dir[i]);
+ /*
+ * if entries under a_src_dir are all moved away,
+ * recursively remove a_src_dir to cleanup
+ */
+ if (index_range_of_same_dir(a_src_dir.buf, a_src_dir.len,
+ &dummy, &dummy) < 1) {
+ remove_dir_recursively(&a_src_dir, 0);
+ }
+ strbuf_reset(&a_src_dir);
+ }
+
+ strbuf_release(&a_src_dir);
+}
+
int cmd_mv(int argc, const char **argv, const char *prefix)
{
int i, flags, gitmodules_modified = 0;
@@ -177,18 +191,21 @@
OPT_BOOL(0, "sparse", &ignore_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
OPT_END(),
};
- const char **source, **destination, **dest_path, **submodule_gitfile;
- const char *dst_w_slash;
- const char **src_dir = NULL;
- int src_dir_nr = 0, src_dir_alloc = 0;
- struct strbuf a_src_dir = STRBUF_INIT;
+ struct strvec sources = STRVEC_INIT;
+ struct strvec dest_paths = STRVEC_INIT;
+ struct strvec destinations = STRVEC_INIT;
+ struct strvec submodule_gitfiles_to_free = STRVEC_INIT;
+ const char **submodule_gitfiles;
+ char *dst_w_slash = NULL;
+ struct strvec src_dir = STRVEC_INIT;
enum update_mode *modes, dst_mode = 0;
struct stat st, dest_st;
- struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+ struct string_list src_for_dst = STRING_LIST_INIT_DUP;
struct lock_file lock_file = LOCK_INIT;
struct cache_entry *ce;
- struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
- struct string_list dirty_paths = STRING_LIST_INIT_NODUP;
+ struct string_list only_match_skip_worktree = STRING_LIST_INIT_DUP;
+ struct string_list dirty_paths = STRING_LIST_INIT_DUP;
+ int ret;
git_config(git_default_config, NULL);
@@ -201,7 +218,7 @@
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- source = internal_prefix_pathspec(prefix, argv, argc, 0);
+ internal_prefix_pathspec(&sources, prefix, argv, argc, 0);
CALLOC_ARRAY(modes, argc);
/*
@@ -212,45 +229,39 @@
flags = KEEP_TRAILING_SLASH;
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
flags = 0;
- dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
- dst_w_slash = add_slash(dest_path[0]);
- submodule_gitfile = xcalloc(argc, sizeof(char *));
+ internal_prefix_pathspec(&dest_paths, prefix, argv + argc, 1, flags);
+ dst_w_slash = add_slash(dest_paths.v[0]);
+ submodule_gitfiles = xcalloc(argc, sizeof(char *));
- if (dest_path[0][0] == '\0')
+ if (dest_paths.v[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
- else if (!lstat(dest_path[0], &st) &&
- S_ISDIR(st.st_mode)) {
- destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
+ internal_prefix_pathspec(&destinations, dest_paths.v[0], argv, argc, DUP_BASENAME);
+ else if (!lstat(dest_paths.v[0], &st) && S_ISDIR(st.st_mode)) {
+ internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+ } else if (!path_in_sparse_checkout(dst_w_slash, the_repository->index) &&
+ empty_dir_has_sparse_contents(dst_w_slash)) {
+ internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+ dst_mode = SKIP_WORKTREE_DIR;
+ } else if (argc != 1) {
+ die(_("destination '%s' is not a directory"), dest_paths.v[0]);
} else {
- if (!path_in_sparse_checkout(dst_w_slash, &the_index) &&
- empty_dir_has_sparse_contents(dst_w_slash)) {
- destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
- dst_mode = SKIP_WORKTREE_DIR;
- } else if (argc != 1) {
- die(_("destination '%s' is not a directory"), dest_path[0]);
- } else {
- destination = dest_path;
- /*
- * <destination> is a file outside of sparse-checkout
- * cone. Insist on cone mode here for backward
- * compatibility. We don't want dst_mode to be assigned
- * for a file when the repo is using no-cone mode (which
- * is deprecated at this point) sparse-checkout. As
- * SPARSE here is only considering cone-mode situation.
- */
- if (!path_in_cone_mode_sparse_checkout(destination[0], &the_index))
- dst_mode = SPARSE;
- }
- }
- if (dst_w_slash != dest_path[0]) {
- free((char *)dst_w_slash);
- dst_w_slash = NULL;
+ strvec_pushv(&destinations, dest_paths.v);
+
+ /*
+ * <destination> is a file outside of sparse-checkout
+ * cone. Insist on cone mode here for backward
+ * compatibility. We don't want dst_mode to be assigned
+ * for a file when the repo is using no-cone mode (which
+ * is deprecated at this point) sparse-checkout. As
+ * SPARSE here is only considering cone-mode situation.
+ */
+ if (!path_in_cone_mode_sparse_checkout(destinations.v[0], the_repository->index))
+ dst_mode = SPARSE;
}
/* Checking */
for (i = 0; i < argc; i++) {
- const char *src = source[i], *dst = destination[i];
+ const char *src = sources.v[i], *dst = destinations.v[i];
int length;
const char *bad = NULL;
int skip_sparse = 0;
@@ -263,20 +274,22 @@
int pos;
const struct cache_entry *ce;
- pos = index_name_pos(&the_index, src, length);
+ pos = index_name_pos(the_repository->index, src, length);
if (pos < 0) {
- const char *src_w_slash = add_slash(src);
- if (!path_in_sparse_checkout(src_w_slash, &the_index) &&
+ char *src_w_slash = add_slash(src);
+ if (!path_in_sparse_checkout(src_w_slash, the_repository->index) &&
empty_dir_has_sparse_contents(src)) {
+ free(src_w_slash);
modes[i] |= SKIP_WORKTREE_DIR;
goto dir_check;
}
+ free(src_w_slash);
/* only error if existence is expected. */
if (!(modes[i] & SPARSE))
bad = _("bad source");
goto act_on_entry;
}
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (!ce_skip_worktree(ce)) {
bad = _("bad source");
goto act_on_entry;
@@ -286,7 +299,7 @@
goto act_on_entry;
}
/* Check if dst exists in index */
- if (index_name_pos(&the_index, dst, strlen(dst)) < 0) {
+ if (index_name_pos(the_repository->index, dst, strlen(dst)) < 0) {
modes[i] |= SPARSE;
goto act_on_entry;
}
@@ -310,12 +323,16 @@
dir_check:
if (S_ISDIR(st.st_mode)) {
- int j, dst_len, n;
- int first = index_name_pos(&the_index, src, length), last;
+ char *dst_with_slash;
+ size_t dst_with_slash_len;
+ int j, n;
+ int first = index_name_pos(the_repository->index, src, length), last;
if (first >= 0) {
- prepare_move_submodule(src, first,
- submodule_gitfile + i);
+ const char *path = submodule_gitfile_path(src, first);
+ if (path != SUBMODULE_WITH_GITDIR)
+ path = strvec_push(&submodule_gitfiles_to_free, path);
+ submodule_gitfiles[i] = path;
goto act_on_entry;
} else if (index_range_of_same_dir(src, length,
&first, &last) < 1) {
@@ -326,32 +343,35 @@
/* last - first >= 1 */
modes[i] |= WORKING_DIRECTORY;
- ALLOC_GROW(src_dir, src_dir_nr + 1, src_dir_alloc);
- src_dir[src_dir_nr++] = src;
+ strvec_push(&src_dir, src);
n = argc + last - first;
- REALLOC_ARRAY(source, n);
- REALLOC_ARRAY(destination, n);
REALLOC_ARRAY(modes, n);
- REALLOC_ARRAY(submodule_gitfile, n);
+ REALLOC_ARRAY(submodule_gitfiles, n);
- dst = add_slash(dst);
- dst_len = strlen(dst);
+ dst_with_slash = add_slash(dst);
+ dst_with_slash_len = strlen(dst_with_slash);
for (j = 0; j < last - first; j++) {
- const struct cache_entry *ce = the_index.cache[first + j];
+ const struct cache_entry *ce = the_repository->index->cache[first + j];
const char *path = ce->name;
- source[argc + j] = path;
- destination[argc + j] =
- prefix_path(dst, dst_len, path + length + 1);
+ char *prefixed_path = prefix_path(dst_with_slash, dst_with_slash_len, path + length + 1);
+
+ strvec_push(&sources, path);
+ strvec_push(&destinations, prefixed_path);
+
memset(modes + argc + j, 0, sizeof(enum update_mode));
modes[argc + j] |= ce_skip_worktree(ce) ? SPARSE : INDEX;
- submodule_gitfile[argc + j] = NULL;
+ submodule_gitfiles[argc + j] = NULL;
+
+ free(prefixed_path);
}
+
+ free(dst_with_slash);
argc += last - first;
goto act_on_entry;
}
- if (!(ce = index_file_exists(&the_index, src, length, 0))) {
+ if (!(ce = index_file_exists(the_repository->index, src, length, 0))) {
bad = _("not under version control");
goto act_on_entry;
}
@@ -387,7 +407,7 @@
if (ignore_sparse &&
(dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
- index_entry_exists(&the_index, dst, strlen(dst))) {
+ index_entry_exists(the_repository->index, dst, strlen(dst))) {
bad = _("destination exists in the index");
if (force) {
if (verbose)
@@ -404,12 +424,12 @@
* option as a way to have a successful run.
*/
if (!ignore_sparse &&
- !path_in_sparse_checkout(src, &the_index)) {
+ !path_in_sparse_checkout(src, the_repository->index)) {
string_list_append(&only_match_skip_worktree, src);
skip_sparse = 1;
}
if (!ignore_sparse &&
- !path_in_sparse_checkout(dst, &the_index)) {
+ !path_in_sparse_checkout(dst, the_repository->index)) {
string_list_append(&only_match_skip_worktree, dst);
skip_sparse = 1;
}
@@ -428,28 +448,30 @@
remove_entry:
if (--argc > 0) {
int n = argc - i;
- MOVE_ARRAY(source + i, source + i + 1, n);
- MOVE_ARRAY(destination + i, destination + i + 1, n);
+ strvec_remove(&sources, i);
+ strvec_remove(&destinations, i);
MOVE_ARRAY(modes + i, modes + i + 1, n);
- MOVE_ARRAY(submodule_gitfile + i,
- submodule_gitfile + i + 1, n);
+ MOVE_ARRAY(submodule_gitfiles + i,
+ submodule_gitfiles + i + 1, n);
i--;
}
}
if (only_match_skip_worktree.nr) {
advise_on_updating_sparse_paths(&only_match_skip_worktree);
- if (!ignore_errors)
- return 1;
+ if (!ignore_errors) {
+ ret = 1;
+ goto out;
+ }
}
for (i = 0; i < argc; i++) {
- const char *src = source[i], *dst = destination[i];
+ const char *src = sources.v[i], *dst = destinations.v[i];
enum update_mode mode = modes[i];
int pos;
int sparse_and_dirty = 0;
struct checkout state = CHECKOUT_INIT;
- state.istate = &the_index;
+ state.istate = the_repository->index;
if (force)
state.force = 1;
@@ -464,26 +486,26 @@
continue;
die_errno(_("renaming '%s' failed"), src);
}
- if (submodule_gitfile[i]) {
+ if (submodule_gitfiles[i]) {
if (!update_path_in_gitmodules(src, dst))
gitmodules_modified = 1;
- if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
+ if (submodule_gitfiles[i] != SUBMODULE_WITH_GITDIR)
connect_work_tree_and_git_dir(dst,
- submodule_gitfile[i],
+ submodule_gitfiles[i],
1);
}
if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
continue;
- pos = index_name_pos(&the_index, src, strlen(src));
+ pos = index_name_pos(the_repository->index, src, strlen(src));
assert(pos >= 0);
if (!(mode & SPARSE) && !lstat(src, &st))
- sparse_and_dirty = ie_modified(&the_index,
- the_index.cache[pos],
+ sparse_and_dirty = ie_modified(the_repository->index,
+ the_repository->index->cache[pos],
&st,
0);
- rename_index_entry_at(&the_index, pos, dst);
+ rename_index_entry_at(the_repository->index, pos, dst);
if (ignore_sparse &&
core_apply_sparse_checkout &&
@@ -495,11 +517,11 @@
* should be added in a future patch.
*/
if ((mode & SPARSE) &&
- path_in_sparse_checkout(dst, &the_index)) {
+ path_in_sparse_checkout(dst, the_repository->index)) {
/* from out-of-cone to in-cone */
- int dst_pos = index_name_pos(&the_index, dst,
+ int dst_pos = index_name_pos(the_repository->index, dst,
strlen(dst));
- struct cache_entry *dst_ce = the_index.cache[dst_pos];
+ struct cache_entry *dst_ce = the_repository->index->cache[dst_pos];
dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -507,11 +529,11 @@
die(_("cannot checkout %s"), dst_ce->name);
} else if ((dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
!(mode & SPARSE) &&
- !path_in_sparse_checkout(dst, &the_index)) {
+ !path_in_sparse_checkout(dst, the_repository->index)) {
/* from in-cone to out-of-cone */
- int dst_pos = index_name_pos(&the_index, dst,
+ int dst_pos = index_name_pos(the_repository->index, dst,
strlen(dst));
- struct cache_entry *dst_ce = the_index.cache[dst_pos];
+ struct cache_entry *dst_ce = the_repository->index->cache[dst_pos];
/*
* if src is clean, it will suffice to remove it
@@ -535,41 +557,31 @@
}
}
- /*
- * cleanup the empty src_dirs
- */
- for (i = 0; i < src_dir_nr; i++) {
- int dummy;
- strbuf_addstr(&a_src_dir, src_dir[i]);
- /*
- * if entries under a_src_dir are all moved away,
- * recursively remove a_src_dir to cleanup
- */
- if (index_range_of_same_dir(a_src_dir.buf, a_src_dir.len,
- &dummy, &dummy) < 1) {
- remove_dir_recursively(&a_src_dir, 0);
- }
- strbuf_reset(&a_src_dir);
- }
-
- strbuf_release(&a_src_dir);
- free(src_dir);
+ remove_empty_src_dirs(src_dir.v, src_dir.nr);
if (dirty_paths.nr)
advise_on_moving_dirty_path(&dirty_paths);
if (gitmodules_modified)
- stage_updated_gitmodules(&the_index);
+ stage_updated_gitmodules(the_repository->index);
- if (write_locked_index(&the_index, &lock_file,
+ if (write_locked_index(the_repository->index, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
+ ret = 0;
+
+out:
+ strvec_clear(&src_dir);
+ free(dst_w_slash);
string_list_clear(&src_for_dst, 0);
string_list_clear(&dirty_paths, 0);
- UNLEAK(source);
- UNLEAK(dest_path);
- free(submodule_gitfile);
+ string_list_clear(&only_match_skip_worktree, 0);
+ strvec_clear(&sources);
+ strvec_clear(&dest_paths);
+ strvec_clear(&destinations);
+ strvec_clear(&submodule_gitfiles_to_free);
+ free(submodule_gitfiles);
free(modes);
- return 0;
+ return ret;
}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index ad9930c..70e9ec4 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -296,7 +296,8 @@
char *short_refname = NULL;
if (shorten_unambiguous)
- short_refname = shorten_unambiguous_ref(refname, 0);
+ short_refname = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ refname, 0);
else if (skip_prefix(refname, "refs/heads/", &refname))
; /* refname already advanced */
else
@@ -647,7 +648,7 @@
adjust_cutoff_timestamp_for_slop();
- for_each_ref(name_ref, &data);
+ refs_for_each_ref(get_main_ref_store(the_repository), name_ref, &data);
name_tips(&string_pool);
if (annotate_stdin) {
diff --git a/builtin/notes.c b/builtin/notes.c
index cb01130..7f80b34 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -794,9 +794,9 @@
* notes_merge_abort() to remove .git/NOTES_MERGE_WORKTREE.
*/
- if (delete_ref(NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
- if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
ret += error(_("failed to delete ref NOTES_MERGE_REF"));
if (notes_merge_abort(o))
ret += error(_("failed to remove 'git notes merge' worktree"));
@@ -834,7 +834,8 @@
init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
o->local_ref = local_ref_to_free =
- resolve_refdup("NOTES_MERGE_REF", 0, &oid, NULL);
+ refs_resolve_refdup(get_main_ref_store(the_repository),
+ "NOTES_MERGE_REF", 0, &oid, NULL);
if (!o->local_ref)
die(_("failed to resolve NOTES_MERGE_REF"));
@@ -847,9 +848,10 @@
&pretty_ctx);
strbuf_trim(&msg);
strbuf_insertstr(&msg, 0, "notes: ");
- update_ref(msg.buf, o->local_ref, &oid,
- is_null_oid(&parent_oid) ? NULL : &parent_oid,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ o->local_ref, &oid,
+ is_null_oid(&parent_oid) ? NULL : &parent_oid,
+ 0, UPDATE_REFS_DIE_ON_ERR);
free_notes(t);
strbuf_release(&msg);
@@ -961,14 +963,16 @@
if (result >= 0) /* Merge resulted (trivially) in result_oid */
/* Update default notes ref with new commit */
- update_ref(msg.buf, default_notes_ref(), &result_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ default_notes_ref(), &result_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else { /* Merge has unresolved conflicts */
struct worktree **worktrees;
const struct worktree *wt;
/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
- update_ref(msg.buf, "NOTES_MERGE_PARTIAL", &result_oid, NULL,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ "NOTES_MERGE_PARTIAL", &result_oid, NULL,
+ 0, UPDATE_REFS_DIE_ON_ERR);
/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
worktrees = get_worktrees();
wt = find_shared_symref(worktrees, "NOTES_MERGE_REF",
@@ -977,7 +981,7 @@
die(_("a notes merge into %s is already in-progress at %s"),
default_notes_ref(), wt->path);
free_worktrees(worktrees);
- if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
+ if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", default_notes_ref(), NULL))
die(_("failed to store link to current notes ref (%s)"),
default_notes_ref());
fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s "
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index baf0090..dd97fdd 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -779,7 +779,7 @@
if (entry)
entry->tagged = 1;
- if (!peel_iterated_oid(oid, &peeled)) {
+ if (!peel_iterated_oid(the_repository, oid, &peeled)) {
entry = packlist_find(&to_pack, &peeled);
if (entry)
entry->tagged = 1;
@@ -939,7 +939,8 @@
/*
* Mark objects that are at the tip of tags.
*/
- for_each_tag_ref(mark_tagged, NULL);
+ refs_for_each_tag_ref(get_main_ref_store(the_repository), mark_tagged,
+ NULL);
if (use_delta_islands) {
max_layers = compute_pack_layers(&to_pack);
@@ -1314,6 +1315,7 @@
if (!pack_to_stdout) {
struct stat st;
struct strbuf tmpname = STRBUF_INIT;
+ struct bitmap_writer bitmap_writer;
char *idx_tmp_name = NULL;
/*
@@ -1339,8 +1341,10 @@
hash_to_hex(hash));
if (write_bitmap_index) {
- bitmap_writer_set_checksum(hash);
- bitmap_writer_build_type_index(
+ bitmap_writer_init(&bitmap_writer,
+ the_repository);
+ bitmap_writer_set_checksum(&bitmap_writer, hash);
+ bitmap_writer_build_type_index(&bitmap_writer,
&to_pack, written_list, nr_written);
}
@@ -1358,12 +1362,17 @@
strbuf_addstr(&tmpname, "bitmap");
stop_progress(&progress_state);
- bitmap_writer_show_progress(progress);
- bitmap_writer_select_commits(indexed_commits, indexed_commits_nr, -1);
- if (bitmap_writer_build(&to_pack) < 0)
+ bitmap_writer_show_progress(&bitmap_writer,
+ progress);
+ bitmap_writer_select_commits(&bitmap_writer,
+ indexed_commits,
+ indexed_commits_nr);
+ if (bitmap_writer_build(&bitmap_writer, &to_pack) < 0)
die(_("failed to write bitmap index"));
- bitmap_writer_finish(written_list, nr_written,
+ bitmap_writer_finish(&bitmap_writer,
+ written_list, nr_written,
tmpname.buf, write_bitmap_options);
+ bitmap_writer_free(&bitmap_writer);
write_bitmap_index = 0;
strbuf_setlen(&tmpname, tmpname_len);
}
@@ -3124,7 +3133,7 @@
{
struct object_id peeled;
- if (!peel_iterated_oid(oid, &peeled) && obj_is_packed(&peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled) && obj_is_packed(&peeled))
add_tag_chain(oid);
return 0;
}
@@ -4073,7 +4082,7 @@
struct object_id peeled;
struct object *object;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
object = parse_object_or_die(oid, refname);
@@ -4093,7 +4102,9 @@
return;
for_each_string_list_item(item, preferred_tips) {
- for_each_ref_in(item->string, mark_bitmap_preferred_tip, NULL);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ item->string, mark_bitmap_preferred_tip,
+ NULL);
}
}
@@ -4588,7 +4599,8 @@
}
cleanup_preferred_base();
if (include_tag && nr_result)
- for_each_tag_ref(add_ref_tag, NULL);
+ refs_for_each_tag_ref(get_main_ref_store(the_repository),
+ add_ref_tag, NULL);
stop_progress(&progress_state);
trace2_region_leave("pack-objects", "enumerate-objects",
the_repository);
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b..583099c 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -5,6 +5,7 @@
#include "hash.h"
#include "hex.h"
#include "parse-options.h"
+#include "setup.h"
static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
{
@@ -237,6 +238,18 @@
argc = parse_options(argc, argv, prefix, builtin_patch_id_options,
patch_id_usage, 0);
+ /*
+ * We rely on `the_hash_algo` to compute patch IDs. This is dubious as
+ * it means that the hash algorithm now depends on the object hash of
+ * the repository, even though git-patch-id(1) clearly defines that
+ * patch IDs always use SHA1.
+ *
+ * NEEDSWORK: This hack should be removed in favor of converting
+ * the code that computes patch IDs to always use SHA1.
+ */
+ if (!the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
generate_id_list(opts ? opts > 1 : config.stable,
opts ? opts == 3 : config.verbatim);
return 0;
diff --git a/builtin/pull.c b/builtin/pull.c
index 72cbb76..2d0429f 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -5,7 +5,7 @@
*
* Fetch one or more remote refs and merge it/them into the current HEAD.
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -71,48 +71,48 @@
/* Shared options */
static int opt_verbosity;
-static char *opt_progress;
+static const char *opt_progress;
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
/* Options passed to git-merge or git-rebase */
static enum rebase_type opt_rebase = -1;
-static char *opt_diffstat;
-static char *opt_log;
-static char *opt_signoff;
-static char *opt_squash;
-static char *opt_commit;
-static char *opt_edit;
-static char *cleanup_arg;
-static char *opt_ff;
-static char *opt_verify_signatures;
-static char *opt_verify;
+static const char *opt_diffstat;
+static const char *opt_log;
+static const char *opt_signoff;
+static const char *opt_squash;
+static const char *opt_commit;
+static const char *opt_edit;
+static const char *cleanup_arg;
+static const char *opt_ff;
+static const char *opt_verify_signatures;
+static const char *opt_verify;
static int opt_autostash = -1;
static int config_autostash;
static int check_trust_level = 1;
static struct strvec opt_strategies = STRVEC_INIT;
static struct strvec opt_strategy_opts = STRVEC_INIT;
-static char *opt_gpg_sign;
+static const char *opt_gpg_sign;
static int opt_allow_unrelated_histories;
/* Options passed to git-fetch */
-static char *opt_all;
-static char *opt_append;
-static char *opt_upload_pack;
+static const char *opt_all;
+static const char *opt_append;
+static const char *opt_upload_pack;
static int opt_force;
-static char *opt_tags;
-static char *opt_prune;
-static char *max_children;
+static const char *opt_tags;
+static const char *opt_prune;
+static const char *max_children;
static int opt_dry_run;
-static char *opt_keep;
-static char *opt_depth;
-static char *opt_unshallow;
-static char *opt_update_shallow;
-static char *opt_refmap;
-static char *opt_ipv4;
-static char *opt_ipv6;
+static const char *opt_keep;
+static const char *opt_depth;
+static const char *opt_unshallow;
+static const char *opt_update_shallow;
+static const char *opt_refmap;
+static const char *opt_ipv4;
+static const char *opt_ipv6;
static int opt_show_forced_updates = -1;
-static char *set_upstream;
+static const char *set_upstream;
static struct strvec opt_fetch = STRVEC_INIT;
static struct option pull_options[] = {
@@ -611,7 +611,7 @@
merge_head, 0))
return 1;
- if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+ if (refs_update_ref(get_main_ref_store(the_repository), "initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
return 1;
return 0;
@@ -1044,7 +1044,7 @@
if (opt_autostash == -1)
opt_autostash = config_autostash;
- if (is_null_oid(&orig_head) && !is_index_unborn(&the_index))
+ if (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))
die(_("Updating an unborn branch with changes added to the index."));
if (!opt_autostash)
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 6f89cec..a8cf850 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -4,7 +4,6 @@
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -159,8 +158,8 @@
memset(&opts, 0, sizeof(opts));
opts.head_idx = -1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
git_config(git_read_tree_config, NULL);
@@ -197,7 +196,7 @@
die(_("You need to resolve your current index first"));
stage = opts.merge = 1;
}
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
@@ -225,7 +224,7 @@
setup_work_tree();
if (opts.skip_sparse_checkout)
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
if (opts.merge) {
switch (stage - 1) {
@@ -237,7 +236,7 @@
break;
case 2:
opts.fn = twoway_merge;
- opts.initial_checkout = is_index_unborn(&the_index);
+ opts.initial_checkout = is_index_unborn(the_repository->index);
break;
case 3:
default:
@@ -258,7 +257,7 @@
if (nr_trees == 1 && !opts.prefix)
opts.skip_cache_tree_update = 1;
- cache_tree_free(&the_index.cache_tree);
+ cache_tree_free(&the_repository->index->cache_tree);
for (i = 0; i < nr_trees; i++) {
struct tree *tree = trees[i];
if (parse_tree(tree) < 0)
@@ -282,7 +281,7 @@
the_repository->index,
trees[0]);
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die("unable to write new index file");
return 0;
}
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 891f284..e3a8e74 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -4,7 +4,6 @@
* Copyright (c) 2018 Pratik Karki
*/
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "environment.h"
@@ -84,7 +83,7 @@
struct rebase_options {
enum rebase_type type;
enum empty_type empty;
- const char *default_backend;
+ char *default_backend;
const char *state_dir;
struct commit *upstream;
const char *upstream_name;
@@ -136,7 +135,7 @@
.type = REBASE_UNSPECIFIED, \
.empty = EMPTY_UNSPECIFIED, \
.keep_empty = 1, \
- .default_backend = "merge", \
+ .default_backend = xstrdup("merge"), \
.flags = REBASE_NO_QUIET, \
.git_am_opts = STRVEC_INIT, \
.exec = STRING_LIST_INIT_NODUP, \
@@ -152,6 +151,19 @@
.strategy_opts = STRING_LIST_INIT_NODUP,\
}
+static void rebase_options_release(struct rebase_options *opts)
+{
+ free(opts->default_backend);
+ free(opts->reflog_action);
+ free(opts->head_name);
+ strvec_clear(&opts->git_am_opts);
+ free(opts->gpg_sign_opt);
+ string_list_clear(&opts->exec, 0);
+ free(opts->strategy);
+ string_list_clear(&opts->strategy_opts, 0);
+ strbuf_release(&opts->git_format_patch_opt);
+}
+
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
{
struct replay_opts replay = REPLAY_OPTS_INIT;
@@ -194,7 +206,7 @@
return replay;
}
-static int edit_todo_file(unsigned flags)
+static int edit_todo_file(unsigned flags, struct replay_opts *opts)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT,
@@ -205,7 +217,8 @@
return error_errno(_("could not read '%s'."), todo_file);
strbuf_stripspace(&todo_list.buf, comment_line_str);
- res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);
+ res = edit_todo_list(the_repository, opts, &todo_list, &new_todo,
+ NULL, NULL, flags);
if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,
NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))
res = error_errno(_("could not write '%s'"), todo_file);
@@ -252,7 +265,7 @@
if (!is_directory(merge_dir()) && mkdir_in_gitdir(merge_dir()))
return error_errno(_("could not create temporary %s"), merge_dir());
- delete_reflog("REBASE_HEAD");
+ refs_delete_reflog(get_main_ref_store(the_repository), "REBASE_HEAD");
interactive = fopen(path_interactive(), "w");
if (!interactive)
@@ -295,9 +308,9 @@
if (ret)
error(_("could not generate todo list"));
else {
- discard_index(&the_index);
- if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,
- &todo_list))
+ discard_index(the_repository->index);
+ if (todo_list_parse_insn_buffer(the_repository, &replay,
+ todo_list.buf.buf, &todo_list))
BUG("unusable todo list");
ret = complete_action(the_repository, &replay, flags,
@@ -352,9 +365,13 @@
replay_opts_release(&replay_opts);
break;
}
- case ACTION_EDIT_TODO:
- ret = edit_todo_file(flags);
+ case ACTION_EDIT_TODO: {
+ struct replay_opts replay_opts = get_replay_opts(opts);
+
+ ret = edit_todo_file(flags, &replay_opts);
+ replay_opts_release(&replay_opts);
break;
+ }
case ACTION_SHOW_CURRENT_PATCH: {
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -514,8 +531,10 @@
struct strbuf dir = STRBUF_INIT;
int ret = 0;
- delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
- delete_ref(NULL, "AUTO_MERGE", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "REBASE_HEAD", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "AUTO_MERGE", NULL, REF_NO_DEREF);
apply_autostash(state_dir_path("autostash", opts));
/*
* We ignore errors in 'git maintenance run --auto', since the
@@ -795,6 +814,7 @@
}
if (!strcmp(var, "rebase.backend")) {
+ FREE_AND_NULL(opts->default_backend);
return git_config_string(&opts->default_backend, var, value);
}
@@ -1046,6 +1066,7 @@
{
struct rebase_options options = REBASE_OPTIONS_INIT;
const char *branch_name;
+ const char *strategy_opt = NULL;
int ret, flags, total_argc, in_progress = 0;
int keep_base = 0;
int ok_to_skip_pre_rebase = 0;
@@ -1160,7 +1181,7 @@
PARSE_OPT_OPTARG, parse_opt_rebase_merges),
OPT_BOOL(0, "fork-point", &options.fork_point,
N_("use 'merge-base --fork-point' to refine upstream")),
- OPT_STRING('s', "strategy", &options.strategy,
+ OPT_STRING('s', "strategy", &strategy_opt,
N_("strategy"), N_("use the given merge strategy")),
OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts,
N_("option"),
@@ -1469,13 +1490,12 @@
}
}
- if (options.strategy_opts.nr && !options.strategy)
- options.strategy = "ort";
-
- if (options.strategy) {
- options.strategy = xstrdup(options.strategy);
+ if (strategy_opt)
+ options.strategy = xstrdup(strategy_opt);
+ else if (options.strategy_opts.nr && !options.strategy)
+ options.strategy = xstrdup("ort");
+ if (options.strategy)
imply_merge(&options, "--strategy");
- }
if (options.root && !options.onto_name)
imply_merge(&options, "--root without --onto");
@@ -1623,7 +1643,7 @@
/* Is it a local branch? */
strbuf_reset(&buf);
strbuf_addf(&buf, "refs/heads/%s", branch_name);
- if (!read_ref(buf.buf, &branch_oid)) {
+ if (!refs_read_ref(get_main_ref_store(the_repository), buf.buf, &branch_oid)) {
die_if_checked_out(buf.buf, 1);
options.head_name = xstrdup(buf.buf);
options.orig_head =
@@ -1640,8 +1660,8 @@
} else if (argc == 0) {
/* Do not need to switch branches, we are already on it. */
options.head_name =
- xstrdup_or_null(resolve_ref_unsafe("HEAD", 0, NULL,
- &flags));
+ xstrdup_or_null(refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL,
+ &flags));
if (!options.head_name)
die(_("No such ref: %s"), "HEAD");
if (flags & REF_ISSYMREF) {
@@ -1735,7 +1755,7 @@
if (!(options.flags & REBASE_NO_QUIET))
; /* be quiet */
else if (!strcmp(branch_name, "HEAD") &&
- resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+ refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag))
puts(_("HEAD is up to date."));
else
printf(_("Current branch %s is up to date.\n"),
@@ -1745,7 +1765,7 @@
} else if (!(options.flags & REBASE_NO_QUIET))
; /* be quiet */
else if (!strcmp(branch_name, "HEAD") &&
- resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+ refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag))
puts(_("HEAD is up to date, rebase forced."));
else
printf(_("Current branch %s is up to date, rebase "
@@ -1832,14 +1852,7 @@
cleanup:
strbuf_release(&buf);
strbuf_release(&revisions);
- free(options.reflog_action);
- free(options.head_name);
- strvec_clear(&options.git_am_opts);
- free(options.gpg_sign_opt);
- string_list_clear(&options.exec, 0);
- free(options.strategy);
- string_list_clear(&options.strategy_opts, 0);
- strbuf_release(&options.git_format_patch_opt);
+ rebase_options_release(&options);
free(squash_onto_name);
free(keep_base_onto_name);
return !!ret;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index e8d7df1..f67f37f 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -88,7 +88,7 @@
static struct object_id push_cert_oid;
static struct signature_check sigcheck;
static const char *push_cert_nonce;
-static const char *cert_nonce_seed;
+static char *cert_nonce_seed;
static struct strvec hidden_refs = STRVEC_INIT;
static const char *NONCE_UNSOLICITED = "UNSOLICITED";
@@ -168,13 +168,13 @@
}
if (strcmp(var, "receive.fsck.skiplist") == 0) {
- const char *path;
+ char *path;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
fsck_msg_types.len ? ',' : '=', path);
- free((char *)path);
+ free(path);
return 0;
}
@@ -1249,7 +1249,7 @@
return code;
}
-static char *refuse_unconfigured_deny_msg =
+static const char *refuse_unconfigured_deny_msg =
N_("By default, updating the current branch in a non-bare repository\n"
"is denied, because it will make the index and work tree inconsistent\n"
"with what you pushed, and will require 'git reset --hard' to match\n"
@@ -1269,7 +1269,7 @@
rp_error("%s", _(refuse_unconfigured_deny_msg));
}
-static char *refuse_unconfigured_deny_delete_current_msg =
+static const char *refuse_unconfigured_deny_delete_current_msg =
N_("By default, deleting the current branch is denied, because the next\n"
"'git clone' won't result in any file checked out, causing confusion.\n"
"\n"
@@ -1566,7 +1566,7 @@
struct strbuf err = STRBUF_INIT;
if (!parse_object(the_repository, old_oid)) {
old_oid = NULL;
- if (ref_exists(name)) {
+ if (refs_ref_exists(get_main_ref_store(the_repository), name)) {
rp_warning("allowing deletion of corrupt ref");
} else {
rp_warning("deleting a non-existent ref");
@@ -1576,7 +1576,8 @@
if (ref_transaction_delete(transaction,
namespaced_name,
old_oid,
- 0, "push", &err)) {
+ NULL, 0,
+ "push", &err)) {
rp_error("%s", err.buf);
ret = "failed to delete";
} else {
@@ -1595,6 +1596,7 @@
if (ref_transaction_update(transaction,
namespaced_name,
new_oid, old_oid,
+ NULL, NULL,
0, "push",
&err)) {
rp_error("%s", err.buf);
@@ -1693,7 +1695,8 @@
int flag;
strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
- dst_name = resolve_ref_unsafe(buf.buf, 0, NULL, &flag);
+ dst_name = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ buf.buf, 0, NULL, &flag);
check_aliased_update_internal(cmd, list, dst_name, flag);
strbuf_release(&buf);
}
@@ -1829,7 +1832,8 @@
if (!should_process_cmd(cmd) || cmd->run_proc_receive)
continue;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction) {
rp_error("%s", err.buf);
strbuf_reset(&err);
@@ -1857,7 +1861,8 @@
struct strbuf err = STRBUF_INIT;
const char *reported_error = "atomic push failure";
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction) {
rp_error("%s", err.buf);
strbuf_reset(&err);
@@ -1983,7 +1988,9 @@
check_aliased_updates(commands);
free(head_name_to_free);
- head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL);
+ head_name = head_name_to_free = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL,
+ NULL);
if (run_proc_receive &&
run_proc_receive_hook(commands, push_options))
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 060eb33..0d2ff95 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -364,11 +364,12 @@
};
set_reflog_expiry_param(&cb.cmd, item->string);
- status |= reflog_expire(item->string, flags,
- reflog_expiry_prepare,
- should_prune_fn,
- reflog_expiry_cleanup,
- &cb);
+ status |= refs_reflog_expire(get_main_ref_store(the_repository),
+ item->string, flags,
+ reflog_expiry_prepare,
+ should_prune_fn,
+ reflog_expiry_cleanup,
+ &cb);
}
string_list_clear(&collected.reflogs, 0);
}
@@ -377,16 +378,17 @@
char *ref;
struct expire_reflog_policy_cb cb = { .cmd = cmd };
- if (!dwim_log(argv[i], strlen(argv[i]), NULL, &ref)) {
+ if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {
status |= error(_("%s points nowhere!"), argv[i]);
continue;
}
set_reflog_expiry_param(&cb.cmd, ref);
- status |= reflog_expire(ref, flags,
- reflog_expiry_prepare,
- should_prune_fn,
- reflog_expiry_cleanup,
- &cb);
+ status |= refs_reflog_expire(get_main_ref_store(the_repository),
+ ref, flags,
+ reflog_expiry_prepare,
+ should_prune_fn,
+ reflog_expiry_cleanup,
+ &cb);
free(ref);
}
return status;
@@ -437,7 +439,8 @@
refname = argv[0];
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
die(_("invalid ref format: %s"), refname);
- return !reflog_exists(refname);
+ return !refs_reflog_exists(get_main_ref_store(the_repository),
+ refname);
}
/*
diff --git a/builtin/refs.c b/builtin/refs.c
new file mode 100644
index 0000000..46dcd15
--- /dev/null
+++ b/builtin/refs.c
@@ -0,0 +1,75 @@
+#include "builtin.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "repository.h"
+#include "strbuf.h"
+
+#define REFS_MIGRATE_USAGE \
+ N_("git refs migrate --ref-format=<format> [--dry-run]")
+
+static int cmd_refs_migrate(int argc, const char **argv, const char *prefix)
+{
+ const char * const migrate_usage[] = {
+ REFS_MIGRATE_USAGE,
+ NULL,
+ };
+ const char *format_str = NULL;
+ enum ref_storage_format format;
+ unsigned int flags = 0;
+ struct option options[] = {
+ OPT_STRING_F(0, "ref-format", &format_str, N_("format"),
+ N_("specify the reference format to convert to"),
+ PARSE_OPT_NONEG),
+ OPT_BIT(0, "dry-run", &flags,
+ N_("perform a non-destructive dry-run"),
+ REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN),
+ OPT_END(),
+ };
+ struct strbuf errbuf = STRBUF_INIT;
+ int err;
+
+ argc = parse_options(argc, argv, prefix, options, migrate_usage, 0);
+ if (argc)
+ usage(_("too many arguments"));
+ if (!format_str)
+ usage(_("missing --ref-format=<format>"));
+
+ format = ref_storage_format_by_name(format_str);
+ if (format == REF_STORAGE_FORMAT_UNKNOWN) {
+ err = error(_("unknown ref storage format '%s'"), format_str);
+ goto out;
+ }
+
+ if (the_repository->ref_storage_format == format) {
+ err = error(_("repository already uses '%s' format"),
+ ref_storage_format_to_name(format));
+ goto out;
+ }
+
+ if (repo_migrate_ref_storage_format(the_repository, format, flags, &errbuf) < 0) {
+ err = error("%s", errbuf.buf);
+ goto out;
+ }
+
+ err = 0;
+
+out:
+ strbuf_release(&errbuf);
+ return err;
+}
+
+int cmd_refs(int argc, const char **argv, const char *prefix)
+{
+ const char * const refs_usage[] = {
+ REFS_MIGRATE_USAGE,
+ NULL,
+ };
+ parse_opt_subcommand_fn *fn = NULL;
+ struct option opts[] = {
+ OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, opts, refs_usage, 0);
+ return fn(argc, argv, prefix);
+}
diff --git a/builtin/remote.c b/builtin/remote.c
index 8412d12..8230f33 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -240,7 +240,7 @@
strbuf_reset(&buf2);
strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
- if (create_symref(buf.buf, buf2.buf, "remote add"))
+ if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
return error(_("Could not setup master '%s'"), master);
}
@@ -376,7 +376,7 @@
for (ref = fetch_map; ref; ref = ref->next) {
if (omit_name_by_refspec(ref->name, &states->remote->fetch))
string_list_append(&states->skipped, abbrev_branch(ref->name));
- else if (!ref->peer_ref || !ref_exists(ref->peer_ref->name))
+ else if (!ref->peer_ref || !refs_ref_exists(get_main_ref_store(the_repository), ref->peer_ref->name))
string_list_append(&states->new_refs, abbrev_branch(ref->name));
else
string_list_append(&states->tracked, abbrev_branch(ref->name));
@@ -493,12 +493,13 @@
{
struct ref *ref, *matches;
struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
- struct refspec_item refspec;
+ struct refspec_item refspec = {
+ .force = 0,
+ .pattern = 1,
+ .src = (char *) "refs/heads/*",
+ .dst = (char *) "refs/heads/*",
+ };
- memset(&refspec, 0, sizeof(refspec));
- refspec.force = 0;
- refspec.pattern = 1;
- refspec.src = refspec.dst = "refs/heads/*";
get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
fetch_map, 1);
@@ -507,7 +508,6 @@
free_refs(fetch_map);
free_refs(matches);
-
return 0;
}
@@ -598,8 +598,9 @@
strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
if (starts_with(refname, buf.buf)) {
item = string_list_append(rename->remote_branches, refname);
- symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
- NULL, &flag);
+ symref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ refname, RESOLVE_REF_READING,
+ NULL, &flag);
if (symref && (flag & REF_ISSYMREF)) {
item->util = xstrdup(symref);
rename->symrefs_nr++;
@@ -789,7 +790,8 @@
* First remove symrefs, then rename the rest, finally create
* the new symrefs.
*/
- for_each_ref(read_remote_branches, &rename);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ read_remote_branches, &rename);
if (show_progress) {
/*
* Count symrefs twice, since "renaming" them is done by
@@ -805,7 +807,7 @@
if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
&referent))
continue;
- if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, item->string, NULL, REF_NO_DEREF))
die(_("deleting '%s' failed"), item->string);
strbuf_release(&referent);
@@ -823,7 +825,7 @@
strbuf_reset(&buf2);
strbuf_addf(&buf2, "remote: renamed %s to %s",
item->string, buf.buf);
- if (rename_ref(item->string, buf.buf, buf2.buf))
+ if (refs_rename_ref(get_main_ref_store(the_repository), item->string, buf.buf, buf2.buf))
die(_("renaming '%s' failed"), item->string);
display_progress(progress, ++refs_renamed_nr);
}
@@ -843,7 +845,7 @@
strbuf_reset(&buf3);
strbuf_addf(&buf3, "remote: renamed %s to %s",
item->string, buf.buf);
- if (create_symref(buf.buf, buf2.buf, buf3.buf))
+ if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
die(_("creating '%s' failed"), buf.buf);
display_progress(progress, ++refs_renamed_nr);
}
@@ -917,11 +919,14 @@
* refs, which are invalidated when deleting a branch.
*/
cb_data.remote = remote;
- result = for_each_ref(add_branch_for_removal, &cb_data);
+ result = refs_for_each_ref(get_main_ref_store(the_repository),
+ add_branch_for_removal, &cb_data);
strbuf_release(&buf);
if (!result)
- result = delete_refs("remote: remove", &branches, REF_NO_DEREF);
+ result = refs_delete_refs(get_main_ref_store(the_repository),
+ "remote: remove", &branches,
+ REF_NO_DEREF);
string_list_clear(&branches, 0);
if (skipped.nr) {
@@ -1010,7 +1015,8 @@
get_push_ref_states(remote_refs, states);
transport_disconnect(transport);
} else {
- for_each_ref(append_ref_to_tracked_list, states);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_ref_to_tracked_list, states);
string_list_sort(&states->tracked);
get_push_ref_states_noquery(states);
}
@@ -1407,7 +1413,7 @@
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
- if (delete_ref(NULL, buf.buf, NULL, REF_NO_DEREF))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, buf.buf, NULL, REF_NO_DEREF))
result |= error(_("Could not delete %s"), buf.buf);
} else
usage_with_options(builtin_remote_sethead_usage, options);
@@ -1415,9 +1421,9 @@
if (head_name) {
strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
/* make sure it's valid */
- if (!ref_exists(buf2.buf))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf))
result |= error(_("Not a valid ref: %s"), buf2.buf);
- else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
+ else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head"))
result |= error(_("Could not setup %s"), buf.buf);
else if (opt_a)
printf("%s/HEAD set to %s\n", argv[0], head_name);
@@ -1457,7 +1463,8 @@
string_list_sort(&refs_to_prune);
if (!dry_run)
- result |= delete_refs("remote: prune", &refs_to_prune, 0);
+ result |= refs_delete_refs(get_main_ref_store(the_repository),
+ "remote: prune", &refs_to_prune, 0);
for_each_string_list_item(item, &states.stale) {
const char *refname = item->util;
@@ -1470,7 +1477,8 @@
abbrev_ref(refname, "refs/remotes/"));
}
- warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);
+ refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
+ stdout, dangling_msg, &refs_to_prune);
string_list_clear(&refs_to_prune, 0);
free_remote_ref_states(&states);
diff --git a/builtin/repack.c b/builtin/repack.c
index 15e4ccc..f0317fa 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -48,10 +48,10 @@
);
struct pack_objects_args {
- const char *window;
- const char *window_memory;
- const char *depth;
- const char *threads;
+ char *window;
+ char *window_memory;
+ char *depth;
+ char *threads;
unsigned long max_pack_size;
int no_reuse_delta;
int no_reuse_object;
@@ -673,7 +673,7 @@
struct midx_snapshot_ref_data *data = _data;
struct object_id peeled;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oidset_insert(&data->seen, oid))
@@ -706,11 +706,14 @@
data.preferred = 1;
for_each_string_list_item(item, preferred)
- for_each_ref_in(item->string, midx_snapshot_ref_one, &data);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ item->string,
+ midx_snapshot_ref_one, &data);
data.preferred = 0;
}
- for_each_ref(midx_snapshot_ref_one, &data);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ midx_snapshot_ref_one, &data);
if (close_tempfile_gently(f)) {
int save_errno = errno;
diff --git a/builtin/replace.c b/builtin/replace.c
index da59600..ce9f697 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -43,11 +43,12 @@
};
struct show_data {
+ struct repository *repo;
const char *pattern;
enum replace_format format;
};
-static int show_reference(struct repository *r, const char *refname,
+static int show_reference(const char *refname,
const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
@@ -62,11 +63,11 @@
struct object_id object;
enum object_type obj_type, repl_type;
- if (repo_get_oid(r, refname, &object))
+ if (repo_get_oid(data->repo, refname, &object))
return error(_("failed to resolve '%s' as a valid ref"), refname);
- obj_type = oid_object_info(r, &object, NULL);
- repl_type = oid_object_info(r, oid, NULL);
+ obj_type = oid_object_info(data->repo, &object, NULL);
+ repl_type = oid_object_info(data->repo, oid, NULL);
printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
oid_to_hex(oid), type_name(repl_type));
@@ -80,6 +81,7 @@
{
struct show_data data;
+ data.repo = the_repository;
if (!pattern)
pattern = "*";
data.pattern = pattern;
@@ -99,7 +101,8 @@
"valid formats are 'short', 'medium' and 'long'"),
format);
- for_each_replace_ref(the_repository, show_reference, (void *)&data);
+ refs_for_each_replace_ref(get_main_ref_store(the_repository),
+ show_reference, (void *)&data);
return 0;
}
@@ -130,7 +133,7 @@
strbuf_addstr(&ref, oid_to_hex(&oid));
full_hex = ref.buf + base_len;
- if (read_ref(ref.buf, &oid)) {
+ if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &oid)) {
error(_("replace ref '%s' not found"), full_hex);
had_error = 1;
continue;
@@ -145,7 +148,7 @@
static int delete_replace_ref(const char *name, const char *ref,
const struct object_id *oid)
{
- if (delete_ref(NULL, ref, oid, 0))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, ref, oid, 0))
return 1;
printf_ln(_("Deleted replace ref '%s'"), name);
return 0;
@@ -163,7 +166,7 @@
if (check_refname_format(ref->buf, 0))
return error(_("'%s' is not a valid ref name"), ref->buf);
- if (read_ref(ref->buf, prev))
+ if (refs_read_ref(get_main_ref_store(the_repository), ref->buf, prev))
oidclr(prev);
else if (!force)
return error(_("replace ref '%s' already exists"), ref->buf);
@@ -198,10 +201,11 @@
return -1;
}
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, repl, &prev,
- 0, NULL, &err) ||
+ NULL, NULL, 0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
res = error("%s", err.buf);
diff --git a/builtin/replay.c b/builtin/replay.c
index 6bc4b47..6bf0691 100644
--- a/builtin/replay.c
+++ b/builtin/replay.c
@@ -2,7 +2,6 @@
* "git replay" builtin command
*/
-#define USE_THE_INDEX_VARIABLE
#include "git-compat-util.h"
#include "builtin.h"
diff --git a/builtin/reset.c b/builtin/reset.c
index 1d62ff6..5f941fb 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -7,7 +7,7 @@
*
* Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -66,8 +66,8 @@
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.fn = oneway_merge;
opts.merge = 1;
init_checkout_metadata(&opts.meta, ref, oid, NULL);
@@ -159,11 +159,11 @@
struct cache_entry *ce;
if (!is_in_reset_tree && !intent_to_add) {
- remove_file_from_index(&the_index, one->path);
+ remove_file_from_index(the_repository->index, one->path);
continue;
}
- ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
+ ce = make_cache_entry(the_repository->index, one->mode, &one->oid, one->path,
0, 0);
/*
@@ -174,9 +174,9 @@
* if this entry is outside the sparse cone - this is necessary
* to properly construct the reset sparse directory.
*/
- pos = index_name_pos(&the_index, one->path, strlen(one->path));
- if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
- (pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))
+ pos = index_name_pos(the_repository->index, one->path, strlen(one->path));
+ if ((pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) ||
+ (pos < 0 && !path_in_sparse_checkout(one->path, the_repository->index)))
ce->ce_flags |= CE_SKIP_WORKTREE;
if (!ce)
@@ -186,7 +186,7 @@
ce->ce_flags |= CE_INTENT_TO_ADD;
set_object_name_for_intent_to_add_entry(ce);
}
- add_index_entry(&the_index, ce,
+ add_index_entry(the_repository->index, ce,
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
}
@@ -208,8 +208,8 @@
opt.change = diff_change;
opt.add_remove = diff_addremove;
- if (pathspec->nr && pathspec_needs_expanded_index(&the_index, pathspec))
- ensure_full_index(&the_index);
+ if (pathspec->nr && pathspec_needs_expanded_index(the_repository->index, pathspec))
+ ensure_full_index(the_repository->index);
if (do_diff_cache(tree_oid, &opt))
return 1;
@@ -235,7 +235,7 @@
static void die_if_unmerged_cache(int reset_type)
{
- if (is_merge() || unmerged_index(&the_index))
+ if (is_merge() || unmerged_index(the_repository->index))
die(_("Cannot do a %s reset in the middle of a merge."),
_(reset_type_names[reset_type]));
@@ -307,13 +307,16 @@
if (!repo_get_oid(the_repository, "HEAD", &oid_orig)) {
orig = &oid_orig;
set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
- update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
- UPDATE_REFS_MSG_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ "ORIG_HEAD", orig, old_orig, 0,
+ UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
- delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "ORIG_HEAD", old_orig, 0);
set_reflog_message(&msg, "updating HEAD", rev);
- update_ref_status = update_ref(msg.buf, "HEAD", oid, orig, 0,
- UPDATE_REFS_MSG_ON_ERR);
+ update_ref_status = refs_update_ref(get_main_ref_store(the_repository),
+ msg.buf, "HEAD", oid, orig, 0,
+ UPDATE_REFS_MSG_ON_ERR);
strbuf_release(&msg);
return update_ref_status;
}
@@ -470,12 +473,12 @@
update_ref_status = 1;
goto cleanup;
}
- the_index.updated_skipworktree = 1;
+ the_repository->index->updated_skipworktree = 1;
if (!no_refresh && get_git_work_tree()) {
uint64_t t_begin, t_delta_in_ms;
t_begin = getnanotime();
- refresh_index(&the_index, flags, NULL, NULL,
+ refresh_index(the_repository->index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
if (!quiet && advice_enabled(ADVICE_RESET_NO_REFRESH_WARNING) && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
@@ -501,7 +504,7 @@
free(ref);
}
- if (write_locked_index(&the_index, &lock, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK))
die(_("Could not write new index file."));
}
@@ -516,7 +519,7 @@
if (!pathspec.nr)
remove_branch_state(the_repository, 0);
- discard_index(&the_index);
+ discard_index(the_repository->index);
cleanup:
clear_pathspec(&pathspec);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 624182e..1e2919f 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "abspath.h"
#include "config.h"
@@ -160,8 +160,9 @@
case 1: /* happy */
if (abbrev_ref) {
char *old = full;
- full = shorten_unambiguous_ref(full,
- abbrev_ref_strict);
+ full = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ full,
+ abbrev_ref_strict);
free(old);
}
show_with_type(type, full);
@@ -599,9 +600,12 @@
static void handle_ref_opt(const char *pattern, const char *prefix)
{
if (pattern)
- for_each_glob_ref_in(show_reference, pattern, prefix, NULL);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ show_reference, pattern, prefix,
+ NULL);
else
- for_each_ref_in(prefix, show_reference, NULL);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ prefix, show_reference, NULL);
clear_ref_exclusions(&ref_excludes);
}
@@ -687,7 +691,6 @@
const char *name = NULL;
struct object_context unused;
struct strbuf buf = STRBUF_INIT;
- const int hexsz = the_hash_algo->hexsz;
int seen_end_of_options = 0;
enum format_type format = FORMAT_DEFAULT;
@@ -863,8 +866,8 @@
abbrev = strtoul(arg, NULL, 10);
if (abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
- else if (hexsz <= abbrev)
- abbrev = hexsz;
+ else if ((int)the_hash_algo->hexsz <= abbrev)
+ abbrev = the_hash_algo->hexsz;
continue;
}
if (!strcmp(arg, "--sq")) {
@@ -898,7 +901,8 @@
continue;
}
if (!strcmp(arg, "--all")) {
- for_each_ref(show_reference, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ show_reference, NULL);
clear_ref_exclusions(&ref_excludes);
continue;
}
@@ -908,8 +912,14 @@
continue;
}
if (!strcmp(arg, "--bisect")) {
- for_each_fullref_in("refs/bisect/bad", show_reference, NULL);
- for_each_fullref_in("refs/bisect/good", anti_reference, NULL);
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/bisect/bad",
+ NULL, show_reference,
+ NULL);
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/bisect/good",
+ NULL, anti_reference,
+ NULL);
continue;
}
if (opt_with_value(arg, "--branches", &arg)) {
@@ -1049,8 +1059,8 @@
if (!strcmp(arg, "--shared-index-path")) {
if (repo_read_index(the_repository) < 0)
die(_("Could not read the index"));
- if (the_index.split_index) {
- const struct object_id *oid = &the_index.split_index->base_oid;
+ if (the_repository->index->split_index) {
+ const struct object_id *oid = &the_repository->index->split_index->base_oid;
const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
print_path(path, prefix, format, DEFAULT_RELATIVE);
}
diff --git a/builtin/revert.c b/builtin/revert.c
index 53935d2..7bf2b4e 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -179,7 +179,7 @@
/* Check for incompatible command line arguments */
if (cmd) {
- char *this_operation;
+ const char *this_operation;
if (cmd == 'q')
this_operation = "--quit";
else if (cmd == 'c')
diff --git a/builtin/rm.c b/builtin/rm.c
index fd130ce..d195c16 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds 2006
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -41,8 +41,8 @@
{
int i = -pos - 1;
- while ((i < the_index.cache_nr) && !strcmp(the_index.cache[i]->name, path)) {
- if (ce_stage(the_index.cache[i]) == 2)
+ while ((i < the_repository->index->cache_nr) && !strcmp(the_repository->index->cache[i]->name, path)) {
+ if (ce_stage(the_repository->index->cache[i]) == 2)
return i;
i++;
}
@@ -78,13 +78,13 @@
int pos;
const struct cache_entry *ce;
- pos = index_name_pos(&the_index, name, strlen(name));
+ pos = index_name_pos(the_repository->index, name, strlen(name));
if (pos < 0) {
pos = get_ours_cache_pos(name, pos);
if (pos < 0)
continue;
}
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (!S_ISGITLINK(ce->ce_mode) ||
!file_exists(ce->name) ||
@@ -122,7 +122,7 @@
int local_changes = 0;
int staged_changes = 0;
- pos = index_name_pos(&the_index, name, strlen(name));
+ pos = index_name_pos(the_repository->index, name, strlen(name));
if (pos < 0) {
/*
* Skip unmerged entries except for populated submodules
@@ -132,11 +132,11 @@
if (pos < 0)
continue;
- if (!S_ISGITLINK(the_index.cache[pos]->ce_mode) ||
+ if (!S_ISGITLINK(the_repository->index->cache[pos]->ce_mode) ||
is_empty_dir(name))
continue;
}
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (lstat(ce->name, &st) < 0) {
if (!is_missing_file_error(errno))
@@ -173,7 +173,7 @@
* Is the index different from the file in the work tree?
* If it's a submodule, is its work tree modified?
*/
- if (ie_match_stat(&the_index, ce, &st, 0) ||
+ if (ie_match_stat(the_repository->index, ce, &st, 0) ||
(S_ISGITLINK(ce->ce_mode) &&
bad_to_remove_submodule(ce->name,
SUBMODULE_REMOVAL_DIE_ON_ERROR |
@@ -301,27 +301,27 @@
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
seen = xcalloc(pathspec.nr, 1);
- if (pathspec_needs_expanded_index(&the_index, &pathspec))
- ensure_full_index(&the_index);
+ if (pathspec_needs_expanded_index(the_repository->index, &pathspec))
+ ensure_full_index(the_repository->index);
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
if (!include_sparse &&
(ce_skip_worktree(ce) ||
- !path_in_sparse_checkout(ce->name, &the_index)))
+ !path_in_sparse_checkout(ce->name, the_repository->index)))
continue;
- if (!ce_path_match(&the_index, ce, &pathspec, seen))
+ if (!ce_path_match(the_repository->index, ce, &pathspec, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
list.entry[list.nr].name = xstrdup(ce->name);
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
- !is_staging_gitmodules_ok(&the_index))
+ !is_staging_gitmodules_ok(the_repository->index))
die(_("please stage your changes to .gitmodules or stash them to proceed"));
}
@@ -391,7 +391,7 @@
if (!quiet)
printf("rm '%s'\n", path);
- if (remove_file_from_index(&the_index, path))
+ if (remove_file_from_index(the_repository->index, path))
die(_("git rm: unable to remove %s"), path);
}
@@ -432,10 +432,10 @@
}
strbuf_release(&buf);
if (gitmodules_modified)
- stage_updated_gitmodules(&the_index);
+ stage_updated_gitmodules(the_repository->index);
}
- if (write_locked_index(&the_index, &lock_file,
+ if (write_locked_index(the_repository->index, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 3df9eaa..17cae6b 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -336,5 +336,7 @@
/* stable plumbing output; do not modify or localize */
fprintf(stderr, "Everything up-to-date\n");
+ free_refs(remote_refs);
+ free_refs(local_refs);
return ret;
}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 3c7cd2d..d4daf31 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -435,7 +435,7 @@
usage_with_options(shortlog_usage, options);
}
- if (setup_revisions(argc, argv, &rev, NULL) != 1) {
+ if (!nongit && setup_revisions(argc, argv, &rev, NULL) != 1) {
error(_("unrecognized argument: %s"), argv[1]);
usage_with_options(shortlog_usage, options);
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index b01ec76..d72f4cb 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -479,13 +479,15 @@
if (head) {
int orig_cnt = ref_name_cnt;
- for_each_ref(append_head_ref, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_head_ref, NULL);
sort_ref_range(orig_cnt, ref_name_cnt);
}
if (remotes) {
int orig_cnt = ref_name_cnt;
- for_each_ref(append_remote_ref, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_remote_ref, NULL);
sort_ref_range(orig_cnt, ref_name_cnt);
}
}
@@ -549,7 +551,8 @@
match_ref_pattern = av;
match_ref_slash = count_slashes(av);
- for_each_ref(append_matching_ref, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_matching_ref, NULL);
if (saved_matches == ref_name_cnt &&
ref_name_cnt < MAX_REVS)
error(_("no matching refs with %s"), av);
@@ -740,9 +743,11 @@
if (ac == 0) {
static const char *fake_av[2];
- fake_av[0] = resolve_refdup("HEAD",
- RESOLVE_REF_READING, &oid,
- NULL);
+ fake_av[0] = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD",
+ RESOLVE_REF_READING,
+ &oid,
+ NULL);
fake_av[1] = NULL;
av = fake_av;
ac = 1;
@@ -815,8 +820,9 @@
snarf_refs(all_heads, all_remotes);
}
- head = resolve_refdup("HEAD", RESOLVE_REF_READING,
- &head_oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ RESOLVE_REF_READING,
+ &head_oid, NULL);
if (with_current_branch && head) {
int has_head = 0;
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 1c15421..839a5c2 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -11,8 +11,8 @@
static const char * const show_ref_usage[] = {
N_("git show-ref [--head] [-d | --dereference]\n"
- " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
- " [--heads] [--] [<pattern>...]"),
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+ " [--] [<pattern>...]"),
N_("git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
" [--] [<ref>...]"),
@@ -50,7 +50,7 @@
if (!opts->deref_tags)
return;
- if (!peel_iterated_oid(oid, &peeled)) {
+ if (!peel_iterated_oid(the_repository, oid, &peeled)) {
hex = repo_find_unique_abbrev(the_repository, &peeled, opts->abbrev);
printf("%s %s^{}\n", hex, refname);
}
@@ -129,7 +129,8 @@
char buf[1024];
int patternlen = opts->pattern ? strlen(opts->pattern) : 0;
- for_each_ref(add_existing, &existing_refs);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_existing,
+ &existing_refs);
while (fgets(buf, sizeof(buf), stdin)) {
char *ref;
int len = strlen(buf);
@@ -173,7 +174,7 @@
struct object_id oid;
if ((starts_with(*refs, "refs/") || refname_is_safe(*refs)) &&
- !read_ref(*refs, &oid)) {
+ !refs_read_ref(get_main_ref_store(the_repository), *refs, &oid)) {
show_one(show_one_opts, *refs, &oid);
}
else if (!show_one_opts->quiet)
@@ -188,7 +189,7 @@
struct patterns_options {
int show_head;
- int heads_only;
+ int branches_only;
int tags_only;
};
@@ -205,14 +206,20 @@
show_ref_data.patterns = patterns;
if (opts->show_head)
- head_ref(show_ref, &show_ref_data);
- if (opts->heads_only || opts->tags_only) {
- if (opts->heads_only)
- for_each_fullref_in("refs/heads/", show_ref, &show_ref_data);
+ refs_head_ref(get_main_ref_store(the_repository), show_ref,
+ &show_ref_data);
+ if (opts->branches_only || opts->tags_only) {
+ if (opts->branches_only)
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/heads/", NULL,
+ show_ref, &show_ref_data);
if (opts->tags_only)
- for_each_fullref_in("refs/tags/", show_ref, &show_ref_data);
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/tags/", NULL, show_ref,
+ &show_ref_data);
} else {
- for_each_ref(show_ref, &show_ref_data);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ show_ref, &show_ref_data);
}
if (!show_ref_data.found_match)
return 1;
@@ -286,8 +293,10 @@
struct show_one_options show_one_opts = {0};
int verify = 0, exists = 0;
const struct option show_ref_options[] = {
- OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with heads)")),
- OPT_BOOL(0, "heads", &patterns_opts.heads_only, N_("only show heads (can be combined with tags)")),
+ OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with branches)")),
+ OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with tags)")),
+ OPT_HIDDEN_BOOL(0, "heads", &patterns_opts.branches_only,
+ N_("deprecated synonym for --branches")),
OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")),
OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
"requires exact ref path")),
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 0f52e25..3f2bfce 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -96,10 +96,11 @@
printf("\n");
}
- return 0;
+ string_list_clear(&sl, 0);
+ } else {
+ write_patterns_to_file(stdout, &pl);
}
- write_patterns_to_file(stdout, &pl);
clear_pattern_list(&pl);
return 0;
@@ -205,11 +206,13 @@
struct unpack_trees_options o;
struct lock_file lock_file = LOCK_INIT;
struct repository *r = the_repository;
+ struct pattern_list *old_pl;
/* If no branch has been checked out, there are no updates to make. */
if (is_index_unborn(r->index))
return UPDATE_SPARSITY_SUCCESS;
+ old_pl = r->index->sparse_checkout_patterns;
r->index->sparse_checkout_patterns = pl;
memset(&o, 0, sizeof(o));
@@ -241,7 +244,12 @@
clean_tracked_sparse_directories(r);
- r->index->sparse_checkout_patterns = NULL;
+ if (r->index->sparse_checkout_patterns != pl) {
+ clear_pattern_list(r->index->sparse_checkout_patterns);
+ FREE_AND_NULL(r->index->sparse_checkout_patterns);
+ }
+ r->index->sparse_checkout_patterns = old_pl;
+
return result;
}
@@ -311,6 +319,8 @@
fprintf(fp, "%s/\n", pattern);
free(pattern);
}
+
+ string_list_clear(&sl, 0);
}
static int write_patterns_and_update(struct pattern_list *pl)
@@ -440,7 +450,6 @@
char *sparse_filename;
int res;
struct object_id oid;
- struct strbuf pattern = STRBUF_INIT;
static struct option builtin_sparse_checkout_init_options[] = {
OPT_BOOL(0, "cone", &init_opts.cone_mode,
@@ -471,6 +480,7 @@
/* If we already have a sparse-checkout file, use it. */
if (res >= 0) {
free(sparse_filename);
+ clear_pattern_list(&pl);
return update_working_directory(NULL);
}
@@ -491,10 +501,10 @@
return 0;
}
- strbuf_addstr(&pattern, "/*");
- add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
- strbuf_addstr(&pattern, "!/*/");
- add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
+ free(sparse_filename);
+
+ add_pattern("/*", empty_base, 0, &pl, 0);
+ add_pattern("!/*/", empty_base, 0, &pl, 0);
pl.use_cone_patterns = init_opts.cone_mode;
return write_patterns_and_update(&pl);
@@ -513,6 +523,7 @@
char *slash = strrchr(e->pattern, '/');
char *oldpattern = e->pattern;
size_t newlen;
+ struct pattern_entry *dup;
if (!slash || slash == e->pattern)
break;
@@ -523,8 +534,14 @@
e->pattern = xstrndup(oldpattern, newlen);
hashmap_entry_init(&e->ent, fspathhash(e->pattern));
- if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
+ dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
+ if (!dup) {
hashmap_add(&pl->parent_hashmap, &e->ent);
+ } else {
+ free(e->pattern);
+ free(e);
+ e = dup;
+ }
}
}
@@ -581,15 +598,15 @@
strbuf_to_cone_pattern(&line, pl);
}
}
+ strbuf_release(&line);
} else {
if (file) {
struct strbuf line = STRBUF_INIT;
- while (!strbuf_getline(&line, file)) {
- size_t len;
- char *buf = strbuf_detach(&line, &len);
- add_pattern(buf, empty_base, 0, pl, 0);
- }
+ while (!strbuf_getline(&line, file))
+ add_pattern(line.buf, empty_base, 0, pl, 0);
+
+ strbuf_release(&line);
} else {
for (i = 0; i < argc; i++)
add_pattern(argv[i], empty_base, 0, pl, 0);
@@ -891,7 +908,6 @@
OPT_END(),
};
struct pattern_list pl;
- struct strbuf match_all = STRBUF_INIT;
/*
* We do not exit early if !core_apply_sparse_checkout; due to the
@@ -917,8 +933,7 @@
pl.use_cone_patterns = 0;
core_apply_sparse_checkout = 1;
- strbuf_addstr(&match_all, "/*");
- add_pattern(strbuf_detach(&match_all, NULL), empty_base, 0, &pl, 0);
+ add_pattern("/*", empty_base, 0, &pl, 0);
prepare_repo_settings(the_repository);
the_repository->settings.sparse_index = 0;
diff --git a/builtin/stash.c b/builtin/stash.c
index 062be1f..7859bc0 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "config.h"
@@ -196,7 +195,7 @@
commit = argv[0];
if (!commit) {
- if (!ref_exists(ref_stash)) {
+ if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash)) {
fprintf_ln(stderr, _("No stash entries found."));
return -1;
}
@@ -244,7 +243,8 @@
if (repo_get_oid(the_repository, ref_stash, &obj))
return 0;
- return delete_ref(NULL, ref_stash, &obj, 0);
+ return refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ ref_stash, &obj, 0);
}
static int clear_stash(int argc, const char **argv, const char *prefix)
@@ -273,7 +273,7 @@
struct lock_file lock_file = LOCK_INIT;
repo_read_index_preload(the_repository, NULL, 0);
- if (refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL))
+ if (refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL))
return -1;
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -287,8 +287,8 @@
init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size);
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.merge = 1;
opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
opts.update = update;
@@ -299,7 +299,7 @@
if (unpack_trees(nr_trees, t, &opts))
return -1;
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
return error(_("unable to write new index file"));
return 0;
@@ -430,7 +430,7 @@
state.force = 1;
state.quiet = 1;
state.refresh_cache = 1;
- state.istate = &the_index;
+ state.istate = the_repository->index;
/*
* Step 1: get a difference between orig_tree (which corresponding
@@ -454,7 +454,7 @@
/* Look up the path's position in the current index. */
p = diff_queued_diff.queue[i];
- pos = index_name_pos(&the_index, p->two->path,
+ pos = index_name_pos(the_repository->index, p->two->path,
strlen(p->two->path));
/*
@@ -465,10 +465,10 @@
* path, but left it out of the working tree, then clear the
* SKIP_WORKTREE bit and write it to the working tree.
*/
- if (pos >= 0 && ce_skip_worktree(the_index.cache[pos])) {
+ if (pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) {
struct stat st;
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (!lstat(ce->name, &st)) {
/* Conflicting path present; relocate it */
struct strbuf new_path = STRBUF_INIT;
@@ -504,12 +504,12 @@
if (pos < 0)
option = ADD_CACHE_OK_TO_ADD;
- ce = make_cache_entry(&the_index,
+ ce = make_cache_entry(the_repository->index,
p->one->mode,
&p->one->oid,
p->one->path,
0, 0);
- add_index_entry(&the_index, ce, option);
+ add_index_entry(the_repository->index, ce, option);
}
}
diff_flush(&diff_opts);
@@ -518,7 +518,7 @@
* Step 4: write the new index to disk
*/
repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
- if (write_locked_index(&the_index, &lock,
+ if (write_locked_index(the_repository->index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("could not write index"));
}
@@ -539,7 +539,7 @@
NULL, NULL, NULL))
return error(_("could not write index"));
- if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0,
+ if (write_index_as_tree(&c_tree, the_repository->index, get_index_file(), 0,
NULL))
return error(_("cannot apply a stash in the middle of a merge"));
@@ -562,14 +562,14 @@
return error(_("conflicts in index. "
"Try without --index."));
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
- if (write_index_as_tree(&index_tree, &the_index,
+ if (write_index_as_tree(&index_tree, the_repository->index,
get_index_file(), 0, NULL))
return error(_("could not save index tree"));
reset_head();
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
}
}
@@ -687,7 +687,8 @@
static int reflog_is_empty(const char *refname)
{
- return !for_each_reflog_ent(refname, reject_reflog_ent, NULL);
+ return !refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ refname, reject_reflog_ent, NULL);
}
static int do_drop_stash(struct stash_info *info, int quiet)
@@ -824,7 +825,7 @@
git_stash_list_usage,
PARSE_OPT_KEEP_UNKNOWN_OPT);
- if (!ref_exists(ref_stash))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash))
return 0;
cp.git_cmd = 1;
@@ -875,8 +876,8 @@
}
unpack_tree_opt.head_idx = -1;
- unpack_tree_opt.src_index = &the_index;
- unpack_tree_opt.dst_index = &the_index;
+ unpack_tree_opt.src_index = the_repository->index;
+ unpack_tree_opt.dst_index = the_repository->index;
unpack_tree_opt.merge = 1;
unpack_tree_opt.fn = stash_worktree_untracked_merge;
@@ -998,10 +999,10 @@
if (!stash_msg)
stash_msg = "Created via \"git stash store\".";
- if (update_ref(stash_msg, ref_stash, w_commit, NULL,
- REF_FORCE_CREATE_REFLOG,
- quiet ? UPDATE_REFS_QUIET_ON_ERR :
- UPDATE_REFS_MSG_ON_ERR)) {
+ if (refs_update_ref(get_main_ref_store(the_repository), stash_msg, ref_stash, w_commit, NULL,
+ REF_FORCE_CREATE_REFLOG,
+ quiet ? UPDATE_REFS_QUIET_ON_ERR :
+ UPDATE_REFS_MSG_ON_ERR)) {
if (!quiet) {
fprintf_ln(stderr, _("Cannot update %s with %s"),
ref_stash, oid_to_hex(w_commit));
@@ -1205,8 +1206,8 @@
}
cp_diff_tree.git_cmd = 1;
- strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD",
- oid_to_hex(&info->w_tree), "--", NULL);
+ strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "--binary",
+ "-U1", "HEAD", oid_to_hex(&info->w_tree), "--", NULL);
if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) {
ret = -1;
goto done;
@@ -1384,7 +1385,8 @@
goto done;
}
- branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
+ branch_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &flags);
if (flags & REF_ISSYMREF)
skip_prefix(branch_ref, "refs/heads/", &branch_name);
head_short_sha1 = repo_find_unique_abbrev(the_repository,
@@ -1395,7 +1397,7 @@
strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
commit_list_insert(head_commit, &parents);
- if (write_index_as_tree(&info->i_tree, &the_index, get_index_file(), 0,
+ if (write_index_as_tree(&info->i_tree, the_repository->index, get_index_file(), 0,
NULL) ||
commit_tree(commit_tree_label.buf, commit_tree_label.len,
&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
@@ -1540,9 +1542,9 @@
char *ps_matched = xcalloc(ps->nr, 1);
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++)
- ce_path_match(&the_index, the_index.cache[i], ps,
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++)
+ ce_path_match(the_repository->index, the_repository->index->cache[i], ps,
ps_matched);
if (report_path_error(ps_matched, ps)) {
@@ -1566,7 +1568,7 @@
goto done;
}
- if (!reflog_exists(ref_stash) && do_clear_stash()) {
+ if (!refs_reflog_exists(get_main_ref_store(the_repository), ref_stash) && do_clear_stash()) {
ret = -1;
if (!quiet)
fprintf_ln(stderr, _("Cannot initialize stash"));
@@ -1612,7 +1614,7 @@
goto done;
}
}
- discard_index(&the_index);
+ discard_index(the_repository->index);
if (ps->nr) {
struct child_process cp_add = CHILD_PROCESS_INIT;
struct child_process cp_diff = CHILD_PROCESS_INIT;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5a71b1e..880ab44 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1,4 +1,3 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "environment.h"
@@ -207,18 +206,18 @@
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
- if (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce),
+ if (!match_pathspec(the_repository->index, pathspec, ce->name, ce_namelen(ce),
0, ps_matched, 1) ||
!S_ISGITLINK(ce->ce_mode))
continue;
ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
list->entries[list->nr++] = ce;
- while (i + 1 < the_index.cache_nr &&
- !strcmp(ce->name, the_index.cache[i + 1]->name))
+ while (i + 1 < the_repository->index->cache_nr &&
+ !strcmp(ce->name, the_repository->index->cache[i + 1]->name))
/*
* Skip entries with the same name in different stages
* to make sure an entry is returned only once.
@@ -257,11 +256,9 @@
static char *get_up_path(const char *path)
{
- int i;
struct strbuf sb = STRBUF_INIT;
- for (i = count_slashes(path); i; i--)
- strbuf_addstr(&sb, "../");
+ strbuf_addstrings(&sb, "../", count_slashes(path));
/*
* Check if 'path' ends with slash or not
@@ -680,7 +677,8 @@
displaypath);
} else if (!(flags & OPT_CACHED)) {
struct object_id oid;
- struct ref_store *refs = get_submodule_ref_store(path);
+ struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
+ path);
if (!refs) {
print_status(flags, '-', path, ce_oid, displaypath);
@@ -904,7 +902,8 @@
if (!info->cached && oideq(&p->oid_dst, null_oid())) {
if (S_ISGITLINK(p->mod_dst)) {
- struct ref_store *refs = get_submodule_ref_store(p->sm_path);
+ struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
+ p->sm_path);
if (refs)
refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
@@ -913,7 +912,7 @@
int fd = open(p->sm_path, O_RDONLY);
if (fd < 0 || fstat(fd, &st) < 0 ||
- index_fd(&the_index, &p->oid_dst, fd, &st, OBJ_BLOB,
+ index_fd(the_repository->index, &p->oid_dst, fd, &st, OBJ_BLOB,
p->sm_path, 0))
error(_("couldn't hash object from '%s'"), p->sm_path);
} else {
@@ -2457,7 +2456,9 @@
}
if (!strcmp(*branch, ".")) {
- const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+ const char *refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL,
+ NULL);
if (!refname)
return die_message(_("No such ref: %s"), "HEAD");
@@ -2597,7 +2598,8 @@
if (update_data->just_cloned)
oidcpy(&update_data->suboid, null_oid());
- else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
+ else if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
+ "HEAD", &update_data->suboid))
return die_message(_("Unable to find current revision in submodule path '%s'"),
update_data->displaypath);
@@ -2624,7 +2626,8 @@
update_data->sm_path);
}
- if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
+ if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
+ remote_ref, &update_data->oid))
return die_message(_("Unable to find %s revision in submodule path '%s'"),
remote_ref, update_data->sm_path);
@@ -2875,7 +2878,8 @@
argv++;
argc--;
/* Get the submodule's head ref and determine if it is detached */
- head = resolve_refdup("HEAD", 0, &head_oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ 0, &head_oid, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
if (!strcmp(head, "HEAD"))
@@ -3322,21 +3326,21 @@
char *ps_matched = xcalloc(ps.nr, 1);
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
/*
* Since there is only one pathspec, we just need to
* check ps_matched[0] to know if a cache entry matched.
*/
- for (i = 0; i < the_index.cache_nr; i++) {
- ce_path_match(&the_index, the_index.cache[i], &ps,
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ ce_path_match(the_repository->index, the_repository->index->cache[i], &ps,
ps_matched);
if (ps_matched[0]) {
if (!force)
die(_("'%s' already exists in the index"),
path);
- if (!S_ISGITLINK(the_index.cache[i]->ce_mode))
+ if (!S_ISGITLINK(the_repository->index->cache[i]->ce_mode))
die(_("'%s' already exists in the index "
"and is not a submodule"), path);
break;
@@ -3353,7 +3357,7 @@
strbuf_addstr(&sb, path);
if (is_nonbare_repository_dir(&sb)) {
struct object_id oid;
- if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
die(_("'%s' does not have a commit checked out"), path);
}
strbuf_release(&sb);
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index c9defe4..81abdd1 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -18,7 +18,8 @@
const char *refname;
resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
- refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
+ refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ HEAD, resolve_flags, NULL, &flag);
if (!refname)
die("No such ref: %s", HEAD);
@@ -31,7 +32,9 @@
if (print) {
char *to_free = NULL;
if (shorten)
- refname = to_free = shorten_unambiguous_ref(refname, 0);
+ refname = to_free = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ refname,
+ 0);
puts(refname);
free(to_free);
}
@@ -66,7 +69,8 @@
die("Cannot delete %s, not a symbolic ref", argv[0]);
if (!strcmp(argv[0], "HEAD"))
die("deleting '%s' is not allowed", argv[0]);
- return delete_ref(NULL, argv[0], NULL, REF_NO_DEREF);
+ return refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, argv[0], NULL, REF_NO_DEREF);
}
switch (argc) {
@@ -79,7 +83,8 @@
die("Refusing to point HEAD outside of refs/");
if (check_refname_format(argv[1], REFNAME_ALLOW_ONELEVEL) < 0)
die("Refusing to set '%s' to invalid ref '%s'", argv[0], argv[1]);
- ret = !!create_symref(argv[0], argv[1], msg);
+ ret = !!refs_update_symref(get_main_ref_store(the_repository),
+ argv[0], argv[1], msg);
break;
default:
usage_with_options(git_symbolic_ref_usage, options);
diff --git a/builtin/tag.c b/builtin/tag.c
index 9a33cb5..6e2c0cf 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -28,9 +28,11 @@
#include "date.h"
#include "write-or-die.h"
#include "object-file-convert.h"
+#include "trailer.h"
static const char * const git_tag_usage[] = {
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+ " [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"),
N_("git tag -d <tagname>..."),
N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
@@ -87,7 +89,7 @@
for (p = argv; *p; p++) {
strbuf_reset(&ref);
strbuf_addf(&ref, "refs/tags/%s", *p);
- if (read_ref(ref.buf, &oid)) {
+ if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &oid)) {
error(_("tag '%s' not found."), *p);
had_error = 1;
continue;
@@ -116,13 +118,13 @@
struct string_list_item *item;
result = for_each_tag_name(argv, collect_tags, (void *)&refs_to_delete);
- if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
+ if (refs_delete_refs(get_main_ref_store(the_repository), NULL, &refs_to_delete, REF_NO_DEREF))
result = 1;
for_each_string_list_item(item, &refs_to_delete) {
const char *name = item->string;
struct object_id *oid = item->util;
- if (!ref_exists(name))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), name))
printf(_("Deleted tag '%s' (was %s)\n"),
item->string + 10,
repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
@@ -290,10 +292,12 @@
static void create_tag(const struct object_id *object, const char *object_ref,
const char *tag,
struct strbuf *buf, struct create_tag_options *opt,
- struct object_id *prev, struct object_id *result, char *path)
+ struct object_id *prev, struct object_id *result,
+ struct strvec *trailer_args, char *path)
{
enum object_type type;
struct strbuf header = STRBUF_INIT;
+ int should_edit;
type = oid_object_info(the_repository, object, NULL);
if (type <= OBJ_NONE)
@@ -313,13 +317,15 @@
tag,
git_committer_info(IDENT_STRICT));
- if (!opt->message_given || opt->use_editor) {
+ should_edit = opt->use_editor || !opt->message_given;
+ if (should_edit || trailer_args->nr) {
int fd;
/* write the template message before editing: */
fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (opt->message_given) {
+ if (opt->message_given && buf->len) {
+ strbuf_complete(buf, '\n');
write_or_die(fd, buf->buf, buf->len);
strbuf_reset(buf);
} else if (!is_null_oid(prev)) {
@@ -338,10 +344,19 @@
}
close(fd);
- if (launch_editor(path, buf, NULL)) {
- fprintf(stderr,
- _("Please supply the message using either -m or -F option.\n"));
- exit(1);
+ if (trailer_args->nr && amend_file_with_trailers(path, trailer_args))
+ die(_("unable to pass trailers to --trailers"));
+
+ if (should_edit) {
+ if (launch_editor(path, buf, NULL)) {
+ fprintf(stderr,
+ _("Please supply the message using either -m or -F option.\n"));
+ exit(1);
+ }
+ } else if (trailer_args->nr) {
+ strbuf_reset(buf);
+ if (strbuf_read_file(buf, path, 0) < 0)
+ die_errno(_("failed to read '%s'"), path);
}
}
@@ -463,6 +478,7 @@
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
+ struct strvec trailer_args = STRVEC_INIT;
int icase = 0;
int edit_flag = 0;
struct option options[] = {
@@ -479,6 +495,8 @@
OPT_CALLBACK_F('m', "message", &msg, N_("message"),
N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg),
OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
+ OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"),
+ N_("add custom trailer(s)"), PARSE_OPT_NONEG),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
OPT_CLEANUP(&cleanup_arg),
@@ -548,7 +566,8 @@
opt.sign = 1;
set_signing_key(keyid);
}
- create_tag_object = (opt.sign || annotate || msg.given || msgfile);
+ create_tag_object = (opt.sign || annotate || msg.given || msgfile ||
+ edit_flag || trailer_args.nr);
if ((create_tag_object || force) && (cmdmode != 0))
usage_with_options(git_tag_usage, options);
@@ -630,7 +649,7 @@
if (strbuf_check_tag_ref(&ref, tag))
die(_("'%s' is not a valid tag name."), tag);
- if (read_ref(ref.buf, &prev))
+ if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
oidclr(&prev);
else if (!force)
die(_("tag '%s' already exists"), tag);
@@ -654,12 +673,14 @@
opt.sign = 1;
path = git_pathdup("TAG_EDITMSG");
create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
- path);
+ &trailer_args, path);
}
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, &object, &prev,
+ NULL, NULL,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
ref_transaction_commit(transaction, &err)) {
@@ -686,6 +707,7 @@
strbuf_release(&reflog_msg);
strbuf_release(&msg.buf);
strbuf_release(&err);
+ strvec_clear(&trailer_args);
free(msgfile);
return ret;
}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 7bcaa14..d343416 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "bulk-checkin.h"
#include "config.h"
@@ -247,16 +247,16 @@
static int mark_ce_flags(const char *path, int flag, int mark)
{
int namelen = strlen(path);
- int pos = index_name_pos(&the_index, path, namelen);
+ int pos = index_name_pos(the_repository->index, path, namelen);
if (0 <= pos) {
- mark_fsmonitor_invalid(&the_index, the_index.cache[pos]);
+ mark_fsmonitor_invalid(the_repository->index, the_repository->index->cache[pos]);
if (mark)
- the_index.cache[pos]->ce_flags |= flag;
+ the_repository->index->cache[pos]->ce_flags |= flag;
else
- the_index.cache[pos]->ce_flags &= ~flag;
- the_index.cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
- cache_tree_invalidate_path(&the_index, path);
- the_index.cache_changed |= CE_ENTRY_CHANGED;
+ the_repository->index->cache[pos]->ce_flags &= ~flag;
+ the_repository->index->cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
+ cache_tree_invalidate_path(the_repository->index, path);
+ the_repository->index->cache_changed |= CE_ENTRY_CHANGED;
return 0;
}
return -1;
@@ -266,7 +266,7 @@
{
if (!allow_remove)
return error("%s: does not exist and --remove not passed", path);
- if (remove_file_from_index(&the_index, path))
+ if (remove_file_from_index(the_repository->index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
@@ -291,24 +291,24 @@
struct cache_entry *ce;
/* Was the old index entry already up-to-date? */
- if (old && !ce_stage(old) && !ie_match_stat(&the_index, old, st, 0))
+ if (old && !ce_stage(old) && !ie_match_stat(the_repository->index, old, st, 0))
return 0;
- ce = make_empty_cache_entry(&the_index, len);
+ ce = make_empty_cache_entry(the_repository->index, len);
memcpy(ce->name, path, len);
ce->ce_flags = create_ce_flags(0);
ce->ce_namelen = len;
- fill_stat_cache_info(&the_index, ce, st);
+ fill_stat_cache_info(the_repository->index, ce, st);
ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
- if (index_path(&the_index, &ce->oid, path, st,
+ if (index_path(the_repository->index, &ce->oid, path, st,
info_only ? 0 : HASH_WRITE_OBJECT)) {
discard_cache_entry(ce);
return -1;
}
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_index_entry(&the_index, ce, option)) {
+ if (add_index_entry(the_repository->index, ce, option)) {
discard_cache_entry(ce);
return error("%s: cannot add to the index - missing --add option?", path);
}
@@ -341,15 +341,16 @@
static int process_directory(const char *path, int len, struct stat *st)
{
struct object_id oid;
- int pos = index_name_pos(&the_index, path, len);
+ int pos = index_name_pos(the_repository->index, path, len);
/* Exact match: file or existing gitlink */
if (pos >= 0) {
- const struct cache_entry *ce = the_index.cache[pos];
+ const struct cache_entry *ce = the_repository->index->cache[pos];
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
- if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, path,
+ "HEAD", &oid) < 0)
return 0;
return add_one_path(ce, path, len, st);
@@ -360,8 +361,8 @@
/* Inexact match: is there perhaps a subdirectory match? */
pos = -pos-1;
- while (pos < the_index.cache_nr) {
- const struct cache_entry *ce = the_index.cache[pos++];
+ while (pos < the_repository->index->cache_nr) {
+ const struct cache_entry *ce = the_repository->index->cache[pos++];
if (strncmp(ce->name, path, len))
break;
@@ -375,7 +376,7 @@
}
/* No match - should we add it as a gitlink? */
- if (!resolve_gitlink_ref(path, "HEAD", &oid))
+ if (!repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid))
return add_one_path(NULL, path, len, st);
/* Error out. */
@@ -391,8 +392,8 @@
if (has_symlink_leading_path(path, len))
return error("'%s' is beyond a symbolic link", path);
- pos = index_name_pos(&the_index, path, len);
- ce = pos < 0 ? NULL : the_index.cache[pos];
+ pos = index_name_pos(the_repository->index, path, len);
+ ce = pos < 0 ? NULL : the_repository->index->cache[pos];
if (ce && ce_skip_worktree(ce)) {
/*
* working directory version is assumed "good"
@@ -400,7 +401,7 @@
* On the other hand, removing it from index should work
*/
if (!ignore_skip_worktree_entries && allow_remove &&
- remove_file_from_index(&the_index, path))
+ remove_file_from_index(the_repository->index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
@@ -428,7 +429,7 @@
return error("Invalid path '%s'", path);
len = strlen(path);
- ce = make_empty_cache_entry(&the_index, len);
+ ce = make_empty_cache_entry(the_repository->index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, path, len);
@@ -439,7 +440,7 @@
ce->ce_flags |= CE_VALID;
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_index_entry(&the_index, ce, option))
+ if (add_index_entry(the_repository->index, ce, option))
return error("%s: cannot add to the index - missing --add option?",
path);
report("add '%s'", path);
@@ -451,11 +452,11 @@
int pos;
struct cache_entry *ce;
- pos = index_name_pos(&the_index, path, strlen(path));
+ pos = index_name_pos(the_repository->index, path, strlen(path));
if (pos < 0)
goto fail;
- ce = the_index.cache[pos];
- if (chmod_index_entry(&the_index, ce, flip) < 0)
+ ce = the_repository->index->cache[pos];
+ if (chmod_index_entry(the_repository->index, ce, flip) < 0)
goto fail;
report("chmod %cx '%s'", flip, path);
@@ -498,7 +499,7 @@
}
if (force_remove) {
- if (remove_file_from_index(&the_index, path))
+ if (remove_file_from_index(the_repository->index, path))
die("git update-index: unable to remove %s", path);
report("remove '%s'", path);
return;
@@ -581,7 +582,7 @@
if (!mode) {
/* mode == 0 means there is no such path -- remove */
- if (remove_file_from_index(&the_index, path_name))
+ if (remove_file_from_index(the_repository->index, path_name))
die("git update-index: unable to remove %s",
ptr);
}
@@ -622,12 +623,12 @@
error("%s: not in %s branch.", path, which);
return NULL;
}
- if (!the_index.sparse_index && mode == S_IFDIR) {
+ if (!the_repository->index->sparse_index && mode == S_IFDIR) {
if (which)
error("%s: not a blob in %s branch.", path, which);
return NULL;
}
- ce = make_empty_cache_entry(&the_index, namelen);
+ ce = make_empty_cache_entry(the_repository->index, namelen);
oidcpy(&ce->oid, &oid);
memcpy(ce->name, path, namelen);
@@ -642,12 +643,12 @@
struct string_list_item *item;
int res = 0;
- if (!the_index.resolve_undo)
+ if (!the_repository->index->resolve_undo)
return res;
- item = string_list_lookup(the_index.resolve_undo, path);
+ item = string_list_lookup(the_repository->index->resolve_undo, path);
if (!item)
return res; /* no resolve-undo record for the path */
- res = unmerge_index_entry(&the_index, path, item->util, 0);
+ res = unmerge_index_entry(the_repository->index, path, item->util, 0);
FREE_AND_NULL(item->util);
return res;
}
@@ -682,19 +683,19 @@
PATHSPEC_PREFER_CWD,
prefix, paths);
- if (read_ref("HEAD", &head_oid))
+ if (refs_read_ref(get_main_ref_store(the_repository), "HEAD", &head_oid))
/* If there is no HEAD, that means it is an initial
* commit. Update everything in the index.
*/
has_head = 0;
redo:
- for (pos = 0; pos < the_index.cache_nr; pos++) {
- const struct cache_entry *ce = the_index.cache[pos];
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+ const struct cache_entry *ce = the_repository->index->cache[pos];
struct cache_entry *old = NULL;
int save_nr;
char *path;
- if (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL))
+ if (ce_stage(ce) || !ce_path_match(the_repository->index, ce, &pathspec, NULL))
continue;
if (has_head)
old = read_one_ent(NULL, &head_oid,
@@ -710,7 +711,7 @@
* to process each path individually
*/
if (S_ISSPARSEDIR(ce->ce_mode)) {
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
goto redo;
}
@@ -718,12 +719,12 @@
* path anymore, in which case, under 'allow_remove',
* or worse yet 'allow_replace', active_nr may decrease.
*/
- save_nr = the_index.cache_nr;
+ save_nr = the_repository->index->cache_nr;
path = xstrdup(ce->name);
update_one(path);
free(path);
discard_cache_entry(old);
- if (save_nr != the_index.cache_nr)
+ if (save_nr != the_repository->index->cache_nr)
goto redo;
}
clear_pathspec(&pathspec);
@@ -739,9 +740,9 @@
{
setup_work_tree();
repo_read_index(the_repository);
- *o->has_errors |= refresh_index(&the_index, o->flags | flag, NULL,
+ *o->has_errors |= refresh_index(the_repository->index, o->flags | flag, NULL,
NULL, NULL);
- if (has_racy_timestamp(&the_index)) {
+ if (has_racy_timestamp(the_repository->index)) {
/*
* Even if nothing else has changed, updating the file
* increases the chance that racy timestamps become
@@ -750,7 +751,7 @@
* refresh_index() as these are no actual errors.
* cmd_status() does the same.
*/
- the_index.cache_changed |= SOMETHING_CHANGED;
+ the_repository->index->cache_changed |= SOMETHING_CHANGED;
}
return 0;
}
@@ -787,7 +788,7 @@
{
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
return 0;
}
@@ -888,7 +889,7 @@
*has_errors = do_unresolve(ctx->argc, ctx->argv,
prefix, prefix ? strlen(prefix) : 0);
if (*has_errors)
- the_index.cache_changed = 0;
+ the_repository->index->cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
@@ -909,7 +910,7 @@
setup_work_tree();
*has_errors = do_reupdate(ctx->argv + 1, prefix);
if (*has_errors)
- the_index.cache_changed = 0;
+ the_repository->index->cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
@@ -1056,7 +1057,7 @@
if (entries < 0)
die("cache corrupted");
- the_index.updated_skipworktree = 1;
+ the_repository->index->updated_skipworktree = 1;
/*
* Custom copy of parse_options() because we want to handle
@@ -1111,18 +1112,18 @@
getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
if (preferred_index_format) {
if (preferred_index_format < 0) {
- printf(_("%d\n"), the_index.version);
+ printf(_("%d\n"), the_repository->index->version);
} else if (preferred_index_format < INDEX_FORMAT_LB ||
INDEX_FORMAT_UB < preferred_index_format) {
die("index-version %d not in range: %d..%d",
preferred_index_format,
INDEX_FORMAT_LB, INDEX_FORMAT_UB);
} else {
- if (the_index.version != preferred_index_format)
- the_index.cache_changed |= SOMETHING_CHANGED;
+ if (the_repository->index->version != preferred_index_format)
+ the_repository->index->cache_changed |= SOMETHING_CHANGED;
report(_("index-version: was %d, set to %d"),
- the_index.version, preferred_index_format);
- the_index.version = preferred_index_format;
+ the_repository->index->version, preferred_index_format);
+ the_repository->index->version = preferred_index_format;
}
}
@@ -1159,16 +1160,16 @@
warning(_("core.splitIndex is set to false; "
"remove or change it, if you really want to "
"enable split index"));
- if (the_index.split_index)
- the_index.cache_changed |= SPLIT_INDEX_ORDERED;
+ if (the_repository->index->split_index)
+ the_repository->index->cache_changed |= SPLIT_INDEX_ORDERED;
else
- add_split_index(&the_index);
+ add_split_index(the_repository->index);
} else if (!split_index) {
if (git_config_get_split_index() == 1)
warning(_("core.splitIndex is set to true; "
"remove or change it, if you really want to "
"disable split index"));
- remove_split_index(&the_index);
+ remove_split_index(the_repository->index);
}
prepare_repo_settings(r);
@@ -1180,7 +1181,7 @@
warning(_("core.untrackedCache is set to true; "
"remove or change it, if you really want to "
"disable the untracked cache"));
- remove_untracked_cache(&the_index);
+ remove_untracked_cache(the_repository->index);
report(_("Untracked cache disabled"));
break;
case UC_TEST:
@@ -1192,7 +1193,7 @@
warning(_("core.untrackedCache is set to false; "
"remove or change it, if you really want to "
"enable the untracked cache"));
- add_untracked_cache(&the_index);
+ add_untracked_cache(the_repository->index);
report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
break;
default:
@@ -1222,7 +1223,7 @@
"set it if you really want to "
"enable fsmonitor"));
}
- add_fsmonitor(&the_index);
+ add_fsmonitor(the_repository->index);
report(_("fsmonitor enabled"));
} else if (!fsmonitor) {
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
@@ -1230,17 +1231,17 @@
warning(_("core.fsmonitor is set; "
"remove it if you really want to "
"disable fsmonitor"));
- remove_fsmonitor(&the_index);
+ remove_fsmonitor(the_repository->index);
report(_("fsmonitor disabled"));
}
- if (the_index.cache_changed || force_write) {
+ if (the_repository->index->cache_changed || force_write) {
if (newfd < 0) {
if (refresh_args.flags & REFRESH_QUIET)
exit(128);
unable_to_lock_die(get_index_file(), lock_error);
}
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
}
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index e46afbc..471fa5c 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -77,6 +77,65 @@
}
/*
+ * Wrapper around parse_refname which skips the next delimiter.
+ */
+static char *parse_next_refname(const char **next)
+{
+ if (line_termination) {
+ /* Without -z, consume SP and use next argument */
+ if (!**next || **next == line_termination)
+ return NULL;
+ if (**next != ' ')
+ die("expected SP but got: %s", *next);
+ } else {
+ /* With -z, read the next NUL-terminated line */
+ if (**next)
+ return NULL;
+ }
+ /* Skip the delimiter */
+ (*next)++;
+
+ return parse_refname(next);
+}
+
+/*
+ * Wrapper around parse_arg which skips the next delimiter.
+ */
+static char *parse_next_arg(const char **next)
+{
+ struct strbuf arg = STRBUF_INIT;
+
+ if (line_termination) {
+ /* Without -z, consume SP and use next argument */
+ if (!**next || **next == line_termination)
+ return NULL;
+ if (**next != ' ')
+ die("expected SP but got: %s", *next);
+ } else {
+ /* With -z, read the next NUL-terminated line */
+ if (**next)
+ return NULL;
+ }
+ /* Skip the delimiter */
+ (*next)++;
+
+ if (line_termination) {
+ /* Without -z, use the next argument */
+ *next = parse_arg(*next, &arg);
+ } else {
+ /* With -z, use everything up to the next NUL */
+ strbuf_addstr(&arg, *next);
+ *next += arg.len;
+ }
+
+ if (arg.len)
+ return strbuf_detach(&arg, NULL);
+
+ strbuf_release(&arg);
+ return NULL;
+}
+
+/*
* The value being parsed is <old-oid> (as opposed to <new-oid>; the
* difference affects which error messages are generated):
*/
@@ -204,6 +263,7 @@
if (ref_transaction_update(transaction, refname,
&new_oid, have_old ? &old_oid : NULL,
+ NULL, NULL,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
@@ -213,6 +273,61 @@
strbuf_release(&err);
}
+static void parse_cmd_symref_update(struct ref_transaction *transaction,
+ const char *next, const char *end)
+{
+ char *refname, *new_target, *old_arg;
+ char *old_target = NULL;
+ struct strbuf err = STRBUF_INIT;
+ struct object_id old_oid;
+ int have_old_oid = 0;
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-update: missing <ref>");
+
+ new_target = parse_next_refname(&next);
+ if (!new_target)
+ die("symref-update %s: missing <new-target>", refname);
+
+ old_arg = parse_next_arg(&next);
+ if (old_arg) {
+ old_target = parse_next_arg(&next);
+ if (!old_target)
+ die("symref-update %s: expected old value", refname);
+
+ if (!strcmp(old_arg, "oid")) {
+ if (repo_get_oid(the_repository, old_target, &old_oid))
+ die("symref-update %s: invalid oid: %s", refname, old_target);
+
+ have_old_oid = 1;
+ } else if (!strcmp(old_arg, "ref")) {
+ if (check_refname_format(old_target, REFNAME_ALLOW_ONELEVEL))
+ die("symref-update %s: invalid ref: %s", refname, old_target);
+ } else {
+ die("symref-update %s: invalid arg '%s' for old value", refname, old_arg);
+ }
+ }
+
+ if (*next != line_termination)
+ die("symref-update %s: extra input: %s", refname, next);
+
+ if (ref_transaction_update(transaction, refname, NULL,
+ have_old_oid ? &old_oid : NULL,
+ new_target,
+ have_old_oid ? NULL : old_target,
+ update_flags | create_reflog_flag,
+ msg, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ free(old_arg);
+ free(old_target);
+ free(new_target);
+ strbuf_release(&err);
+}
+
static void parse_cmd_create(struct ref_transaction *transaction,
const char *next, const char *end)
{
@@ -233,7 +348,7 @@
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
- if (ref_transaction_create(transaction, refname, &new_oid,
+ if (ref_transaction_create(transaction, refname, &new_oid, NULL,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
@@ -243,6 +358,35 @@
strbuf_release(&err);
}
+
+static void parse_cmd_symref_create(struct ref_transaction *transaction,
+ const char *next, const char *end)
+{
+ struct strbuf err = STRBUF_INIT;
+ char *refname, *new_target;
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-create: missing <ref>");
+
+ new_target = parse_next_refname(&next);
+ if (!new_target)
+ die("symref-create %s: missing <new-target>", refname);
+
+ if (*next != line_termination)
+ die("symref-create %s: extra input: %s", refname, next);
+
+ if (ref_transaction_create(transaction, refname, NULL, new_target,
+ update_flags | create_reflog_flag,
+ msg, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ free(new_target);
+ strbuf_release(&err);
+}
+
static void parse_cmd_delete(struct ref_transaction *transaction,
const char *next, const char *end)
{
@@ -269,7 +413,7 @@
if (ref_transaction_delete(transaction, refname,
have_old ? &old_oid : NULL,
- update_flags, msg, &err))
+ NULL, update_flags, msg, &err))
die("%s", err.buf);
update_flags = default_flags;
@@ -277,6 +421,36 @@
strbuf_release(&err);
}
+
+static void parse_cmd_symref_delete(struct ref_transaction *transaction,
+ const char *next, const char *end)
+{
+ struct strbuf err = STRBUF_INIT;
+ char *refname, *old_target;
+
+ if (!(update_flags & REF_NO_DEREF))
+ die("symref-delete: cannot operate with deref mode");
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-delete: missing <ref>");
+
+ old_target = parse_next_refname(&next);
+
+ if (*next != line_termination)
+ die("symref-delete %s: extra input: %s", refname, next);
+
+ if (ref_transaction_delete(transaction, refname, NULL,
+ old_target, update_flags, msg, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ free(old_target);
+ strbuf_release(&err);
+}
+
+
static void parse_cmd_verify(struct ref_transaction *transaction,
const char *next, const char *end)
{
@@ -296,7 +470,7 @@
die("verify %s: extra input: %s", refname, next);
if (ref_transaction_verify(transaction, refname, &old_oid,
- update_flags, &err))
+ NULL, update_flags, &err))
die("%s", err.buf);
update_flags = default_flags;
@@ -304,6 +478,42 @@
strbuf_release(&err);
}
+static void parse_cmd_symref_verify(struct ref_transaction *transaction,
+ const char *next, const char *end)
+{
+ struct strbuf err = STRBUF_INIT;
+ struct object_id old_oid;
+ char *refname, *old_target;
+
+ if (!(update_flags & REF_NO_DEREF))
+ die("symref-verify: cannot operate with deref mode");
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-verify: missing <ref>");
+
+ /*
+ * old_ref is optional, if not provided, we need to ensure that the
+ * ref doesn't exist.
+ */
+ old_target = parse_next_refname(&next);
+ if (!old_target)
+ oidcpy(&old_oid, null_oid());
+
+ if (*next != line_termination)
+ die("symref-verify %s: extra input: %s", refname, next);
+
+ if (ref_transaction_verify(transaction, refname,
+ old_target ? NULL : &old_oid,
+ old_target, update_flags, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ free(old_target);
+ strbuf_release(&err);
+}
+
static void report_ok(const char *command)
{
fprintf(stdout, "%s: ok\n", command);
@@ -379,15 +589,19 @@
unsigned args;
enum update_refs_state state;
} command[] = {
- { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
- { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
- { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
- { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
- { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
- { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
- { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
- { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
- { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
+ { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
+ { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
+ { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
+ { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
+ { "symref-update", parse_cmd_symref_update, 4, UPDATE_REFS_OPEN },
+ { "symref-create", parse_cmd_symref_create, 2, UPDATE_REFS_OPEN },
+ { "symref-delete", parse_cmd_symref_delete, 2, UPDATE_REFS_OPEN },
+ { "symref-verify", parse_cmd_symref_verify, 2, UPDATE_REFS_OPEN },
+ { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
+ { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
+ { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
+ { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
+ { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
};
static void update_refs_stdin(void)
@@ -397,7 +611,8 @@
struct ref_transaction *transaction;
int i, j;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction)
die("%s", err.buf);
@@ -464,7 +679,8 @@
* get a "start".
*/
state = cmd->state;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ &err);
if (!transaction)
die("%s", err.buf);
@@ -571,11 +787,14 @@
* For purposes of backwards compatibility, we treat
* NULL_SHA1 as "don't care" here:
*/
- return delete_ref(msg, refname,
- (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
- default_flags);
+ return refs_delete_ref(get_main_ref_store(the_repository),
+ msg, refname,
+ (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
+ default_flags);
else
- return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL,
- default_flags | create_reflog_flag,
- UPDATE_REFS_DIE_ON_ERR);
+ return refs_update_ref(get_main_ref_store(the_repository),
+ msg, refname, &oid,
+ oldval ? &oldoid : NULL,
+ default_flags | create_reflog_flag,
+ UPDATE_REFS_DIE_ON_ERR);
}
diff --git a/builtin/var.c b/builtin/var.c
index cf55672..5dc3848 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -46,7 +46,7 @@
static char *default_branch(int ident_flag UNUSED)
{
- return xstrdup_or_null(git_default_branch_name(1));
+ return repo_default_branch_name(the_repository, 1);
}
static char *shell_path(int ident_flag UNUSED)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7c6c725..1d51e54 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -433,7 +433,7 @@
/* is 'refname' a branch or commit? */
if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
- ref_exists(symref.buf)) {
+ refs_ref_exists(get_main_ref_store(the_repository), symref.buf)) {
is_branch = 1;
if (!opts->force)
die_if_checked_out(symref.buf, 0);
@@ -509,7 +509,7 @@
}
wt_refs = get_worktree_ref_store(wt);
- ret = refs_init_db(wt_refs, REFS_INIT_DB_IS_WORKTREE, &sb);
+ ret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);
if (ret)
goto done;
@@ -517,7 +517,7 @@
ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid,
NULL, 0, UPDATE_REFS_MSG_ON_ERR);
else
- ret = refs_create_symref(wt_refs, "HEAD", symref.buf, NULL);
+ ret = refs_update_symref(wt_refs, "HEAD", symref.buf, NULL);
if (ret)
goto done;
@@ -605,7 +605,7 @@
} else {
struct strbuf s = STRBUF_INIT;
if (!detach && !strbuf_check_branch_ref(&s, branch) &&
- ref_exists(s.buf))
+ refs_ref_exists(get_main_ref_store(the_repository), s.buf))
fprintf_ln(stderr, _("Preparing worktree (checking out '%s')"),
branch);
else {
@@ -647,9 +647,9 @@
*/
static int can_use_local_refs(const struct add_opts *opts)
{
- if (head_ref(first_valid_ref, NULL)) {
+ if (refs_head_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
return 1;
- } else if (for_each_branch_ref(first_valid_ref, NULL)) {
+ } else if (refs_for_each_branch_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
if (!opts->quiet) {
struct strbuf path = STRBUF_INIT;
struct strbuf contents = STRBUF_INIT;
@@ -689,7 +689,7 @@
{
if (!guess_remote) {
return 0;
- } else if (for_each_remote_ref(first_valid_ref, NULL)) {
+ } else if (refs_for_each_remote_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
return 1;
} else if (!opts->force && remote_get(NULL)) {
die(_("No local or remote refs exist despite at least one remote\n"
@@ -736,18 +736,17 @@
return 1;
}
-static const char *dwim_branch(const char *path, const char **new_branch)
+static char *dwim_branch(const char *path, char **new_branch)
{
int n;
int branch_exists;
const char *s = worktree_basename(path, &n);
- const char *branchname = xstrndup(s, n);
+ char *branchname = xstrndup(s, n);
struct strbuf ref = STRBUF_INIT;
- UNLEAK(branchname);
-
branch_exists = !strbuf_check_branch_ref(&ref, branchname) &&
- ref_exists(ref.buf);
+ refs_ref_exists(get_main_ref_store(the_repository),
+ ref.buf);
strbuf_release(&ref);
if (branch_exists)
return branchname;
@@ -755,8 +754,7 @@
*new_branch = branchname;
if (guess_remote) {
struct object_id oid;
- const char *remote =
- unique_tracking_name(*new_branch, &oid, NULL);
+ char *remote = unique_tracking_name(*new_branch, &oid, NULL);
return remote;
}
return NULL;
@@ -768,6 +766,8 @@
const char *new_branch_force = NULL;
char *path;
const char *branch;
+ char *branch_to_free = NULL;
+ char *new_branch_to_free = NULL;
const char *new_branch = NULL;
const char *opt_track = NULL;
const char *lock_reason = NULL;
@@ -838,7 +838,7 @@
if (!opts.force &&
!strbuf_check_branch_ref(&symref, new_branch) &&
- ref_exists(symref.buf))
+ refs_ref_exists(get_main_ref_store(the_repository), symref.buf))
die_if_checked_out(symref.buf, 0);
strbuf_release(&symref);
}
@@ -858,16 +858,17 @@
opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
} else if (ac < 2) {
/* DWIM: Guess branch name from path. */
- const char *s = dwim_branch(path, &new_branch);
+ char *s = dwim_branch(path, &new_branch_to_free);
if (s)
- branch = s;
+ branch = branch_to_free = s;
+ new_branch = new_branch_to_free;
/* DWIM: Infer --orphan when repo has no refs. */
opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);
} else if (ac == 2) {
struct object_id oid;
struct commit *commit;
- const char *remote;
+ char *remote;
commit = lookup_commit_reference_by_name(branch);
if (!commit) {
@@ -922,6 +923,8 @@
ret = add_worktree(path, branch, &opts);
free(path);
+ free(branch_to_free);
+ free(new_branch_to_free);
return ret;
}
@@ -974,7 +977,9 @@
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
else if (wt->head_ref) {
- char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
+ char *ref = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ wt->head_ref,
+ 0);
strbuf_addf(&sb, "[%s]", ref);
free(ref);
} else
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 66e83d0..8c75b46 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+
#include "builtin.h"
#include "config.h"
#include "environment.h"
@@ -44,8 +44,8 @@
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags,
- tree_prefix);
+ ret = write_index_as_tree(&oid, the_repository->index, get_index_file(),
+ flags, tree_prefix);
switch (ret) {
case 0:
printf("%s\n", oid_to_hex(&oid));
diff --git a/bundle-uri.c b/bundle-uri.c
index ca32050..91b3319 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -395,11 +395,13 @@
strbuf_setlen(&bundle_ref, bundle_prefix_len);
strbuf_addstr(&bundle_ref, branch_name);
- has_old = !read_ref(bundle_ref.buf, &old_oid);
- update_ref("fetched bundle", bundle_ref.buf, oid,
- has_old ? &old_oid : NULL,
- REF_SKIP_OID_VERIFICATION,
- UPDATE_REFS_MSG_ON_ERR);
+ has_old = !refs_read_ref(get_main_ref_store(the_repository),
+ bundle_ref.buf, &old_oid);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "fetched bundle", bundle_ref.buf, oid,
+ has_old ? &old_oid : NULL,
+ REF_SKIP_OID_VERIFICATION,
+ UPDATE_REFS_MSG_ON_ERR);
}
bundle_header_release(&header);
diff --git a/bundle.c b/bundle.c
index a9744da..95367c2 100644
--- a/bundle.c
+++ b/bundle.c
@@ -389,7 +389,7 @@
if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
&oid, &ref, 0) != 1)
goto skip_write_ref;
- if (read_ref_full(e->name, RESOLVE_REF_READING, &oid, &flag))
+ if (refs_read_ref_full(get_main_ref_store(the_repository), e->name, RESOLVE_REF_READING, &oid, &flag))
flag = 0;
display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
diff --git a/checkout.c b/checkout.c
index 4256e71..cfaea4b 100644
--- a/checkout.c
+++ b/checkout.c
@@ -45,8 +45,8 @@
return 0;
}
-const char *unique_tracking_name(const char *name, struct object_id *oid,
- int *dwim_remotes_matched)
+char *unique_tracking_name(const char *name, struct object_id *oid,
+ int *dwim_remotes_matched)
{
struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
const char *default_remote = NULL;
diff --git a/checkout.h b/checkout.h
index 3c514a5..ba15a13 100644
--- a/checkout.h
+++ b/checkout.h
@@ -8,8 +8,8 @@
* tracking branch. Return the name of the remote if such a branch
* exists, NULL otherwise.
*/
-const char *unique_tracking_name(const char *name,
- struct object_id *oid,
- int *dwim_remotes_matched);
+char *unique_tracking_name(const char *name,
+ struct object_id *oid,
+ int *dwim_remotes_matched);
#endif /* CHECKOUT_H */
diff --git a/ci/check-whitespace.sh b/ci/check-whitespace.sh
new file mode 100755
index 0000000..db39909
--- /dev/null
+++ b/ci/check-whitespace.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+#
+# Check that commits after a specified point do not contain new or modified
+# lines with whitespace errors. An optional formatted summary can be generated
+# by providing an output file path and url as additional arguments.
+#
+
+baseCommit=$1
+outputFile=$2
+url=$3
+
+if test "$#" -ne 1 && test "$#" -ne 3
+then
+ echo "USAGE: $0 <BASE_COMMIT> [<OUTPUT_FILE> <URL>]"
+ exit 1
+fi
+
+problems=()
+commit=
+commitText=
+commitTextmd=
+goodParent=
+
+while read dash sha etc
+do
+ case "${dash}" in
+ "---") # Line contains commit information.
+ if test -z "${goodParent}"
+ then
+ # Assume the commit has no whitespace errors until detected otherwise.
+ goodParent=${sha}
+ fi
+
+ commit="${sha}"
+ commitText="${sha} ${etc}"
+ commitTextmd="[${sha}](${url}/commit/${sha}) ${etc}"
+ ;;
+ "")
+ ;;
+ *) # Line contains whitespace error information for current commit.
+ if test -n "${goodParent}"
+ then
+ problems+=("1) --- ${commitTextmd}")
+ echo ""
+ echo "--- ${commitText}"
+ goodParent=
+ fi
+
+ case "${dash}" in
+ *:[1-9]*:) # contains file and line number information
+ dashend=${dash#*:}
+ problems+=("[${dash}](${url}/blob/${commit}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}")
+ ;;
+ *)
+ problems+=("\`${dash} ${sha} ${etc}\`")
+ ;;
+ esac
+ echo "${dash} ${sha} ${etc}"
+ ;;
+ esac
+done <<< "$(git log --check --pretty=format:"---% h% s" "${baseCommit}"..)"
+
+if test ${#problems[*]} -gt 0
+then
+ if test -z "${goodParent}"
+ then
+ goodParent=${baseCommit: 0:7}
+ fi
+
+ echo "A whitespace issue was found in onen of more of the commits."
+ echo "Run the following command to resolve whitespace issues:"
+ echo "git rebase --whitespace=fix ${goodParent}"
+
+ # If target output file is provided, write formatted output.
+ if test -n "$outputFile"
+ then
+ echo "🛑 Please review the Summary output for further information."
+ (
+ echo "### :x: A whitespace issue was found in one or more of the commits."
+ echo ""
+ echo "Run these commands to correct the problem:"
+ echo "1. \`git rebase --whitespace=fix ${goodParent}\`"
+ echo "1. \`git push --force\`"
+ echo ""
+ echo "Errors:"
+
+ for i in "${problems[@]}"
+ do
+ echo "${i}"
+ done
+ ) >"$outputFile"
+ fi
+
+ exit 2
+fi
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index fa0c00c..6ec0f85 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -1,34 +1,69 @@
-#!/usr/bin/env bash
+#!/bin/sh
#
# Install dependencies required to build and test Git on Linux and macOS
#
. ${0%/*}/lib.sh
+begin_group "Install dependencies"
+
P4WHENCE=https://cdist2.perforce.com/perforce/r21.2
LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION
-UBUNTU_COMMON_PKGS="make libssl-dev libcurl4-openssl-dev libexpat-dev
- tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl
- libemail-valid-perl libio-socket-ssl-perl libnet-smtp-ssl-perl"
+JGITWHENCE=https://repo.eclipse.org/content/groups/releases//org/eclipse/jgit/org.eclipse.jgit.pgm/6.8.0.202311291450-r/org.eclipse.jgit.pgm-6.8.0.202311291450-r.sh
-case "$runs_on_pool" in
+# Make sudo a no-op and execute the command directly when running as root.
+# While using sudo would be fine on most platforms when we are root already,
+# some platforms like e.g. Alpine Linux do not have sudo available by default
+# and would thus break.
+if test "$(id -u)" -eq 0
+then
+ sudo () {
+ "$@"
+ }
+fi
+
+case "$distro" in
+alpine-*)
+ apk add --update shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
+ pcre2-dev python3 musl-libintl perl-utils ncurses \
+ apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \
+ bash cvs gnupg perl-cgi perl-dbd-sqlite perl-io-tty >/dev/null
+ ;;
+fedora-*)
+ dnf -yq update >/dev/null &&
+ dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
+ ;;
ubuntu-*)
+ # Required so that apt doesn't wait for user input on certain packages.
+ export DEBIAN_FRONTEND=noninteractive
+
sudo apt-get -q update
- sudo apt-get -q -y install language-pack-is libsvn-perl apache2 \
- $UBUNTU_COMMON_PKGS $CC_PACKAGE $PYTHON_PACKAGE
- mkdir --parents "$P4_PATH"
- pushd "$P4_PATH"
- wget --quiet "$P4WHENCE/bin.linux26x86_64/p4d"
- wget --quiet "$P4WHENCE/bin.linux26x86_64/p4"
- chmod u+x p4d
- chmod u+x p4
- popd
- mkdir --parents "$GIT_LFS_PATH"
- pushd "$GIT_LFS_PATH"
- wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
- tar --extract --gunzip --file "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
- cp git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs .
- popd
+ sudo apt-get -q -y install \
+ language-pack-is libsvn-perl apache2 cvs cvsps git gnupg subversion \
+ make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \
+ tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \
+ libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \
+ ${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE
+
+ mkdir --parents "$CUSTOM_PATH"
+ wget --quiet --directory-prefix="$CUSTOM_PATH" \
+ "$P4WHENCE/bin.linux26x86_64/p4d" "$P4WHENCE/bin.linux26x86_64/p4"
+ chmod a+x "$CUSTOM_PATH/p4d" "$CUSTOM_PATH/p4"
+
+ wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
+ tar -xzf "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" \
+ -C "$CUSTOM_PATH" --strip-components=1 "git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs"
+ rm "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
+
+ wget --quiet "$JGITWHENCE" --output-document="$CUSTOM_PATH/jgit"
+ chmod a+x "$CUSTOM_PATH/jgit"
+ ;;
+ubuntu32-*)
+ sudo linux32 --32bit i386 sh -c '
+ apt update >/dev/null &&
+ apt install -y build-essential libcurl4-openssl-dev \
+ libssl-dev libexpat-dev gettext python >/dev/null
+ '
;;
macos-*)
export HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1
@@ -36,12 +71,11 @@
# brew install gnu-time
brew link --force gettext
- mkdir -p "$P4_PATH"
- pushd "$P4_PATH"
- wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" &&
- tar -xf helix-core-server.tgz &&
- sudo xattr -d com.apple.quarantine p4 p4d 2>/dev/null || true
- popd
+ mkdir -p "$CUSTOM_PATH"
+ wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" &&
+ tar -xf helix-core-server.tgz -C "$CUSTOM_PATH" p4 p4d &&
+ sudo xattr -d com.apple.quarantine "$CUSTOM_PATH/p4" "$CUSTOM_PATH/p4d" 2>/dev/null || true
+ rm helix-core-server.tgz
if test -n "$CC_PACKAGE"
then
@@ -70,10 +104,6 @@
test -n "$ALREADY_HAVE_ASCIIDOCTOR" ||
sudo gem install --version 1.5.8 asciidoctor
;;
-linux-gcc-default)
- sudo apt-get -q update
- sudo apt-get -q -y install $UBUNTU_COMMON_PKGS
- ;;
esac
if type p4d >/dev/null 2>&1 && type p4 >/dev/null 2>&1
@@ -85,6 +115,7 @@
else
echo >&2 "WARNING: perforce wasn't installed, see above for clues why"
fi
+
if type git-lfs >/dev/null 2>&1
then
echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)"
@@ -92,3 +123,13 @@
else
echo >&2 "WARNING: git-lfs wasn't installed, see above for clues why"
fi
+
+if type jgit >/dev/null 2>&1
+then
+ echo "$(tput setaf 6)JGit Version$(tput sgr0)"
+ jgit version
+else
+ echo >&2 "WARNING: JGit wasn't installed, see above for clues why"
+fi
+
+end_group "Install dependencies"
diff --git a/ci/install-docker-dependencies.sh b/ci/install-docker-dependencies.sh
deleted file mode 100755
index eb2c9e1..0000000
--- a/ci/install-docker-dependencies.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-#
-# Install dependencies required to build and test Git inside container
-#
-
-. ${0%/*}/lib.sh
-
-begin_group "Install dependencies"
-
-case "$jobname" in
-linux32)
- linux32 --32bit i386 sh -c '
- apt update >/dev/null &&
- apt install -y build-essential libcurl4-openssl-dev \
- libssl-dev libexpat-dev gettext python >/dev/null
- '
- ;;
-linux-musl)
- apk add --update shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
- pcre2-dev python3 musl-libintl perl-utils ncurses \
- apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \
- bash cvs gnupg perl-cgi perl-dbd-sqlite >/dev/null
- ;;
-linux-*|StaticAnalysis)
- # Required so that apt doesn't wait for user input on certain packages.
- export DEBIAN_FRONTEND=noninteractive
-
- apt update -q &&
- apt install -q -y sudo git make language-pack-is libsvn-perl apache2 libssl-dev \
- libcurl4-openssl-dev libexpat-dev tcl tk gettext zlib1g-dev \
- perl-modules liberror-perl libauthen-sasl-perl libemail-valid-perl \
- libdbd-sqlite3-perl libio-socket-ssl-perl libnet-smtp-ssl-perl ${CC_PACKAGE:-${CC:-gcc}} \
- apache2 cvs cvsps gnupg libcgi-pm-perl subversion
-
- if test "$jobname" = StaticAnalysis
- then
- apt install -q -y coccinelle
- fi
- ;;
-pedantic)
- dnf -yq update >/dev/null &&
- dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
- ;;
-esac
-
-end_group "Install dependencies"
diff --git a/ci/lib.sh b/ci/lib.sh
index 0a73fc7..814578f 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -18,7 +18,7 @@
then
begin_group () {
need_to_end_group=t
- printf "\e[0Ksection_start:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K$1\n"
+ printf "\e[0Ksection_start:$(date +%s):$(echo "$1" | tr ' ' _)[collapsed=true]\r\e[0K$1\n"
trap "end_group '$1'" EXIT
set -x
}
@@ -279,7 +279,7 @@
cache_dir="$HOME/none"
- runs_on_pool=$(echo "$CI_JOB_IMAGE" | tr : -)
+ distro=$(echo "$CI_JOB_IMAGE" | tr : -)
JOBS=$(nproc)
else
echo "Could not identify CI type" >&2
@@ -318,16 +318,20 @@
export GIT_TEST_CLONE_2GB=true
export SKIP_DASHED_BUILT_INS=YesPlease
-case "$runs_on_pool" in
+case "$distro" in
ubuntu-*)
if test "$jobname" = "linux-gcc-default"
then
break
fi
- PYTHON_PACKAGE=python2
- if test "$jobname" = linux-gcc
+ # Python 2 is end of life, and Ubuntu 23.04 and newer don't actually
+ # have it anymore. We thus only test with Python 2 on older LTS
+ # releases.
+ if test "$distro" = "ubuntu-20.04"
then
+ PYTHON_PACKAGE=python2
+ else
PYTHON_PACKAGE=python3
fi
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/$PYTHON_PACKAGE"
@@ -340,10 +344,6 @@
# image.
# Keep that in mind when you encounter a broken OS X build!
export LINUX_GIT_LFS_VERSION="1.5.2"
-
- P4_PATH="$HOME/custom/p4"
- GIT_LFS_PATH="$HOME/custom/git-lfs"
- export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH"
;;
macos-*)
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
@@ -351,12 +351,12 @@
then
MAKEFLAGS="$MAKEFLAGS APPLE_COMMON_CRYPTO_SHA1=Yes"
fi
-
- P4_PATH="$HOME/custom/p4"
- export PATH="$P4_PATH:$PATH"
;;
esac
+CUSTOM_PATH="${CUSTOM_PATH:-$HOME/path}"
+export PATH="$CUSTOM_PATH:$PATH"
+
case "$jobname" in
linux32)
CC=gcc
diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh
index a51076d..797d65c 100755
--- a/ci/run-build-and-minimal-fuzzers.sh
+++ b/ci/run-build-and-minimal-fuzzers.sh
@@ -7,7 +7,7 @@
group "Build fuzzers" make \
CC=clang \
- CXX=clang++ \
+ FUZZ_CXX=clang++ \
CFLAGS="-fsanitize=fuzzer-no-link,address" \
LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \
fuzz-all
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index c192bd6..98dda42 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -53,8 +53,6 @@
then
group "Run tests" make test ||
handle_failed_tests
- group "Run unit tests" \
- make DEFAULT_UNIT_TEST_TARGET=unit-tests-prove unit-tests
fi
check_unignored_build_artifacts
diff --git a/ci/run-test-slice.sh b/ci/run-test-slice.sh
index ae80943..e167e64 100755
--- a/ci/run-test-slice.sh
+++ b/ci/run-test-slice.sh
@@ -17,7 +17,7 @@
# We only have one unit test at the moment, so run it in the first slice
if [ "$1" == "0" ] ; then
- group "Run unit tests" make --quiet -C t unit-tests-prove
+ group "Run unit tests" make --quiet -C t unit-tests-test-tool
fi
check_unignored_build_artifacts
diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh
index de41888..02b3af3 100755
--- a/ci/test-documentation.sh
+++ b/ci/test-documentation.sh
@@ -11,6 +11,7 @@
-e '/^ \* new asciidoc flags$/d' \
-e '/stripped namespace before processing/d' \
-e '/Attributed.*IDs for element/d' \
+ -e '/SyntaxWarning: invalid escape sequence/d' \
"$1"
}
diff --git a/color.c b/color.c
index f663c06..227a5ab 100644
--- a/color.c
+++ b/color.c
@@ -64,12 +64,16 @@
return !strncasecmp(word, match, len) && !match[len];
}
-static int get_hex_color(const char *in, unsigned char *out)
+static int get_hex_color(const char **inp, int width, unsigned char *out)
{
+ const char *in = *inp;
unsigned int val;
- val = (hexval(in[0]) << 4) | hexval(in[1]);
+
+ assert(width == 1 || width == 2);
+ val = (hexval(in[0]) << 4) | hexval(in[width - 1]);
if (val & ~0xff)
return -1;
+ *inp += width;
*out = val;
return 0;
}
@@ -135,11 +139,14 @@
return 0;
}
- /* Try a 24-bit RGB value */
- if (len == 7 && name[0] == '#') {
- if (!get_hex_color(name + 1, &out->red) &&
- !get_hex_color(name + 3, &out->green) &&
- !get_hex_color(name + 5, &out->blue)) {
+ /* Try a 24- or 12-bit RGB value prefixed with '#' */
+ if ((len == 7 || len == 4) && name[0] == '#') {
+ int width_per_color = (len == 7) ? 2 : 1;
+ const char *color = name + 1;
+
+ if (!get_hex_color(&color, width_per_color, &out->red) &&
+ !get_hex_color(&color, width_per_color, &out->green) &&
+ !get_hex_color(&color, width_per_color, &out->blue)) {
out->type = COLOR_RGB;
return 0;
}
diff --git a/color.h b/color.h
index bb28343..7ed259a 100644
--- a/color.h
+++ b/color.h
@@ -112,7 +112,8 @@
* Translate a Git color from 'value' into a string that the terminal can
* interpret and store it into 'dst'. The Git color values are of the form
* "foreground [background] [attr]" where fore- and background can be a color
- * name ("red"), a RGB code (#0xFF0000) or a 256-color-mode from the terminal.
+ * name ("red"), a RGB code (#FF0000 or #F00) or a 256-color-mode from the
+ * terminal.
*/
int color_parse(const char *value, char *dst);
int color_parse_mem(const char *value, int len, char *dst);
diff --git a/combine-diff.c b/combine-diff.c
index d6d6fa1..4960d90 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1066,7 +1066,8 @@
elem->mode = canon_mode(st.st_mode);
} else if (S_ISDIR(st.st_mode)) {
struct object_id oid;
- if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, elem->path,
+ "HEAD", &oid) < 0)
result = grab_blob(opt->repo, &elem->oid,
elem->mode, &result_size,
NULL, NULL);
diff --git a/command-list.txt b/command-list.txt
index c4cd0f3..e0bb87b 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -157,6 +157,7 @@
git-rebase mainporcelain history
git-receive-pack synchelpers
git-reflog ancillarymanipulators complete
+git-refs ancillarymanipulators complete
git-remote ancillarymanipulators complete
git-repack ancillarymanipulators complete
git-replace ancillarymanipulators complete
diff --git a/commit-graph.c b/commit-graph.c
index 45417d7..41a2e1b 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1597,7 +1597,7 @@
timestamp_t gen;
repo_parse_commit(info->r, c);
gen = info->get_generation(c, info->data);
- display_progress(info->progress, info->progress_cnt + 1);
+ display_progress(info->progress, ++info->progress_cnt);
if (gen != GENERATION_NUMBER_ZERO && gen != GENERATION_NUMBER_INFINITY)
continue;
@@ -1821,7 +1821,7 @@
struct object_id peeled;
struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) == OBJ_COMMIT)
oidset_insert(data->commits, oid);
@@ -1845,7 +1845,8 @@
data.progress = start_delayed_progress(
_("Collecting referenced commits"), 0);
- for_each_ref(add_ref_to_set, &data);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,
+ &data);
stop_progress(&data.progress);
diff --git a/commit-reach.c b/commit-reach.c
index 8f9b008..384aee1 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -1106,6 +1106,10 @@
/* STALE is used here, PARENT2 is used by insert_no_dup(). */
repo_clear_commit_marks(r, PARENT2 | STALE);
+ while (prio_queue_peek(&queue)) {
+ struct commit *c = prio_queue_get(&queue);
+ free_bit_array(c);
+ }
clear_bit_arrays(&bit_arrays);
clear_prio_queue(&queue);
}
diff --git a/commit.c b/commit.c
index 1a479a9..1d08951 100644
--- a/commit.c
+++ b/commit.c
@@ -1070,7 +1070,8 @@
memset(&revs, 0, sizeof(revs));
revs.initial = 1;
- for_each_reflog_ent(full_refname, collect_one_reflog_ent, &revs);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ full_refname, collect_one_reflog_ent, &revs);
if (!revs.nr)
add_one_commit(&oid, &revs);
diff --git a/common-main.c b/common-main.c
index 033778b..b86f406 100644
--- a/common-main.c
+++ b/common-main.c
@@ -48,7 +48,7 @@
setlocale(LC_CTYPE, "");
git_setup_gettext();
- initialize_the_repository();
+ initialize_repository(the_repository);
attr_start();
diff --git a/compat/basename.c b/compat/basename.c
index 96bd953..c33579e 100644
--- a/compat/basename.c
+++ b/compat/basename.c
@@ -10,7 +10,13 @@
skip_dos_drive_prefix(&path);
if (!path || !*path)
- return ".";
+ /*
+ * basename(3P) is mis-specified because it returns a
+ * non-constant pointer even though it is specified to return a
+ * pointer to internal memory at times. The cast is a result of
+ * that.
+ */
+ return (char *) ".";
for (base = path; *path; path++) {
if (!is_dir_sep(*path))
@@ -34,7 +40,13 @@
int dos_drive_prefix;
if (!p)
- return ".";
+ /*
+ * dirname(3P) is mis-specified because it returns a
+ * non-constant pointer even though it is specified to return a
+ * pointer to internal memory at times. The cast is a result of
+ * that.
+ */
+ return (char *) ".";
if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p)
goto dot;
diff --git a/compat/mingw.c b/compat/mingw.c
index 4876344..d378cd0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2279,7 +2279,11 @@
p->pw_name = user_name;
p->pw_gecos = get_extended_user_info(NameDisplay);
if (!p->pw_gecos)
- p->pw_gecos = "unknown";
+ /*
+ * Data ret