aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml9
-rw-r--r--.gitignore3
-rw-r--r--.gitlab-ci.yml6
-rw-r--r--Documentation/.gitignore2
-rw-r--r--Documentation/CodingGuidelines22
-rw-r--r--Documentation/Makefile53
-rw-r--r--Documentation/RelNotes/2.48.0.txt80
-rw-r--r--Documentation/asciidoc.conf.in (renamed from Documentation/asciidoc.conf)3
-rw-r--r--Documentation/asciidoctor-extensions.rb.in (renamed from Documentation/asciidoctor-extensions.rb)8
-rwxr-xr-xDocumentation/build-docdep.perl2
-rwxr-xr-xDocumentation/cmd-list.perl23
-rw-r--r--Documentation/config/diff.txt2
-rw-r--r--Documentation/config/extensions.txt6
-rw-r--r--Documentation/config/merge.txt2
-rw-r--r--Documentation/config/remote.txt13
-rw-r--r--Documentation/config/worktree.txt10
-rwxr-xr-xDocumentation/generate-mergetool-list.sh17
-rw-r--r--Documentation/git-bundle.txt2
-rw-r--r--Documentation/git-clone.txt9
-rw-r--r--Documentation/git-update-ref.txt8
-rw-r--r--Documentation/git-worktree.txt8
-rw-r--r--Documentation/git.txt32
-rw-r--r--Documentation/gitcli.txt9
-rw-r--r--Documentation/gitcredentials.txt6
-rw-r--r--Documentation/meson.build324
-rw-r--r--Documentation/rev-list-options.txt3
-rw-r--r--Documentation/technical/build-systems.txt224
-rw-r--r--GIT-BUILD-OPTIONS.in47
-rw-r--r--GIT-VERSION-FILE.in1
-rwxr-xr-xGIT-VERSION-GEN76
-rw-r--r--Makefile253
-rw-r--r--advice.c3
-rw-r--r--advice.h1
-rw-r--r--attr.c40
-rw-r--r--attr.h43
-rw-r--r--bin-wrappers/.gitignore9
-rw-r--r--bin-wrappers/meson.build28
-rwxr-xr-xbin-wrappers/wrap-for-bin.sh37
-rw-r--r--branch.c2
-rw-r--r--builtin/branch.c10
-rw-r--r--builtin/bundle.c2
-rw-r--r--builtin/cat-file.c7
-rw-r--r--builtin/check-ref-format.c2
-rw-r--r--builtin/checkout.c2
-rw-r--r--builtin/count-objects.c2
-rw-r--r--builtin/describe.c16
-rw-r--r--builtin/fast-import.c21
-rw-r--r--builtin/fetch.c141
-rw-r--r--builtin/fsck.c20
-rw-r--r--builtin/gc.c12
-rw-r--r--builtin/index-pack.c125
-rw-r--r--builtin/log.c8
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/multi-pack-index.c6
-rw-r--r--builtin/pack-objects.c11
-rw-r--r--builtin/pack-redundant.c2
-rw-r--r--builtin/remote.c82
-rw-r--r--builtin/repack.c4
-rw-r--r--builtin/rev-list.c2
-rw-r--r--builtin/tag.c13
-rw-r--r--builtin/upload-pack.c5
-rw-r--r--builtin/worktree.c37
-rw-r--r--bundle-uri.c7
-rw-r--r--bundle.c43
-rw-r--r--bundle.h17
-rwxr-xr-xci/install-dependencies.sh19
-rwxr-xr-xci/lib.sh11
-rwxr-xr-xci/run-build-and-minimal-fuzzers.sh13
-rwxr-xr-xci/test-documentation.sh2
-rw-r--r--commit-graph.c4
-rw-r--r--commit.c2
-rw-r--r--config.c22
-rw-r--r--configure.ac2
-rw-r--r--connected.c3
-rw-r--r--contrib/buildsystems/CMakeLists.txt302
-rw-r--r--contrib/buildsystems/git-version.in1
-rw-r--r--contrib/completion/git-completion.bash2
-rw-r--r--contrib/completion/meson.build16
-rw-r--r--contrib/meson.build1
-rw-r--r--daemon.c6
-rw-r--r--diff.c3
-rw-r--r--environment.c3
-rw-r--r--environment.h1
-rw-r--r--fetch-pack.c26
-rw-r--r--fetch-pack.h11
-rw-r--r--fsck.c2
-rwxr-xr-xgenerate-cmdlist.sh42
-rwxr-xr-xgenerate-configlist.sh20
-rwxr-xr-xgenerate-hooklist.sh15
-rwxr-xr-xgenerate-perl.sh37
-rwxr-xr-xgenerate-python.sh20
-rwxr-xr-xgenerate-script.sh34
-rwxr-xr-xgit-cvsserver.perl2
-rwxr-xr-xgit-difftool--helper.sh8
-rwxr-xr-xgit-instaweb.sh8
-rw-r--r--git-mergetool--lib.sh12
-rwxr-xr-xgit-request-pull.sh2
-rwxr-xr-xgit-send-email.perl2
-rw-r--r--git-sh-i18n.sh6
-rw-r--r--git-sh-setup.sh6
-rwxr-xr-xgit-svn.perl2
-rw-r--r--git.rc.in (renamed from git.rc)6
-rwxr-xr-xgitk-git/gitk86
-rw-r--r--gitk-git/po/sv.po734
-rw-r--r--gitweb/GITWEB-BUILD-OPTIONS.in24
-rw-r--r--gitweb/Makefile62
-rwxr-xr-xgitweb/generate-gitweb-cgi.sh47
-rwxr-xr-xgitweb/generate-gitweb-js.sh12
-rwxr-xr-xgitweb/gitweb.perl46
-rw-r--r--gitweb/meson.build89
-rw-r--r--hook.c2
-rw-r--r--http.c4
-rw-r--r--list-objects.c7
-rw-r--r--meson.build1901
-rw-r--r--meson_options.txt81
-rw-r--r--midx-write.c129
-rw-r--r--midx.c88
-rw-r--r--midx.h27
-rw-r--r--object-name.c42
-rw-r--r--object-store-ll.h9
-rw-r--r--oss-fuzz/.gitignore3
-rw-r--r--oss-fuzz/fuzz-credential-from-url-gently.c32
-rw-r--r--oss-fuzz/fuzz-parse-attr-line.c41
-rw-r--r--oss-fuzz/fuzz-url-decode-mem.c43
-rw-r--r--pack-bitmap.c95
-rw-r--r--pack-objects.h3
-rw-r--r--pack-revindex.c2
-rw-r--r--pack-write.c1
-rw-r--r--pack.h2
-rw-r--r--packfile.c144
-rw-r--r--packfile.h18
-rw-r--r--path.c10
-rw-r--r--path.h17
-rw-r--r--perl/FromCPAN/Mail/meson.build7
-rw-r--r--perl/FromCPAN/meson.build9
-rw-r--r--perl/Git/I18N.pm6
-rw-r--r--perl/Git/LoadCPAN.pm6
-rw-r--r--perl/Git/LoadCPAN/Mail/meson.build7
-rw-r--r--perl/Git/LoadCPAN/meson.build9
-rw-r--r--perl/Git/SVN/Memoize/meson.build7
-rw-r--r--perl/Git/SVN/meson.build20
-rw-r--r--perl/Git/meson.build18
-rw-r--r--perl/header_templates/fixed_prefix.template.pl2
-rw-r--r--perl/header_templates/runtime_prefix.template.pl8
-rw-r--r--perl/meson.build12
-rw-r--r--po/meson.build27
-rw-r--r--promisor-remote.c2
-rw-r--r--prune-packed.c2
-rw-r--r--reachable.c4
-rw-r--r--refs.c94
-rw-r--r--refs.h48
-rw-r--r--refs/files-backend.c31
-rw-r--r--refs/refs-internal.h5
-rw-r--r--refs/reftable-backend.c438
-rw-r--r--reftable/basics.c20
-rw-r--r--reftable/basics.h10
-rw-r--r--reftable/merged.c18
-rw-r--r--reftable/merged.h3
-rw-r--r--reftable/reader.c14
-rw-r--r--reftable/reader.h4
-rw-r--r--reftable/reftable-basics.h13
-rw-r--r--reftable/reftable-merged.h4
-rw-r--r--reftable/reftable-reader.h2
-rw-r--r--reftable/reftable-record.h12
-rw-r--r--reftable/reftable-stack.h3
-rw-r--r--reftable/reftable-writer.h17
-rw-r--r--reftable/stack.c207
-rw-r--r--reftable/system.c126
-rw-r--r--reftable/system.h89
-rw-r--r--reftable/writer.c32
-rw-r--r--remote.c18
-rw-r--r--remote.h10
-rw-r--r--repo-settings.c18
-rw-r--r--repo-settings.h7
-rw-r--r--repository.c1
-rw-r--r--repository.h1
-rw-r--r--revision.c13
-rw-r--r--setup.c39
-rw-r--r--setup.h1
-rw-r--r--strbuf.h22
-rw-r--r--strvec.c11
-rw-r--r--subprojects/.gitignore1
-rw-r--r--subprojects/curl.wrap13
-rw-r--r--subprojects/expat.wrap13
-rw-r--r--subprojects/openssl.wrap15
-rw-r--r--subprojects/pcre2.wrap16
-rw-r--r--subprojects/zlib.wrap13
-rw-r--r--t/helper/meson.build91
-rw-r--r--t/helper/test-read-midx.c8
-rw-r--r--t/helper/test-reftable.c4
-rw-r--r--t/lib-gettext.sh4
-rw-r--r--t/meson.build1114
-rwxr-xr-xt/perf/p6100-describe.sh30
-rwxr-xr-xt/t0001-init.sh22
-rwxr-xr-xt/t0018-advice.sh2
-rwxr-xr-xt/t0411-clone-from-partial.sh3
-rwxr-xr-xt/t1500-rev-parse.sh15
-rwxr-xr-xt/t2400-worktree-add.sh46
-rwxr-xr-xt/t2401-worktree-prune.sh3
-rwxr-xr-xt/t2402-worktree-list.sh22
-rwxr-xr-xt/t2403-worktree-move.sh25
-rwxr-xr-xt/t2406-worktree-repair.sh39
-rwxr-xr-xt/t2408-worktree-relative.sh38
-rwxr-xr-xt/t3200-branch.sh2
-rwxr-xr-xt/t3404-rebase-interactive.sh6
-rwxr-xr-xt/t3501-revert-cherry-pick.sh2
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh6
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh2
-rwxr-xr-xt/t3511-cherry-pick-x.sh2
-rwxr-xr-xt/t3602-rm-sparse-checkout.sh2
-rwxr-xr-xt/t3700-add.sh6
-rwxr-xr-xt/t3705-add-sparse-checkout.sh2
-rwxr-xr-xt/t4069-remerge-diff.sh7
-rwxr-xr-xt/t4207-log-decoration-colors.sh3
-rwxr-xr-xt/t5504-fetch-receive-strict.sh6
-rwxr-xr-xt/t5505-remote.sh118
-rwxr-xr-xt/t5510-fetch.sh179
-rwxr-xr-xt/t5512-ls-remote.sh2
-rwxr-xr-xt/t5514-fetch-multiple.sh17
-rwxr-xr-xt/t5516-fetch-push.sh3
-rwxr-xr-xt/t5527-fetch-odd-refs.sh3
-rwxr-xr-xt/t5604-clone-reference.sh6
-rwxr-xr-xt/t5605-clone-local.sh10
-rwxr-xr-xt/t5607-clone-bundle.sh7
-rwxr-xr-xt/t6020-bundle-misc.sh44
-rwxr-xr-xt/t6120-describe.sh24
-rwxr-xr-xt/t7002-mv-sparse-checkout.sh4
-rwxr-xr-xt/t7004-tag.sh14
-rwxr-xr-xt/t7201-co.sh4
-rwxr-xr-xt/t7400-submodule-basic.sh2
-rwxr-xr-xt/t7508-status.sh2
-rwxr-xr-xt/t7609-mergetool--lib.sh2
-rwxr-xr-xt/t7610-mergetool.sh8
-rwxr-xr-xt/t7900-maintenance.sh3
-rwxr-xr-xt/t9210-scalar.sh5
-rwxr-xr-xt/t9211-scalar-clone.sh6
-rwxr-xr-xt/t9300-fast-import.sh113
-rwxr-xr-xt/t9350-fast-export.sh2
-rwxr-xr-xt/t9902-completion.sh65
-rw-r--r--t/test-lib.sh31
-rw-r--r--t/unit-tests/lib-reftable.c5
-rw-r--r--t/unit-tests/lib-reftable.h2
-rw-r--r--t/unit-tests/strvec.c10
-rw-r--r--t/unit-tests/t-reftable-block.c41
-rw-r--r--t/unit-tests/t-reftable-merged.c99
-rw-r--r--t/unit-tests/t-reftable-pq.c3
-rw-r--r--t/unit-tests/t-reftable-reader.c4
-rw-r--r--t/unit-tests/t-reftable-readwrite.c88
-rw-r--r--t/unit-tests/t-reftable-record.c59
-rw-r--r--t/unit-tests/t-reftable-stack.c45
-rw-r--r--tag.c2
-rw-r--r--templates/Makefile39
-rw-r--r--templates/branches--1
-rw-r--r--templates/description (renamed from templates/this--description)0
-rwxr-xr-xtemplates/hooks/applypatch-msg.sample (renamed from templates/hooks--applypatch-msg.sample)0
-rwxr-xr-xtemplates/hooks/commit-msg.sample (renamed from templates/hooks--commit-msg.sample)0
-rwxr-xr-xtemplates/hooks/fsmonitor-watchman.sample (renamed from templates/hooks--fsmonitor-watchman.sample)0
-rw-r--r--templates/hooks/meson.build26
-rwxr-xr-xtemplates/hooks/post-update.sample (renamed from templates/hooks--post-update.sample)0
-rwxr-xr-xtemplates/hooks/pre-applypatch.sample (renamed from templates/hooks--pre-applypatch.sample)0
-rwxr-xr-xtemplates/hooks/pre-commit.sample (renamed from templates/hooks--pre-commit.sample)0
-rwxr-xr-xtemplates/hooks/pre-merge-commit.sample (renamed from templates/hooks--pre-merge-commit.sample)0
-rwxr-xr-xtemplates/hooks/pre-push.sample (renamed from templates/hooks--pre-push.sample)0
-rwxr-xr-xtemplates/hooks/pre-rebase.sample (renamed from templates/hooks--pre-rebase.sample)0
-rwxr-xr-xtemplates/hooks/pre-receive.sample (renamed from templates/hooks--pre-receive.sample)0
-rwxr-xr-xtemplates/hooks/prepare-commit-msg.sample (renamed from templates/hooks--prepare-commit-msg.sample)0
-rwxr-xr-xtemplates/hooks/push-to-checkout.sample (renamed from templates/hooks--push-to-checkout.sample)0
-rwxr-xr-xtemplates/hooks/sendemail-validate.sample (renamed from templates/hooks--sendemail-validate.sample)0
-rwxr-xr-xtemplates/hooks/update.sample (renamed from templates/hooks--update.sample)0
-rw-r--r--templates/info/exclude (renamed from templates/info--exclude)0
-rw-r--r--templates/info/meson.build7
-rw-r--r--templates/meson.build15
-rw-r--r--transport.c26
-rw-r--r--unimplemented.sh2
-rw-r--r--version-def.h.in8
-rw-r--r--version.c1
-rw-r--r--worktree.c157
-rw-r--r--worktree.h22
-rw-r--r--wrap-for-bin.sh36
279 files changed, 8829 insertions, 2103 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 9301a1edd6..808ddc19b8 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -342,12 +342,21 @@ jobs:
- jobname: linux-musl
image: alpine
distro: alpine-latest
+ # Supported until 2025-04-02.
- jobname: linux32
image: i386/ubuntu:focal
distro: ubuntu32-20.04
- jobname: pedantic
image: fedora
distro: fedora-latest
+ # A RHEL 8 compatible distro. Supported until 2029-05-31.
+ - jobname: almalinux-8
+ image: almalinux:8
+ distro: almalinux-8
+ # Supported until 2026-08-31.
+ - jobname: debian-11
+ image: debian:11
+ distro: debian-11
env:
jobname: ${{matrix.vector.jobname}}
distro: ${{matrix.vector.distro}}
diff --git a/.gitignore b/.gitignore
index 6687bd6db4..e82aa19df0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,7 +12,6 @@
/GIT-TEST-SUITES
/GIT-USER-AGENT
/GIT-VERSION-FILE
-/bin-wrappers/
/git
/git-add
/git-am
@@ -195,9 +194,11 @@
/config-list.h
/command-list.h
/hook-list.h
+/version-def.h
*.tar.gz
*.dsc
*.deb
+/git.rc
/git.spec
*.exe
*.[aos]
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 526ecfe030..008966cae4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -35,7 +35,7 @@ test:linux:
parallel:
matrix:
- jobname: linux-old
- image: ubuntu:16.04
+ image: ubuntu:20.04
CC: gcc
- jobname: linux-sha256
image: ubuntu:latest
@@ -99,10 +99,10 @@ test:osx:
parallel:
matrix:
- jobname: osx-clang
- image: macos-13-xcode-14
+ image: macos-14-xcode-15
CC: clang
- jobname: osx-reftable
- image: macos-13-xcode-14
+ image: macos-14-xcode-15
CC: clang
artifacts:
paths:
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
index a48448de32..649df89474 100644
--- a/Documentation/.gitignore
+++ b/Documentation/.gitignore
@@ -15,3 +15,5 @@ tmp-doc-diff/
GIT-ASCIIDOCFLAGS
/.build/
/GIT-EXCLUDED-PROGRAMS
+/asciidoc.conf
+/asciidoctor-extensions.rb
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 87904791cb..ba047ed224 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -583,7 +583,7 @@ For C programs:
Run `GIT_DEBUGGER=1 ./bin-wrappers/git foo` to simply use gdb as is, or
run `GIT_DEBUGGER="<debugger> <debugger-args>" ./bin-wrappers/git foo` to
use your own debugger and arguments. Example: `GIT_DEBUGGER="ddd --gdb"
- ./bin-wrappers/git log` (See `wrap-for-bin.sh`.)
+ ./bin-wrappers/git log` (See `bin-wrappers/wrap-for-bin.sh`.)
- The primary data structure that a subsystem 'S' deals with is called
`struct S`. Functions that operate on `struct S` are named
@@ -703,16 +703,30 @@ Program Output
Error Messages
- - Do not end error messages with a full stop.
+ - Do not end a single-sentence error message with a full stop.
- Do not capitalize the first word, only because it is the first word
- in the message ("unable to open %s", not "Unable to open %s"). But
+ in the message ("unable to open '%s'", not "Unable to open '%s'"). But
"SHA-3 not supported" is fine, because the reason the first word is
capitalized is not because it is at the beginning of the sentence,
but because the word would be spelled in capital letters even when
it appeared in the middle of the sentence.
- - Say what the error is first ("cannot open %s", not "%s: cannot open")
+ - Say what the error is first ("cannot open '%s'", not "%s: cannot open").
+
+ - Enclose the subject of an error inside a pair of single quotes,
+ e.g. `die(_("unable to open '%s'"), path)`.
+
+ - Unless there is a compelling reason not to, error messages from
+ porcelain commands should be marked for translation, e.g.
+ `die(_("bad revision %s"), revision)`.
+
+ - Error messages from the plumbing commands are sometimes meant for
+ machine consumption and should not be marked for translation,
+ e.g., `die("bad revision %s", revision)`.
+
+ - BUG("message") are for communicating the specific error to developers,
+ thus should not be translated.
Externally Visible Names
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 0f55baa252..3392e1ce7e 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,6 +1,8 @@
# Import tree-wide shared Makefile behavior and libraries
include ../shared.mak
+.PHONY: FORCE
+
# Guard against environment variables
MAN1_TXT =
MAN5_TXT =
@@ -111,6 +113,7 @@ TECH_DOCS += MyFirstObjectWalk
TECH_DOCS += SubmittingPatches
TECH_DOCS += ToolsForGit
TECH_DOCS += technical/bitmap-format
+TECH_DOCS += technical/build-systems
TECH_DOCS += technical/bundle-uri
TECH_DOCS += technical/hash-function-transition
TECH_DOCS += technical/long-running-process-protocol
@@ -148,16 +151,12 @@ man5dir = $(mandir)/man5
man7dir = $(mandir)/man7
# DESTDIR =
-GIT_DATE := $(shell git show --quiet --pretty='%as')
-
ASCIIDOC = asciidoc
ASCIIDOC_EXTRA =
ASCIIDOC_HTML = xhtml11
ASCIIDOC_DOCBOOK = docbook
ASCIIDOC_CONF = -f asciidoc.conf
-ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF) \
- -amanmanual='Git Manual' -amansource='Git $(GIT_VERSION)' \
- -arevdate='$(GIT_DATE)'
+ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF)
ASCIIDOC_DEPS = asciidoc.conf GIT-ASCIIDOCFLAGS
TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK)
@@ -210,6 +209,14 @@ ASCIIDOC_DEPS = asciidoctor-extensions.rb GIT-ASCIIDOCFLAGS
DBLATEX_COMMON =
XMLTO_EXTRA += --skip-validation
XMLTO_EXTRA += -x manpage.xsl
+
+asciidoctor-extensions.rb: asciidoctor-extensions.rb.in FORCE
+ $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@+
+ @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
+else
+asciidoc.conf: asciidoc.conf.in FORCE
+ $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@+
+ @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
endif
ASCIIDOC_DEPS += docinfo.html
@@ -218,6 +225,7 @@ SHELL_PATH ?= $(SHELL)
# Shell quote;
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+ASCIIDOC_EXTRA += -abuild_dir='$(shell pwd)'
ifdef DEFAULT_PAGER
DEFAULT_PAGER_SQ = $(subst ','\'',$(DEFAULT_PAGER))
ASCIIDOC_EXTRA += -a 'git-default-pager=$(DEFAULT_PAGER_SQ)'
@@ -275,15 +283,17 @@ ifneq ($(filter-out lint-docs clean,$(MAKECMDGOALS)),)
-include ../GIT-VERSION-FILE
endif
+mergetools_txt = mergetools-diff.txt mergetools-merge.txt
+
#
# Determine "include::" file references in asciidoc files.
#
docdep_prereqs = \
- mergetools-list.made $(mergetools_txt) \
+ $(mergetools_txt) \
cmd-list.made $(cmds_txt)
doc.dep : $(docdep_prereqs) $(DOC_DEP_TXT) build-docdep.perl
- $(QUIET_GEN)$(PERL_PATH) ./build-docdep.perl >$@ $(QUIET_STDERR)
+ $(QUIET_GEN)$(PERL_PATH) ./build-docdep.perl "$(shell pwd)" >$@ $(QUIET_STDERR)
ifneq ($(MAKECMDGOALS),clean)
-include doc.dep
@@ -305,22 +315,14 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
$(cmds_txt): cmd-list.made
cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
- $(QUIET_GEN)$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(cmds_txt) $(QUIET_STDERR) && \
+ $(QUIET_GEN)$(PERL_PATH) ./cmd-list.perl .. . $(cmds_txt) && \
date >$@
-mergetools_txt = mergetools-diff.txt mergetools-merge.txt
-
-$(mergetools_txt): mergetools-list.made
-
-mergetools-list.made: ../git-mergetool--lib.sh $(wildcard ../mergetools/*)
- $(QUIET_GEN) \
- $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && TOOL_MODE=diff && \
- . ../git-mergetool--lib.sh && \
- show_tool_names can_diff' | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >mergetools-diff.txt && \
- $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && TOOL_MODE=merge && \
- . ../git-mergetool--lib.sh && \
- show_tool_names can_merge' | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >mergetools-merge.txt && \
- date >$@
+mergetools-%.txt: generate-mergetool-list.sh ../git-mergetool--lib.sh $(wildcard ../mergetools/*)
+mergetools-diff.txt:
+ $(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. diff $@
+mergetools-merge.txt:
+ $(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. merge $@
TRACK_ASCIIDOCFLAGS = $(subst ','\'',$(ASCIIDOC_COMMON):$(ASCIIDOC_HTML):$(ASCIIDOC_DOCBOOK))
@@ -341,6 +343,7 @@ clean:
$(RM) SubmittingPatches.txt
$(RM) $(cmds_txt) $(mergetools_txt) *.made
$(RM) GIT-ASCIIDOCFLAGS
+ $(RM) asciidoc.conf asciidoctor-extensions.rb
docinfo.html: docinfo-html.in
$(QUIET_GEN)$(RM) $@ && cat $< >$@
@@ -364,7 +367,7 @@ manpage-cmd = $(QUIET_XMLTO)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
%.xml : %.txt $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d manpage -o $@ $<
-user-manual.xml: user-manual.txt user-manual.conf asciidoctor-extensions.rb GIT-ASCIIDOCFLAGS
+user-manual.xml: user-manual.txt user-manual.conf $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d book -o $@ $<
technical/api-index.txt: technical/api-index-skel.txt \
@@ -373,7 +376,7 @@ technical/api-index.txt: technical/api-index-skel.txt \
technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt \
- asciidoc.conf GIT-ASCIIDOCFLAGS
+ $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt
SubmittingPatches.txt: SubmittingPatches
@@ -416,13 +419,13 @@ $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
howto-index.txt: howto-index.sh $(HOWTO_TXT)
$(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto-index.sh $(sort $(HOWTO_TXT)) >$@
-$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
+$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt
WEBDOC_DEST = /pub/software/scm/git/docs
howto/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
-$(patsubst %.txt,%.html,$(HOWTO_TXT)): %.html : %.txt GIT-ASCIIDOCFLAGS
+$(patsubst %.txt,%.html,$(HOWTO_TXT)): %.html : %.txt $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC) \
sed -e '1,/^$$/d' $< | \
$(TXT_TO_HTML) - >$@
diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt
index b9d1b129cd..cc752d5466 100644
--- a/Documentation/RelNotes/2.48.0.txt
+++ b/Documentation/RelNotes/2.48.0.txt
@@ -21,6 +21,20 @@ UI, Workflows & Features
* Drop support for older libcURL and Perl.
+ * End-user experience of "git mergetool" when the command errors out
+ has been improved.
+
+ * "git bundle --unbundle" and "git clone" running on a bundle file
+ both learned to trigger fsck over the new objects with configurable
+ fck check levels.
+
+ * When "git fetch $remote" notices that refs/remotes/$remote/HEAD is
+ missing and discovers what branch the other side points with its
+ HEAD, refs/remotes/$remote/HEAD is updated to point to it.
+
+ * "git fetch" honors "remote.<remote>.followRemoteHEAD" settings to
+ tweak the remote-tracking HEAD in "refs/remotes/<remote>/HEAD".
+
Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
@@ -107,6 +121,26 @@ Performance, Internal Implementation, Development Support etc.
* Built-in Git subcommands are supplied the repository object to work
with; they learned to do the same when they invoke sub-subcommands.
+ * Drop support for ancient environments in various CI jobs.
+
+ * Isolates the reftable subsystem from the rest of Git's codebase by
+ using fewer pieces of Git's infrastructure.
+
+ * Optimize reading random references out of the reftable backend by
+ allowing reuse of iterator objects.
+
+ * Backport oss-fuzz tests for us to our codebase.
+
+ * Introduce a new repository extension to prevent older Git versions
+ from mis-interpreting worktrees created with relative paths.
+
+ * Yet another "pass the repository through the callchain" topic.
+
+ * "git describe" learned to stop digging the history needlessly
+ deeper.
+
+ * Build procedure update plus introduction of Meson based builds.
+
Fixes since v2.47
-----------------
@@ -204,8 +238,54 @@ Fixes since v2.47
* The sequencer failed to honor core.commentString in some places.
+ * Describe a case where an option value needs to be spelled as a
+ separate argument, i.e. "--opt val", not "--opt=val".
+ (merge 1bc1e94091 jc/doc-opt-tilde-expand later to maint).
+
+ * Loosen overly strict ownership check introduced in the recent past,
+ to keep the promise "cloning a suspicious repository is a safe
+ first step to inspect it".
+ (merge 0ffb5a6bf1 bc/allow-upload-pack-from-other-people later to maint).
+
+ * "git fast-import" learned to reject paths with ".." and "." as
+ their components to avoid creating invalid tree objects.
+ (merge 8cb4c6e62f en/fast-import-verify-path later to maint).
+
+ * The --ancestry-path option is designed to be given a commit that is
+ on the path, which was not documented, which has been corrected.
+ (merge bc1a980759 kk/doc-ancestry-path later to maint).
+
+
+ * "git tag" has been taught to refuse to create refs/tags/HEAD
+ as such a tag will be confusing in the context of UI provided by
+ the Git Porcelain commands.
+ (merge bbd445d5ef jc/forbid-head-as-tagname later to maint).
+
+ * The advice messages now tell the newer 'git config set' command to
+ set the advice.token configuration variable to squelch a message.
+ (merge 6c397d0104 bf/explicit-config-set-in-advice-messages later to maint).
+
+ * The syntax ":/<text>" to name the latest commit with the matching
+ text was broken with a recent change, which has been corrected.
+ (merge 0ff919e87a ps/commit-with-message-syntax-fix later to maint).
+
+ * Fix performance regression of a recent "fatten promisor pack with
+ local objects" protection against an unwanted gc.
+
+ * "git log -p --remerge-diff --reverse" was completely broken.
+ (merge f94bfa1516 js/log-remerge-keep-ancestry later to maint).
+
+ * "git bundle create" with an annotated tag on the positive end of
+ the revision range had a workaround code for older limitation in
+ the revision walker, which has become unnecessary.
+ (merge dd1072dfa8 tc/bundle-with-tag-remove-workaround later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 77af53f56f aa/t7300-modernize later to maint).
(merge dcd590a39d bf/t-readme-mention-reftable later to maint).
(merge 68e3c69efa kh/trailer-in-glossary later to maint).
(merge 91f88f76e6 tb/boundary-traversal-fix later to maint).
+ (merge 168ebb7159 jc/doc-error-message-guidelines later to maint).
+ (merge 18693d7d65 kh/doc-bundle-typofix later to maint).
+ (merge e2f5d3b491 kh/doc-update-ref-grammofix later to maint).
+ (merge 8525e92886 mh/doc-windows-home-env later to maint).
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf.in
index f6da6d1fbd..dbe36a52ea 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf.in
@@ -21,6 +21,9 @@ tilde=&#126;
apostrophe=&#39;
backtick=&#96;
litdd=&#45;&#45;
+manmanual='Git Manual'
+mansource='Git @GIT_VERSION@'
+revdate='@GIT_DATE@'
ifdef::backend-docbook[]
[linkgit-inlinemacro]
diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb.in
index cb24480b63..c4c200dace 100644
--- a/Documentation/asciidoctor-extensions.rb
+++ b/Documentation/asciidoctor-extensions.rb.in
@@ -29,13 +29,9 @@ module Git
class DocumentPostProcessor < Asciidoctor::Extensions::Postprocessor
def process document, output
if document.basebackend? 'docbook'
- mansource = document.attributes['mansource']
- manversion = document.attributes['manversion']
- manmanual = document.attributes['manmanual']
new_tags = "" \
- "<refmiscinfo class=\"source\">#{mansource}</refmiscinfo>\n" \
- "<refmiscinfo class=\"version\">#{manversion}</refmiscinfo>\n" \
- "<refmiscinfo class=\"manual\">#{manmanual}</refmiscinfo>\n"
+ "<refmiscinfo class=\"source\">@GIT_VERSION@</refmiscinfo>\n" \
+ "<refmiscinfo class=\"manual\">Git Manual</refmiscinfo>\n"
output = output.sub(/<\/refmeta>/, new_tags + "</refmeta>")
end
output
diff --git a/Documentation/build-docdep.perl b/Documentation/build-docdep.perl
index 1b3ac8fdd9..315efaa2fa 100755
--- a/Documentation/build-docdep.perl
+++ b/Documentation/build-docdep.perl
@@ -1,5 +1,6 @@
#!/usr/bin/perl
+my ($build_dir) = @ARGV;
my %include = ();
my %included = ();
@@ -10,6 +11,7 @@ for my $text (<*.txt>) {
chomp;
s/^include::\s*//;
s/\[\]//;
+ s/{build_dir}/${build_dir}/;
$include{$text}{$_} = 1;
$included{$_} = 1;
}
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index 755a110bc4..e260a98977 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -3,12 +3,13 @@
use File::Compare qw(compare);
sub format_one {
- my ($out, $nameattr) = @_;
+ my ($source_dir, $out, $nameattr) = @_;
my ($name, $attr) = @$nameattr;
+ my ($path) = "$source_dir/Documentation/$name.txt";
my ($state, $description);
my $mansection;
$state = 0;
- open I, '<', "$name.txt" or die "No such file $name.txt";
+ open I, '<', "$path" or die "No such file $path.txt";
while (<I>) {
if (/^(?:git|scalar)[a-z0-9-]*\(([0-9])\)$/) {
$mansection = $1;
@@ -29,7 +30,7 @@ sub format_one {
}
close I;
if (!defined $description) {
- die "No description found in $name.txt";
+ die "No description found in $path.txt";
}
if (my ($verify_name, $text) = ($description =~ /^($name) - (.*)/)) {
print $out "linkgit:$name\[$mansection\]::\n\t";
@@ -43,9 +44,9 @@ sub format_one {
}
}
-my ($input, @categories) = @ARGV;
+my ($source_dir, $build_dir, @categories) = @ARGV;
-open IN, "<$input";
+open IN, "<$source_dir/command-list.txt";
while (<IN>) {
last if /^### command list/;
}
@@ -63,17 +64,17 @@ close IN;
for my $out (@categories) {
my ($cat) = $out =~ /^cmds-(.*)\.txt$/;
- open O, '>', "$out+" or die "Cannot open output file $out+";
+ my ($path) = "$build_dir/$out";
+ open O, '>', "$path+" or die "Cannot open output file $out+";
for (@{$cmds{$cat}}) {
- format_one(\*O, $_);
+ format_one($source_dir, \*O, $_);
}
close O;
- if (-f "$out" && compare("$out", "$out+") == 0) {
- unlink "$out+";
+ if (-f "$path" && compare("$path", "$path+") == 0) {
+ unlink "$path+";
}
else {
- print STDERR "$out\n";
- rename "$out+", "$out";
+ rename "$path+", "$path";
}
}
diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt
index 45f3fe855c..fdae13a212 100644
--- a/Documentation/config/diff.txt
+++ b/Documentation/config/diff.txt
@@ -218,7 +218,7 @@ endif::git-diff[]
Set this option to `true` to make the diff driver cache the text
conversion outputs. See linkgit:gitattributes[5] for details.
-include::../mergetools-diff.txt[]
+include::{build_dir}/mergetools-diff.txt[]
`diff.indentHeuristic`::
Set this option to `false` to disable the default heuristics
diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.txt
index 5dc569d1c9..5cb4721a0e 100644
--- a/Documentation/config/extensions.txt
+++ b/Documentation/config/extensions.txt
@@ -63,6 +63,12 @@ Note that this setting should only be set by linkgit:git-init[1] or
linkgit:git-clone[1]. Trying to change it after initialization will not
work and will produce hard-to-diagnose issues.
+relativeWorktrees::
+ If enabled, indicates at least one worktree has been linked with
+ relative paths. Automatically set if a worktree has been created or
+ repaired with either the `--relative-paths` option or with the
+ `worktree.useRelativePaths` config set to `true`.
+
worktreeConfig::
If enabled, then worktrees will load config settings from the
`$GIT_DIR/config.worktree` file in addition to the
diff --git a/Documentation/config/merge.txt b/Documentation/config/merge.txt
index 8851b6cede..82554d65a0 100644
--- a/Documentation/config/merge.txt
+++ b/Documentation/config/merge.txt
@@ -101,7 +101,7 @@ merge.guitool::
Any other value is treated as a custom merge tool and requires that a
corresponding mergetool.<guitool>.cmd variable is defined.
-include::../mergetools-merge.txt[]
+include::{build_dir}/mergetools-merge.txt[]
merge.verbosity::
Controls the amount of output shown by the recursive merge
diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt
index 6d8b7d6c63..4118c219c1 100644
--- a/Documentation/config/remote.txt
+++ b/Documentation/config/remote.txt
@@ -101,6 +101,19 @@ remote.<name>.serverOption::
The default set of server options used when fetching from this remote.
These server options can be overridden by the `--server-option=` command
line arguments.
+
+remote.<name>.followRemoteHEAD::
+ How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`.
+ The default value is "create", which will create `remotes/<name>/HEAD`
+ if it exists on the remote, but not locally, but will not touch an
+ already existing local reference. Setting to "warn" will print
+ a message if the remote has a different value, than the local one and
+ in case there is no local reference, it behaves like "create".
+ A variant on "warn" is "warn-if-not-$branch", which behaves like
+ "warn", but if `HEAD` on the remote is `$branch` it will be silent.
+ Setting to "always" will silently update it to the value on the remote.
+ Finally, setting it to "never" will never change or create the local
+ reference.
+
This is a multi-valued variable, and an empty value can be used in a higher
priority configuration file (e.g. `.git/config` in a repository) to clear
diff --git a/Documentation/config/worktree.txt b/Documentation/config/worktree.txt
index 048e349482..5e35c7d018 100644
--- a/Documentation/config/worktree.txt
+++ b/Documentation/config/worktree.txt
@@ -7,3 +7,13 @@ worktree.guessRemote::
such a branch exists, it is checked out and set as "upstream"
for the new branch. If no such match can be found, it falls
back to creating a new branch from the current HEAD.
+
+worktree.useRelativePaths::
+ Link worktrees using relative paths (when "true") or absolute
+ paths (when "false"). This is particularly useful for setups
+ where the repository and worktrees may be moved between
+ different locations or environments. Defaults to "false".
++
+Note that setting `worktree.useRelativePaths` to "true" implies enabling the
+`extension.relativeWorktrees` config (see linkgit:git-config[1]),
+thus making it incompatible with older versions of Git.
diff --git a/Documentation/generate-mergetool-list.sh b/Documentation/generate-mergetool-list.sh
new file mode 100755
index 0000000000..6700498b93
--- /dev/null
+++ b/Documentation/generate-mergetool-list.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if test "$#" -ne 3
+then
+ echo >&2 "USAGE: $0 <SOURCE_DIR> <MODE> <OUTPUT>"
+ exit 1
+fi
+
+SOURCE_DIR="$1"
+TOOL_MODE="$2"
+OUTPUT="$3"
+MERGE_TOOLS_DIR="$SOURCE_DIR/mergetools"
+
+(
+ . "$SOURCE_DIR"/git-mergetool--lib.sh &&
+ show_tool_names can_$TOOL_MODE
+) | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >"$OUTPUT"
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 504b8a8143..03cd36fe8d 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -32,7 +32,7 @@ Git commands that fetch or otherwise "read" via protocols such as
possible linkgit:git-clone[1] a new repository from a bundle, to use
linkgit:git-fetch[1] to fetch from one, and to list the references
contained within it with linkgit:git-ls-remote[1]. There's no
-corresponding "write" support, i.e.a 'git push' into a bundle is not
+corresponding "write" support, i.e. a 'git push' into a bundle is not
supported.
BUNDLE FORMAT
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 7acb4cb176..de8d8f5893 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -63,6 +63,9 @@ symbolic link, the clone will fail. This is a security measure to
prevent the unintentional copying of files by dereferencing the symbolic
links.
+
+This option does not work with repositories owned by other users for security
+reasons, and `--no-local` must be specified for the clone to succeed.
++
*NOTE*: this operation can race with concurrent modification to the
source repository, similar to running `cp -r <src> <dst>` while modifying
_<src>_.
@@ -384,6 +387,12 @@ $ cd my-linux
$ git clone --bare -l /home/proj/.git /pub/scm/proj.git
------------
+* Clone a local repository from a different user:
++
+------------
+$ git clone --no-local /home/otheruser/proj.git /pub/scm/proj.git
+------------
+
CONFIGURATION
-------------
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 8a4281cde9..9e6935d38d 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -93,11 +93,11 @@ update::
ref does not exist before the update.
create::
- Create <ref> with <new-oid> after verifying it does not
+ Create <ref> with <new-oid> after verifying that it does not
exist. The given <new-oid> may not be zero.
delete::
- Delete <ref> after verifying it exists with <old-oid>, if
+ Delete <ref> after verifying that it exists with <old-oid>, if
given. If given, <old-oid> may not be zero.
symref-update::
@@ -110,11 +110,11 @@ verify::
<old-oid> is zero or missing, the ref must not exist.
symref-create:
- Create symbolic ref <ref> with <new-target> after verifying
+ Create symbolic ref <ref> with <new-target> after verifying that
it does not exist.
symref-delete::
- Delete <ref> after verifying it exists with <old-target>, if given.
+ Delete <ref> after verifying that it exists with <old-target>, if given.
symref-verify::
Verify symbolic <ref> against <old-target> but do not change it.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 70437c815f..8340b7f028 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -216,6 +216,14 @@ To remove a locked worktree, specify `--force` twice.
This can also be set up as the default behaviour by using the
`worktree.guessRemote` config option.
+--[no-]relative-paths::
+ Link worktrees using relative paths or absolute paths (default).
+ Overrides the `worktree.useRelativePaths` config option, see
+ linkgit:git-config[1].
++
+With `repair`, the linking files will be updated if there's an absolute/relative
+mismatch, even if the links are correct.
+
--[no-]track::
When creating a new branch, if `<commit-ish>` is a branch,
mark it as "upstream" from the new branch. This is the
diff --git a/Documentation/git.txt b/Documentation/git.txt
index d15a869762..81498393af 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -245,17 +245,17 @@ ancillary user utilities.
Main porcelain commands
~~~~~~~~~~~~~~~~~~~~~~~
-include::cmds-mainporcelain.txt[]
+include::{build_dir}/cmds-mainporcelain.txt[]
Ancillary Commands
~~~~~~~~~~~~~~~~~~
Manipulators:
-include::cmds-ancillarymanipulators.txt[]
+include::{build_dir}/cmds-ancillarymanipulators.txt[]
Interrogators:
-include::cmds-ancillaryinterrogators.txt[]
+include::{build_dir}/cmds-ancillaryinterrogators.txt[]
Interacting with Others
@@ -264,7 +264,7 @@ Interacting with Others
These commands are to interact with foreign SCM and with other
people via patch over e-mail.
-include::cmds-foreignscminterface.txt[]
+include::{build_dir}/cmds-foreignscminterface.txt[]
Reset, restore and revert
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -313,13 +313,13 @@ repositories.
Manipulation commands
~~~~~~~~~~~~~~~~~~~~~
-include::cmds-plumbingmanipulators.txt[]
+include::{build_dir}/cmds-plumbingmanipulators.txt[]
Interrogation commands
~~~~~~~~~~~~~~~~~~~~~~
-include::cmds-plumbinginterrogators.txt[]
+include::{build_dir}/cmds-plumbinginterrogators.txt[]
In general, the interrogate commands do not touch the files in
the working tree.
@@ -328,12 +328,12 @@ the working tree.
Syncing repositories
~~~~~~~~~~~~~~~~~~~~
-include::cmds-synchingrepositories.txt[]
+include::{build_dir}/cmds-synchingrepositories.txt[]
The following are helper commands used by the above; end users
typically do not use them directly.
-include::cmds-synchelpers.txt[]
+include::{build_dir}/cmds-synchelpers.txt[]
Internal helper commands
@@ -342,14 +342,14 @@ Internal helper commands
These are internal helper commands used by other commands; end
users typically do not use them directly.
-include::cmds-purehelpers.txt[]
+include::{build_dir}/cmds-purehelpers.txt[]
Guides
------
The following documentation pages are guides about Git concepts.
-include::cmds-guide.txt[]
+include::{build_dir}/cmds-guide.txt[]
Repository, command and file interfaces
---------------------------------------
@@ -358,7 +358,7 @@ This documentation discusses repository and command interfaces which
users are expected to interact with directly. See `--user-formats` in
linkgit:git-help[1] for more details on the criteria.
-include::cmds-userinterfaces.txt[]
+include::{build_dir}/cmds-userinterfaces.txt[]
File formats, protocols and other developer interfaces
------------------------------------------------------
@@ -367,7 +367,7 @@ This documentation discusses file formats, over-the-wire protocols and
other git developer interfaces. See `--developer-interfaces` in
linkgit:git-help[1].
-include::cmds-developerinterfaces.txt[]
+include::{build_dir}/cmds-developerinterfaces.txt[]
Configuration Mechanism
-----------------------
@@ -477,6 +477,14 @@ their values the same way as Boolean valued configuration variables, e.g.
Here are the variables:
+System
+~~~~~~~~~~~~~~~~~~
+`HOME`::
+ Specifies the path to the user's home directory. On Windows, if
+ unset, Git will set a process environment variable equal to:
+ `$HOMEDRIVE$HOMEPATH` if both `$HOMEDRIVE` and `$HOMEPATH` exist;
+ otherwise `$USERPROFILE` if `$USERPROFILE` exists.
+
The Git Repository
~~~~~~~~~~~~~~~~~~
These environment variables apply to 'all' core Git commands. Nb: it
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 7c709324ba..bd62cbd043 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -90,6 +90,15 @@ scripting Git:
for long options. An option that takes optional option-argument must be
written in the 'stuck' form.
+ * Despite the above suggestion, when Arg is a path relative to the
+ home directory of a user, e.g. ~/directory/file or ~u/d/f, you
+ may want to use the separate form, e.g. `git foo --file ~/mine`,
+ not `git foo --file=~/mine`. The shell will expand `~/` in the
+ former to your home directory, but most shells keep the tilde in
+ the latter. Some of our commands know how to tilde-expand the
+ option value even when given in the stuck form, but not all of
+ them do.
+
* When you give a revision parameter to a command, make sure the parameter is
not ambiguous with a name of a file in the work tree. E.g. do not write
`git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 71dd19731a..35a7452c8f 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -242,6 +242,12 @@ Here are some example specifications:
[credential]
helper = "foo --bar='whitespace arg'"
+# store helper (discouraged) with custom location for the db file;
+# use `--file ~/.git-secret.txt`, rather than `--file=~/.git-secret.txt`,
+# to allow the shell to expand tilde to the home directory.
+[credential]
+ helper = "store --file ~/.git-secret.txt"
+
# you can also use an absolute path, which will not use the git wrapper
[credential]
helper = "/path/to/my/helper --with-arguments"
diff --git a/Documentation/meson.build b/Documentation/meson.build
new file mode 100644
index 0000000000..f2426ccaa3
--- /dev/null
+++ b/Documentation/meson.build
@@ -0,0 +1,324 @@
+manpages = {
+ # Category 1.
+ 'git-add.txt' : 1,
+ 'git-am.txt' : 1,
+ 'git-annotate.txt' : 1,
+ 'git-apply.txt' : 1,
+ 'git-archimport.txt' : 1,
+ 'git-archive.txt' : 1,
+ 'git-bisect.txt' : 1,
+ 'git-blame.txt' : 1,
+ 'git-branch.txt' : 1,
+ 'git-bugreport.txt' : 1,
+ 'git-bundle.txt' : 1,
+ 'git-cat-file.txt' : 1,
+ 'git-check-attr.txt' : 1,
+ 'git-check-ignore.txt' : 1,
+ 'git-check-mailmap.txt' : 1,
+ 'git-checkout-index.txt' : 1,
+ 'git-checkout.txt' : 1,
+ 'git-check-ref-format.txt' : 1,
+ 'git-cherry-pick.txt' : 1,
+ 'git-cherry.txt' : 1,
+ 'git-citool.txt' : 1,
+ 'git-clean.txt' : 1,
+ 'git-clone.txt' : 1,
+ 'git-column.txt' : 1,
+ 'git-commit-graph.txt' : 1,
+ 'git-commit-tree.txt' : 1,
+ 'git-commit.txt' : 1,
+ 'git-config.txt' : 1,
+ 'git-count-objects.txt' : 1,
+ 'git-credential-cache--daemon.txt' : 1,
+ 'git-credential-cache.txt' : 1,
+ 'git-credential-store.txt' : 1,
+ 'git-credential.txt' : 1,
+ 'git-cvsexportcommit.txt' : 1,
+ 'git-cvsimport.txt' : 1,
+ 'git-cvsserver.txt' : 1,
+ 'git-daemon.txt' : 1,
+ 'git-describe.txt' : 1,
+ 'git-diagnose.txt' : 1,
+ 'git-diff-files.txt' : 1,
+ 'git-diff-index.txt' : 1,
+ 'git-difftool.txt' : 1,
+ 'git-diff-tree.txt' : 1,
+ 'git-diff.txt' : 1,
+ 'git-fast-export.txt' : 1,
+ 'git-fast-import.txt' : 1,
+ 'git-fetch-pack.txt' : 1,
+ 'git-fetch.txt' : 1,
+ 'git-filter-branch.txt' : 1,
+ 'git-fmt-merge-msg.txt' : 1,
+ 'git-for-each-ref.txt' : 1,
+ 'git-for-each-repo.txt' : 1,
+ 'git-format-patch.txt' : 1,
+ 'git-fsck-objects.txt' : 1,
+ 'git-fsck.txt' : 1,
+ 'git-fsmonitor--daemon.txt' : 1,
+ 'git-gc.txt' : 1,
+ 'git-get-tar-commit-id.txt' : 1,
+ 'git-grep.txt' : 1,
+ 'git-gui.txt' : 1,
+ 'git-hash-object.txt' : 1,
+ 'git-help.txt' : 1,
+ 'git-hook.txt' : 1,
+ 'git-http-backend.txt' : 1,
+ 'git-http-fetch.txt' : 1,
+ 'git-http-push.txt' : 1,
+ 'git-imap-send.txt' : 1,
+ 'git-index-pack.txt' : 1,
+ 'git-init-db.txt' : 1,
+ 'git-init.txt' : 1,
+ 'git-instaweb.txt' : 1,
+ 'git-interpret-trailers.txt' : 1,
+ 'git-log.txt' : 1,
+ 'git-ls-files.txt' : 1,
+ 'git-ls-remote.txt' : 1,
+ 'git-ls-tree.txt' : 1,
+ 'git-mailinfo.txt' : 1,
+ 'git-mailsplit.txt' : 1,
+ 'git-maintenance.txt' : 1,
+ 'git-merge-base.txt' : 1,
+ 'git-merge-file.txt' : 1,
+ 'git-merge-index.txt' : 1,
+ 'git-merge-one-file.txt' : 1,
+ 'git-mergetool--lib.txt' : 1,
+ 'git-mergetool.txt' : 1,
+ 'git-merge-tree.txt' : 1,
+ 'git-merge.txt' : 1,
+ 'git-mktag.txt' : 1,
+ 'git-mktree.txt' : 1,
+ 'git-multi-pack-index.txt' : 1,
+ 'git-mv.txt' : 1,
+ 'git-name-rev.txt' : 1,
+ 'git-notes.txt' : 1,
+ 'git-p4.txt' : 1,
+ 'git-pack-objects.txt' : 1,
+ 'git-pack-redundant.txt' : 1,
+ 'git-pack-refs.txt' : 1,
+ 'git-patch-id.txt' : 1,
+ 'git-prune-packed.txt' : 1,
+ 'git-prune.txt' : 1,
+ 'git-pull.txt' : 1,
+ 'git-push.txt' : 1,
+ 'git-quiltimport.txt' : 1,
+ 'git-range-diff.txt' : 1,
+ 'git-read-tree.txt' : 1,
+ 'git-rebase.txt' : 1,
+ 'git-receive-pack.txt' : 1,
+ 'git-reflog.txt' : 1,
+ 'git-refs.txt' : 1,
+ 'git-remote-ext.txt' : 1,
+ 'git-remote-fd.txt' : 1,
+ 'git-remote.txt' : 1,
+ 'git-repack.txt' : 1,
+ 'git-replace.txt' : 1,
+ 'git-replay.txt' : 1,
+ 'git-request-pull.txt' : 1,
+ 'git-rerere.txt' : 1,
+ 'git-reset.txt' : 1,
+ 'git-restore.txt' : 1,
+ 'git-revert.txt' : 1,
+ 'git-rev-list.txt' : 1,
+ 'git-rev-parse.txt' : 1,
+ 'git-rm.txt' : 1,
+ 'git-send-email.txt' : 1,
+ 'git-send-pack.txt' : 1,
+ 'git-shell.txt' : 1,
+ 'git-sh-i18n--envsubst.txt' : 1,
+ 'git-sh-i18n.txt' : 1,
+ 'git-shortlog.txt' : 1,
+ 'git-show-branch.txt' : 1,
+ 'git-show-index.txt' : 1,
+ 'git-show-ref.txt' : 1,
+ 'git-show.txt' : 1,
+ 'git-sh-setup.txt' : 1,
+ 'git-sparse-checkout.txt' : 1,
+ 'git-stage.txt' : 1,
+ 'git-stash.txt' : 1,
+ 'git-status.txt' : 1,
+ 'git-stripspace.txt' : 1,
+ 'git-submodule.txt' : 1,
+ 'git-svn.txt' : 1,
+ 'git-switch.txt' : 1,
+ 'git-symbolic-ref.txt' : 1,
+ 'git-tag.txt' : 1,
+ 'git-unpack-file.txt' : 1,
+ 'git-unpack-objects.txt' : 1,
+ 'git-update-index.txt' : 1,
+ 'git-update-ref.txt' : 1,
+ 'git-update-server-info.txt' : 1,
+ 'git-upload-archive.txt' : 1,
+ 'git-upload-pack.txt' : 1,
+ 'git-var.txt' : 1,
+ 'git-verify-commit.txt' : 1,
+ 'git-verify-pack.txt' : 1,
+ 'git-verify-tag.txt' : 1,
+ 'git-version.txt' : 1,
+ 'git-web--browse.txt' : 1,
+ 'git-whatchanged.txt' : 1,
+ 'git-worktree.txt' : 1,
+ 'git-write-tree.txt' : 1,
+ 'git.txt' : 1,
+ 'gitk.txt' : 1,
+ 'gitweb.txt' : 1,
+ 'scalar.txt' : 1,
+
+ # Category 5.
+ 'gitattributes.txt' : 5,
+ 'gitformat-bundle.txt' : 5,
+ 'gitformat-chunk.txt' : 5,
+ 'gitformat-commit-graph.txt' : 5,
+ 'gitformat-index.txt' : 5,
+ 'gitformat-pack.txt' : 5,
+ 'gitformat-signature.txt' : 5,
+ 'githooks.txt' : 5,
+ 'gitignore.txt' : 5,
+ 'gitmailmap.txt' : 5,
+ 'gitmodules.txt' : 5,
+ 'gitprotocol-capabilities.txt' : 5,
+ 'gitprotocol-common.txt' : 5,
+ 'gitprotocol-http.txt' : 5,
+ 'gitprotocol-pack.txt' : 5,
+ 'gitprotocol-v2.txt' : 5,
+ 'gitrepository-layout.txt' : 5,
+ 'gitweb.conf.txt' : 5,
+
+ # Category 7.
+ 'gitcli.txt' : 7,
+ 'gitcore-tutorial.txt' : 7,
+ 'gitcredentials.txt' : 7,
+ 'gitcvs-migration.txt' : 7,
+ 'gitdiffcore.txt' : 7,
+ 'giteveryday.txt' : 7,
+ 'gitfaq.txt' : 7,
+ 'gitglossary.txt' : 7,
+ 'gitpacking.txt' : 7,
+ 'gitnamespaces.txt' : 7,
+ 'gitremote-helpers.txt' : 7,
+ 'gitrevisions.txt' : 7,
+ 'gitsubmodules.txt' : 7,
+ 'gittutorial-2.txt' : 7,
+ 'gittutorial.txt' : 7,
+ 'gitworkflows.txt' : 7,
+}
+
+asciidoc = find_program('asciidoc')
+git = find_program('git', required: false)
+xmlto = find_program('xmlto')
+
+asciidoc_conf = custom_target(
+ command: [
+ shell,
+ meson.project_source_root() / 'GIT-VERSION-GEN',
+ meson.project_source_root(),
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ input: meson.current_source_dir() / 'asciidoc.conf.in',
+ output: 'asciidoc.conf',
+ depends: [git_version_file],
+)
+
+asciidoc_common_options = [
+ asciidoc,
+ '--conf-file=' + asciidoc_conf.full_path(),
+ '--attribute=build_dir=' + meson.current_build_dir(),
+]
+
+cmd_lists = [
+ 'cmds-ancillaryinterrogators.txt',
+ 'cmds-ancillarymanipulators.txt',
+ 'cmds-mainporcelain.txt',
+ 'cmds-plumbinginterrogators.txt',
+ 'cmds-plumbingmanipulators.txt',
+ 'cmds-synchingrepositories.txt',
+ 'cmds-synchelpers.txt',
+ 'cmds-guide.txt',
+ 'cmds-developerinterfaces.txt',
+ 'cmds-userinterfaces.txt',
+ 'cmds-purehelpers.txt',
+ 'cmds-foreignscminterface.txt',
+]
+
+documentation_deps = [
+ asciidoc_conf,
+]
+
+documentation_deps += custom_target(
+ command: [
+ perl,
+ meson.current_source_dir() / 'cmd-list.perl',
+ meson.project_source_root(),
+ meson.current_build_dir(),
+ ] + cmd_lists,
+ output: cmd_lists
+)
+
+foreach mode : [ 'diff', 'merge' ]
+ documentation_deps += custom_target(
+ command: [
+ shell,
+ meson.current_source_dir() / 'generate-mergetool-list.sh',
+ '..',
+ 'diff',
+ '@OUTPUT@'
+ ],
+ env: [
+ 'MERGE_TOOLS_DIR=' + meson.project_source_root() / 'mergetools',
+ 'TOOL_MODE=' + mode,
+ ],
+ output: 'mergetools-' + mode + '.txt',
+ )
+endforeach
+
+foreach manpage, category : manpages
+ if get_option('docs').contains('man')
+ manpage_xml_target = custom_target(
+ command: asciidoc_common_options + [
+ '--backend=docbook',
+ '--doctype=manpage',
+ '--out-file=@OUTPUT@',
+ meson.current_source_dir() / manpage,
+ ],
+ depends: documentation_deps,
+ output: fs.stem(manpage) + '.xml',
+ )
+
+ manpage_path = fs.stem(manpage) + '.' + category.to_string()
+ manpage_target = custom_target(
+ command: [
+ xmlto,
+ '-m',
+ meson.current_source_dir() / 'manpage-normal.xsl',
+ '-m',
+ meson.current_source_dir() / 'manpage-bold-literal.xsl',
+ '--stringparam',
+ 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+ 'man',
+ manpage_xml_target,
+ '-o',
+ meson.current_build_dir(),
+ ],
+ output: manpage_path,
+ install: true,
+ install_dir: get_option('mandir') / 'man' + category.to_string(),
+ )
+ endif
+
+ if get_option('docs').contains('html') and category == 1
+ custom_target(
+ command: asciidoc_common_options + [
+ '--backend=xhtml11',
+ '--doctype=manpage',
+ '--out-file=@OUTPUT@',
+ meson.current_source_dir() / manpage,
+ ],
+ depends: documentation_deps,
+ output: fs.stem(manpage) + '.html',
+ install: true,
+ install_dir: get_option('datadir') / 'doc/git-doc',
+ )
+ endif
+endforeach
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 00ccf68744..459e5a02f5 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -412,7 +412,8 @@ Default mode::
--ancestry-path[=<commit>]::
When given a range of commits to display (e.g. 'commit1..commit2'
- or 'commit2 {caret}commit1'), only display commits in that range
+ or 'commit2 {caret}commit1'), and a commit <commit> in that range,
+ only display commits in that range
that are ancestors of <commit>, descendants of <commit>, or
<commit> itself. If no commit is specified, use 'commit1' (the
excluded part of the range) as <commit>. Can be passed multiple
diff --git a/Documentation/technical/build-systems.txt b/Documentation/technical/build-systems.txt
new file mode 100644
index 0000000000..d9dafb407c
--- /dev/null
+++ b/Documentation/technical/build-systems.txt
@@ -0,0 +1,224 @@
+= Build Systems
+
+The build system is the primary way for both developers and system integrators
+to interact with the Git project. As such, being easy to use and extend for
+those who are not directly developing Git itself is just as important as other
+requirements we have on any potential build system.
+
+This document outlines the different requirements that we have for the build
+system and then compares available build systems using these criteria.
+
+== Requirements
+
+The following subsections present a list of requirements that we have for any
+potential build system. Sections are sorted by decreasing priority.
+
+=== Platform support
+
+The build system must have support for all of our platforms that we continually
+test against as outlined by our platform support policy. These platforms are:
+
+ - Linux
+ - Windows
+ - macOS
+
+Furthermore, the build system should have support for the following platforms
+that generally have somebody running test pipelines against regularly:
+
+ - AIX
+ - FreeBSD
+ - NetBSD
+ - NonStop
+ - OpenBSD
+
+The platforms which must be supported by the tool should be aligned with our
+[platform support policy](platform-support.txt).
+
+=== Auto-detection of supported features
+
+The build system must support auto-detection of features which are or aren't
+available on the current platform. Platform maintainers should not be required
+to manually configure the complete build.
+
+Auto-detection of the following items is considered to be important:
+
+ - Check for the existence of headers.
+ - Check for the existence of libraries.
+ - Check for the existence of exectuables.
+ - Check for the runtime behavior of specific functions.
+ - Check for specific link order requirements when multiple libraries are
+ involved.
+
+=== Ease of use
+
+The build system should be both easy to use and easy to extend. While this is
+naturally a subjective metric it is likely not controversial to say that some
+build systems are considerably harder to use than others.
+
+=== IDE support
+
+The build system should integrate with well-known IDEs. Well-known IDEs include:
+
+ - Microsoft Visual Studio
+ - Visual Studio Code
+ - Xcode
+
+There are four levels of support:
+
+ - Native integration into the IDE.
+ - Integration into the IDE via a plugin.
+ - Integration into the IDE via generating a project description with the build
+ system.
+ - No integration.
+
+Native integration is preferable, but integration via either a plugin or by
+generating a project description via the build system are considered feasible
+alternatives.
+
+Another important distinction is the level of integration. There are two
+features that one generally wants to have:
+
+ - Integration of build targets.
+ - Automatic setup of features like code completion with detected build
+ dependencies.
+
+The first bullet point is the bare minimum, but is not sufficient to be
+considered proper integration.
+
+=== Out-of-tree builds
+
+The build system should support out-of-tree builds. Out-of-tree builds allow a
+developer to configure multiple different build directories with different
+configuration, e.g. one "debug" build and one "release" build.
+
+=== Cross-platform builds
+
+The build system should support cross-platform builds, e.g. building for arm on
+an x86-64 host.
+
+=== Language support
+
+The following languages and toolchains are of relevance and should be supported
+by the build system:
+
+ - C: the primary compiled language used by Git, must be supported. Relevant
+ toolchains are GCC, Clang and MSVC.
+ - Rust: candidate as a second compiled lanugage, should be supported. Relevant
+ toolchains is the LLVM-based rustc.
+
+Built-in support for the respective languages is preferred over support that
+needs to be wired up manually to avoid unnecessary complexity. Native support
+includes the following features:
+
+ - Compiling objects.
+ - Dependency tracking.
+ - Detection of available features.
+ - Discovery of relevant toolchains.
+ - Linking libraries and executables.
+ - Templating placeholders in scripts.
+
+=== Test integration
+
+It should be possible to integrate tests into the build system such that it is
+possible to build and test Git within the build system. Features which are nice
+to have:
+
+ - Track build-time dependencies for respective tests. Unit tests have
+ different requirements than integration tests.
+ - Allow filtering of which tests to run.
+ - Allow running tests such that utilities like `test_pause` or `debug` work.
+
+== Comparison
+
+The following list of build systems are considered:
+
+- GNU Make
+- autoconf
+- CMake
+- Meson
+
+=== GNU Make
+
+- Platform support: ubitquitous on all platforms, but not well-integrated into Windows.
+- Auto-detection: no built-in support for auto-detection of features.
+- Ease of use: easy to use, but discovering available options is hard. Makefile
+ rules can quickly get out of hand once reaching a certain scope.
+- IDE support: execution of Makefile targets is supported by many IDEs
+- Out-of-tree builds: supported in theory, not wired up in practice.
+- Cross-platform builds: supported in theory, not wired up in practice.
+- Language support:
+ - C: Limited built-in support, many parts need to be wired up manually.
+ - Rust: No built-in support, needs to be wired up manually.
+- Test integration: partially supported, many parts need to be wired up
+ manually.
+
+=== autoconf
+
+- Platform support: ubiquitous on all platforms, but not well-integrated into Windows.
+- Auto-detection: supported.
+- Ease of use: easy to use, discovering available options is comparatively
+ easy. The autoconf syntax is prohibitively hard to extend though due to its
+ complex set of interacting files and the hard-to-understand M4 language.
+- IDE support: no integration into IDEs at generation time. The generated
+ Makefiles have the same level of support as GNU Make.
+- Out-of-tree builds: supported in theory, not wired up in practice.
+- Cross-platform builds: supported.
+- Language support:
+ - C: Limited built-in support, many parts need to be wired up manually.
+ - Rust: No built-in support, needs to be wired up manually.
+- Test integration: partially supported, many parts need to be wired up
+ manually.
+
+=== CMake
+
+- Platform support: not as extensive as GNU Make or autoconf, but all major
+ platforms are supported.
+ - AIX
+ - Cygwin
+ - FreeBSD
+ - Linux
+ - OpenBSD
+ - Solaris
+ - Windows
+ - macOS
+- Ease of use: easy to use, discovering available options is not always
+ trivial. The scripting language used by CMake is somewhat cumbersome to use,
+ but extending CMake build instructions is doable.
+- IDE support: natively integrated into Microsoft Visual Studio. Can generate
+ project descriptions for Xcode. An extension is available for Visual Studio
+ Code. Many other IDEs have plugins for CMake.
+- Out-of-tree builds: supported.
+- Cross-platform builds: supported.
+- Language support:
+ - C: Supported for GCC, Clang, MSVC and other toolchains.
+ - Rust: No built-in support, needs to be wired up manually.
+- Test integration: supported, even though test dependencies are a bit
+ cumbersome to use via "test fixtures". Interactive test runs are not
+ supported.
+
+=== Meson
+
+- Platform: not as extensive as GNU Make or autoconf, but all major platforms
+ and some smaller ones are supported.
+ - AIX
+ - Cygwin
+ - DragonflyBSD
+ - FreeBSD
+ - Haiku
+ - Linux
+ - NetBSD
+ - OpenBSD
+ - Solaris
+ - Windows
+ - macOS
+- Ease of use: easy to use, discovering available options is easy. The
+ scripting language is straight-forward to use.
+- IDE support: Supports generating build instructions for Xcode and Microsoft
+ Visual Studio, a plugin exists for Visual Studio Code.
+- Out-of-tree builds: supported.
+- Cross-platform builds: supported.
+- Language support:
+ - C: Supported for GCC, Clang, MSVC and other toolchains.
+ - Rust: Supported for rustc.
+- Test integration: supported. Interactive tests are supported starting with
+ Meson 1.5.0 via the `--interactive` flag.
diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in
new file mode 100644
index 0000000000..f651116102
--- /dev/null
+++ b/GIT-BUILD-OPTIONS.in
@@ -0,0 +1,47 @@
+SHELL_PATH=@SHELL_PATH@
+TEST_SHELL_PATH=@TEST_SHELL_PATH@
+PERL_PATH=@PERL_PATH@
+PERL_LOCALEDIR=@PERL_LOCALEDIR@
+NO_PERL_CPAN_FALLBACKS=@NO_PERL_CPAN_FALLBACKS@
+DIFF=@DIFF@
+PYTHON_PATH=@PYTHON_PATH@
+TAR=@TAR@
+NO_CURL=@NO_CURL@
+NO_ICONV=@NO_ICONV@
+NO_EXPAT=@NO_EXPAT@
+USE_LIBPCRE2=@USE_LIBPCRE2@
+NO_PERL=@NO_PERL@
+NO_PTHREADS=@NO_PTHREADS@
+NO_PYTHON=@NO_PYTHON@
+NO_REGEX=@NO_REGEX@
+NO_UNIX_SOCKETS=@NO_UNIX_SOCKETS@
+PAGER_ENV=@PAGER_ENV@
+SANITIZE_LEAK=@SANITIZE_LEAK@
+SANITIZE_ADDRESS=@SANITIZE_ADDRESS@
+X=@X@
+FSMONITOR_DAEMON_BACKEND=@FSMONITOR_DAEMON_BACKEND@
+FSMONITOR_OS_SETTINGS=@FSMONITOR_OS_SETTINGS@
+TEST_OUTPUT_DIRECTORY=@TEST_OUTPUT_DIRECTORY@
+GIT_TEST_OPTS=@GIT_TEST_OPTS@
+GIT_TEST_CMP=@GIT_TEST_CMP@
+GIT_TEST_CMP_USE_COPIED_CONTEXT=@GIT_TEST_CMP_USE_COPIED_CONTEXT@
+GIT_TEST_UTF8_LOCALE=@GIT_TEST_UTF8_LOCALE@
+NO_GETTEXT=@NO_GETTEXT@
+GIT_PERF_REPEAT_COUNT=@GIT_PERF_REPEAT_COUNT@
+GIT_PERF_REPO=@GIT_PERF_REPO@
+GIT_PERF_LARGE_REPO=@GIT_PERF_LARGE_REPO@
+GIT_PERF_MAKE_OPTS=@GIT_PERF_MAKE_OPTS@
+GIT_PERF_MAKE_COMMAND=@GIT_PERF_MAKE_COMMAND@
+GIT_INTEROP_MAKE_OPTS=@GIT_INTEROP_MAKE_OPTS@
+GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@
+GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@
+GIT_TEST_TEXTDOMAINDIR=@GIT_TEST_TEXTDOMAINDIR@
+GIT_TEST_POPATH=@GIT_TEST_POPATH@
+GIT_TEST_TEMPLATE_DIR=@GIT_TEST_TEMPLATE_DIR@
+GIT_TEST_GITPERLLIB=@GIT_TEST_GITPERLLIB@
+GIT_TEST_MERGE_TOOLS_DIR=@GIT_TEST_MERGE_TOOLS_DIR@
+RUNTIME_PREFIX=@RUNTIME_PREFIX@
+GITWEBDIR=@GITWEBDIR@
+USE_GETTEXT_SCHEME=@USE_GETTEXT_SCHEME@
+LOCALEDIR=@LOCALEDIR@
+BROKEN_PATH_FIX=@BROKEN_PATH_FIX@
diff --git a/GIT-VERSION-FILE.in b/GIT-VERSION-FILE.in
new file mode 100644
index 0000000000..3789a48a34
--- /dev/null
+++ b/GIT-VERSION-FILE.in
@@ -0,0 +1 @@
+GIT_VERSION=@GIT_VERSION@
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 78e8631f67..de0e63bdfb 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,23 +1,48 @@
#!/bin/sh
-GVF=GIT-VERSION-FILE
-DEF_VER=v2.47.GIT
+DEF_VER=v2.48.0-rc0
LF='
'
+if test "$#" -ne 3
+then
+ echo >&2 "USAGE: $0 <SOURCE_DIR> <INPUT> <OUTPUT>"
+ exit 1
+fi
+
+SOURCE_DIR="$1"
+INPUT="$2"
+OUTPUT="$3"
+
+if ! test -f "$INPUT"
+then
+ echo >&2 "Input is not a file: $INPUT"
+ exit 1
+fi
+
+# Protect us from reading Git version information outside of the Git directory
+# in case it is not a repository itself, but embedded in an unrelated
+# repository.
+GIT_CEILING_DIRECTORIES="$SOURCE_DIR/.."
+export GIT_CEILING_DIRECTORIES
+
# First see if there is a version file (included in release tarballs),
# then try git-describe, then default.
-if test -f version
+if test -f "$SOURCE_DIR"/version
then
- VN=$(cat version) || VN="$DEF_VER"
-elif { test -d "${GIT_DIR:-.git}" || test -f .git; } &&
- VN=$(git describe --match "v[0-9]*" HEAD 2>/dev/null) &&
+ VN=$(cat "$SOURCE_DIR"/version) || VN="$DEF_VER"
+elif {
+ test -d "$SOURCE_DIR/.git" ||
+ test -d "${GIT_DIR:-.git}" ||
+ test -f "$SOURCE_DIR"/.git;
+ } &&
+ VN=$(git -C "$SOURCE_DIR" describe --match "v[0-9]*" HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*)
- git update-index -q --refresh
- test -z "$(git diff-index --name-only HEAD --)" ||
+ git -C "$SOURCE_DIR" update-index -q --refresh
+ test -z "$(git -C "$SOURCE_DIR" diff-index --name-only HEAD --)" ||
VN="$VN-dirty" ;;
esac
then
@@ -26,15 +51,34 @@ else
VN="$DEF_VER"
fi
-VN=$(expr "$VN" : v*'\(.*\)')
+GIT_VERSION=$(expr "$VN" : v*'\(.*\)')
+GIT_BUILT_FROM_COMMIT=$(git -C "$SOURCE_DIR" rev-parse -q --verify HEAD 2>/dev/null)
+GIT_DATE=$(git -C "$SOURCE_DIR" show --quiet --format='%as' 2>/dev/null)
+if test -z "$GIT_USER_AGENT"
+then
+ GIT_USER_AGENT="git/$GIT_VERSION"
+fi
+
+# While released Git versions only have three numbers, development builds also
+# have a fourth number that corresponds to the number of patches since the last
+# release.
+read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION GIT_PATCH_LEVEL trailing <<EOF
+$(echo "$GIT_VERSION" 0 0 0 0 | tr '.a-zA-Z-' ' ')
+EOF
+
+sed -e "s|@GIT_VERSION@|$GIT_VERSION|" \
+ -e "s|@GIT_MAJOR_VERSION@|$GIT_MAJOR_VERSION|" \
+ -e "s|@GIT_MINOR_VERSION@|$GIT_MINOR_VERSION|" \
+ -e "s|@GIT_MICRO_VERSION@|$GIT_MICRO_VERSION|" \
+ -e "s|@GIT_PATCH_LEVEL@|$GIT_PATCH_LEVEL|" \
+ -e "s|@GIT_BUILT_FROM_COMMIT@|$GIT_BUILT_FROM_COMMIT|" \
+ -e "s|@GIT_USER_AGENT@|$GIT_USER_AGENT|" \
+ -e "s|@GIT_DATE@|$GIT_DATE|" \
+ "$INPUT" >"$OUTPUT"+
-if test -r $GVF
+if ! test -f "$OUTPUT" || ! cmp "$OUTPUT"+ "$OUTPUT" >/dev/null
then
- VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
+ mv "$OUTPUT"+ "$OUTPUT"
else
- VC=unset
+ rm "$OUTPUT"+
fi
-test "$VN" = "$VC" || {
- echo >&2 "GIT_VERSION = $VN"
- echo "GIT_VERSION = $VN" >$GVF
-}
diff --git a/Makefile b/Makefile
index 549b24e7fd..79739a13d2 100644
--- a/Makefile
+++ b/Makefile
@@ -592,7 +592,10 @@ include shared.mak
# Disable -pedantic compilation.
GIT-VERSION-FILE: FORCE
- @$(SHELL_PATH) ./GIT-VERSION-GEN
+ @OLD=$$(cat $@ 2>/dev/null || :) && \
+ $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" GIT-VERSION-FILE.in $@ && \
+ NEW=$$(cat $@ 2>/dev/null || :) && \
+ if test "$$OLD" != "$$NEW"; then echo "$$NEW" >&2; fi
-include GIT-VERSION-FILE
# Set our default configuration.
@@ -1555,10 +1558,10 @@ endif
ifdef SANE_TOOL_PATH
SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
-BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|'
+BROKEN_PATH_FIX = s|^\# @BROKEN_PATH_FIX@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|
PATH := $(SANE_TOOL_PATH):${PATH}
else
-BROKEN_PATH_FIX = '/^\# @@BROKEN_PATH_FIX@@$$/d'
+BROKEN_PATH_FIX = /^\# @BROKEN_PATH_FIX@$$/d
endif
ifeq (,$(HOST_CPU))
@@ -2422,9 +2425,12 @@ endif
FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o
FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
FUZZ_OBJS += oss-fuzz/fuzz-config.o
+FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o
FUZZ_OBJS += oss-fuzz/fuzz-date.o
FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
+FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o
+FUZZ_OBJS += oss-fuzz/fuzz-url-decode-mem.o
.PHONY: fuzz-objs
fuzz-objs: $(FUZZ_OBJS)
@@ -2505,13 +2511,11 @@ PAGER_ENV_CQ_SQ = $(subst ','\'',$(PAGER_ENV_CQ))
pager.sp pager.s pager.o: EXTRA_CPPFLAGS = \
-DPAGER_ENV='$(PAGER_ENV_CQ_SQ)'
-version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
-version.sp version.s version.o: EXTRA_CPPFLAGS = \
- '-DGIT_VERSION="$(GIT_VERSION)"' \
- '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)' \
- '-DGIT_BUILT_FROM_COMMIT="$(shell \
- GIT_CEILING_DIRECTORIES="$(CURDIR)/.." \
- git rev-parse -q --verify HEAD 2>/dev/null)"'
+version-def.h: version-def.h.in GIT-VERSION-GEN GIT-VERSION-FILE GIT-USER-AGENT
+ $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@+
+ @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
+
+version.sp version.s version.o: version-def.h
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
@@ -2522,17 +2526,17 @@ $(BUILT_INS): git$X
config-list.h: generate-configlist.sh
config-list.h: Documentation/*config.txt Documentation/config/*.txt
- $(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh >$@
+ $(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh . $@
command-list.h: generate-cmdlist.sh command-list.txt
command-list.h: $(wildcard Documentation/git*.txt)
$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh \
$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \
- command-list.txt >$@
+ . $@
hook-list.h: generate-hooklist.sh Documentation/githooks.txt
- $(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh >$@
+ $(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh . $@
SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\
$(localedir_SQ):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
@@ -2545,33 +2549,16 @@ GIT-SCRIPT-DEFINES: FORCE
echo "$$FLAGS" >$@; \
fi
-define cmd_munge_script
-sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
- -e 's|@@DIFF@@|$(DIFF_SQ)|' \
- -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
- -e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \
- -e $(BROKEN_PATH_FIX) \
- -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
- -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
- -e 's|@@PAGER_ENV@@|$(PAGER_ENV_SQ)|g' \
- $@.sh >$@+
-endef
-
-$(SCRIPT_SH_GEN) : % : %.sh GIT-SCRIPT-DEFINES
- $(QUIET_GEN)$(cmd_munge_script) && \
- chmod +x $@+ && \
+$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES
+ $(QUIET_GEN)./generate-script.sh "$<" "$@+" ./GIT-BUILD-OPTIONS && \
mv $@+ $@
-$(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
- $(QUIET_GEN)$(cmd_munge_script) && \
- mv $@+ $@
+git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE
+ $(QUIET_GEN)$(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@+
+ @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
-git.res: git.rc GIT-VERSION-FILE GIT-PREFIX
- $(QUIET_RC)$(RC) \
- $(join -DMAJOR= -DMINOR= -DMICRO= -DPATCHLEVEL=, $(wordlist 1, 4, \
- $(shell echo $(GIT_VERSION) 0 0 0 0 | tr '.a-zA-Z-' ' '))) \
- -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" -i $< -o $@
+git.res: git.rc GIT-PREFIX
+ $(QUIET_RC)$(RC) -i $< -o $@
# This makes sure we depend on the NO_PERL setting itself.
$(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS
@@ -2604,16 +2591,8 @@ endif
PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir)
-$(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE
- $(QUIET_GEN) \
- sed -e '1{' \
- -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
- -e ' r GIT-PERL-HEADER' \
- -e ' G' \
- -e '}' \
- -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
- $< >$@+ && \
- chmod +x $@+ && \
+$(SCRIPT_PERL_GEN): % : %.perl generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE
+ $(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER "$<" "$@+" && \
mv $@+ $@
PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES))
@@ -2629,11 +2608,11 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile
INSTLIBDIR='$(perllibdir_SQ)' && \
INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
- sed -e 's=@@PATHSEP@@=$(pathsep)=g' \
- -e "s=@@INSTLIBDIR@@=$$INSTLIBDIR=g" \
- -e 's=@@PERLLIBDIR_REL@@=$(perllibdir_relative_SQ)=g' \
- -e 's=@@GITEXECDIR_REL@@=$(gitexecdir_relative_SQ)=g' \
- -e 's=@@LOCALEDIR_REL@@=$(localedir_relative_SQ)=g' \
+ sed -e 's=@PATHSEP@=$(pathsep)=g' \
+ -e "s=@INSTLIBDIR@=$$INSTLIBDIR=g" \
+ -e 's=@PERLLIBDIR_REL@=$(perllibdir_relative_SQ)=g' \
+ -e 's=@GITEXECDIR_REL@=$(gitexecdir_relative_SQ)=g' \
+ -e 's=@LOCALEDIR_REL@=$(localedir_relative_SQ)=g' \
$< >$@+ && \
mv $@+ $@
@@ -2641,15 +2620,15 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile
perllibdir:
@echo '$(perllibdir_SQ)'
-git-instaweb: git-instaweb.sh GIT-SCRIPT-DEFINES
- $(QUIET_GEN)$(cmd_munge_script) && \
+git-instaweb: git-instaweb.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES
+ $(QUIET_GEN)./generate-script.sh "$<" "$@+" ./GIT-BUILD-OPTIONS && \
chmod +x $@+ && \
mv $@+ $@
else # NO_PERL
$(SCRIPT_PERL_GEN) git-instaweb: % : unimplemented.sh
$(QUIET_GEN) \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's|@@REASON@@|NO_PERL=$(NO_PERL)|g' \
+ -e 's|@REASON@|NO_PERL=$(NO_PERL)|g' \
unimplemented.sh >$@+ && \
chmod +x $@+ && \
mv $@+ $@
@@ -2659,24 +2638,20 @@ endif # NO_PERL
$(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS
ifndef NO_PYTHON
-$(SCRIPT_PYTHON_GEN): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
+$(SCRIPT_PYTHON_GEN): generate-python.sh
$(SCRIPT_PYTHON_GEN): % : %.py
- $(QUIET_GEN) \
- sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
- $< >$@+ && \
- chmod +x $@+ && \
- mv $@+ $@
+ $(QUIET_GEN)$(SHELL_PATH) generate-python.sh ./GIT-BUILD-OPTIONS "$<" "$@"
else # NO_PYTHON
$(SCRIPT_PYTHON_GEN): % : unimplemented.sh
$(QUIET_GEN) \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's|@@REASON@@|NO_PYTHON=$(NO_PYTHON)|g' \
+ -e 's|@REASON@|NO_PYTHON=$(NO_PYTHON)|g' \
unimplemented.sh >$@+ && \
chmod +x $@+ && \
mv $@+ $@
endif # NO_PYTHON
-CONFIGURE_RECIPE = sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+CONFIGURE_RECIPE = sed -e 's/@GIT_VERSION@/$(GIT_VERSION)/g' \
configure.ac >configure.ac+ && \
autoconf -o configure configure.ac+ && \
$(RM) configure.ac+
@@ -2722,6 +2697,7 @@ REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o
REFTABLE_OBJS += reftable/stack.o
+REFTABLE_OBJS += reftable/system.o
REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o
@@ -3101,13 +3077,9 @@ endif
NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\'',$(NO_PERL_CPAN_FALLBACKS))
endif
-perl/build/lib/%.pm: perl/%.pm GIT-PERL-DEFINES
+perl/build/lib/%.pm: perl/%.pm generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES
$(call mkdir_p_parent_template)
- $(QUIET_GEN) \
- sed -e 's|@@LOCALEDIR@@|$(perl_localedir_SQ)|g' \
- -e 's|@@NO_GETTEXT@@|$(NO_GETTEXT_SQ)|g' \
- -e 's|@@NO_PERL_CPAN_FALLBACKS@@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \
- < $< > $@
+ $(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER "$<" "$@"
perl/build/man/man3/Git.3pm: perl/Git.pm
$(call mkdir_p_parent_template)
@@ -3160,80 +3132,66 @@ GIT-LDFLAGS: FORCE
echo "$$FLAGS" >GIT-LDFLAGS; \
fi
+ifdef RUNTIME_PREFIX
+RUNTIME_PREFIX_OPTION = true
+else
+RUNTIME_PREFIX_OPTION = false
+endif
+
# We need to apply sq twice, once to protect from the shell
# that runs GIT-BUILD-OPTIONS, and then again to protect it
# and the first level quoting from the shell that runs "echo".
GIT-BUILD-OPTIONS: FORCE
- @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@+
- @echo TEST_SHELL_PATH=\''$(subst ','\'',$(TEST_SHELL_PATH_SQ))'\' >>$@+
- @echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@+
- @echo DIFF=\''$(subst ','\'',$(subst ','\'',$(DIFF)))'\' >>$@+
- @echo PYTHON_PATH=\''$(subst ','\'',$(PYTHON_PATH_SQ))'\' >>$@+
- @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@+
- @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@+
- @echo NO_ICONV=\''$(subst ','\'',$(subst ','\'',$(NO_ICONV)))'\' >>$@+
- @echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@+
- @echo USE_LIBPCRE2=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE2)))'\' >>$@+
- @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
- @echo NO_PTHREADS=\''$(subst ','\'',$(subst ','\'',$(NO_PTHREADS)))'\' >>$@+
- @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+
- @echo NO_REGEX=\''$(subst ','\'',$(subst ','\'',$(NO_REGEX)))'\' >>$@+
- @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
- @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
- @echo SANITIZE_LEAK=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_LEAK)))'\' >>$@+
- @echo SANITIZE_ADDRESS=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_ADDRESS)))'\' >>$@+
- @echo X=\'$(X)\' >>$@+
-ifdef FSMONITOR_DAEMON_BACKEND
- @echo FSMONITOR_DAEMON_BACKEND=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_DAEMON_BACKEND)))'\' >>$@+
-endif
-ifdef FSMONITOR_OS_SETTINGS
- @echo FSMONITOR_OS_SETTINGS=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_OS_SETTINGS)))'\' >>$@+
-endif
-ifdef TEST_OUTPUT_DIRECTORY
- @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+
-endif
-ifdef GIT_TEST_OPTS
- @echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@+
-endif
-ifdef GIT_TEST_CMP
- @echo GIT_TEST_CMP=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_CMP)))'\' >>$@+
-endif
-ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
- @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@+
-endif
-ifdef GIT_TEST_UTF8_LOCALE
- @echo GIT_TEST_UTF8_LOCALE=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_UTF8_LOCALE)))'\' >>$@+
-endif
- @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@+
-ifdef GIT_PERF_REPEAT_COUNT
- @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@+
-endif
-ifdef GIT_PERF_REPO
- @echo GIT_PERF_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPO)))'\' >>$@+
-endif
-ifdef GIT_PERF_LARGE_REPO
- @echo GIT_PERF_LARGE_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_LARGE_REPO)))'\' >>$@+
-endif
-ifdef GIT_PERF_MAKE_OPTS
- @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@+
-endif
-ifdef GIT_PERF_MAKE_COMMAND
- @echo GIT_PERF_MAKE_COMMAND=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_COMMAND)))'\' >>$@+
-endif
-ifdef GIT_INTEROP_MAKE_OPTS
- @echo GIT_INTEROP_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_INTEROP_MAKE_OPTS)))'\' >>$@+
-endif
-ifdef GIT_TEST_INDEX_VERSION
- @echo GIT_TEST_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_INDEX_VERSION)))'\' >>$@+
-endif
-ifdef GIT_TEST_PERL_FATAL_WARNINGS
- @echo GIT_TEST_PERL_FATAL_WARNINGS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_PERL_FATAL_WARNINGS)))'\' >>$@+
-endif
-ifdef RUNTIME_PREFIX
- @echo RUNTIME_PREFIX=\'true\' >>$@+
-else
- @echo RUNTIME_PREFIX=\'false\' >>$@+
-endif
+ @sed \
+ -e "s|@SHELL_PATH@|\'$(SHELL_PATH_SQ)\'|" \
+ -e "s|@TEST_SHELL_PATH@|\'$(TEST_SHELL_PATH_SQ)\'|" \
+ -e "s|@PERL_PATH@|\'$(PERL_PATH_SQ)\'|" \
+ -e "s|@PERL_LOCALEDIR@|\'$(perl_localedir_SQ)\'|" \
+ -e "s|@NO_PERL_CPAN_FALLBACKS@|\'$(NO_PERL_CPAN_FALLBACKS_SQ)\'|" \
+ -e "s|@DIFF@|\'$(DIFF)\'|" \
+ -e "s|@PYTHON_PATH@|\'$(PYTHON_PATH_SQ)\'|" \
+ -e "s|@TAR@|\'$(TAR)\'|" \
+ -e "s|@NO_CURL@|\'$(NO_CURL)\'|" \
+ -e "s|@NO_ICONV@|\'$(NO_ICONV)\'|" \
+ -e "s|@NO_EXPAT@|\'$(NO_EXPAT)\'|" \
+ -e "s|@USE_LIBPCRE2@|\'$(USE_LIBPCRE2)\'|" \
+ -e "s|@NO_PERL@|\'$(NO_PERL)\'|" \
+ -e "s|@NO_PTHREADS@|\'$(NO_PTHREADS)\'|" \
+ -e "s|@NO_PYTHON@|\'$(NO_PYTHON)\'|" \
+ -e "s|@NO_REGEX@|\'$(NO_REGEX)\'|" \
+ -e "s|@NO_UNIX_SOCKETS@|\'$(NO_UNIX_SOCKETS)\'|" \
+ -e "s|@PAGER_ENV@|\'$(PAGER_ENV)\'|" \
+ -e "s|@SANITIZE_LEAK@|\'$(SANITIZE_LEAK)\'|" \
+ -e "s|@SANITIZE_ADDRESS@|\'$(SANITIZE_ADDRESS)\'|" \
+ -e "s|@X@|\'$(X)\'|" \
+ -e "s|@FSMONITOR_DAEMON_BACKEND@|\'$(FSMONITOR_DAEMON_BACKEND)\'|" \
+ -e "s|@FSMONITOR_OS_SETTINGS@|\'$(FSMONITOR_OS_SETTINGS)\'|" \
+ -e "s|@TEST_OUTPUT_DIRECTORY@|\'$(TEST_OUTPUT_DIRECTORY)\'|" \
+ -e "s|@GIT_TEST_OPTS@|\'$(GIT_TEST_OPTS)\'|" \
+ -e "s|@GIT_TEST_CMP@|\'$(GIT_TEST_CMP)\'|" \
+ -e "s|@GIT_TEST_CMP_USE_COPIED_CONTEXT@|\'$(GIT_TEST_CMP_USE_COPIED_CONTEXT)\'|" \
+ -e "s|@GIT_TEST_UTF8_LOCALE@|\'$(GIT_TEST_UTF8_LOCALE)\'|" \
+ -e "s|@NO_GETTEXT@|\'$(NO_GETTEXT)\'|" \
+ -e "s|@GIT_PERF_REPEAT_COUNT@|\'$(GIT_PERF_REPEAT_COUNT)\'|" \
+ -e "s|@GIT_PERF_REPO@|\'$(GIT_PERF_REPO)\'|" \
+ -e "s|@GIT_PERF_LARGE_REPO@|\'$(GIT_PERF_LARGE_REPO)\'|" \
+ -e "s|@GIT_PERF_MAKE_OPTS@|\'$(GIT_PERF_MAKE_OPTS)\'|" \
+ -e "s|@GIT_PERF_MAKE_COMMAND@|\'$(GIT_PERF_MAKE_COMMAND)\'|" \
+ -e "s|@GIT_INTEROP_MAKE_OPTS@|\'$(GIT_INTEROP_MAKE_OPTS)\'|" \
+ -e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \
+ -e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \
+ -e "s|@GIT_TEST_TEXTDOMAINDIR@|\'$(shell pwd)/po/build/locale\'|" \
+ -e "s|@GIT_TEST_POPATH@|\'$(shell pwd)/po\'|" \
+ -e "s|@GIT_TEST_TEMPLATE_DIR@|\'$(shell pwd)/templates/blt\'|" \
+ -e "s|@GIT_TEST_GITPERLLIB@|\'$(shell pwd)/perl/build/lib\'|" \
+ -e "s|@GIT_TEST_MERGE_TOOLS_DIR@|\'$(shell pwd)/mergetools\'|" \
+ -e "s|@RUNTIME_PREFIX@|\'$(RUNTIME_PREFIX_OPTION)\'|" \
+ -e "s|@GITWEBDIR@|\'$(gitwebdir_SQ)\'|" \
+ -e "s|@USE_GETTEXT_SCHEME@|\'$(USE_GETTEXT_SCHEME)\'|" \
+ -e "s|@LOCALEDIR@|\'$(localedir_SQ)\'|" \
+ -e "s!@BROKEN_PATH_FIX@!\'$(BROKEN_PATH_FIX)\'!" \
+ GIT-BUILD-OPTIONS.in >$@+
+ @if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi
@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
@if test -f GIT-BUILD-DIR; then rm GIT-BUILD-DIR; fi
@@ -3253,11 +3211,14 @@ test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(
all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
-bin-wrappers/%: wrap-for-bin.sh
- $(call mkdir_p_parent_template)
+$(test_bindir_programs): bin-wrappers/%: bin-wrappers/wrap-for-bin.sh
$(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's|@@BUILD_DIR@@|$(shell pwd)|' \
- -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \
+ -e 's|@BUILD_DIR@|$(shell pwd)|' \
+ -e 's|@GIT_TEXTDOMAINDIR@|$(shell pwd)/po/build/locale|' \
+ -e 's|@GITPERLLIB@|$(shell pwd)/perl/build/lib|' \
+ -e 's|@MERGE_TOOLS_DIR@|$(shell pwd)/mergetools|' \
+ -e 's|@TEMPLATE_DIR@|$(shell pwd)/templates/blt|' \
+ -e 's|@PROG@|$(shell pwd)/$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \
chmod +x $@
# GNU make supports exporting all variables by "export" without parameters.
@@ -3741,7 +3702,7 @@ clean: profile-clean coverage-clean cocciclean
$(RM) -r .build $(UNIT_TEST_BIN)
$(RM) GIT-TEST-SUITES
$(RM) po/git.pot po/git-core.pot
- $(RM) git.res
+ $(RM) git.rc git.res
$(RM) $(OBJECTS)
$(RM) headless-git.o
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB)
@@ -3750,7 +3711,9 @@ clean: profile-clean coverage-clean cocciclean
$(RM) $(FUZZ_PROGRAMS)
$(RM) $(SP_OBJ)
$(RM) $(HCC)
- $(RM) -r bin-wrappers $(dep_dirs) $(compdb_dir) compile_commands.json
+ $(RM) version-def.h
+ $(RM) -r $(dep_dirs) $(compdb_dir) compile_commands.json
+ $(RM) $(test_bindir_programs)
$(RM) -r po/build/
$(RM) *.pyc *.pyo */*.pyc */*.pyo $(GENERATED_H) $(ETAGS_TARGET) tags cscope*
$(RM) -r .dist-tmp-dir .doc-tmp-dir
diff --git a/advice.c b/advice.c
index 147b596d33..1df43b7536 100644
--- a/advice.c
+++ b/advice.c
@@ -53,6 +53,7 @@ static struct {
[ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge" },
[ADVICE_DETACHED_HEAD] = { "detachedHead" },
[ADVICE_DIVERGING] = { "diverging" },
+ [ADVICE_FETCH_SET_HEAD_WARN] = { "fetchRemoteHEADWarn" },
[ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates" },
[ADVICE_FORCE_DELETE_BRANCH] = { "forceDeleteBranch" },
[ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated" },
@@ -93,7 +94,7 @@ static struct {
static const char turn_off_instructions[] =
N_("\n"
- "Disable this message with \"git config advice.%s false\"");
+ "Disable this message with \"git config set advice.%s false\"");
static void vadvise(const char *advice, int display_instructions,
const char *key, va_list params)
diff --git a/advice.h b/advice.h
index d7466bc0ef..cf2284ec43 100644
--- a/advice.h
+++ b/advice.h
@@ -20,6 +20,7 @@ enum advice_type {
ADVICE_COMMIT_BEFORE_MERGE,
ADVICE_DETACHED_HEAD,
ADVICE_DIVERGING,
+ ADVICE_FETCH_SET_HEAD_WARN,
ADVICE_FETCH_SHOW_FORCED_UPDATES,
ADVICE_FORCE_DELETE_BRANCH,
ADVICE_GRAFT_FILE_DEPRECATED,
diff --git a/attr.c b/attr.c
index 67f11c96a5..0bd2750528 100644
--- a/attr.c
+++ b/attr.c
@@ -260,42 +260,6 @@ const struct git_attr *git_attr(const char *name)
return git_attr_internal(name, strlen(name));
}
-/* What does a matched pattern decide? */
-struct attr_state {
- const struct git_attr *attr;
- const char *setto;
-};
-
-struct pattern {
- const char *pattern;
- int patternlen;
- int nowildcardlen;
- unsigned flags; /* PATTERN_FLAG_* */
-};
-
-/*
- * One rule, as from a .gitattributes file.
- *
- * If is_macro is true, then u.attr is a pointer to the git_attr being
- * defined.
- *
- * If is_macro is false, then u.pat is the filename pattern to which the
- * rule applies.
- *
- * In either case, num_attr is the number of attributes affected by
- * this rule, and state is an array listing them. The attributes are
- * listed as they appear in the file (macros unexpanded).
- */
-struct match_attr {
- union {
- struct pattern pat;
- const struct git_attr *attr;
- } u;
- char is_macro;
- size_t num_attr;
- struct attr_state state[FLEX_ARRAY];
-};
-
static const char blank[] = " \t\r\n";
/* Flags usable in read_attr() and parse_attr_line() family of functions. */
@@ -354,8 +318,8 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
return ep + strspn(ep, blank);
}
-static struct match_attr *parse_attr_line(const char *line, const char *src,
- int lineno, unsigned flags)
+struct match_attr *parse_attr_line(const char *line, const char *src,
+ int lineno, unsigned flags)
{
size_t namelen, num_attr, i;
const char *cp, *name, *states;
diff --git a/attr.h b/attr.h
index bb33b60880..a04a521092 100644
--- a/attr.h
+++ b/attr.h
@@ -240,4 +240,47 @@ int git_attr_system_is_enabled(void);
extern char *git_attr_tree;
+/*
+ * Exposed for fuzz-testing only.
+ */
+
+/* What does a matched pattern decide? */
+struct attr_state {
+ const struct git_attr *attr;
+ const char *setto;
+};
+
+struct pattern {
+ const char *pattern;
+ int patternlen;
+ int nowildcardlen;
+ unsigned flags; /* PATTERN_FLAG_* */
+};
+
+/*
+ * One rule, as from a .gitattributes file.
+ *
+ * If is_macro is true, then u.attr is a pointer to the git_attr being
+ * defined.
+ *
+ * If is_macro is false, then u.pat is the filename pattern to which the
+ * rule applies.
+ *
+ * In either case, num_attr is the number of attributes affected by
+ * this rule, and state is an array listing them. The attributes are
+ * listed as they appear in the file (macros unexpanded).
+ */
+struct match_attr {
+ union {
+ struct pattern pat;
+ const struct git_attr *attr;
+ } u;
+ char is_macro;
+ size_t num_attr;
+ struct attr_state state[FLEX_ARRAY];
+};
+
+struct match_attr *parse_attr_line(const char *line, const char *src,
+ int lineno, unsigned flags);
+
#endif /* ATTR_H */
diff --git a/bin-wrappers/.gitignore b/bin-wrappers/.gitignore
new file mode 100644
index 0000000000..1c6c90458b
--- /dev/null
+++ b/bin-wrappers/.gitignore
@@ -0,0 +1,9 @@
+/git
+/git-cvsserver
+/git-receive-pack
+/git-shell
+/git-upload-archive
+/git-upload-pack
+/scalar
+/test-fake-ssh
+/test-tool
diff --git a/bin-wrappers/meson.build b/bin-wrappers/meson.build
new file mode 100644
index 0000000000..8a4e910c9b
--- /dev/null
+++ b/bin-wrappers/meson.build
@@ -0,0 +1,28 @@
+bin_wrappers_config = configuration_data()
+foreach key, value : {
+ 'BUILD_DIR': meson.project_build_root(),
+ 'MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools',
+ 'TEMPLATE_DIR': meson.project_build_root() / 'templates',
+ 'GIT_TEXTDOMAINDIR': meson.project_build_root() / 'po',
+ 'GITPERLLIB': meson.project_build_root() / 'perl/lib',
+}
+ # Paths need to be Unix-style without drive prefixes as they get added to the
+ # PATH variable. And given that drive prefixes contain a colon we'd otherwise
+ # end up with a broken PATH if we didn't convert them.
+ if cygpath.found()
+ value = run_command(cygpath, value, check: true).stdout().strip()
+ endif
+ bin_wrappers_config.set(key, value)
+endforeach
+
+foreach executable : bin_wrappers
+ executable_config = configuration_data()
+ executable_config.merge_from(bin_wrappers_config)
+ executable_config.set('PROG', executable.full_path())
+
+ configure_file(
+ input: 'wrap-for-bin.sh',
+ output: fs.stem(executable.full_path()),
+ configuration: executable_config,
+ )
+endforeach
diff --git a/bin-wrappers/wrap-for-bin.sh b/bin-wrappers/wrap-for-bin.sh
new file mode 100755
index 0000000000..4b658ffd2d
--- /dev/null
+++ b/bin-wrappers/wrap-for-bin.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# wrap-for-bin.sh: Template for git executable wrapper scripts
+# to run test suite against sandbox, but with only bindir-installed
+# executables in PATH. The Makefile copies this into various
+# files in bin-wrappers, substituting
+# @BUILD_DIR@, @TEMPLATE_DIR@ and @PROG@.
+
+GIT_EXEC_PATH='@BUILD_DIR@'
+if test -n "$NO_SET_GIT_TEMPLATE_DIR"
+then
+ unset GIT_TEMPLATE_DIR
+else
+ GIT_TEMPLATE_DIR='@TEMPLATE_DIR@'
+ export GIT_TEMPLATE_DIR
+fi
+MERGE_TOOLS_DIR='@MERGE_TOOLS_DIR@'
+GITPERLLIB='@GITPERLLIB@'"${GITPERLLIB:+:$GITPERLLIB}"
+GIT_TEXTDOMAINDIR='@GIT_TEXTDOMAINDIR@'
+PATH='@BUILD_DIR@/bin-wrappers:'"$PATH"
+
+export MERGE_TOOLS_DIR GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR
+
+case "$GIT_DEBUGGER" in
+'')
+ exec "@PROG@" "$@"
+ ;;
+1)
+ unset GIT_DEBUGGER
+ exec gdb --args "@PROG@" "$@"
+ ;;
+*)
+ GIT_DEBUGGER_ARGS="$GIT_DEBUGGER"
+ unset GIT_DEBUGGER
+ exec ${GIT_DEBUGGER_ARGS} "@PROG@" "$@"
+ ;;
+esac
diff --git a/branch.c b/branch.c
index ebaa870c01..77716966fe 100644
--- a/branch.c
+++ b/branch.c
@@ -372,7 +372,7 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
*/
int validate_branchname(const char *name, struct strbuf *ref)
{
- if (strbuf_check_branch_ref(ref, name)) {
+ if (check_branch_ref(ref, name)) {
int code = die_message(_("'%s' is not a valid branch name"), name);
advise_if_enabled(ADVICE_REF_SYNTAX,
_("See `man git check-ref-format`"));
diff --git a/builtin/branch.c b/builtin/branch.c
index 3737a11cbf..6e7b0cfddb 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -259,7 +259,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
char *target = NULL;
int flags = 0;
- strbuf_branchname(&bname, argv[i], allowed_interpret);
+ copy_branchname(&bname, argv[i], allowed_interpret);
free(name);
name = mkpathdup(fmt, bname.buf);
@@ -581,7 +581,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
int recovery = 0, oldref_usage = 0;
struct worktree **worktrees = get_worktrees();
- if (strbuf_check_branch_ref(&oldref, oldname)) {
+ if (check_branch_ref(&oldref, oldname)) {
/*
* Bad name --- this could be an attempt to rename a
* ref that we used to allow to be created by accident.
@@ -898,7 +898,7 @@ int cmd_branch(int argc,
die(_("cannot give description to detached HEAD"));
branch_name = head;
} else if (argc == 1) {
- strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
branch_name = buf.buf;
} else {
die(_("cannot edit description of more than one branch"));
@@ -941,7 +941,7 @@ int cmd_branch(int argc,
if (!argc)
branch = branch_get(NULL);
else if (argc == 1) {
- strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
branch = branch_get(buf.buf);
} else
die(_("too many arguments to set new upstream"));
@@ -971,7 +971,7 @@ int cmd_branch(int argc,
if (!argc)
branch = branch_get(NULL);
else if (argc == 1) {
- strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
branch = branch_get(buf.buf);
} else
die(_("too many arguments to unset upstream"));
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 3f14754197..1e170e9278 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -222,7 +222,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix,
strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
_("Unbundling objects"), NULL);
ret = !!unbundle(the_repository, &header, bundle_fd,
- &extra_index_pack_args, 0) ||
+ &extra_index_pack_args, NULL) ||
list_bundle_refs(&header, argc, argv);
bundle_header_release(&header);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 825d7d83b2..b13561cf73 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -830,15 +830,16 @@ static int batch_objects(struct batch_options *opt)
cb.seen = &seen;
for_each_loose_object(batch_unordered_loose, &cb, 0);
- for_each_packed_object(batch_unordered_packed, &cb,
- FOR_EACH_OBJECT_PACK_ORDER);
+ for_each_packed_object(the_repository, batch_unordered_packed,
+ &cb, FOR_EACH_OBJECT_PACK_ORDER);
oidset_clear(&seen);
} else {
struct oid_array sa = OID_ARRAY_INIT;
for_each_loose_object(collect_loose_object, &sa, 0);
- for_each_packed_object(collect_packed_object, &sa, 0);
+ for_each_packed_object(the_repository, collect_packed_object,
+ &sa, 0);
oid_array_for_each_unique(&sa, batch_object_cb, &cb);
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index e86d8ef980..cef1ffe3ce 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -42,7 +42,7 @@ static int check_ref_format_branch(const char *arg)
int nongit;
setup_git_directory_gently(&nongit);
- if (strbuf_check_branch_ref(&sb, arg) ||
+ if (check_branch_ref(&sb, arg) ||
!skip_prefix(sb.buf, "refs/heads/", &name))
die("'%s' is not a valid branch name", arg);
printf("%s\n", name);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 1f92e8297b..01ea9ff8b2 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -744,7 +744,7 @@ static void setup_branch_path(struct branch_info *branch)
&branch->oid, &branch->refname, 0))
repo_get_oid_committish(the_repository, branch->name, &branch->oid);
- strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
if (strcmp(buf.buf, branch->name)) {
free(branch->name);
branch->name = xstrdup(buf.buf);
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 04d80887e0..1e89148ed7 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -67,7 +67,7 @@ static int count_loose(const struct object_id *oid, const char *path,
else {
loose_size += on_disk_bytes(st);
loose++;
- if (verbose && has_object_pack(oid))
+ if (verbose && has_object_pack(the_repository, oid))
packed_loose++;
}
return 0;
diff --git a/builtin/describe.c b/builtin/describe.c
index 9045e583b7..e2e73f3d75 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -368,6 +368,13 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
struct commit_name **slot;
seen_commits++;
+
+ if (match_cnt == max_candidates ||
+ match_cnt == hashmap_get_size(&names)) {
+ gave_up_on = c;
+ break;
+ }
+
slot = commit_names_peek(&commit_names, c);
n = slot ? *slot : NULL;
if (n) {
@@ -383,10 +390,6 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
if (n->prio == 2)
annotated_cnt++;
}
- else {
- gave_up_on = c;
- break;
- }
}
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
struct possible_tag *t = &all_matches[cur_match];
@@ -472,9 +475,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
if (gave_up_on) {
fprintf(stderr,
- _("more than %i tags found; listed %i most recent\n"
- "gave up search at %s\n"),
- max_candidates, max_candidates,
+ _("found %i tags; gave up search at %s\n"),
+ max_candidates,
oid_to_hex(&gave_up_on->object.oid));
}
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 1cc5911bb0..1fa2929a01 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -15,6 +15,7 @@
#include "delta.h"
#include "pack.h"
#include "path.h"
+#include "read-cache-ll.h"
#include "refs.h"
#include "csum-file.h"
#include "quote.h"
@@ -768,6 +769,7 @@ static void start_packfile(void)
p->pack_fd = pack_fd;
p->do_not_close = 1;
+ p->repo = the_repository;
pack_file = hashfd(pack_fd, p->pack_name);
pack_data = p;
@@ -808,7 +810,7 @@ static char *keep_pack(const char *curr_index_name)
struct strbuf name = STRBUF_INIT;
int keep_fd;
- odb_pack_name(&name, pack_data->hash, "keep");
+ odb_pack_name(pack_data->repo, &name, pack_data->hash, "keep");
keep_fd = odb_pack_keep(name.buf);
if (keep_fd < 0)
die_errno("cannot create keep file");
@@ -816,11 +818,11 @@ static char *keep_pack(const char *curr_index_name)
if (close(keep_fd))
die_errno("failed to write keep file");
- odb_pack_name(&name, pack_data->hash, "pack");
+ odb_pack_name(pack_data->repo, &name, pack_data->hash, "pack");
if (finalize_object_file(pack_data->pack_name, name.buf))
die("cannot store pack file");
- odb_pack_name(&name, pack_data->hash, "idx");
+ odb_pack_name(pack_data->repo, &name, pack_data->hash, "idx");
if (finalize_object_file(curr_index_name, name.buf))
die("cannot store index file");
free((void *)curr_index_name);
@@ -834,7 +836,7 @@ static void unkeep_all_packs(void)
for (k = 0; k < pack_id; k++) {
struct packed_git *p = all_packs[k];
- odb_pack_name(&name, p->hash, "keep");
+ odb_pack_name(p->repo, &name, p->hash, "keep");
unlink_or_warn(name.buf);
}
strbuf_release(&name);
@@ -891,7 +893,7 @@ static void end_packfile(void)
idx_name = keep_pack(create_index());
/* Register the packfile with core git's machinery. */
- new_p = add_packed_git(idx_name, strlen(idx_name), 1);
+ new_p = add_packed_git(pack_data->repo, idx_name, strlen(idx_name), 1);
if (!new_p)
die("core git rejected index %s", idx_name);
all_packs[pack_id] = new_p;
@@ -2427,6 +2429,9 @@ static void file_change_m(const char *p, struct branch *b)
tree_content_replace(&b->branch_tree, &oid, mode, NULL);
return;
}
+
+ if (!verify_path(path.buf, mode))
+ die("invalid path '%s'", path.buf);
tree_content_set(&b->branch_tree, path.buf, &oid, mode, NULL);
}
@@ -2464,6 +2469,8 @@ static void file_change_cr(const char *p, struct branch *b, int rename)
leaf.tree);
return;
}
+ if (!verify_path(dest.buf, leaf.versions[1].mode))
+ die("invalid path '%s'", dest.buf);
tree_content_set(&b->branch_tree, dest.buf,
&leaf.versions[1].oid,
leaf.versions[1].mode,
@@ -3554,7 +3561,7 @@ static void parse_argv(void)
int cmd_fast_import(int argc,
const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
unsigned int i;
@@ -3675,7 +3682,7 @@ int cmd_fast_import(int argc,
fprintf(stderr, " pools: %10lu KiB\n", (unsigned long)((tree_entry_allocd + fi_mem_pool.pool_alloc) /1024));
fprintf(stderr, " objects: %10" PRIuMAX " KiB\n", (alloc_count*sizeof(struct object_entry))/1024);
fprintf(stderr, "---------------------------------------------------------------------\n");
- pack_report();
+ pack_report(repo);
fprintf(stderr, "---------------------------------------------------------------------\n");
fprintf(stderr, "\n");
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b7457a7274..2d37a378ba 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1577,6 +1577,135 @@ static int backfill_tags(struct display_state *display_state,
return retcode;
}
+static const char *strip_refshead(const char *name){
+ skip_prefix(name, "refs/heads/", &name);
+ return name;
+}
+
+static void set_head_advice_msg(const char *remote, const char *head_name)
+{
+ const char message_advice_set_head[] =
+ N_("Run 'git remote set-head %s %s' to follow the change, or set\n"
+ "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
+ "if you do not want to see this message. Specifically running\n"
+ "'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
+ "until the remote changes HEAD to something else.");
+
+ advise_if_enabled(ADVICE_FETCH_SET_HEAD_WARN, _(message_advice_set_head),
+ remote, head_name, remote, remote, head_name);
+}
+
+static void report_set_head(const char *remote, const char *head_name,
+ struct strbuf *buf_prev, int updateres) {
+ struct strbuf buf_prefix = STRBUF_INIT;
+ const char *prev_head = NULL;
+
+ strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote);
+ skip_prefix(buf_prev->buf, buf_prefix.buf, &prev_head);
+
+ if (prev_head && strcmp(prev_head, head_name)) {
+ printf("'HEAD' at '%s' is '%s', but we have '%s' locally.\n",
+ remote, head_name, prev_head);
+ set_head_advice_msg(remote, head_name);
+ }
+ else if (updateres && buf_prev->len) {
+ printf("'HEAD' at '%s' is '%s', "
+ "but we have a detached HEAD pointing to '%s' locally.\n",
+ remote, head_name, buf_prev->buf);
+ set_head_advice_msg(remote, head_name);
+ }
+ strbuf_release(&buf_prefix);
+}
+
+static int set_head(const struct ref *remote_refs, int follow_remote_head,
+ const char *no_warn_branch)
+{
+ int result = 0, create_only, is_bare, was_detached;
+ struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
+ b_local_head = STRBUF_INIT;
+ const char *remote = gtransport->remote->name;
+ char *head_name = NULL;
+ struct ref *ref, *matches;
+ struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
+ struct refspec_item refspec = {
+ .force = 0,
+ .pattern = 1,
+ .src = (char *) "refs/heads/*",
+ .dst = (char *) "refs/heads/*",
+ };
+ struct string_list heads = STRING_LIST_INIT_DUP;
+ struct ref_store *refs = get_main_ref_store(the_repository);
+
+ get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
+ matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
+ fetch_map, 1);
+ for (ref = matches; ref; ref = ref->next) {
+ string_list_append(&heads, strip_refshead(ref->name));
+ }
+
+ if (follow_remote_head == FOLLOW_REMOTE_NEVER)
+ goto cleanup;
+
+ if (!heads.nr)
+ result = 1;
+ else if (heads.nr > 1)
+ result = 1;
+ else
+ head_name = xstrdup(heads.items[0].string);
+
+ if (!head_name)
+ goto cleanup;
+ is_bare = is_bare_repository();
+ create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !is_bare;
+ if (is_bare) {
+ strbuf_addstr(&b_head, "HEAD");
+ strbuf_addf(&b_remote_head, "refs/heads/%s", head_name);
+ } else {
+ strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote);
+ strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name);
+ }
+ /* make sure it's valid */
+ if (!is_bare && !refs_ref_exists(refs, b_remote_head.buf)) {
+ result = 1;
+ goto cleanup;
+ }
+ was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
+ "fetch", &b_local_head, create_only);
+ if (was_detached == -1) {
+ result = 1;
+ goto cleanup;
+ }
+ if (verbosity >= 0 &&
+ follow_remote_head == FOLLOW_REMOTE_WARN &&
+ (!no_warn_branch || strcmp(no_warn_branch, head_name)))
+ report_set_head(remote, head_name, &b_local_head, was_detached);
+
+cleanup:
+ free(head_name);
+ free_refs(fetch_map);
+ free_refs(matches);
+ string_list_clear(&heads, 0);
+ strbuf_release(&b_head);
+ strbuf_release(&b_local_head);
+ strbuf_release(&b_remote_head);
+ return result;
+}
+
+static int uses_remote_tracking(struct transport *transport, struct refspec *rs)
+{
+ if (!remote_is_configured(transport->remote, 0))
+ return 0;
+
+ if (!rs->nr)
+ rs = &transport->remote->fetch;
+
+ for (int i = 0; i < rs->nr; i++)
+ if (rs->items[i].dst)
+ return 1;
+
+ return 0;
+}
+
static int do_fetch(struct transport *transport,
struct refspec *rs,
const struct fetch_config *config)
@@ -1646,6 +1775,11 @@ static int do_fetch(struct transport *transport,
"refs/tags/");
}
+ if (uses_remote_tracking(transport, rs)) {
+ must_list_refs = 1;
+ strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+ }
+
if (must_list_refs) {
trace2_region_enter("fetch", "remote_refs", the_repository);
remote_refs = transport_get_remote_refs(transport,
@@ -1790,6 +1924,13 @@ static int do_fetch(struct transport *transport,
"you need to specify exactly one branch with the --set-upstream option"));
}
}
+ if (set_head(remote_refs, transport->remote->follow_remote_head,
+ transport->remote->no_warn_branch))
+ ;
+ /*
+ * Way too many cases where this can go wrong
+ * so let's just fail silently for now.
+ */
cleanup:
if (retcode) {
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 7f4e2f0414..0196c54eb6 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -150,7 +150,7 @@ static int mark_object(struct object *obj, enum object_type type,
return 0;
obj->flags |= REACHABLE;
- if (is_promisor_object(&obj->oid))
+ if (is_promisor_object(the_repository, &obj->oid))
/*
* Further recursion does not need to be performed on this
* object since it is a promisor object (so it does not need to
@@ -270,9 +270,9 @@ static void check_reachable_object(struct object *obj)
* do a full fsck
*/
if (!(obj->flags & HAS_OBJ)) {
- if (is_promisor_object(&obj->oid))
+ if (is_promisor_object(the_repository, &obj->oid))
return;
- if (has_object_pack(&obj->oid))
+ if (has_object_pack(the_repository, &obj->oid))
return; /* it is in pack - forget about it */
printf_ln(_("missing %s %s"),
printable_type(&obj->oid, obj->type),
@@ -391,7 +391,10 @@ static void check_connectivity(void)
* traversal.
*/
for_each_loose_object(mark_loose_unreachable_referents, NULL, 0);
- for_each_packed_object(mark_packed_unreachable_referents, NULL, 0);
+ for_each_packed_object(the_repository,
+ mark_packed_unreachable_referents,
+ NULL,
+ 0);
}
/* Look up all the requirements, warn about missing objects.. */
@@ -488,7 +491,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
refname, timestamp);
obj->flags |= USED;
mark_object_reachable(obj);
- } else if (!is_promisor_object(oid)) {
+ } else if (!is_promisor_object(the_repository, oid)) {
error(_("%s: invalid reflog entry %s"),
refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
@@ -531,7 +534,7 @@ static int fsck_handle_ref(const char *refname, const char *referent UNUSED, con
obj = parse_object(the_repository, oid);
if (!obj) {
- if (is_promisor_object(oid)) {
+ if (is_promisor_object(the_repository, oid)) {
/*
* Increment default_refs anyway, because this is a
* valid ref.
@@ -966,7 +969,8 @@ int cmd_fsck(int argc,
if (connectivity_only) {
for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
- for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
+ for_each_packed_object(the_repository,
+ mark_packed_for_connectivity, NULL, 0);
} else {
prepare_alt_odb(the_repository);
for (odb = the_repository->objects->odb; odb; odb = odb->next)
@@ -1011,7 +1015,7 @@ int cmd_fsck(int argc,
&oid);
if (!obj || !(obj->flags & HAS_OBJ)) {
- if (is_promisor_object(&oid))
+ if (is_promisor_object(the_repository, &oid))
continue;
error(_("%s: object missing"), oid_to_hex(&oid));
errors_found |= ERROR_OBJECT;
diff --git a/builtin/gc.c b/builtin/gc.c
index a5879d6b6b..a9b1c36de2 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -141,6 +141,11 @@ struct gc_config {
char *repack_filter_to;
unsigned long big_pack_threshold;
unsigned long max_delta_cache_size;
+ /*
+ * Remove this member from gc_config once repo_settings is passed
+ * through the callchain.
+ */
+ size_t delta_base_cache_limit;
};
#define GC_CONFIG_INIT { \
@@ -156,6 +161,7 @@ struct gc_config {
.prune_expire = xstrdup("2.weeks.ago"), \
.prune_worktrees_expire = xstrdup("3.months.ago"), \
.max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \
+ .delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \
}
static void gc_config_release(struct gc_config *cfg)
@@ -171,6 +177,7 @@ static void gc_config(struct gc_config *cfg)
{
const char *value;
char *owned = NULL;
+ unsigned long ulongval;
if (!git_config_get_value("gc.packrefs", &value)) {
if (value && !strcmp(value, "notbare"))
@@ -209,6 +216,9 @@ static void gc_config(struct gc_config *cfg)
git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
+ if (!git_config_get_ulong("core.deltabasecachelimit", &ulongval))
+ cfg->delta_base_cache_limit = ulongval;
+
if (!git_config_get_string("gc.repackfilter", &owned)) {
free(cfg->repack_filter);
cfg->repack_filter = owned;
@@ -419,7 +429,7 @@ static uint64_t estimate_repack_memory(struct gc_config *cfg,
* read_sha1_file() (either at delta calculation phase, or
* writing phase) also fills up the delta base cache
*/
- heap += delta_base_cache_limit;
+ heap += cfg->delta_base_cache_limit;
/* and of course pack-objects has its own delta cache */
heap += cfg->max_delta_cache_size;
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 54c7faf6ee..d773809c4c 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -157,11 +157,11 @@ static int input_fd, output_fd;
static const char *curr_pack;
/*
- * local_links is guarded by read_mutex, and record_local_links is read-only in
- * a thread.
+ * outgoing_links is guarded by read_mutex, and record_outgoing_links is
+ * read-only in a thread.
*/
-static struct oidset local_links = OIDSET_INIT;
-static int record_local_links;
+static struct oidset outgoing_links = OIDSET_INIT;
+static int record_outgoing_links;
static struct thread_local_data *thread_data;
static int nr_dispatched;
@@ -814,18 +814,41 @@ static int check_collison(struct object_entry *entry)
return 0;
}
-static void record_if_local_object(const struct object_id *oid)
+static void record_outgoing_link(const struct object_id *oid)
{
- struct object_info info = OBJECT_INFO_INIT;
- if (oid_object_info_extended(the_repository, oid, &info, 0))
- /* Missing; assume it is a promisor object */
- return;
- if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
- return;
- oidset_insert(&local_links, oid);
+ oidset_insert(&outgoing_links, oid);
+}
+
+static void maybe_record_name_entry(const struct name_entry *entry)
+{
+ /*
+ * Checking only trees here results in a significantly faster packfile
+ * indexing, but the drawback is that if the packfile to be indexed
+ * references a local blob only directly (that is, never through a
+ * local tree), that local blob is in danger of being garbage
+ * collected. Such a situation may arise if we push local commits,
+ * including one with a change to a blob in the root tree, and then the
+ * server incorporates them into its main branch through a "rebase" or
+ * "squash" merge strategy, and then we fetch the new main branch from
+ * the server.
+ *
+ * This situation has not been observed yet - we have only noticed
+ * missing commits, not missing trees or blobs. (In fact, if it were
+ * believed that only missing commits are problematic, one could argue
+ * that we should also exclude trees during the outgoing link check;
+ * but it is safer to include them.)
+ *
+ * Due to the rarity of the situation (it has not been observed to
+ * happen in real life), and because the "penalty" in such a situation
+ * is merely to refetch the missing blob when it's needed (and this
+ * happens only once - when refetched, the blob goes into a promisor
+ * pack, so it won't be GC-ed, the tradeoff seems worth it.
+ */
+ if (S_ISDIR(entry->mode))
+ record_outgoing_link(&entry->oid);
}
-static void do_record_local_links(struct object *obj)
+static void do_record_outgoing_links(struct object *obj)
{
if (obj->type == OBJ_TREE) {
struct tree *tree = (struct tree *)obj;
@@ -839,16 +862,17 @@ static void do_record_local_links(struct object *obj)
*/
return;
while (tree_entry_gently(&desc, &entry))
- record_if_local_object(&entry.oid);
+ maybe_record_name_entry(&entry);
} else if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
struct commit_list *parents = commit->parents;
+ record_outgoing_link(get_commit_tree_oid(commit));
for (; parents; parents = parents->next)
- record_if_local_object(&parents->item->object.oid);
+ record_outgoing_link(&parents->item->object.oid);
} else if (obj->type == OBJ_TAG) {
struct tag *tag = (struct tag *) obj;
- record_if_local_object(get_tagged_oid(tag));
+ record_outgoing_link(get_tagged_oid(tag));
}
}
@@ -898,7 +922,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
free(has_data);
}
- if (strict || do_fsck_object || record_local_links) {
+ if (strict || do_fsck_object || record_outgoing_links) {
read_lock();
if (type == OBJ_BLOB) {
struct blob *blob = lookup_blob(the_repository, oid);
@@ -930,8 +954,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
die(_("fsck error in packed object"));
if (strict && fsck_walk(obj, NULL, &fsck_options))
die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
- if (record_local_links)
- do_record_local_links(obj);
+ if (record_outgoing_links)
+ do_record_outgoing_links(obj);
if (obj->type == OBJ_TREE) {
struct tree *item = (struct tree *) obj;
@@ -1293,7 +1317,7 @@ static void parse_pack_objects(unsigned char *hash)
* recursively checking if the resulting object is used as a base
* for some more deltas.
*/
-static void resolve_deltas(void)
+static void resolve_deltas(struct pack_idx_option *opts)
{
int i;
@@ -1309,7 +1333,7 @@ static void resolve_deltas(void)
nr_ref_deltas + nr_ofs_deltas);
nr_dispatched = 0;
- base_cache_limit = delta_base_cache_limit * nr_threads;
+ base_cache_limit = opts->delta_base_cache_limit * nr_threads;
if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
init_thread();
work_lock();
@@ -1534,7 +1558,7 @@ static void write_special_file(const char *suffix, const char *msg,
if (pack_name)
filename = derive_filename(pack_name, "pack", suffix, &name_buf);
else
- filename = odb_pack_name(&name_buf, hash, suffix);
+ filename = odb_pack_name(the_repository, &name_buf, hash, suffix);
fd = odb_pack_keep(filename);
if (fd < 0) {
@@ -1562,7 +1586,7 @@ static void rename_tmp_packfile(const char **final_name,
{
if (!*final_name || strcmp(*final_name, curr_name)) {
if (!*final_name)
- *final_name = odb_pack_name(name, hash, ext);
+ *final_name = odb_pack_name(the_repository, name, hash, ext);
if (finalize_object_file(curr_name, *final_name))
die(_("unable to rename temporary '*.%s' file to '%s'"),
ext, *final_name);
@@ -1607,7 +1631,8 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (do_fsck_object) {
struct packed_git *p;
- p = add_packed_git(final_index_name, strlen(final_index_name), 0);
+ p = add_packed_git(the_repository, final_index_name,
+ strlen(final_index_name), 0);
if (p)
install_packed_git(the_repository, p);
}
@@ -1658,6 +1683,10 @@ static int git_index_pack_config(const char *k, const char *v,
else
opts->flags &= ~WRITE_REV;
}
+ if (!strcmp(k, "core.deltabasecachelimit")) {
+ opts->delta_base_cache_limit = git_config_ulong(k, v, ctx->kvi);
+ return 0;
+ }
return git_default_config(k, v, ctx, cb);
}
@@ -1705,7 +1734,8 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
{
- struct packed_git *p = add_packed_git(pack_name, strlen(pack_name), 1);
+ struct packed_git *p = add_packed_git(the_repository, pack_name,
+ strlen(pack_name), 1);
if (!p)
die(_("Cannot open existing pack file '%s'"), pack_name);
@@ -1781,28 +1811,43 @@ static void repack_local_links(void)
struct strbuf line = STRBUF_INIT;
struct oidset_iter iter;
struct object_id *oid;
- char *base_name;
+ char *base_name = NULL;
- if (!oidset_size(&local_links))
+ if (!oidset_size(&outgoing_links))
return;
- base_name = mkpathdup("%s/pack/pack", repo_get_object_directory(the_repository));
+ oidset_iter_init(&outgoing_links, &iter);
+ while ((oid = oidset_iter_next(&iter))) {
+ struct object_info info = OBJECT_INFO_INIT;
+ if (oid_object_info_extended(the_repository, oid, &info, 0))
+ /* Missing; assume it is a promisor object */
+ continue;
+ if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
+ continue;
- strvec_push(&cmd.args, "pack-objects");
- strvec_push(&cmd.args, "--exclude-promisor-objects-best-effort");
- strvec_push(&cmd.args, base_name);
- cmd.git_cmd = 1;
- cmd.in = -1;
- cmd.out = -1;
- if (start_command(&cmd))
- die(_("could not start pack-objects to repack local links"));
+ if (!cmd.args.nr) {
+ base_name = mkpathdup(
+ "%s/pack/pack",
+ repo_get_object_directory(the_repository));
+ strvec_push(&cmd.args, "pack-objects");
+ strvec_push(&cmd.args,
+ "--exclude-promisor-objects-best-effort");
+ strvec_push(&cmd.args, base_name);
+ cmd.git_cmd = 1;
+ cmd.in = -1;
+ cmd.out = -1;
+ if (start_command(&cmd))
+ die(_("could not start pack-objects to repack local links"));
+ }
- oidset_iter_init(&local_links, &iter);
- while ((oid = oidset_iter_next(&iter))) {
if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
write_in_full(cmd.in, "\n", 1) < 0)
die(_("failed to feed local object to pack-objects"));
}
+
+ if (!cmd.args.nr)
+ return;
+
close(cmd.in);
out = xfdopen(cmd.out, "r");
@@ -1901,7 +1946,7 @@ int cmd_index_pack(int argc,
} else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
; /* nothing to do */
} else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
- record_local_links = 1;
+ record_outgoing_links = 1;
} else if (starts_with(arg, "--threads=")) {
char *end;
nr_threads = strtoul(arg+10, &end, 0);
@@ -2037,7 +2082,7 @@ int cmd_index_pack(int argc,
parse_pack_objects(pack_hash);
if (report_end_of_input)
write_in_full(2, "\0", 1);
- resolve_deltas();
+ resolve_deltas(&opts);
conclude_pack(fix_thin_pack, curr_pack, pack_hash);
free(ofs_deltas);
free(ref_deltas);
diff --git a/builtin/log.c b/builtin/log.c
index cb41a035c6..75e1b34123 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -531,10 +531,14 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
* but we didn't actually show the commit.
*/
rev->max_count++;
- if (!rev->reflog_info) {
+ if (!rev->reflog_info && !rev->remerge_diff) {
/*
* We may show a given commit multiple times when
- * walking the reflogs.
+ * walking the reflogs. Therefore we still need it.
+ *
+ * Likewise, we potentially still need the parents
+ * of * already shown commits to determine merge
+ * bases when showing remerge diffs.
*/
free_commit_buffer(the_repository->parsed_objects,
commit);
diff --git a/builtin/merge.c b/builtin/merge.c
index a2712a0bab..5f67007bba 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -501,7 +501,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
char *found_ref = NULL;
int len, early;
- strbuf_branchname(&bname, remote, 0);
+ copy_branchname(&bname, remote, 0);
remote = bname.buf;
oidclr(&branch_head, the_repository->hash_algo);
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 85e40a4b6d..2a938466f5 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -120,7 +120,7 @@ static void read_packs_from_stdin(struct string_list *to)
static int cmd_multi_pack_index_write(int argc, const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
struct option *options;
static struct option builtin_multi_pack_index_write_options[] = {
@@ -165,7 +165,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
read_packs_from_stdin(&packs);
- ret = write_midx_file_only(opts.object_dir, &packs,
+ ret = write_midx_file_only(repo, opts.object_dir, &packs,
opts.preferred_pack,
opts.refs_snapshot, opts.flags);
@@ -176,7 +176,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
}
- ret = write_midx_file(opts.object_dir, opts.preferred_pack,
+ ret = write_midx_file(repo, opts.object_dir, opts.preferred_pack,
opts.refs_snapshot, opts.flags);
free(opts.refs_snapshot);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index a5d6f8db60..1c3b842651 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1517,7 +1517,7 @@ static int want_found_object(const struct object_id *oid, int exclude,
return 0;
if (ignore_packed_keep_in_core && p->pack_keep_in_core)
return 0;
- if (has_object_kept_pack(oid, flags))
+ if (has_object_kept_pack(p->repo, oid, flags))
return 0;
}
@@ -3615,7 +3615,7 @@ static void show_cruft_commit(struct commit *commit, void *data)
static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
{
- return !has_object_kept_pack(&obj->oid, IN_CORE_KEEP_PACKS);
+ return !has_object_kept_pack(to_pack.repo, &obj->oid, IN_CORE_KEEP_PACKS);
}
static int cruft_include_check(struct commit *commit, void *data)
@@ -3846,7 +3846,8 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
* Quietly ignore EXPECTED missing objects. This avoids problems with
* staging them now and getting an odd error later.
*/
- if (!has_object(the_repository, &obj->oid, 0) && is_promisor_object(&obj->oid))
+ if (!has_object(the_repository, &obj->oid, 0) &&
+ is_promisor_object(to_pack.repo, &obj->oid))
return;
show_object(obj, name, data);
@@ -3915,7 +3916,9 @@ static int add_object_in_unpacked_pack(const struct object_id *oid,
static void add_objects_in_unpacked_packs(void)
{
- if (for_each_packed_object(add_object_in_unpacked_pack, NULL,
+ if (for_each_packed_object(to_pack.repo,
+ add_object_in_unpacked_pack,
+ NULL,
FOR_EACH_OBJECT_PACK_ORDER |
FOR_EACH_OBJECT_LOCAL_ONLY |
FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 275333f543..e046575871 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -690,7 +690,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s
pl = red = pack_list_difference(local_packs, min);
while (pl) {
printf("%s\n%s\n",
- odb_pack_name(&idx_name, pl->pack->hash, "idx"),
+ odb_pack_name(pl->pack->repo, &idx_name, pl->pack->hash, "idx"),
pl->pack->pack_name);
pl = pl->next;
}
diff --git a/builtin/remote.c b/builtin/remote.c
index b2b13a7dd2..0435963286 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1405,12 +1405,42 @@ static int show(int argc, const char **argv, const char *prefix,
return result;
}
+static void report_set_head_auto(const char *remote, const char *head_name,
+ struct strbuf *b_local_head, int was_detached) {
+ struct strbuf buf_prefix = STRBUF_INIT;
+ const char *prev_head = NULL;
+
+ strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote);
+ skip_prefix(b_local_head->buf, buf_prefix.buf, &prev_head);
+
+ if (prev_head && !strcmp(prev_head, head_name))
+ printf(_("'%s/HEAD' is unchanged and points to '%s'\n"),
+ remote, head_name);
+ else if (prev_head)
+ printf(_("'%s/HEAD' has changed from '%s' and now points to '%s'\n"),
+ remote, prev_head, head_name);
+ else if (!b_local_head->len)
+ printf(_("'%s/HEAD' is now created and points to '%s'\n"),
+ remote, head_name);
+ else if (was_detached && b_local_head->len)
+ printf(_("'%s/HEAD' was detached at '%s' and now points to '%s'\n"),
+ remote, b_local_head->buf, head_name);
+ else
+ printf(_("'%s/HEAD' used to point to '%s' "
+ "(which is not a remote branch), but now points to '%s'\n"),
+ remote, b_local_head->buf, head_name);
+ strbuf_release(&buf_prefix);
+}
+
static int set_head(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, opt_a = 0, opt_d = 0, result = 0;
- struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
+ int i, opt_a = 0, opt_d = 0, result = 0, was_detached;
+ struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
+ b_local_head = STRBUF_INIT;
char *head_name = NULL;
+ struct ref_store *refs = get_main_ref_store(the_repository);
+ struct remote *remote;
struct option options[] = {
OPT_BOOL('a', "auto", &opt_a,
@@ -1421,8 +1451,10 @@ static int set_head(int argc, const char **argv, const char *prefix,
};
argc = parse_options(argc, argv, prefix, options,
builtin_remote_sethead_usage, 0);
- if (argc)
- strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
+ if (argc) {
+ strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]);
+ remote = remote_get(argv[0]);
+ }
if (!opt_a && !opt_d && argc == 2) {
head_name = xstrdup(argv[1]);
@@ -1441,25 +1473,39 @@ static int set_head(int argc, const char **argv, const char *prefix,
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
- if (refs_delete_ref(get_main_ref_store(the_repository), NULL, buf.buf, NULL, REF_NO_DEREF))
- result |= error(_("Could not delete %s"), buf.buf);
+ if (refs_delete_ref(refs, NULL, b_head.buf, NULL, REF_NO_DEREF))
+ result |= error(_("Could not delete %s"), b_head.buf);
} else
usage_with_options(builtin_remote_sethead_usage, options);
- if (head_name) {
- strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
- /* make sure it's valid */
- if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf))
- result |= error(_("Not a valid ref: %s"), buf2.buf);
- 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);
- free(head_name);
+ if (!head_name)
+ goto cleanup;
+ strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", argv[0], head_name);
+ if (!refs_ref_exists(refs, b_remote_head.buf)) {
+ result |= error(_("Not a valid ref: %s"), b_remote_head.buf);
+ goto cleanup;
+ }
+ was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
+ "remote set-head", &b_local_head, 0);
+ if (was_detached == -1) {
+ result |= error(_("Could not set up %s"), b_head.buf);
+ goto cleanup;
+ }
+ if (opt_a)
+ report_set_head_auto(argv[0], head_name, &b_local_head, was_detached);
+ if (remote->follow_remote_head == FOLLOW_REMOTE_ALWAYS) {
+ struct strbuf config_name = STRBUF_INIT;
+ strbuf_addf(&config_name,
+ "remote.%s.followremotehead", remote->name);
+ git_config_set(config_name.buf, "warn");
+ strbuf_release(&config_name);
}
- strbuf_release(&buf);
- strbuf_release(&buf2);
+cleanup:
+ free(head_name);
+ strbuf_release(&b_head);
+ strbuf_release(&b_remote_head);
+ strbuf_release(&b_local_head);
return result;
}
diff --git a/builtin/repack.c b/builtin/repack.c
index fd2ef166de..0c6dad7df4 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -406,7 +406,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
* {type -> existing pack order} ordering when computing deltas instead
* of a {type -> size} ordering, which may produce better deltas.
*/
- for_each_packed_object(write_oid, &cmd,
+ for_each_packed_object(the_repository, write_oid, &cmd,
FOR_EACH_OBJECT_PROMISOR_ONLY);
if (cmd.in == -1) {
@@ -1571,7 +1571,7 @@ int cmd_repack(int argc,
unsigned flags = 0;
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
flags |= MIDX_WRITE_INCREMENTAL;
- write_midx_file(repo_get_object_directory(the_repository),
+ write_midx_file(the_repository, repo_get_object_directory(the_repository),
NULL, NULL, flags);
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 9b41d0b62a..3196da7b2d 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -123,7 +123,7 @@ static inline void finish_object__ma(struct object *obj)
return;
case MA_ALLOW_PROMISOR:
- if (is_promisor_object(&obj->oid))
+ if (is_promisor_object(the_repository, &obj->oid))
return;
die("unexpected missing %s object '%s'",
type_name(obj->type), oid_to_hex(&obj->oid));
diff --git a/builtin/tag.c b/builtin/tag.c
index 9d4dfe8ab0..c4bd145831 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -450,17 +450,6 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
-{
- if (name[0] == '-')
- return -1;
-
- strbuf_reset(sb);
- strbuf_addf(sb, "refs/tags/%s", name);
-
- return check_refname_format(sb->buf, 0);
-}
-
int cmd_tag(int argc,
const char **argv,
const char *prefix,
@@ -653,7 +642,7 @@ int cmd_tag(int argc,
if (repo_get_oid(the_repository, object_ref, &object))
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
- if (strbuf_check_tag_ref(&ref, tag))
+ if (check_tag_ref(&ref, tag))
die(_("'%s' is not a valid tag name."), tag);
if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 3b6c83fbce..dd63d6eadf 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -39,6 +39,7 @@ int cmd_upload_pack(int argc,
N_("interrupt transfer after <n> seconds of inactivity")),
OPT_END()
};
+ unsigned enter_repo_flags = ENTER_REPO_ANY_OWNER_OK;
packet_trace_identity("upload-pack");
disable_replace_refs();
@@ -54,7 +55,9 @@ int cmd_upload_pack(int argc,
dir = argv[0];
- if (!enter_repo(dir, strict))
+ if (strict)
+ enter_repo_flags |= ENTER_REPO_STRICT;
+ if (!enter_repo(dir, enter_repo_flags))
die("'%s' does not appear to be a git repository", dir);
switch (determine_protocol_version_server()) {
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7dd46e7fc9..c043d4d523 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -122,12 +122,14 @@ struct add_opts {
int quiet;
int checkout;
int orphan;
+ int relative_paths;
const char *keep_locked;
};
static int show_only;
static int verbose;
static int guess_remote;
+static int use_relative_paths;
static timestamp_t expire;
static int git_worktree_config(const char *var, const char *value,
@@ -136,6 +138,9 @@ static int git_worktree_config(const char *var, const char *value,
if (!strcmp(var, "worktree.guessremote")) {
guess_remote = git_config_bool(var, value);
return 0;
+ } else if (!strcmp(var, "worktree.userelativepaths")) {
+ use_relative_paths = git_config_bool(var, value);
+ return 0;
}
return git_default_config(var, value, ctx, cb);
@@ -417,8 +422,7 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
- struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT;
- struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT;
const char *name;
struct strvec child_env = STRVEC_INIT;
unsigned int counter = 0;
@@ -436,7 +440,7 @@ static int add_worktree(const char *path, const char *refname,
worktrees = NULL;
/* is 'refname' a branch or commit? */
- if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
+ if (!opts->detach && !check_branch_ref(&symref, refname) &&
refs_ref_exists(get_main_ref_store(the_repository), symref.buf)) {
is_branch = 1;
if (!opts->force)
@@ -494,10 +498,7 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
- strbuf_realpath(&sb_path_realpath, path, 1);
- strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1);
- write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp));
- write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp));
+ write_worktree_linking_files(sb_git, sb, opts->relative_paths);
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@@ -581,12 +582,9 @@ done:
strvec_clear(&child_env);
strbuf_release(&sb);
- strbuf_release(&sb_tmp);
strbuf_release(&symref);
strbuf_release(&sb_repo);
- strbuf_release(&sb_repo_realpath);
strbuf_release(&sb_git);
- strbuf_release(&sb_path_realpath);
strbuf_release(&sb_name);
free_worktree(wt);
return ret;
@@ -609,7 +607,7 @@ static void print_preparing_worktree_line(int detach,
fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
} else {
struct strbuf s = STRBUF_INIT;
- if (!detach && !strbuf_check_branch_ref(&s, branch) &&
+ if (!detach && !check_branch_ref(&s, branch) &&
refs_ref_exists(get_main_ref_store(the_repository), s.buf))
fprintf_ln(stderr, _("Preparing worktree (checking out '%s')"),
branch);
@@ -750,7 +748,7 @@ static char *dwim_branch(const char *path, char **new_branch)
char *branchname = xstrndup(s, n);
struct strbuf ref = STRBUF_INIT;
- branch_exists = !strbuf_check_branch_ref(&ref, branchname) &&
+ branch_exists = !check_branch_ref(&ref, branchname) &&
refs_ref_exists(get_main_ref_store(the_repository),
ref.buf);
strbuf_release(&ref);
@@ -800,12 +798,15 @@ static int add(int ac, const char **av, const char *prefix,
PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
OPT_BOOL(0, "guess-remote", &guess_remote,
N_("try to match the new branch name with a remote-tracking branch")),
+ OPT_BOOL(0, "relative-paths", &opts.relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
int ret;
memset(&opts, 0, sizeof(opts));
opts.checkout = 1;
+ opts.relative_paths = use_relative_paths;
ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0);
if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
@@ -844,7 +845,7 @@ static int add(int ac, const char **av, const char *prefix,
new_branch = new_branch_force;
if (!opts.force &&
- !strbuf_check_branch_ref(&symref, new_branch) &&
+ !check_branch_ref(&symref, new_branch) &&
refs_ref_exists(get_main_ref_store(the_repository), symref.buf))
die_if_checked_out(symref.buf, 0);
strbuf_release(&symref);
@@ -1197,6 +1198,8 @@ static int move_worktree(int ac, const char **av, const char *prefix,
OPT__FORCE(&force,
N_("force move even if worktree is dirty or locked"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL(0, "relative-paths", &use_relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
struct worktree **worktrees, *wt;
@@ -1249,7 +1252,7 @@ static int move_worktree(int ac, const char **av, const char *prefix,
if (rename(wt->path, dst.buf) == -1)
die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf);
- update_worktree_location(wt, dst.buf);
+ update_worktree_location(wt, dst.buf, use_relative_paths);
strbuf_release(&dst);
free_worktrees(worktrees);
@@ -1392,6 +1395,8 @@ static int repair(int ac, const char **av, const char *prefix,
const char **p;
const char *self[] = { ".", NULL };
struct option options[] = {
+ OPT_BOOL(0, "relative-paths", &use_relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
int rc = 0;
@@ -1399,8 +1404,8 @@ static int repair(int ac, const char **av, const char *prefix,
ac = parse_options(ac, av, prefix, options, git_worktree_repair_usage, 0);
p = ac > 0 ? av : self;
for (; *p; p++)
- repair_worktree_at_path(*p, report_repair, &rc);
- repair_worktrees(report_repair, &rc);
+ repair_worktree_at_path(*p, report_repair, &rc, use_relative_paths);
+ repair_worktrees(report_repair, &rc, use_relative_paths);
return rc;
}
diff --git a/bundle-uri.c b/bundle-uri.c
index 38e1d66d79..744257c49c 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -368,6 +368,10 @@ static int unbundle_from_file(struct repository *r, const char *file)
struct string_list_item *refname;
struct strbuf bundle_ref = STRBUF_INIT;
size_t bundle_prefix_len;
+ struct unbundle_opts opts = {
+ .flags = VERIFY_BUNDLE_QUIET |
+ (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0),
+ };
bundle_fd = read_bundle_header(file, &header);
if (bundle_fd < 0) {
@@ -380,8 +384,7 @@ static int unbundle_from_file(struct repository *r, const char *file)
* a reachable ref pointing to the new tips, which will reach
* the prerequisite commits.
*/
- result = unbundle(r, &header, bundle_fd, NULL,
- VERIFY_BUNDLE_QUIET | (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0));
+ result = unbundle(r, &header, bundle_fd, NULL, &opts);
if (result) {
result = 1;
goto cleanup;
diff --git a/bundle.c b/bundle.c
index 0501b74252..f18f98fec9 100644
--- a/bundle.c
+++ b/bundle.c
@@ -421,36 +421,6 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
e->name);
goto skip_write_ref;
}
- /*
- * If you run "git bundle create bndl v1.0..v2.0", the
- * name of the positive ref is "v2.0" but that is the
- * commit that is referenced by the tag, and not the tag
- * itself.
- */
- if (!oideq(&oid, &e->item->oid)) {
- /*
- * Is this the positive end of a range expressed
- * in terms of a tag (e.g. v2.0 from the range
- * "v1.0..v2.0")?
- */
- struct commit *one = lookup_commit_reference(revs->repo, &oid);
- struct object *obj;
-
- if (e->item == &(one->object)) {
- /*
- * Need to include e->name as an
- * independent ref to the pack-objects
- * input, so that the tag is included
- * in the output; otherwise we would
- * end up triggering "empty bundle"
- * error.
- */
- obj = parse_object_or_die(&oid, e->name);
- obj->flags |= SHOWN;
- add_pending_object(revs, obj, e->name);
- }
- goto skip_write_ref;
- }
ref_count++;
write_or_die(bundle_fd, oid_to_hex(&e->item->oid), the_hash_algo->hexsz);
@@ -629,11 +599,15 @@ out:
int unbundle(struct repository *r, struct bundle_header *header,
int bundle_fd, struct strvec *extra_index_pack_args,
- enum verify_bundle_flags flags)
+ struct unbundle_opts *opts)
{
struct child_process ip = CHILD_PROCESS_INIT;
+ struct unbundle_opts opts_fallback = { 0 };
+
+ if (!opts)
+ opts = &opts_fallback;
- if (verify_bundle(r, header, flags))
+ if (verify_bundle(r, header, opts->flags))
return -1;
strvec_pushl(&ip.args, "index-pack", "--fix-thin", "--stdin", NULL);
@@ -642,8 +616,9 @@ int unbundle(struct repository *r, struct bundle_header *header,
if (header->filter.choice)
strvec_push(&ip.args, "--promisor=from-bundle");
- if (flags & VERIFY_BUNDLE_FSCK)
- strvec_push(&ip.args, "--fsck-objects");
+ if (opts->flags & VERIFY_BUNDLE_FSCK)
+ strvec_pushf(&ip.args, "--fsck-objects%s",
+ opts->fsck_msg_types ? opts->fsck_msg_types : "");
if (extra_index_pack_args)
strvec_pushv(&ip.args, extra_index_pack_args->v);
diff --git a/bundle.h b/bundle.h
index 5ccc9a061a..a80aa8ad9b 100644
--- a/bundle.h
+++ b/bundle.h
@@ -39,6 +39,17 @@ enum verify_bundle_flags {
int verify_bundle(struct repository *r, struct bundle_header *header,
enum verify_bundle_flags flags);
+struct unbundle_opts {
+ enum verify_bundle_flags flags;
+ /*
+ * fsck_msg_types may optionally contain fsck message severity
+ * configuration. If present, this configuration gets directly appended
+ * to a '--fsck-objects' option and therefore must be prefixed with '='.
+ * (E.g. "=missingEmail=ignore,gitmodulesUrl=ignore")
+ */
+ const char *fsck_msg_types;
+};
+
/**
* Unbundle after reading the header with read_bundle_header().
*
@@ -49,12 +60,12 @@ int verify_bundle(struct repository *r, struct bundle_header *header,
* (e.g. "-v" for verbose/progress), NULL otherwise. The provided
* "extra_index_pack_args" (if any) will be strvec_clear()'d for you.
*
- * Before unbundling, this method will call verify_bundle() with the
- * given 'flags'.
+ * Before unbundling, this method will call verify_bundle() with 'flags'
+ * provided in 'opts'.
*/
int unbundle(struct repository *r, struct bundle_header *header,
int bundle_fd, struct strvec *extra_index_pack_args,
- enum verify_bundle_flags flags);
+ struct unbundle_opts *opts);
int list_bundle_refs(struct bundle_header *header,
int argc, const char **argv);
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index 126e570eb4..d020cb7aa5 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -29,37 +29,38 @@ alpine-*)
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-*)
+fedora-*|almalinux-*)
dnf -yq update >/dev/null &&
dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
;;
-ubuntu-*|ubuntu32-*)
+ubuntu-*|ubuntu32-*|debian-*)
# Required so that apt doesn't wait for user input on certain packages.
export DEBIAN_FRONTEND=noninteractive
case "$distro" in
ubuntu-*)
SVN='libsvn-perl subversion'
+ LANGUAGES='language-pack-is'
;;
- *)
+ ubuntu32-*)
SVN=
+ LANGUAGES='language-pack-is'
+ ;;
+ *)
+ SVN='libsvn-perl subversion'
+ LANGUAGES='locales-all'
;;
esac
sudo apt-get -q update
sudo apt-get -q -y install \
- language-pack-is apache2 cvs cvsps git gnupg $SVN \
+ $LANGUAGES apache2 cvs cvsps git gnupg $SVN \
make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \
tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \
libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \
${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE
case "$distro" in
- ubuntu-16.04)
- # Does not support JGit, but we also don't really care about
- # the others. We rather care whether Git still compiles and
- # runs fine overall.
- ;;
ubuntu-*)
mkdir --parents "$CUSTOM_PATH"
diff --git a/ci/lib.sh b/ci/lib.sh
index 930f98d722..5440eb6dc0 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -18,7 +18,8 @@ elif test true = "$GITLAB_CI"
then
begin_group () {
need_to_end_group=t
- printf "\e[0Ksection_start:$(date +%s):$(echo "$1" | tr ' ' _)[collapsed=true]\r\e[0K$1\n"
+ printf '\e[0Ksection_start:%s:%s[collapsed=true]\r\e[0K%s\n' \
+ "$(date +%s)" "$(echo "$1" | tr ' ' _)" "$1"
trap "end_group '$1'" EXIT
set -x
}
@@ -27,7 +28,8 @@ then
test -n "$need_to_end_group" || return 0
set +x
need_to_end_group=
- printf "\e[0Ksection_end:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K\n"
+ printf '\e[0Ksection_end:%s:%s\r\e[0K\n' \
+ "$(date +%s)" "$(echo "$1" | tr ' ' _)"
trap - EXIT
}
else
@@ -55,8 +57,7 @@ group () {
return $res
}
-begin_group "CI setup"
-trap "end_group 'CI setup'" EXIT
+begin_group "CI setup via $(basename $0)"
# Set 'exit on error' for all CI scripts to let the caller know that
# something went wrong.
@@ -394,5 +395,5 @@ esac
MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}"
-end_group "CI setup"
+end_group "CI setup via $(basename $0)"
set -x
diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh
index af8065f349..e7b97952e7 100755
--- a/ci/run-build-and-minimal-fuzzers.sh
+++ b/ci/run-build-and-minimal-fuzzers.sh
@@ -13,7 +13,18 @@ group "Build fuzzers" make \
LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \
fuzz-all
-for fuzzer in commit-graph config date pack-headers pack-idx ; do
+fuzzers="
+commit-graph
+config
+credential-from-url-gently
+date
+pack-headers
+pack-idx
+parse-attr-line
+url-decode-mem
+"
+
+for fuzzer in $fuzzers; do
begin_group "fuzz-$fuzzer"
./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1
end_group "fuzz-$fuzzer"
diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh
index 02b3af3941..6c018b673e 100755
--- a/ci/test-documentation.sh
+++ b/ci/test-documentation.sh
@@ -6,7 +6,7 @@
. ${0%/*}/lib.sh
filter_log () {
- sed -e '/^GIT_VERSION = /d' \
+ sed -e '/^GIT_VERSION=/d' \
-e "/constant Gem::ConfigMap is deprecated/d" \
-e '/^ \* new asciidoc flags$/d' \
-e '/stripped namespace before processing/d' \
diff --git a/commit-graph.c b/commit-graph.c
index 7623a158c8..0df66e5a24 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1915,7 +1915,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
struct packed_git *p;
strbuf_setlen(&packname, dirlen);
strbuf_addstr(&packname, pack_indexes->items[i].string);
- p = add_packed_git(packname.buf, packname.len, 1);
+ p = add_packed_git(ctx->r, packname.buf, packname.len, 1);
if (!p) {
ret = error(_("error adding pack %s"), packname.buf);
goto cleanup;
@@ -1961,7 +1961,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
ctx->progress = start_delayed_progress(
_("Finding commits for commit graph among packed objects"),
ctx->approx_nr_objects);
- for_each_packed_object(add_packed_commits, ctx,
+ for_each_packed_object(ctx->r, add_packed_commits, ctx,
FOR_EACH_OBJECT_PACK_ORDER);
if (ctx->progress_done < ctx->approx_nr_objects)
display_progress(ctx->progress, ctx->approx_nr_objects);
diff --git a/commit.c b/commit.c
index 8f6045a6c3..a127fe60c5 100644
--- a/commit.c
+++ b/commit.c
@@ -276,7 +276,7 @@ static int read_graft_file(struct repository *r, const char *graft_file)
"to convert the grafts into replace refs.\n"
"\n"
"Turn this message off by running\n"
- "\"git config advice.graftFileDeprecated false\""));
+ "\"git config set advice.graftFileDeprecated false\""));
while (!strbuf_getwholeline(&buf, fp, '\n')) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
struct commit_graft *graft = read_graft_line(&buf);
diff --git a/config.c b/config.c
index 969bd8630f..50f2d17b39 100644
--- a/config.c
+++ b/config.c
@@ -1494,33 +1494,11 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.packedgitwindowsize")) {
- int pgsz_x2 = getpagesize() * 2;
- packed_git_window_size = git_config_ulong(var, value, ctx->kvi);
-
- /* This value must be multiple of (pagesize * 2) */
- packed_git_window_size /= pgsz_x2;
- if (packed_git_window_size < 1)
- packed_git_window_size = 1;
- packed_git_window_size *= pgsz_x2;
- return 0;
- }
-
if (!strcmp(var, "core.bigfilethreshold")) {
big_file_threshold = git_config_ulong(var, value, ctx->kvi);
return 0;
}
- if (!strcmp(var, "core.packedgitlimit")) {
- packed_git_limit = git_config_ulong(var, value, ctx->kvi);
- return 0;
- }
-
- if (!strcmp(var, "core.deltabasecachelimit")) {
- delta_base_cache_limit = git_config_ulong(var, value, ctx->kvi);
- return 0;
- }
-
if (!strcmp(var, "core.autocrlf")) {
if (value && !strcasecmp(value, "input")) {
auto_crlf = AUTO_CRLF_INPUT;
diff --git a/configure.ac b/configure.ac
index d1a96da14e..5923edc44a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -142,7 +142,7 @@ fi
## Configure body starts here.
AC_PREREQ(2.59)
-AC_INIT([git], [@@GIT_VERSION@@], [git@vger.kernel.org])
+AC_INIT([git], [@GIT_VERSION@], [git@vger.kernel.org])
AC_CONFIG_SRCDIR([git.c])
diff --git a/connected.c b/connected.c
index a9e2e13995..3099da84f3 100644
--- a/connected.c
+++ b/connected.c
@@ -54,7 +54,8 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
strbuf_add(&idx_file, transport->pack_lockfiles.items[0].string,
base_len);
strbuf_addstr(&idx_file, ".idx");
- new_pack = add_packed_git(idx_file.buf, idx_file.len, 1);
+ new_pack = add_packed_git(the_repository, idx_file.buf,
+ idx_file.len, 1);
strbuf_release(&idx_file);
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 8c71f5a1d0..49904ca8a9 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -83,23 +83,12 @@ if(NOT SH_EXE)
"On Windows, you can get it as part of 'Git for Windows' install at https://gitforwindows.org/")
endif()
-#Create GIT-VERSION-FILE using GIT-VERSION-GEN
-if(NOT EXISTS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE)
- message("Generating GIT-VERSION-FILE")
- execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
-endif()
-
-#Parse GIT-VERSION-FILE to get the version
-file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE git_version REGEX "GIT_VERSION = (.*)")
-string(REPLACE "GIT_VERSION = " "" git_version ${git_version})
-string(FIND ${git_version} "GIT" location)
-if(location EQUAL -1)
- string(REGEX MATCH "[0-9]*\\.[0-9]*\\.[0-9]*" git_version ${git_version})
-else()
- string(REGEX MATCH "[0-9]*\\.[0-9]*" git_version ${git_version})
- string(APPEND git_version ".0") #for building from a snapshot
-endif()
+message("Generating Git version")
+execute_process(COMMAND ${SH_EXE} "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_SOURCE_DIR}/contrib/buildsystems/git-version.in"
+ "${CMAKE_BINARY_DIR}/git-version")
+file(STRINGS "${CMAKE_BINARY_DIR}/git-version" git_version)
project(git
VERSION ${git_version}
@@ -110,8 +99,8 @@ project(git
#TODO Enable NLS on windows natively
#macros for parsing the Makefile for sources and scripts
-macro(parse_makefile_for_sources list_var regex)
- file(STRINGS ${CMAKE_SOURCE_DIR}/Makefile ${list_var} REGEX "^${regex} \\+=(.*)")
+macro(parse_makefile_for_sources list_var makefile regex)
+ file(STRINGS ${makefile} ${list_var} REGEX "^${regex} \\+=(.*)")
string(REPLACE "${regex} +=" "" ${list_var} ${${list_var}})
string(REPLACE "$(COMPAT_OBJS)" "" ${list_var} ${${list_var}}) #remove "$(COMPAT_OBJS)" This is only for libgit.
string(STRIP ${${list_var}} ${list_var}) #remove trailing/leading whitespaces
@@ -240,10 +229,7 @@ add_compile_definitions(PAGER_ENV="LESS=FRX LV=-c"
GIT_HTML_PATH="share/doc/git-doc"
DEFAULT_HELP_FORMAT="html"
DEFAULT_GIT_TEMPLATE_DIR="share/git-core/templates"
- GIT_VERSION="${PROJECT_VERSION}.GIT"
- GIT_USER_AGENT="git/${PROJECT_VERSION}.GIT"
- BINDIR="bin"
- GIT_BUILT_FROM_COMMIT="")
+ BINDIR="bin")
if(WIN32)
set(FALLBACK_RUNTIME_PREFIX /mingw64)
@@ -652,60 +638,79 @@ set(EXCLUSION_PROGS_CACHE ${EXCLUSION_PROGS} CACHE STRING "Programs not built" F
if(NOT EXISTS ${CMAKE_BINARY_DIR}/command-list.h OR NOT EXCLUSION_PROGS_CACHE STREQUAL EXCLUSION_PROGS)
list(REMOVE_ITEM EXCLUSION_PROGS empty)
message("Generating command-list.h")
- execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-cmdlist.sh ${EXCLUSION_PROGS} command-list.txt
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- OUTPUT_FILE ${CMAKE_BINARY_DIR}/command-list.h)
+ execute_process(COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-cmdlist.sh"
+ ${EXCLUSION_PROGS}
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_BINARY_DIR}/command-list.h")
endif()
if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)
message("Generating config-list.h")
- execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-configlist.sh
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- OUTPUT_FILE ${CMAKE_BINARY_DIR}/config-list.h)
+ execute_process(COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-configlist.sh"
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_BINARY_DIR}/config-list.h")
endif()
if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)
message("Generating hook-list.h")
- execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-hooklist.sh
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- OUTPUT_FILE ${CMAKE_BINARY_DIR}/hook-list.h)
+ execute_process(COMMAND "${SH_EXE}" ${CMAKE_SOURCE_DIR}/generate-hooklist.sh
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_BINARY_DIR}/hook-list.h")
endif()
include_directories(${CMAKE_BINARY_DIR})
#build
#libgit
-parse_makefile_for_sources(libgit_SOURCES "LIB_OBJS")
+parse_makefile_for_sources(libgit_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "LIB_OBJS")
list(TRANSFORM libgit_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
list(TRANSFORM compat_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+
+add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/version-def.h"
+ COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_SOURCE_DIR}/version-def.h.in"
+ "${CMAKE_BINARY_DIR}/version-def.h"
+ DEPENDS "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+ "${CMAKE_SOURCE_DIR}/version-def.h.in"
+ VERBATIM)
+list(APPEND libgit_SOURCES "${CMAKE_BINARY_DIR}/version-def.h")
+
add_library(libgit ${libgit_SOURCES} ${compat_SOURCES})
#libxdiff
-parse_makefile_for_sources(libxdiff_SOURCES "XDIFF_OBJS")
+parse_makefile_for_sources(libxdiff_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "XDIFF_OBJS")
list(TRANSFORM libxdiff_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
add_library(xdiff STATIC ${libxdiff_SOURCES})
#reftable
-parse_makefile_for_sources(reftable_SOURCES "REFTABLE_OBJS")
+parse_makefile_for_sources(reftable_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "REFTABLE_OBJS")
list(TRANSFORM reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
add_library(reftable STATIC ${reftable_SOURCES})
if(WIN32)
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.rc
+ COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_SOURCE_DIR}/git.rc.in"
+ "${CMAKE_BINARY_DIR}/git.rc"
+ DEPENDS "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+ "${CMAKE_SOURCE_DIR}/git.rc.in"
+ VERBATIM)
+
if(NOT MSVC)#use windres when compiling with gcc and clang
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res
- COMMAND ${WINDRES_EXE} -O coff -DMAJOR=${PROJECT_VERSION_MAJOR} -DMINOR=${PROJECT_VERSION_MINOR}
- -DMICRO=${PROJECT_VERSION_PATCH} -DPATCHLEVEL=0 -DGIT_VERSION="\\\"${PROJECT_VERSION}.GIT\\\""
- -i ${CMAKE_SOURCE_DIR}/git.rc -o ${CMAKE_BINARY_DIR}/git.res
+ COMMAND ${WINDRES_EXE} -O coff -i ${CMAKE_BINARY_DIR}/git.rc -o ${CMAKE_BINARY_DIR}/git.res
+ DEPENDS "${CMAKE_BINARY_DIR}/git.rc"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
VERBATIM)
else()#MSVC use rc
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res
- COMMAND ${CMAKE_RC_COMPILER} /d MAJOR=${PROJECT_VERSION_MAJOR} /d MINOR=${PROJECT_VERSION_MINOR}
- /d MICRO=${PROJECT_VERSION_PATCH} /d PATCHLEVEL=0 /d GIT_VERSION="${PROJECT_VERSION}.GIT"
- /fo ${CMAKE_BINARY_DIR}/git.res ${CMAKE_SOURCE_DIR}/git.rc
+ COMMAND ${CMAKE_RC_COMPILER} /fo ${CMAKE_BINARY_DIR}/git.res ${CMAKE_BINARY_DIR}/git.rc
+ DEPENDS "${CMAKE_BINARY_DIR}/git.rc"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
VERBATIM)
endif()
@@ -752,7 +757,7 @@ elseif(UNIX)
endif()
#git
-parse_makefile_for_sources(git_SOURCES "BUILTIN_OBJS")
+parse_makefile_for_sources(git_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "BUILTIN_OBJS")
list(TRANSFORM git_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
add_executable(git ${CMAKE_SOURCE_DIR}/git.c ${git_SOURCES})
@@ -834,70 +839,87 @@ set(git_shell_scripts
${git_sh_scripts} ${git_shlib_scripts} git-instaweb)
foreach(script ${git_shell_scripts})
- file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.sh content NEWLINE_CONSUME)
- string(REPLACE "@SHELL_PATH@" "${SHELL_PATH}" content "${content}")
- string(REPLACE "@@DIFF@@" "diff" content "${content}")
- string(REPLACE "@LOCALEDIR@" "${LOCALEDIR}" content "${content}")
- string(REPLACE "@GITWEBDIR@" "${GITWEBDIR}" content "${content}")
- string(REPLACE "@@NO_CURL@@" "" content "${content}")
- string(REPLACE "@@USE_GETTEXT_SCHEME@@" "" content "${content}")
- string(REPLACE "# @@BROKEN_PATH_FIX@@" "" content "${content}")
- string(REPLACE "@@PERL@@" "${PERL_PATH}" content "${content}")
- string(REPLACE "@@PAGER_ENV@@" "LESS=FRX LV=-c" content "${content}")
- file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content})
+ if ("${script}" IN_LIST git_sh_scripts)
+ string(REPLACE ".sh" "" shell_gen_path "${script}")
+ else()
+ set(shell_gen_path "${script}")
+ endif()
+
+ add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${shell_gen_path}"
+ COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-script.sh"
+ "${CMAKE_SOURCE_DIR}/${script}.sh"
+ "${CMAKE_BINARY_DIR}/${shell_gen_path}"
+ "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS"
+ DEPENDS "${CMAKE_SOURCE_DIR}/generate-script.sh"
+ "${CMAKE_SOURCE_DIR}/${script}.sh"
+ VERBATIM)
+ list(APPEND shell_gen ${CMAKE_BINARY_DIR}/${shell_gen_path})
endforeach()
+add_custom_target(shell-gen ALL DEPENDS ${shell_gen})
#perl scripts
-parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" ".perl")
+parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" "")
+#perl modules
+file(GLOB_RECURSE perl_modules "${CMAKE_SOURCE_DIR}/perl/*.pm")
+list(TRANSFORM perl_modules REPLACE "${CMAKE_SOURCE_DIR}/" "")
#create perl header
file(STRINGS ${CMAKE_SOURCE_DIR}/perl/header_templates/fixed_prefix.template.pl perl_header )
-string(REPLACE "@@PATHSEP@@" ":" perl_header "${perl_header}")
-string(REPLACE "@@INSTLIBDIR@@" "${INSTLIBDIR}" perl_header "${perl_header}")
-
-foreach(script ${git_perl_scripts})
- file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.perl content NEWLINE_CONSUME)
- string(REPLACE "#!/usr/bin/perl" "#!/usr/bin/perl\n${perl_header}\n" content "${content}")
- string(REPLACE "@@GIT_VERSION@@" "${PROJECT_VERSION}" content "${content}")
- file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content})
-endforeach()
-
-#python script
-file(STRINGS ${CMAKE_SOURCE_DIR}/git-p4.py content NEWLINE_CONSUME)
-string(REPLACE "#!/usr/bin/env python" "#!/usr/bin/python" content "${content}")
-file(WRITE ${CMAKE_BINARY_DIR}/git-p4 ${content})
-
-#perl modules
-file(GLOB_RECURSE perl_modules "${CMAKE_SOURCE_DIR}/perl/*.pm")
+string(REPLACE "@PATHSEP@" ":" perl_header "${perl_header}")
+string(REPLACE "@INSTLIBDIR@" "${INSTLIBDIR}" perl_header "${perl_header}")
+file(WRITE ${CMAKE_BINARY_DIR}/PERL-HEADER ${perl_header})
+
+add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE"
+ COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE.in"
+ "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE"
+ DEPENDS ${SH_EXE} "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+ "${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE.in"
+ VERBATIM)
-foreach(pm ${perl_modules})
- string(REPLACE "${CMAKE_SOURCE_DIR}/perl/" "" file_path ${pm})
- file(STRINGS ${pm} content NEWLINE_CONSUME)
- string(REPLACE "@@LOCALEDIR@@" "${LOCALEDIR}" content "${content}")
- string(REPLACE "@@NO_PERL_CPAN_FALLBACKS@@" "" content "${content}")
- file(WRITE ${CMAKE_BINARY_DIR}/perl/build/lib/${file_path} ${content})
-#test-lib.sh requires perl/build/lib to be the build directory of perl modules
+foreach(script ${git_perl_scripts} ${perl_modules})
+ string(REPLACE ".perl" "" perl_gen_path "${script}")
+
+ get_filename_component(perl_gen_dir "${perl_gen_path}" DIRECTORY)
+ file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/${perl_gen_dir}")
+
+ add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${perl_gen_path}"
+ COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-perl.sh"
+ "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS"
+ "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE"
+ "${CMAKE_BINARY_DIR}/PERL-HEADER"
+ "${CMAKE_SOURCE_DIR}/${script}"
+ "${CMAKE_BINARY_DIR}/${perl_gen_path}"
+ DEPENDS "${CMAKE_SOURCE_DIR}/generate-perl.sh"
+ "${CMAKE_SOURCE_DIR}/${script}"
+ "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS"
+ "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE"
+ VERBATIM)
+ list(APPEND perl_gen ${CMAKE_BINARY_DIR}/${perl_gen_path})
endforeach()
+add_custom_target(perl-gen ALL DEPENDS ${perl_gen})
+
+# Python script
+add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/git-p4"
+ COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-python.sh"
+ "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS"
+ "${CMAKE_SOURCE_DIR}/git-p4.py"
+ "${CMAKE_BINARY_DIR}/git-p4"
+ DEPENDS "${CMAKE_SOURCE_DIR}/generate-python.sh"
+ "${CMAKE_SOURCE_DIR}/git-p4.py"
+ "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS"
+ VERBATIM)
+add_custom_target(python-gen ALL DEPENDS "${CMAKE_BINARY_DIR}/git-p4")
-
-#templates
-file(GLOB templates "${CMAKE_SOURCE_DIR}/templates/*")
-list(TRANSFORM templates REPLACE "${CMAKE_SOURCE_DIR}/templates/" "")
-list(REMOVE_ITEM templates ".gitignore")
-list(REMOVE_ITEM templates "Makefile")
-list(REMOVE_ITEM templates "blt")# Prevents an error when reconfiguring for in source builds
-
-list(REMOVE_ITEM templates "branches--")
-file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/templates/blt/branches) #create branches
-
+#${CMAKE_SOURCE_DIR}/Makefile templates
+parse_makefile_for_sources(templates ${CMAKE_SOURCE_DIR}/templates/Makefile "TEMPLATES")
+string(REPLACE " " ";" templates ${templates})
#templates have @.*@ replacement so use configure_file instead
foreach(tm ${templates})
- string(REPLACE "--" "/" blt_tm ${tm})
- string(REPLACE "this" "" blt_tm ${blt_tm})# for this--
- configure_file(${CMAKE_SOURCE_DIR}/templates/${tm} ${CMAKE_BINARY_DIR}/templates/blt/${blt_tm} @ONLY)
+ configure_file(${CMAKE_SOURCE_DIR}/templates/${tm} ${CMAKE_BINARY_DIR}/templates/blt/${tm} @ONLY)
endforeach()
-
#translations
if(MSGFMT_EXE)
file(GLOB po_files "${CMAKE_SOURCE_DIR}/po/*.po")
@@ -971,7 +993,7 @@ add_executable(test-fake-ssh ${CMAKE_SOURCE_DIR}/t/helper/test-fake-ssh.c)
target_link_libraries(test-fake-ssh common-main)
#unit-tests
-parse_makefile_for_sources(unit-test_SOURCES "UNIT_TEST_OBJS")
+parse_makefile_for_sources(unit-test_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "UNIT_TEST_OBJS")
list(TRANSFORM unit-test_SOURCES REPLACE "\\$\\(UNIT_TEST_DIR\\)/" "${CMAKE_SOURCE_DIR}/t/unit-tests/")
add_library(unit-test-lib STATIC ${unit-test_SOURCES})
@@ -1037,7 +1059,7 @@ if(MSVC)
endif()
#test-tool
-parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
+parse_makefile_for_sources(test-tool_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "TEST_BUILTINS_OBJS")
add_library(test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c)
list(TRANSFORM test-tool_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/t/helper/")
@@ -1063,22 +1085,25 @@ set(wrapper_test_scripts
foreach(script ${wrapper_scripts})
- file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME)
- string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}")
- string(REPLACE "@@PROG@@" "${script}${EXE_EXTENSION}" content "${content}")
+ file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME)
+ string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}")
+ string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/${script}${EXE_EXTENSION}" content "${content}")
file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content})
endforeach()
foreach(script ${wrapper_test_scripts})
- file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME)
- string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}")
- string(REPLACE "@@PROG@@" "t/helper/${script}${EXE_EXTENSION}" content "${content}")
+ file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME)
+ string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}")
+ string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/t/helper/${script}${EXE_EXTENSION}" content "${content}")
file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content})
endforeach()
-file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME)
-string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}")
-string(REPLACE "@@PROG@@" "git-cvsserver" content "${content}")
+file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME)
+string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}")
+string(REPLACE "@GIT_TEXTDOMAINDIR@" "${CMAKE_BINARY_DIR}/po/build/locale" content "${content}")
+string(REPLACE "@GITPERLLIB@" "${CMAKE_BINARY_DIR}/perl/build/lib" content "${content}")
+string(REPLACE "@MERGE_TOOLS_DIR@" "${CMAKE_SOURCE_DIR}/mergetools" content "${content}")
+string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/git-cvsserver" content "${content}")
file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content})
#options for configuring test options
@@ -1125,27 +1150,58 @@ if(NOT PYTHON_TESTS)
set(NO_PYTHON 1)
endif()
-file(WRITE ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "SHELL_PATH='${SHELL_PATH}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "TEST_SHELL_PATH='${TEST_SHELL_PATH}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PERL_PATH='${PERL_PATH}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "DIFF='${DIFF}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PYTHON_PATH='${PYTHON_PATH}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "TAR='${TAR}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_CURL='${NO_CURL}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_ICONV='${NO_ICONV}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_EXPAT='${NO_EXPAT}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PERL='${NO_PERL}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PTHREADS='${NO_PTHREADS}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_UNIX_SOCKETS='${NO_UNIX_SOCKETS}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PAGER_ENV='${PAGER_ENV}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "X='${EXE_EXTENSION}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_GETTEXT='${NO_GETTEXT}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "RUNTIME_PREFIX='${RUNTIME_PREFIX}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PYTHON='${NO_PYTHON}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "SUPPORTS_SIMPLE_IPC='${SUPPORTS_SIMPLE_IPC}'\n")
+file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-BUILD-OPTIONS.in git_build_options NEWLINE_CONSUME)
+string(REPLACE "@SHELL_PATH@" "'${SHELL_PATH}'" git_build_options "${git_build_options}")
+string(REPLACE "@TEST_SHELL_PATH@" "'${TEST_SHELL_PATH}'" git_build_options "${git_build_options}")
+string(REPLACE "@PERL_PATH@" "'${PERL_PATH}'" git_build_options "${git_build_options}")
+string(REPLACE "@PERL_LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}")
+string(REPLACE "@NO_PERL_CPAN_FALLBACKS@" "" git_build_options "${git_build_options}")
+string(REPLACE "@DIFF@" "'${DIFF}'" git_build_options "${git_build_options}")
+string(REPLACE "@PYTHON_PATH@" "'${PYTHON_PATH}'" git_build_options "${git_build_options}")
+string(REPLACE "@TAR@" "'${TAR}'" git_build_options "${git_build_options}")
+string(REPLACE "@NO_CURL@" "${NO_CURL}" git_build_options "${git_build_options}")
+string(REPLACE "@NO_ICONV@" "${NO_ICONV}" git_build_options "${git_build_options}")
+string(REPLACE "@NO_EXPAT@" "${NO_EXPAT}" git_build_options "${git_build_options}")
+string(REPLACE "@USE_LIBPCRE2@" "" git_build_options "${git_build_options}")
+string(REPLACE "@NO_PERL@" "${NO_PERL}" git_build_options "${git_build_options}")
+string(REPLACE "@NO_PTHREADS@" "${NO_PTHREADS}" git_build_options "${git_build_options}")
+string(REPLACE "@NO_PYTHON@" "${NO_PYTHON}" git_build_options "${git_build_options}")
+string(REPLACE "@NO_REGEX@" "" git_build_options "${git_build_options}")
+string(REPLACE "@NO_UNIX_SOCKETS@" "${NO_UNIX_SOCKETS}" git_build_options "${git_build_options}")
+string(REPLACE "@PAGER_ENV@" "'${PAGER_ENV}'" git_build_options "${git_build_options}")
+string(REPLACE "@SANITIZE_LEAK@" "" git_build_options "${git_build_options}")
+string(REPLACE "@SANITIZE_ADDRESS@" "" git_build_options "${git_build_options}")
+string(REPLACE "@X@" "${EXE_EXTENSION}" git_build_options "${git_build_options}")
+string(REPLACE "@FSMONITOR_DAEMON_BACKEND@" "win32" git_build_options "${git_build_options}")
+string(REPLACE "@FSMONITOR_OS_SETTINGS@" "win32" git_build_options "${git_build_options}")
+string(REPLACE "@TEST_OUTPUT_DIRECTORY@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_OPTS@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_CMP@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_CMP_USE_COPIED_CONTEXT@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_UTF8_LOCALE@" "" git_build_options "${git_build_options}")
+string(REPLACE "@NO_GETTEXT@" "${NO_GETTEXT}" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_PERF_REPEAT_COUNT@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_PERF_REPO@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_PERF_LARGE_REPO@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_PERF_MAKE_OPTS@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_PERF_MAKE_COMMAND@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_INTEROP_MAKE_OPTS@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_INDEX_VERSION@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_PERL_FATAL_WARNINGS@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_TEXTDOMAINDIR@" "'${CMAKE_BINARY_DIR}/po/build/locale'" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_POPATH@" "'${CMAKE_BINARY_DIR}/po'" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_GITPERLLIB@" "'${CMAKE_BINARY_DIR}/perl/build/lib'" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_TEST_MERGE_TOOLS_DIR@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}")
+string(REPLACE "@RUNTIME_PREFIX@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}")
+string(REPLACE "@GITWEBDIR@" "'${GITWEBDIR}'" git_build_options "${git_build_options}")
+string(REPLACE "@USE_GETTEXT_SCHEME@" "" git_build_options "${git_build_options}")
+string(REPLACE "@LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}")
+string(REPLACE "@BROKEN_PATH_FIX@" "" git_build_options "${git_build_options}")
if(USE_VCPKG)
- file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n")
+ string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n")
endif()
+file(WRITE ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS ${git_build_options})
#Make the tests work when building out of the source tree
get_filename_component(CACHE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../CMakeCache.txt ABSOLUTE)
diff --git a/contrib/buildsystems/git-version.in b/contrib/buildsystems/git-version.in
new file mode 100644
index 0000000000..9750505ae7
--- /dev/null
+++ b/contrib/buildsystems/git-version.in
@@ -0,0 +1 @@
+@GIT_MAJOR_VERSION@.@GIT_MINOR_VERSION@.@GIT_MICRO_VERSION@
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 3d4dff3185..b3b6aa3bae 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -2331,7 +2331,7 @@ _git_mergetool ()
return
;;
--*)
- __gitcomp "--tool= --prompt --no-prompt --gui --no-gui"
+ __gitcomp "--tool= --tool-help --prompt --no-prompt --gui --no-gui"
return
;;
esac
diff --git a/contrib/completion/meson.build b/contrib/completion/meson.build
new file mode 100644
index 0000000000..3a9ddab594
--- /dev/null
+++ b/contrib/completion/meson.build
@@ -0,0 +1,16 @@
+foreach script : [
+ 'git-completion.bash',
+ 'git-completion.tcsh',
+ 'git-completion.zsh',
+ 'git-prompt.sh'
+]
+ if meson.version().version_compare('>=1.3.0')
+ test_dependencies += fs.copyfile(script)
+ else
+ configure_file(
+ input: script,
+ output: script,
+ copy: true,
+ )
+ endif
+endforeach
diff --git a/contrib/meson.build b/contrib/meson.build
new file mode 100644
index 0000000000..a7b77b87c2
--- /dev/null
+++ b/contrib/meson.build
@@ -0,0 +1 @@
+subdir('completion')
diff --git a/daemon.c b/daemon.c
index 5ca70335fc..d1be61fd57 100644
--- a/daemon.c
+++ b/daemon.c
@@ -152,6 +152,7 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
size_t rlen;
const char *path;
const char *dir;
+ unsigned enter_repo_flags;
dir = directory;
@@ -242,14 +243,15 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
dir = rpath;
}
- path = enter_repo(dir, strict_paths);
+ enter_repo_flags = strict_paths ? ENTER_REPO_STRICT : 0;
+ path = enter_repo(dir, enter_repo_flags);
if (!path && base_path && base_path_relaxed) {
/*
* if we fail and base_path_relaxed is enabled, try without
* prefixing the base path
*/
dir = directory;
- path = enter_repo(dir, strict_paths);
+ path = enter_repo(dir, enter_repo_flags);
}
if (!path) {
diff --git a/diff.c b/diff.c
index 97417cc2a1..d28b4114c8 100644
--- a/diff.c
+++ b/diff.c
@@ -4042,7 +4042,8 @@ static int reuse_worktree_file(struct index_state *istate,
* objects however would tend to be slower as they need
* to be individually opened and inflated.
*/
- if (!FAST_WORKING_DIRECTORY && !want_file && has_object_pack(oid))
+ if (!FAST_WORKING_DIRECTORY && !want_file &&
+ has_object_pack(istate->repo, oid))
return 0;
/*
diff --git a/environment.c b/environment.c
index a2ce998081..8389a27270 100644
--- a/environment.c
+++ b/environment.c
@@ -49,9 +49,6 @@ int fsync_object_files = -1;
int use_fsync = -1;
enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;
enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT;
-size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
-size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
-size_t delta_base_cache_limit = 96 * 1024 * 1024;
unsigned long big_file_threshold = 512 * 1024 * 1024;
char *editor_program;
char *askpass_program;
diff --git a/environment.h b/environment.h
index 923e12661e..2f43340f0b 100644
--- a/environment.h
+++ b/environment.h
@@ -165,7 +165,6 @@ extern int zlib_compression_level;
extern int pack_compression_level;
extern size_t packed_git_window_size;
extern size_t packed_git_limit;
-extern size_t delta_base_cache_limit;
extern unsigned long big_file_threshold;
extern unsigned long pack_size_limit_cfg;
extern int max_allowed_tree_depth;
diff --git a/fetch-pack.c b/fetch-pack.c
index 961cbe2fe3..3a227721ed 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1858,8 +1858,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
return ref;
}
-static int fetch_pack_config_cb(const char *var, const char *value,
- const struct config_context *ctx, void *cb)
+int fetch_pack_fsck_config(const char *var, const char *value,
+ struct strbuf *msg_types)
{
const char *msg_id;
@@ -1867,9 +1867,9 @@ static int fetch_pack_config_cb(const char *var, const char *value,
char *path ;
if (git_config_pathname(&path, var, value))
- return 1;
- strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
- fsck_msg_types.len ? ',' : '=', path);
+ return 0;
+ strbuf_addf(msg_types, "%cskiplist=%s",
+ msg_types->len ? ',' : '=', path);
free(path);
return 0;
}
@@ -1878,14 +1878,24 @@ static int fetch_pack_config_cb(const char *var, const char *value,
if (!value)
return config_error_nonbool(var);
if (is_valid_msg_type(msg_id, value))
- strbuf_addf(&fsck_msg_types, "%c%s=%s",
- fsck_msg_types.len ? ',' : '=', msg_id, value);
+ strbuf_addf(msg_types, "%c%s=%s",
+ msg_types->len ? ',' : '=', msg_id, value);
else
warning("Skipping unknown msg id '%s'", msg_id);
return 0;
}
- return git_default_config(var, value, ctx, cb);
+ return 1;
+}
+
+static int fetch_pack_config_cb(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
+{
+ int ret = fetch_pack_fsck_config(var, value, &fsck_msg_types);
+ if (ret > 0)
+ return git_default_config(var, value, ctx, cb);
+
+ return ret;
}
static void fetch_pack_config(void)
diff --git a/fetch-pack.h b/fetch-pack.h
index b5c579cdae..9d3470366f 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -106,4 +106,15 @@ int report_unmatched_refs(struct ref **sought, int nr_sought);
*/
int fetch_pack_fsck_objects(void);
+/*
+ * Check if the provided config variable pertains to fetch fsck and if so append
+ * the configuration to the provided strbuf.
+ *
+ * When a fetch fsck config option is successfully processed the function
+ * returns 0. If the provided config option is unrelated to fetch fsck, 1 is
+ * returned. Errors return -1.
+ */
+int fetch_pack_fsck_config(const char *var, const char *value,
+ struct strbuf *msg_types);
+
#endif
diff --git a/fsck.c b/fsck.c
index 3756f52459..87ce999a49 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1295,7 +1295,7 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf) {
- if (is_promisor_object(oid))
+ if (is_promisor_object(the_repository, oid))
continue;
ret |= report(options,
oid, OBJ_BLOB, msg_missing,
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index 205541e0f7..b923a5aab8 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -64,7 +64,7 @@ define_category_names () {
print_command_list () {
echo "static struct cmdname_help command_list[] = {"
- echo "$1" |
+ echo "$2" |
while read cmd rest
do
synopsis=
@@ -76,7 +76,7 @@ print_command_list () {
break
;;
esac
- done <"Documentation/$cmd.txt"
+ done <"$1/Documentation/$cmd.txt"
printf '\t{ "%s", N_("%s"), 0' "$cmd" "$synopsis"
printf " | CAT_%s" $rest
@@ -93,18 +93,28 @@ do
shift
done
-commands="$(command_list "$1")"
-categories="$(category_list "$commands")"
+if test "$#" -ne 2
+then
+ die "USAGE: $0 <SOURCE_DIR> <OUTPUT>"
+fi
+
+SOURCE_DIR="$1"
+OUTPUT="$2"
+
+{
+ commands="$(command_list "$SOURCE_DIR"/command-list.txt)"
+ categories="$(category_list "$commands")"
-echo "/* Automatically generated by generate-cmdlist.sh */
-struct cmdname_help {
- const char *name;
- const char *help;
- uint32_t category;
-};
-"
-define_categories "$categories"
-echo
-define_category_names "$categories"
-echo
-print_command_list "$commands"
+ echo "/* Automatically generated by generate-cmdlist.sh */
+ struct cmdname_help {
+ const char *name;
+ const char *help;
+ uint32_t category;
+ };
+ "
+ define_categories "$categories"
+ echo
+ define_category_names "$categories"
+ echo
+ print_command_list "$SOURCE_DIR" "$commands"
+} >"$OUTPUT"
diff --git a/generate-configlist.sh b/generate-configlist.sh
index 8692fe5cf4..579422619c 100755
--- a/generate-configlist.sh
+++ b/generate-configlist.sh
@@ -1,13 +1,19 @@
#!/bin/sh
-echo "/* Automatically generated by generate-configlist.sh */"
-echo
+SOURCE_DIR="$1"
+OUTPUT="$2"
+
+if test -z "$SOURCE_DIR" || ! test -d "$SOURCE_DIR" || test -z "$OUTPUT"
+then
+ echo >&2 "USAGE: $0 <SOURCE_DIR> <OUTPUT>"
+ exit 1
+fi
print_config_list () {
cat <<EOF
static const char *config_name_list[] = {
EOF
- grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
+ grep -h '^[a-zA-Z].*\..*::$' "$SOURCE_DIR"/Documentation/*config.txt "$SOURCE_DIR"/Documentation/config/*.txt |
sed '/deprecated/d; s/::$//; s/, */\n/g' |
sort |
sed 's/^.*$/ "&",/'
@@ -17,5 +23,9 @@ EOF
EOF
}
-echo
-print_config_list
+{
+ echo "/* Automatically generated by generate-configlist.sh */"
+ echo
+ echo
+ print_config_list
+} >"$OUTPUT"
diff --git a/generate-hooklist.sh b/generate-hooklist.sh
index 2f9f54eb54..e22068c2fa 100755
--- a/generate-hooklist.sh
+++ b/generate-hooklist.sh
@@ -2,6 +2,17 @@
#
# Usage: ./generate-hooklist.sh >hook-list.h
+SOURCE_DIR="$1"
+OUTPUT="$2"
+
+if test -z "$SOURCE_DIR" || ! test -d "$SOURCE_DIR" || test -z "$OUTPUT"
+then
+ echo >&2 "USAGE: $0 <SOURCE_DIR> <OUTPUT>"
+ exit 1
+fi
+
+{
+
cat <<EOF
/* Automatically generated by generate-hooklist.sh */
@@ -11,10 +22,12 @@ EOF
sed -n \
-e '/^~~~~*$/ {x; s/^.*$/ "&",/; p;}' \
-e 'x' \
- <Documentation/githooks.txt |
+ <"$SOURCE_DIR"/Documentation/githooks.txt |
LC_ALL=C sort
cat <<EOF
NULL,
};
EOF
+
+} >"$OUTPUT"
diff --git a/generate-perl.sh b/generate-perl.sh
new file mode 100755
index 0000000000..65f122ebfc
--- /dev/null
+++ b/generate-perl.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+set -e
+
+if test $# -ne 5
+then
+ echo >&2 "USAGE: $0 <GIT_BUILD_OPTIONS> <GIT_VERSION_FILE> <PERL_HEADER> <INPUT> <OUTPUT>"
+ exit 1
+fi
+
+GIT_BUILD_OPTIONS="$1"
+GIT_VERSION_FILE="$2"
+PERL_HEADER="$3"
+INPUT="$4"
+OUTPUT="$5"
+
+. "$GIT_BUILD_OPTIONS"
+. "$GIT_VERSION_FILE"
+
+sed -e '1{' \
+ -e " /^#!.*perl/!b" \
+ -e " s|#!.*perl|#!$PERL_PATH|" \
+ -e " r $PERL_HEADER" \
+ -e ' G' \
+ -e '}' \
+ -e "s|@GIT_VERSION@|$GIT_VERSION|g" \
+ -e "s|@LOCALEDIR@|$PERL_LOCALEDIR|g" \
+ -e "s|@NO_GETTEXT@|$NO_GETTEXT|g" \
+ -e "s|@NO_PERL_CPAN_FALLBACKS@|$NO_PERL_CPAN_FALLBACKS|g" \
+ "$INPUT" >"$OUTPUT"
+
+case "$INPUT" in
+*.perl)
+ chmod a+x "$OUTPUT";;
+*)
+ ;;
+esac
diff --git a/generate-python.sh b/generate-python.sh
new file mode 100755
index 0000000000..31ac115689
--- /dev/null
+++ b/generate-python.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -e
+
+if test $# -ne 3
+then
+ echo >&2 "USAGE: $0 <GIT_BUILD_OPTIONS> <INPUT> <OUTPUT>"
+ exit 1
+fi
+
+GIT_BUILD_OPTIONS="$1"
+INPUT="$2"
+OUTPUT="$3"
+
+. "$GIT_BUILD_OPTIONS"
+
+sed -e "1s|#!.*python|#!$PYTHON_PATH|" \
+ "$INPUT" >"$OUTPUT+"
+chmod a+x "$OUTPUT+"
+mv "$OUTPUT+" "$OUTPUT"
diff --git a/generate-script.sh b/generate-script.sh
new file mode 100755
index 0000000000..a149e4f0ba
--- /dev/null
+++ b/generate-script.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+set -e
+
+if test $# -ne 3
+then
+ echo >&2 "USAGE: $0 <INPUT> <OUTPUT> <GIT-BUILD-OPTIONS>"
+ exit 1
+fi
+
+INPUT="$1"
+OUTPUT="$2"
+BUILD_OPTIONS="$3"
+
+. "$BUILD_OPTIONS"
+
+sed -e "1s|#!.*/sh|#!$SHELL_PATH|" \
+ -e "s|@SHELL_PATH@|$SHELL_PATH|" \
+ -e "s|@DIFF@|$DIFF|" \
+ -e "s|@LOCALEDIR@|$LOCALEDIR|g" \
+ -e "s/@USE_GETTEXT_SCHEME@/$USE_GETTEXT_SCHEME/g" \
+ -e "$BROKEN_PATH_FIX" \
+ -e "s|@GITWEBDIR@|$GITWEBDIR|g" \
+ -e "s|@PERL_PATH@|$PERL_PATH|g" \
+ -e "s|@PAGER_ENV@|$PAGER_ENV|g" \
+ "$INPUT" >"$OUTPUT"
+
+case "$(basename "$INPUT")" in
+git-mergetool--lib.sh|git-sh-i18n.sh|git-sh-setup.sh)
+ ;;
+*)
+ chmod a+x "$OUTPUT"
+ ;;
+esac
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index a4ad9a5d2d..a4e1bad33c 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -26,7 +26,7 @@ use File::Path qw/rmtree/;
use File::Basename;
use Getopt::Long qw(:config require_order no_ignore_case);
-my $VERSION = '@@GIT_VERSION@@';
+my $VERSION = '@GIT_VERSION@';
my $log = GITCVS::log->new();
my $cfg;
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
index dd0c9a5b7f..d32e47cc09 100755
--- a/git-difftool--helper.sh
+++ b/git-difftool--helper.sh
@@ -61,9 +61,7 @@ launch_merge_tool () {
export BASE
eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"'
else
- initialize_merge_tool "$merge_tool"
- # ignore the error from the above --- run_merge_tool
- # will diagnose unusable tool by itself
+ initialize_merge_tool "$merge_tool" || exit 1
run_merge_tool "$merge_tool"
fi
}
@@ -87,9 +85,7 @@ if test -n "$GIT_DIFFTOOL_DIRDIFF"
then
LOCAL="$1"
REMOTE="$2"
- initialize_merge_tool "$merge_tool"
- # ignore the error from the above --- run_merge_tool
- # will diagnose unusable tool by itself
+ initialize_merge_tool "$merge_tool" || exit 1
run_merge_tool "$merge_tool" false
status=$?
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 8dbe21d588..5ad50160bb 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2006 Eric Wong
#
-PERL='@@PERL@@'
+PERL='@PERL_PATH@'
OPTIONS_KEEPDASHDASH=
OPTIONS_STUCKLONG=
OPTIONS_SPEC="\
@@ -38,8 +38,8 @@ conf="$GIT_DIR/gitweb/httpd.conf"
# if installed, it doesn't need further configuration (module_path)
test -z "$httpd" && httpd='lighttpd -f'
-# Default is @@GITWEBDIR@@
-test -z "$root" && root='@@GITWEBDIR@@'
+# Default is @GITWEBDIR@
+test -z "$root" && root='@GITWEBDIR@'
# any untaken local port will do...
test -z "$port" && port=1234
@@ -716,7 +716,7 @@ EOF
gitweb_conf() {
cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF
-#!@@PERL@@
+#!@PERL_PATH@
our \$projectroot = "$(dirname "$fqgitdir")";
our \$git_temp = "$fqgitdir/gitweb/tmp";
our \$projects_list = \$projectroot;
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index 1ff26170ff..11ea181259 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -159,7 +159,7 @@ check_unchanged () {
}
valid_tool () {
- setup_tool "$1" && return 0
+ setup_tool "$1" 2>/dev/null && return 0
cmd=$(get_merge_tool_cmd "$1")
test -n "$cmd"
}
@@ -250,7 +250,12 @@ setup_tool () {
. "$MERGE_TOOLS_DIR/${tool%[0-9]}"
else
setup_user_tool
- return $?
+ rc=$?
+ if test $rc -ne 0
+ then
+ echo >&2 "error: ${TOOL_MODE}tool.$tool.cmd not set for tool '$tool'"
+ fi
+ return $rc
fi
# Now let the user override the default command for the tool. If
@@ -259,6 +264,7 @@ setup_tool () {
if ! list_tool_variants | grep -q "^$tool$"
then
+ echo "error: unknown tool variant '$tool'" >&2
return 1
fi
@@ -474,7 +480,7 @@ get_merge_tool_path () {
merge_tool="$1"
if ! valid_tool "$merge_tool"
then
- echo >&2 "Unknown merge tool $merge_tool"
+ echo >&2 "Unknown $TOOL_MODE tool $merge_tool"
exit 1
fi
if diff_mode
diff --git a/git-request-pull.sh b/git-request-pull.sh
index 01640a044b..775ba8ea11 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -112,7 +112,7 @@ find_matching_ref='
}
'
-set fnord $(git ls-remote "$url" | @@PERL@@ -e "$find_matching_ref" "${remote:-HEAD}" "$headrev")
+set fnord $(git ls-remote "$url" | @PERL_PATH@ -e "$find_matching_ref" "${remote:-HEAD}" "$headrev")
remote_sha1=$2
ref=$3
diff --git a/git-send-email.perl b/git-send-email.perl
index c4d12bebc8..798d59b84f 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1501,7 +1501,7 @@ sub gen_header {
@recipients = unique_email_list(@recipients,@cc,@initial_bcc);
@recipients = (map { extract_valid_address_or_die($_) } @recipients);
my $date = format_2822_time($time++);
- my $gitversion = '@@GIT_VERSION@@';
+ my $gitversion = '@GIT_VERSION@';
if ($gitversion =~ m/..GIT_VERSION../) {
$gitversion = Git::version();
}
diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh
index a15c0620db..ae4b2d6ba9 100644
--- a/git-sh-i18n.sh
+++ b/git-sh-i18n.sh
@@ -9,7 +9,7 @@ TEXTDOMAIN=git
export TEXTDOMAIN
if test -z "$GIT_TEXTDOMAINDIR"
then
- TEXTDOMAINDIR="@@LOCALEDIR@@"
+ TEXTDOMAINDIR="@LOCALEDIR@"
else
TEXTDOMAINDIR="$GIT_TEXTDOMAINDIR"
fi
@@ -17,9 +17,9 @@ export TEXTDOMAINDIR
# First decide what scheme to use...
GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough
-if test -n "@@USE_GETTEXT_SCHEME@@"
+if test -n "@USE_GETTEXT_SCHEME@"
then
- GIT_INTERNAL_GETTEXT_SH_SCHEME="@@USE_GETTEXT_SCHEME@@"
+ GIT_INTERNAL_GETTEXT_SH_SCHEME="@USE_GETTEXT_SCHEME@"
elif test -n "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS"
then
: no probing necessary
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index ce273fe0e4..19aef72ec2 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -41,7 +41,7 @@ git_broken_path_fix () {
esac
}
-# @@BROKEN_PATH_FIX@@
+# @BROKEN_PATH_FIX@
# Source git-sh-i18n for gettext support.
. "$(git --exec-path)/git-sh-i18n"
@@ -154,7 +154,7 @@ git_pager() {
else
GIT_PAGER=cat
fi
- for vardef in @@PAGER_ENV@@
+ for vardef in @PAGER_ENV@
do
var=${vardef%%=*}
eval ": \"\${$vardef}\" && export $var"
@@ -280,7 +280,7 @@ get_author_ident_from_commit () {
# remove lines from $1 that are not in $2, leaving only common lines.
create_virtual_base() {
sz0=$(wc -c <"$1")
- @@DIFF@@ -u -La/"$1" -Lb/"$1" "$1" "$2" | git apply --no-add
+ @DIFF@ -u -La/"$1" -Lb/"$1" "$1" "$2" | git apply --no-add
sz1=$(wc -c <"$1")
# If we do not have enough common material, it is not
diff --git a/git-svn.perl b/git-svn.perl
index 9c7c629932..32c648c395 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -9,7 +9,7 @@ use vars qw/ $AUTHOR $VERSION
$_revision $_repository
$_q $_authors $_authors_prog %users/;
$AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
-$VERSION = '@@GIT_VERSION@@';
+$VERSION = '@GIT_VERSION@';
use Carp qw/croak/;
use File::Basename qw/dirname basename/;
diff --git a/git.rc b/git.rc.in
index cc3fdc6cc6..e69444eef3 100644
--- a/git.rc
+++ b/git.rc.in
@@ -1,6 +1,6 @@
1 VERSIONINFO
-FILEVERSION MAJOR,MINOR,MICRO,PATCHLEVEL
-PRODUCTVERSION MAJOR,MINOR,MICRO,PATCHLEVEL
+FILEVERSION @GIT_MAJOR_VERSION@,@GIT_MINOR_VERSION@,@GIT_MICRO_VERSION@,@GIT_PATCH_LEVEL@
+PRODUCTVERSION @GIT_MAJOR_VERSION@,@GIT_MINOR_VERSION@,@GIT_MICRO_VERSION@,@GIT_PATCH_LEVEL@
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -11,7 +11,7 @@ BEGIN
VALUE "InternalName", "git\0"
VALUE "OriginalFilename", "git.exe\0"
VALUE "ProductName", "Git\0"
- VALUE "ProductVersion", GIT_VERSION "\0"
+ VALUE "ProductVersion", "@GIT_VERSION@\0"
END
END
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 7a087f123d..47a7c1d29c 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -1969,6 +1969,10 @@ proc confirm_popup {msg {owner .}} {
return $confirm_ok
}
+proc haveselectionclipboard {} {
+ return [expr {[tk windowingsystem] eq "x11"}]
+}
+
proc setoptions {} {
global use_ttk
@@ -2089,7 +2093,7 @@ proc makewindow {} {
global diffcontextstring diffcontext
global ignorespace
global maincursor textcursor curtextcursor
- global rowctxmenu fakerowmenu mergemax wrapcomment
+ global rowctxmenu fakerowmenu mergemax wrapcomment wrapdefault
global highlight_files gdttype
global searchstring sstring
global bgcolor fgcolor bglist fglist diffcolors diffbgcolors selectbgcolor
@@ -2223,7 +2227,7 @@ proc makewindow {} {
set sha1entry .tf.bar.sha1
set entries $sha1entry
set sha1but .tf.bar.sha1label
- button $sha1but -text "[mc "SHA1 ID:"] " -state disabled -relief flat \
+ button $sha1but -text "[mc "Commit ID:"] " -state disabled -relief flat \
-command gotocommit -width 8
$sha1but conf -disabledforeground [$sha1but cget -foreground]
pack .tf.bar.sha1label -side left
@@ -2431,7 +2435,7 @@ proc makewindow {} {
set ctext .bleft.bottom.ctext
text $ctext -background $bgcolor -foreground $fgcolor \
-state disabled -undo 0 -font textfont \
- -yscrollcommand scrolltext -wrap none \
+ -yscrollcommand scrolltext -wrap $wrapdefault \
-xscrollcommand ".bleft.bottom.sbhorizontal set"
if {$have_tk85} {
$ctext conf -tabstyle wordprocessor
@@ -7344,7 +7348,7 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} {
global mergemax numcommits pending_select
global cmitmode showneartags allcommits
global targetrow targetid lastscrollrows
- global autoselect autosellen jump_to_here
+ global autocopy autoselect autosellen jump_to_here
global vinlinediff
unset -nocomplain pending_select
@@ -7410,9 +7414,13 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} {
$sha1entry delete 0 end
$sha1entry insert 0 $id
- if {$autoselect} {
+ if {$autoselect && [haveselectionclipboard]} {
$sha1entry selection range 0 $autosellen
}
+ if {$autocopy} {
+ clipboard clear
+ clipboard append [string range $id 0 [expr $autosellen - 1]]
+ }
rhighlight_sel $id
$ctext conf -state normal
@@ -8756,7 +8764,7 @@ proc sha1change {n1 n2 op} {
if {$state == "normal"} {
$sha1but conf -state normal -relief raised -text "[mc "Goto:"] "
} else {
- $sha1but conf -state disabled -relief flat -text "[mc "SHA1 ID:"] "
+ $sha1but conf -state disabled -relief flat -text "[mc "Commit ID:"] "
}
}
@@ -8775,7 +8783,7 @@ proc gotocommit {} {
set matches [longid $id]
if {$matches ne {}} {
if {[llength $matches] > 1} {
- error_popup [mc "Short SHA1 id %s is ambiguous" $id]
+ error_popup [mc "Short commit ID %s is ambiguous" $id]
return
}
set id [lindex $matches 0]
@@ -8792,7 +8800,7 @@ proc gotocommit {} {
return
}
if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
- set msg [mc "SHA1 id %s is not known" $sha1string]
+ set msg [mc "Commit ID %s is not known" $sha1string]
} else {
set msg [mc "Revision %s is not in the current view" $sha1string]
}
@@ -11576,12 +11584,13 @@ proc create_prefs_page {w} {
proc prefspage_general {notebook} {
global NS maxwidth maxgraphpct showneartags showlocalchanges
- global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
+ global tabstop wrapcomment wrapdefault limitdiffs
+ global autocopy autoselect autosellen extdifftool perfile_attrs
global hideremotes want_ttk have_ttk maxrefs web_browser
set page [create_prefs_page $notebook.general]
- ${NS}::label $page.ldisp -text [mc "Commit list display options"]
+ ${NS}::label $page.ldisp -text [mc "Commit list display options"] -font mainfontbold
grid $page.ldisp - -sticky w -pady 10
${NS}::label $page.spacer -text " "
${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"]
@@ -11594,19 +11603,38 @@ proc prefspage_general {notebook} {
${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
-variable showlocalchanges
grid x $page.showlocal -sticky w
- ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
- -variable autoselect
- spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
- grid x $page.autoselect $page.autosellen -sticky w
${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
-variable hideremotes
grid x $page.hideremotes -sticky w
- ${NS}::label $page.ddisp -text [mc "Diff display options"]
+ ${NS}::checkbutton $page.autocopy -text [mc "Copy commit ID to clipboard"] \
+ -variable autocopy
+ grid x $page.autocopy -sticky w
+ if {[haveselectionclipboard]} {
+ ${NS}::checkbutton $page.autoselect -text [mc "Copy commit ID to X11 selection"] \
+ -variable autoselect
+ grid x $page.autoselect -sticky w
+ }
+ spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
+ ${NS}::label $page.autosellenl -text [mc "Length of commit ID to copy"]
+ grid x $page.autosellenl $page.autosellen -sticky w
+
+ ${NS}::label $page.ddisp -text [mc "Diff display options"] -font mainfontbold
grid $page.ddisp - -sticky w -pady 10
${NS}::label $page.tabstopl -text [mc "Tab spacing"]
spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
grid x $page.tabstopl $page.tabstop -sticky w
+
+ ${NS}::label $page.wrapcommentl -text [mc "Wrap comment text"]
+ ${NS}::combobox $page.wrapcomment -values {none char word} -state readonly \
+ -textvariable wrapcomment
+ grid x $page.wrapcommentl $page.wrapcomment -sticky w
+
+ ${NS}::label $page.wrapdefaultl -text [mc "Wrap other text"]
+ ${NS}::combobox $page.wrapdefault -values {none char word} -state readonly \
+ -textvariable wrapdefault
+ grid x $page.wrapdefaultl $page.wrapdefault -sticky w
+
${NS}::checkbutton $page.ntag -text [mc "Display nearby tags/heads"] \
-variable showneartags
grid x $page.ntag -sticky w
@@ -11635,7 +11663,7 @@ proc prefspage_general {notebook} {
pack configure $page.webbrowserf.l -padx 10
grid x $page.webbrowserf $page.webbrowser -sticky ew
- ${NS}::label $page.lgen -text [mc "General options"]
+ ${NS}::label $page.lgen -text [mc "General options"] -font mainfontbold
grid $page.lgen - -sticky w -pady 10
${NS}::checkbutton $page.want_ttk -variable want_ttk \
-text [mc "Use themed widgets"]
@@ -11654,7 +11682,7 @@ proc prefspage_colors {notebook} {
set page [create_prefs_page $notebook.colors]
- ${NS}::label $page.cdisp -text [mc "Colors: press to choose"]
+ ${NS}::label $page.cdisp -text [mc "Colors: press to choose"] -font mainfontbold
grid $page.cdisp - -sticky w -pady 10
label $page.ui -padx 40 -relief sunk -background $uicolor
${NS}::button $page.uibut -text [mc "Interface"] \
@@ -11712,7 +11740,7 @@ proc prefspage_colors {notebook} {
proc prefspage_fonts {notebook} {
global NS
set page [create_prefs_page $notebook.fonts]
- ${NS}::label $page.cfont -text [mc "Fonts: press to choose"]
+ ${NS}::label $page.cfont -text [mc "Fonts: press to choose"] -font mainfontbold
grid $page.cfont - -sticky w -pady 10
mkfontdisp mainfont $page [mc "Main font"]
mkfontdisp textfont $page [mc "Diff display font"]
@@ -11725,7 +11753,7 @@ proc doprefs {} {
global oldprefs prefstop showneartags showlocalchanges
global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
- global hideremotes want_ttk have_ttk
+ global hideremotes want_ttk have_ttk wrapcomment wrapdefault
set top .gitkprefs
set prefstop $top
@@ -11734,7 +11762,7 @@ proc doprefs {} {
return
}
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
- limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+ limitdiffs tabstop perfile_attrs hideremotes want_ttk wrapcomment wrapdefault} {
set oldprefs($v) [set $v]
}
ttk_toplevel $top
@@ -11860,7 +11888,7 @@ proc prefscan {} {
global oldprefs prefstop
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
- limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+ limitdiffs tabstop perfile_attrs hideremotes want_ttk wrapcomment wrapdefault} {
global $v
set $v $oldprefs($v)
}
@@ -11874,7 +11902,8 @@ proc prefsok {} {
global oldprefs prefstop showneartags showlocalchanges
global fontpref mainfont textfont uifont
global limitdiffs treediffs perfile_attrs
- global hideremotes
+ global hideremotes wrapcomment wrapdefault
+ global ctext
catch {destroy $prefstop}
unset prefstop
@@ -11923,6 +11952,12 @@ proc prefsok {} {
if {$hideremotes != $oldprefs(hideremotes)} {
rereadrefs
}
+ if {$wrapcomment != $oldprefs(wrapcomment)} {
+ $ctext tag conf comment -wrap $wrapcomment
+ }
+ if {$wrapdefault != $oldprefs(wrapdefault)} {
+ $ctext configure -wrap $wrapdefault
+ }
}
proc formatdate {d} {
@@ -12392,6 +12427,7 @@ set downarrowlen 5
set mingaplen 100
set cmitmode "patch"
set wrapcomment "none"
+set wrapdefault "none"
set showneartags 1
set hideremotes 0
set maxrefs 20
@@ -12400,6 +12436,7 @@ set maxlinelen 200
set showlocalchanges 1
set limitdiffs 1
set datetimeformat "%Y-%m-%d %H:%M:%S"
+set autocopy 0
set autoselect 1
set autosellen 40
set perfile_attrs 0
@@ -12497,7 +12534,8 @@ config_check_tmp_exists 50
set config_variables {
mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth
- cmitmode wrapcomment autoselect autosellen showneartags maxrefs visiblerefs
+ cmitmode wrapcomment wrapdefault autocopy autoselect autosellen
+ showneartags maxrefs visiblerefs
hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk
bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors
markbgcolor diffcontext selectbgcolor foundbgcolor currentsearchhitbgcolor
@@ -12687,7 +12725,7 @@ catch {
wm iconphoto . -default gitlogo gitlogo32
}
# wait for the window to become visible
-tkwait visibility .
+if {![winfo viewable .]} {tkwait visibility .}
set_window_title
update
readrefs
diff --git a/gitk-git/po/sv.po b/gitk-git/po/sv.po
index 2a06fe5bbc..5afbe6da1d 100644
--- a/gitk-git/po/sv.po
+++ b/gitk-git/po/sv.po
@@ -3,14 +3,14 @@
# This file is distributed under the same license as the gitk package.
#
# Mikael Magnusson <mikachu@gmail.com>, 2008.
-# Peter Krefting <peter@softwolves.pp.se>, 2008, 2009, 2010, 2012, 2013, 2015.
+# Peter Krefting <peter@softwolves.pp.se>, 2008-2023.
#
msgid ""
msgstr ""
"Project-Id-Version: sv\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-12-09 09:40+0100\n"
-"PO-Revision-Date: 2015-12-11 09:46+0100\n"
+"POT-Creation-Date: 2023-10-26 21:39+0100\n"
+"PO-Revision-Date: 2023-10-26 21:42+0100\n"
"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -18,35 +18,35 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Gtranslator 2.91.6\n"
+"X-Generator: Gtranslator 3.38.0\n"
-#: gitk:140
+#: gitk:139
msgid "Couldn't get list of unmerged files:"
msgstr "Kunde inte hämta lista över ej sammanslagna filer:"
-#: gitk:212 gitk:2381
+#: gitk:211 gitk:2406
msgid "Color words"
msgstr "Färga ord"
-#: gitk:217 gitk:2381 gitk:8221 gitk:8254
+#: gitk:216 gitk:2406 gitk:8307 gitk:8340
msgid "Markup words"
msgstr "Märk upp ord"
-#: gitk:324
+#: gitk:323
msgid "Error parsing revisions:"
msgstr "Fel vid tolkning av revisioner:"
-#: gitk:380
+#: gitk:379
msgid "Error executing --argscmd command:"
msgstr "Fel vid körning av --argscmd-kommando:"
-#: gitk:393
+#: gitk:392
msgid "No files selected: --merge specified but no files are unmerged."
msgstr ""
"Inga filer valdes: --merge angavs men det finns inga filer som inte har "
"slagits samman."
-#: gitk:396
+#: gitk:395
msgid ""
"No files selected: --merge specified but no unmerged files are within file "
"limit."
@@ -54,322 +54,326 @@ msgstr ""
"Inga filer valdes: --merge angavs men det finns inga filer inom "
"filbegränsningen."
-#: gitk:418 gitk:566
+#: gitk:417 gitk:565
msgid "Error executing git log:"
msgstr "Fel vid körning av git log:"
-#: gitk:436 gitk:582
+#: gitk:435 gitk:581
msgid "Reading"
msgstr "Läser"
-#: gitk:496 gitk:4526
+#: gitk:495 gitk:4572
msgid "Reading commits..."
msgstr "Läser incheckningar..."
-#: gitk:499 gitk:1637 gitk:4529
+#: gitk:498 gitk:1640 gitk:4575
msgid "No commits selected"
msgstr "Inga incheckningar markerade"
-#: gitk:1445 gitk:4046 gitk:12447
+#: gitk:1448 gitk:4092 gitk:12674
msgid "Command line"
msgstr "Kommandorad"
-#: gitk:1511
+#: gitk:1514
msgid "Can't parse git log output:"
msgstr "Kan inte tolka utdata från git log:"
-#: gitk:1740
+#: gitk:1743
msgid "No commit information available"
msgstr "Ingen incheckningsinformation är tillgänglig"
-#: gitk:1903 gitk:1932 gitk:4316 gitk:9684 gitk:11256 gitk:11536
+#: gitk:1910 gitk:1939 gitk:4362 gitk:9847 gitk:11451 gitk:11751
msgid "OK"
msgstr "OK"
-#: gitk:1934 gitk:4318 gitk:9197 gitk:9276 gitk:9406 gitk:9455 gitk:9686
-#: gitk:11257 gitk:11537
+#: gitk:1941 gitk:4364 gitk:9283 gitk:9362 gitk:9492 gitk:9578 gitk:9849
+#: gitk:11452 gitk:11752
msgid "Cancel"
msgstr "Avbryt"
-#: gitk:2069
+#: gitk:2090
msgid "&Update"
msgstr "&Uppdatera"
-#: gitk:2070
+#: gitk:2091
msgid "&Reload"
msgstr "Läs &om"
-#: gitk:2071
+#: gitk:2092
msgid "Reread re&ferences"
msgstr "Läs om &referenser"
-#: gitk:2072
+#: gitk:2093
msgid "&List references"
msgstr "&Visa referenser"
-#: gitk:2074
+#: gitk:2095
msgid "Start git &gui"
msgstr "Starta git &gui"
-#: gitk:2076
+#: gitk:2097
msgid "&Quit"
msgstr "&Avsluta"
-#: gitk:2068
+#: gitk:2089
msgid "&File"
msgstr "&Arkiv"
-#: gitk:2080
+#: gitk:2101
msgid "&Preferences"
msgstr "&Inställningar"
-#: gitk:2079
+#: gitk:2100
msgid "&Edit"
msgstr "&Redigera"
-#: gitk:2084
+#: gitk:2105
msgid "&New view..."
msgstr "&Ny vy..."
-#: gitk:2085
+#: gitk:2106
msgid "&Edit view..."
msgstr "&Ändra vy..."
-#: gitk:2086
+#: gitk:2107
msgid "&Delete view"
msgstr "&Ta bort vy"
-#: gitk:2088
+#: gitk:2109
msgid "&All files"
msgstr "&Alla filer"
-#: gitk:2083
+#: gitk:2104
msgid "&View"
msgstr "&Visa"
-#: gitk:2093 gitk:2103
+#: gitk:2114 gitk:2124
msgid "&About gitk"
msgstr "&Om gitk"
-#: gitk:2094 gitk:2108
+#: gitk:2115 gitk:2129
msgid "&Key bindings"
msgstr "&Tangentbordsbindningar"
-#: gitk:2092 gitk:2107
+#: gitk:2113 gitk:2128
msgid "&Help"
msgstr "&Hjälp"
-#: gitk:2185 gitk:8653
+#: gitk:2206 gitk:8739
msgid "SHA1 ID:"
msgstr "SHA1-id:"
-#: gitk:2229
+#: gitk:2250
msgid "Row"
msgstr "Rad"
-#: gitk:2267
+#: gitk:2288
msgid "Find"
msgstr "Sök"
-#: gitk:2295
+#: gitk:2316
msgid "commit"
msgstr "incheckning"
-#: gitk:2299 gitk:2301 gitk:4688 gitk:4711 gitk:4735 gitk:6756 gitk:6828
-#: gitk:6913
+#: gitk:2320 gitk:2322 gitk:4734 gitk:4757 gitk:4781 gitk:6802 gitk:6874
+#: gitk:6959
msgid "containing:"
msgstr "som innehåller:"
-#: gitk:2302 gitk:3527 gitk:3532 gitk:4764
+#: gitk:2323 gitk:3573 gitk:3578 gitk:4810
msgid "touching paths:"
msgstr "som rör sökväg:"
-#: gitk:2303 gitk:4778
+#: gitk:2324 gitk:4824
msgid "adding/removing string:"
msgstr "som lägger/till tar bort sträng:"
-#: gitk:2304 gitk:4780
+#: gitk:2325 gitk:4826
msgid "changing lines matching:"
msgstr "ändrar rader som matchar:"
-#: gitk:2313 gitk:2315 gitk:4767
+#: gitk:2334 gitk:2336 gitk:4813
msgid "Exact"
msgstr "Exakt"
-#: gitk:2315 gitk:4855 gitk:6724
+#: gitk:2336 gitk:4901 gitk:6770
msgid "IgnCase"
msgstr "IgnVersaler"
-#: gitk:2315 gitk:4737 gitk:4853 gitk:6720
+#: gitk:2336 gitk:4783 gitk:4899 gitk:6766
msgid "Regexp"
msgstr "Reg.uttr."
-#: gitk:2317 gitk:2318 gitk:4875 gitk:4905 gitk:4912 gitk:6849 gitk:6917
+#: gitk:2338 gitk:2339 gitk:4921 gitk:4951 gitk:4958 gitk:6895 gitk:6963
msgid "All fields"
msgstr "Alla fält"
-#: gitk:2318 gitk:4872 gitk:4905 gitk:6787
+#: gitk:2339 gitk:4918 gitk:4951 gitk:6833
msgid "Headline"
msgstr "Rubrik"
-#: gitk:2319 gitk:4872 gitk:6787 gitk:6917 gitk:7390
+#: gitk:2340 gitk:4918 gitk:6833 gitk:6963 gitk:7471
msgid "Comments"
msgstr "Kommentarer"
-#: gitk:2319 gitk:4872 gitk:4877 gitk:4912 gitk:6787 gitk:7325 gitk:8831
-#: gitk:8846
+#: gitk:2340 gitk:4918 gitk:4923 gitk:4958 gitk:6833 gitk:7406 gitk:8917
+#: gitk:8932
msgid "Author"
msgstr "Författare"
-#: gitk:2319 gitk:4872 gitk:6787 gitk:7327
+#: gitk:2340 gitk:4918 gitk:6833 gitk:7408
msgid "Committer"
msgstr "Incheckare"
-#: gitk:2350
+#: gitk:2374
msgid "Search"
msgstr "Sök"
-#: gitk:2358
+#: gitk:2382
msgid "Diff"
msgstr "Diff"
-#: gitk:2360
+#: gitk:2384
msgid "Old version"
msgstr "Gammal version"
-#: gitk:2362
+#: gitk:2386
msgid "New version"
msgstr "Ny version"
-#: gitk:2364
+#: gitk:2389
msgid "Lines of context"
msgstr "Rader sammanhang"
-#: gitk:2374
+#: gitk:2399
msgid "Ignore space change"
msgstr "Ignorera ändringar i blanksteg"
-#: gitk:2378 gitk:2380 gitk:7960 gitk:8207
+#: gitk:2403 gitk:2405 gitk:8041 gitk:8293
msgid "Line diff"
msgstr "Rad-diff"
-#: gitk:2445
+#: gitk:2478
msgid "Patch"
msgstr "Patch"
-#: gitk:2447
+#: gitk:2480
msgid "Tree"
msgstr "Träd"
-#: gitk:2617 gitk:2638
+#: gitk:2650 gitk:2671
msgid "Diff this -> selected"
msgstr "Diff denna -> markerad"
-#: gitk:2618 gitk:2639
+#: gitk:2651 gitk:2672
msgid "Diff selected -> this"
msgstr "Diff markerad -> denna"
-#: gitk:2619 gitk:2640
+#: gitk:2652 gitk:2673
msgid "Make patch"
msgstr "Skapa patch"
-#: gitk:2620 gitk:9255
+#: gitk:2653 gitk:9341
msgid "Create tag"
msgstr "Skapa tagg"
-#: gitk:2621
-msgid "Copy commit summary"
-msgstr "Kopiera incheckningssammanfattning"
+#: gitk:2654
+msgid "Copy commit reference"
+msgstr "Kopiera incheckningsreferens"
-#: gitk:2622 gitk:9386
+#: gitk:2655 gitk:9472
msgid "Write commit to file"
msgstr "Skriv incheckning till fil"
-#: gitk:2623 gitk:9443
+#: gitk:2656
msgid "Create new branch"
msgstr "Skapa ny gren"
-#: gitk:2624
+#: gitk:2657
msgid "Cherry-pick this commit"
msgstr "Plocka denna incheckning"
-#: gitk:2625
+#: gitk:2658
msgid "Reset HEAD branch to here"
msgstr "Återställ HEAD-grenen hit"
-#: gitk:2626
+#: gitk:2659
msgid "Mark this commit"
msgstr "Markera denna incheckning"
-#: gitk:2627
+#: gitk:2660
msgid "Return to mark"
msgstr "Återgå till markering"
-#: gitk:2628
+#: gitk:2661
msgid "Find descendant of this and mark"
msgstr "Hitta efterföljare till denna och markera"
-#: gitk:2629
+#: gitk:2662
msgid "Compare with marked commit"
msgstr "Jämför med markerad incheckning"
-#: gitk:2630 gitk:2641
+#: gitk:2663 gitk:2674
msgid "Diff this -> marked commit"
msgstr "Diff denna -> markerad incheckning"
-#: gitk:2631 gitk:2642
+#: gitk:2664 gitk:2675
msgid "Diff marked commit -> this"
msgstr "Diff markerad incheckning -> denna"
-#: gitk:2632
+#: gitk:2665
msgid "Revert this commit"
msgstr "Ångra denna incheckning"
-#: gitk:2648
+#: gitk:2681
msgid "Check out this branch"
msgstr "Checka ut denna gren"
-#: gitk:2649
+#: gitk:2682
+msgid "Rename this branch"
+msgstr "Byt namn på denna gren"
+
+#: gitk:2683
msgid "Remove this branch"
msgstr "Ta bort denna gren"
-#: gitk:2650
+#: gitk:2684
msgid "Copy branch name"
msgstr "Kopiera namn på gren"
-#: gitk:2657
+#: gitk:2691
msgid "Highlight this too"
msgstr "Markera även detta"
-#: gitk:2658
+#: gitk:2692
msgid "Highlight this only"
msgstr "Markera bara detta"
-#: gitk:2659
+#: gitk:2693
msgid "External diff"
msgstr "Extern diff"
-#: gitk:2660
+#: gitk:2694
msgid "Blame parent commit"
msgstr "Klandra föräldraincheckning"
-#: gitk:2661
+#: gitk:2695
msgid "Copy path"
msgstr "Kopiera sökväg"
-#: gitk:2668
+#: gitk:2702
msgid "Show origin of this line"
msgstr "Visa ursprunget för den här raden"
-#: gitk:2669
+#: gitk:2703
msgid "Run git gui blame on this line"
msgstr "Kör git gui blame på den här raden"
-#: gitk:3013
+#: gitk:3057
msgid "About gitk"
msgstr "Om gitk"
-#: gitk:3015
+#: gitk:3059
msgid ""
"\n"
"Gitk - a commit viewer for git\n"
@@ -385,525 +389,529 @@ msgstr ""
"\n"
"Använd och vidareförmedla enligt villkoren i GNU General Public License"
-#: gitk:3023 gitk:3090 gitk:9872
+#: gitk:3067 gitk:3134 gitk:10062
msgid "Close"
msgstr "Stäng"
-#: gitk:3044
+#: gitk:3088
msgid "Gitk key bindings"
msgstr "Tangentbordsbindningar för Gitk"
-#: gitk:3047
+#: gitk:3091
msgid "Gitk key bindings:"
msgstr "Tangentbordsbindningar för Gitk:"
-#: gitk:3049
+#: gitk:3093
#, tcl-format
msgid "<%s-Q>\t\tQuit"
msgstr "<%s-Q>\t\tAvsluta"
-#: gitk:3050
+#: gitk:3094
#, tcl-format
msgid "<%s-W>\t\tClose window"
msgstr "<%s-W>\t\tStäng fönster"
-#: gitk:3051
+#: gitk:3095
msgid "<Home>\t\tMove to first commit"
msgstr "<Home>\t\tGå till första incheckning"
-#: gitk:3052
+#: gitk:3096
msgid "<End>\t\tMove to last commit"
msgstr "<End>\t\tGå till sista incheckning"
-#: gitk:3053
+#: gitk:3097
msgid "<Up>, p, k\tMove up one commit"
msgstr "<Upp>, p, k\tGå en incheckning upp"
-#: gitk:3054
+#: gitk:3098
msgid "<Down>, n, j\tMove down one commit"
msgstr "<Ned>, n, j\tGå en incheckning ned"
-#: gitk:3055
+#: gitk:3099
msgid "<Left>, z, h\tGo back in history list"
msgstr "<Vänster>, z, h\tGå bakåt i historiken"
-#: gitk:3056
+#: gitk:3100
msgid "<Right>, x, l\tGo forward in history list"
msgstr "<Höger>, x, l\tGå framåt i historiken"
-#: gitk:3057
+#: gitk:3101
#, tcl-format
msgid "<%s-n>\tGo to n-th parent of current commit in history list"
msgstr "<%s-n>\tGå till aktuell inchecknings n:te förälder i historielistan"
-#: gitk:3058
+#: gitk:3102
msgid "<PageUp>\tMove up one page in commit list"
msgstr "<PageUp>\tGå upp en sida i incheckningslistan"
-#: gitk:3059
+#: gitk:3103
msgid "<PageDown>\tMove down one page in commit list"
msgstr "<PageDown>\tGå ned en sida i incheckningslistan"
-#: gitk:3060
+#: gitk:3104
#, tcl-format
msgid "<%s-Home>\tScroll to top of commit list"
msgstr "<%s-Home>\tRulla till början av incheckningslistan"
-#: gitk:3061
+#: gitk:3105
#, tcl-format
msgid "<%s-End>\tScroll to bottom of commit list"
msgstr "<%s-End>\tRulla till slutet av incheckningslistan"
-#: gitk:3062
+#: gitk:3106
#, tcl-format
msgid "<%s-Up>\tScroll commit list up one line"
msgstr "<%s-Upp>\tRulla incheckningslistan upp ett steg"
-#: gitk:3063
+#: gitk:3107
#, tcl-format
msgid "<%s-Down>\tScroll commit list down one line"
msgstr "<%s-Ned>\tRulla incheckningslistan ned ett steg"
-#: gitk:3064
+#: gitk:3108
#, tcl-format
msgid "<%s-PageUp>\tScroll commit list up one page"
msgstr "<%s-PageUp>\tRulla incheckningslistan upp en sida"
-#: gitk:3065
+#: gitk:3109
#, tcl-format
msgid "<%s-PageDown>\tScroll commit list down one page"
msgstr "<%s-PageDown>\tRulla incheckningslistan ned en sida"
-#: gitk:3066
+#: gitk:3110
msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
msgstr "<Skift-Upp>\tSök bakåt (uppåt, senare incheckningar)"
-#: gitk:3067
+#: gitk:3111
msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
msgstr "<Skift-Ned>\tSök framåt (nedåt, tidigare incheckningar)"
-#: gitk:3068
+#: gitk:3112
msgid "<Delete>, b\tScroll diff view up one page"
msgstr "<Delete>, b\tRulla diffvisningen upp en sida"
-#: gitk:3069
+#: gitk:3113
msgid "<Backspace>\tScroll diff view up one page"
msgstr "<Baksteg>\tRulla diffvisningen upp en sida"
-#: gitk:3070
+#: gitk:3114
msgid "<Space>\t\tScroll diff view down one page"
msgstr "<Blanksteg>\tRulla diffvisningen ned en sida"
-#: gitk:3071
+#: gitk:3115
msgid "u\t\tScroll diff view up 18 lines"
msgstr "u\t\tRulla diffvisningen upp 18 rader"
-#: gitk:3072
+#: gitk:3116
msgid "d\t\tScroll diff view down 18 lines"
msgstr "d\t\tRulla diffvisningen ned 18 rader"
-#: gitk:3073
+#: gitk:3117
#, tcl-format
msgid "<%s-F>\t\tFind"
msgstr "<%s-F>\t\tSök"
-#: gitk:3074
+#: gitk:3118
#, tcl-format
msgid "<%s-G>\t\tMove to next find hit"
msgstr "<%s-G>\t\tGå till nästa sökträff"
-#: gitk:3075
+#: gitk:3119
msgid "<Return>\tMove to next find hit"
msgstr "<Return>\t\tGå till nästa sökträff"
-#: gitk:3076
+#: gitk:3120
msgid "g\t\tGo to commit"
msgstr "g\t\tGå till incheckning"
-#: gitk:3077
+#: gitk:3121
msgid "/\t\tFocus the search box"
msgstr "/\t\tFokusera sökrutan"
-#: gitk:3078
+#: gitk:3122
msgid "?\t\tMove to previous find hit"
msgstr "?\t\tGå till föregående sökträff"
-#: gitk:3079
+#: gitk:3123
msgid "f\t\tScroll diff view to next file"
msgstr "f\t\tRulla diffvisningen till nästa fil"
-#: gitk:3080
+#: gitk:3124
#, tcl-format
msgid "<%s-S>\t\tSearch for next hit in diff view"
msgstr "<%s-S>\t\tGå till nästa sökträff i diffvisningen"
-#: gitk:3081
+#: gitk:3125
#, tcl-format
msgid "<%s-R>\t\tSearch for previous hit in diff view"
msgstr "<%s-R>\t\tGå till föregående sökträff i diffvisningen"
-#: gitk:3082
+#: gitk:3126
#, tcl-format
msgid "<%s-KP+>\tIncrease font size"
msgstr "<%s-Num+>\tÖka teckenstorlek"
-#: gitk:3083
+#: gitk:3127
#, tcl-format
msgid "<%s-plus>\tIncrease font size"
msgstr "<%s-plus>\tÖka teckenstorlek"
-#: gitk:3084
+#: gitk:3128
#, tcl-format
msgid "<%s-KP->\tDecrease font size"
msgstr "<%s-Num->\tMinska teckenstorlek"
-#: gitk:3085
+#: gitk:3129
#, tcl-format
msgid "<%s-minus>\tDecrease font size"
msgstr "<%s-minus>\tMinska teckenstorlek"
-#: gitk:3086
+#: gitk:3130
msgid "<F5>\t\tUpdate"
msgstr "<F5>\t\tUppdatera"
-#: gitk:3551 gitk:3560
+#: gitk:3597 gitk:3606
#, tcl-format
msgid "Error creating temporary directory %s:"
msgstr "Fel vid skapande av temporär katalog %s:"
-#: gitk:3573
+#: gitk:3619
#, tcl-format
msgid "Error getting \"%s\" from %s:"
-msgstr "Fel vid hämtning av \"%s\" från %s:"
+msgstr "Fel vid hämtning av ”%s” från %s:"
-#: gitk:3636
+#: gitk:3682
msgid "command failed:"
msgstr "kommando misslyckades:"
-#: gitk:3785
+#: gitk:3831
msgid "No such commit"
msgstr "Incheckning saknas"
-#: gitk:3799
+#: gitk:3845
msgid "git gui blame: command failed:"
msgstr "git gui blame: kommando misslyckades:"
-#: gitk:3830
+#: gitk:3876
#, tcl-format
msgid "Couldn't read merge head: %s"
msgstr "Kunde inte läsa sammanslagningshuvud: %s"
-#: gitk:3838
+#: gitk:3884
#, tcl-format
msgid "Error reading index: %s"
msgstr "Fel vid läsning av index: %s"
-#: gitk:3863
+#: gitk:3909
#, tcl-format
msgid "Couldn't start git blame: %s"
msgstr "Kunde inte starta git blame: %s"
-#: gitk:3866 gitk:6755
+#: gitk:3912 gitk:6801
msgid "Searching"
msgstr "Söker"
-#: gitk:3898
+#: gitk:3944
#, tcl-format
msgid "Error running git blame: %s"
msgstr "Fel vid körning av git blame: %s"
-#: gitk:3926
+#: gitk:3972
#, tcl-format
msgid "That line comes from commit %s, which is not in this view"
msgstr "Raden kommer från incheckningen %s, som inte finns i denna vy"
-#: gitk:3940
+#: gitk:3986
msgid "External diff viewer failed:"
msgstr "Externt diff-verktyg misslyckades:"
-#: gitk:4044
+#: gitk:4090
msgid "All files"
msgstr "Alla filer"
-#: gitk:4068
+#: gitk:4114
msgid "View"
msgstr "Visa"
-#: gitk:4071
+#: gitk:4117
msgid "Gitk view definition"
msgstr "Definition av Gitk-vy"
-#: gitk:4075
+#: gitk:4121
msgid "Remember this view"
msgstr "Spara denna vy"
-#: gitk:4076
+#: gitk:4122
msgid "References (space separated list):"
msgstr "Referenser (blankstegsavdelad lista):"
-#: gitk:4077
+#: gitk:4123
msgid "Branches & tags:"
msgstr "Grenar & taggar:"
-#: gitk:4078
+#: gitk:4124
msgid "All refs"
msgstr "Alla referenser"
-#: gitk:4079
+#: gitk:4125
msgid "All (local) branches"
msgstr "Alla (lokala) grenar"
-#: gitk:4080
+#: gitk:4126
msgid "All tags"
msgstr "Alla taggar"
-#: gitk:4081
+#: gitk:4127
msgid "All remote-tracking branches"
msgstr "Alla fjärrspårande grenar"
-#: gitk:4082
+#: gitk:4128
msgid "Commit Info (regular expressions):"
msgstr "Incheckningsinfo (reguljära uttryck):"
-#: gitk:4083
+#: gitk:4129
msgid "Author:"
msgstr "Författare:"
-#: gitk:4084
+#: gitk:4130
msgid "Committer:"
msgstr "Incheckare:"
-#: gitk:4085
+#: gitk:4131
msgid "Commit Message:"
msgstr "Incheckningsmeddelande:"
-#: gitk:4086
+#: gitk:4132
msgid "Matches all Commit Info criteria"
msgstr "Motsvarar alla kriterier för incheckningsinfo"
-#: gitk:4087
+#: gitk:4133
msgid "Matches no Commit Info criteria"
msgstr "Motsvarar inga kriterier för incheckningsinfo"
-#: gitk:4088
+#: gitk:4134
msgid "Changes to Files:"
msgstr "Ändringar av filer:"
-#: gitk:4089
+#: gitk:4135
msgid "Fixed String"
msgstr "Fast sträng"
-#: gitk:4090
+#: gitk:4136
msgid "Regular Expression"
msgstr "Reguljärt uttryck"
-#: gitk:4091
+#: gitk:4137
msgid "Search string:"
msgstr "Söksträng:"
-#: gitk:4092
+#: gitk:4138
msgid ""
"Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
"15:27:38\"):"
msgstr ""
-"Incheckingsdatum (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
-"15:27:38\"):"
+"Incheckningsdatum (”2 weeks ago”, ”2009-03-17 15:27:38”, ”March 17, 2009 "
+"15:27:38”):"
-#: gitk:4093
+#: gitk:4139
msgid "Since:"
msgstr "Från:"
-#: gitk:4094
+#: gitk:4140
msgid "Until:"
msgstr "Till:"
-#: gitk:4095
+#: gitk:4141
msgid "Limit and/or skip a number of revisions (positive integer):"
msgstr "Begränsa och/eller hoppa över ett antal revisioner (positivt heltal):"
-#: gitk:4096
+#: gitk:4142
msgid "Number to show:"
msgstr "Antal att visa:"
-#: gitk:4097
+#: gitk:4143
msgid "Number to skip:"
msgstr "Antal att hoppa över:"
-#: gitk:4098
+#: gitk:4144
msgid "Miscellaneous options:"
msgstr "Diverse alternativ:"
-#: gitk:4099
+#: gitk:4145
msgid "Strictly sort by date"
msgstr "Strikt datumsortering"
-#: gitk:4100
+#: gitk:4146
msgid "Mark branch sides"
msgstr "Markera sidogrenar"
-#: gitk:4101
+#: gitk:4147
msgid "Limit to first parent"
msgstr "Begränsa till första förälder"
-#: gitk:4102
+#: gitk:4148
msgid "Simple history"
msgstr "Enkel historik"
-#: gitk:4103
+#: gitk:4149
msgid "Additional arguments to git log:"
msgstr "Ytterligare argument till git log:"
-#: gitk:4104
+#: gitk:4150
msgid "Enter files and directories to include, one per line:"
msgstr "Ange filer och kataloger att ta med, en per rad:"
-#: gitk:4105
+#: gitk:4151
msgid "Command to generate more commits to include:"
msgstr "Kommando för att generera fler incheckningar att ta med:"
-#: gitk:4229
+#: gitk:4275
msgid "Gitk: edit view"
msgstr "Gitk: redigera vy"
-#: gitk:4237
+#: gitk:4283
msgid "-- criteria for selecting revisions"
msgstr " - kriterier för val av revisioner"
-#: gitk:4242
+#: gitk:4288
msgid "View Name"
msgstr "Namn på vy"
-#: gitk:4317
+#: gitk:4363
msgid "Apply (F5)"
msgstr "Använd (F5)"
-#: gitk:4355
+#: gitk:4401
msgid "Error in commit selection arguments:"
msgstr "Fel i argument för val av incheckningar:"
-#: gitk:4410 gitk:4463 gitk:4925 gitk:4939 gitk:6209 gitk:12388 gitk:12389
+#: gitk:4456 gitk:4509 gitk:4971 gitk:4985 gitk:6255 gitk:12615 gitk:12616
msgid "None"
msgstr "Inget"
-#: gitk:5022 gitk:5027
+#: gitk:5068 gitk:5073
msgid "Descendant"
msgstr "Avkomling"
-#: gitk:5023
+#: gitk:5069
msgid "Not descendant"
msgstr "Inte avkomling"
-#: gitk:5030 gitk:5035
+#: gitk:5076 gitk:5081
msgid "Ancestor"
msgstr "Förfader"
-#: gitk:5031
+#: gitk:5077
msgid "Not ancestor"
msgstr "Inte förfader"
-#: gitk:5325
+#: gitk:5371
msgid "Local changes checked in to index but not committed"
msgstr "Lokala ändringar sparade i indexet men inte incheckade"
-#: gitk:5361
+#: gitk:5407
msgid "Local uncommitted changes, not checked in to index"
msgstr "Lokala ändringar, ej sparade i indexet"
-#: gitk:7135
+#: gitk:7155
+msgid "Error starting web browser:"
+msgstr "Fel när webbläsaren skulle startas:"
+
+#: gitk:7216
msgid "and many more"
msgstr "med många flera"
-#: gitk:7138
+#: gitk:7219
msgid "many"
msgstr "många"
-#: gitk:7329
+#: gitk:7410
msgid "Tags:"
msgstr "Taggar:"
-#: gitk:7346 gitk:7352 gitk:8826
+#: gitk:7427 gitk:7433 gitk:8912
msgid "Parent"
msgstr "Förälder"
-#: gitk:7357
+#: gitk:7438
msgid "Child"
msgstr "Barn"
-#: gitk:7366
+#: gitk:7447
msgid "Branch"
msgstr "Gren"
-#: gitk:7369
+#: gitk:7450
msgid "Follows"
msgstr "Följer"
-#: gitk:7372
+#: gitk:7453
msgid "Precedes"
msgstr "Föregår"
-#: gitk:7967
+#: gitk:8048
#, tcl-format
msgid "Error getting diffs: %s"
msgstr "Fel vid hämtning av diff: %s"
-#: gitk:8651
+#: gitk:8737
msgid "Goto:"
msgstr "Gå till:"
-#: gitk:8672
+#: gitk:8758
#, tcl-format
msgid "Short SHA1 id %s is ambiguous"
msgstr "Förkortat SHA1-id %s är tvetydigt"
-#: gitk:8679
+#: gitk:8765
#, tcl-format
msgid "Revision %s is not known"
msgstr "Revisionen %s är inte känd"
-#: gitk:8689
+#: gitk:8775
#, tcl-format
msgid "SHA1 id %s is not known"
msgstr "SHA-id:t %s är inte känt"
-#: gitk:8691
+#: gitk:8777
#, tcl-format
msgid "Revision %s is not in the current view"
msgstr "Revisionen %s finns inte i den nuvarande vyn"
-#: gitk:8833 gitk:8848
+#: gitk:8919 gitk:8934
msgid "Date"
msgstr "Datum"
-#: gitk:8836
+#: gitk:8922
msgid "Children"
msgstr "Barn"
-#: gitk:8899
+#: gitk:8985
#, tcl-format
msgid "Reset %s branch to here"
msgstr "Återställ grenen %s hit"
-#: gitk:8901
+#: gitk:8987
msgid "Detached head: can't reset"
msgstr "Frånkopplad head: kan inte återställa"
-#: gitk:9006 gitk:9012
+#: gitk:9092 gitk:9098
msgid "Skipping merge commit "
msgstr "Hoppar över sammanslagningsincheckning "
-#: gitk:9021 gitk:9026
+#: gitk:9107 gitk:9112
msgid "Error getting patch ID for "
msgstr "Fel vid hämtning av patch-id för "
-#: gitk:9022 gitk:9027
+#: gitk:9108 gitk:9113
msgid " - stopping\n"
msgstr " - stannar\n"
-#: gitk:9032 gitk:9035 gitk:9043 gitk:9057 gitk:9066
+#: gitk:9118 gitk:9121 gitk:9129 gitk:9143 gitk:9152
msgid "Commit "
msgstr "Incheckning "
-#: gitk:9036
+#: gitk:9122
msgid ""
" is the same patch as\n"
" "
@@ -911,7 +919,7 @@ msgstr ""
" är samma patch som\n"
" "
-#: gitk:9044
+#: gitk:9130
msgid ""
" differs from\n"
" "
@@ -919,7 +927,7 @@ msgstr ""
" skiljer sig från\n"
" "
-#: gitk:9046
+#: gitk:9132
msgid ""
"Diff of commits:\n"
"\n"
@@ -927,141 +935,158 @@ msgstr ""
"Skillnad mellan incheckningar:\n"
"\n"
-#: gitk:9058 gitk:9067
+#: gitk:9144 gitk:9153
#, tcl-format
msgid " has %s children - stopping\n"
msgstr " har %s barn - stannar\n"
-#: gitk:9086
+#: gitk:9172
#, tcl-format
msgid "Error writing commit to file: %s"
msgstr "Fel vid skrivning av incheckning till fil: %s"
-#: gitk:9092
+#: gitk:9178
#, tcl-format
msgid "Error diffing commits: %s"
msgstr "Fel vid jämförelse av incheckningar: %s"
-#: gitk:9138
+#: gitk:9224
msgid "Top"
msgstr "Topp"
-#: gitk:9139
+#: gitk:9225
msgid "From"
msgstr "Från"
-#: gitk:9144
+#: gitk:9230
msgid "To"
msgstr "Till"
-#: gitk:9168
+#: gitk:9254
msgid "Generate patch"
msgstr "Generera patch"
-#: gitk:9170
+#: gitk:9256
msgid "From:"
msgstr "Från:"
-#: gitk:9179
+#: gitk:9265
msgid "To:"
msgstr "Till:"
-#: gitk:9188
+#: gitk:9274
msgid "Reverse"
msgstr "Vänd"
-#: gitk:9190 gitk:9400
+#: gitk:9276 gitk:9486
msgid "Output file:"
msgstr "Utdatafil:"
-#: gitk:9196
+#: gitk:9282
msgid "Generate"
msgstr "Generera"
-#: gitk:9234
+#: gitk:9320
msgid "Error creating patch:"
msgstr "Fel vid generering av patch:"
-#: gitk:9257 gitk:9388 gitk:9445
+#: gitk:9343 gitk:9474 gitk:9562
msgid "ID:"
msgstr "Id:"
-#: gitk:9266
+#: gitk:9352
msgid "Tag name:"
msgstr "Taggnamn:"
-#: gitk:9269
+#: gitk:9355
msgid "Tag message is optional"
msgstr "Taggmeddelandet är valfritt"
-#: gitk:9271
+#: gitk:9357
msgid "Tag message:"
msgstr "Taggmeddelande:"
-#: gitk:9275 gitk:9454
+#: gitk:9361 gitk:9532
msgid "Create"
msgstr "Skapa"
-#: gitk:9293
+#: gitk:9379
msgid "No tag name specified"
msgstr "Inget taggnamn angavs"
-#: gitk:9297
+#: gitk:9383
#, tcl-format
msgid "Tag \"%s\" already exists"
-msgstr "Taggen \"%s\" finns redan"
+msgstr "Taggen ”%s” finns redan"
-#: gitk:9307
+#: gitk:9393
msgid "Error creating tag:"
msgstr "Fel vid skapande av tagg:"
-#: gitk:9397
+#: gitk:9483
msgid "Command:"
msgstr "Kommando:"
-#: gitk:9405
+#: gitk:9491
msgid "Write"
msgstr "Skriv"
-#: gitk:9423
+#: gitk:9509
msgid "Error writing commit:"
msgstr "Fel vid skrivning av incheckning:"
-#: gitk:9450
+#: gitk:9531
+msgid "Create branch"
+msgstr "Skapa gren"
+
+#: gitk:9547
+#, tcl-format
+msgid "Rename branch %s"
+msgstr "Byt namn på grenen %s"
+
+#: gitk:9548
+msgid "Rename"
+msgstr "Byt namn"
+
+#: gitk:9572
msgid "Name:"
msgstr "Namn:"
-#: gitk:9473
+#: gitk:9596
msgid "Please specify a name for the new branch"
msgstr "Ange ett namn för den nya grenen"
-#: gitk:9478
+#: gitk:9601
#, tcl-format
msgid "Branch '%s' already exists. Overwrite?"
-msgstr "Grenen \"%s\" finns redan. Skriva över?"
+msgstr "Grenen ”%s” finns redan. Skriva över?"
+
+#: gitk:9645
+msgid "Please specify a new name for the branch"
+msgstr "Ange ett nytt namn för grenen"
-#: gitk:9545
+#: gitk:9708
#, tcl-format
msgid "Commit %s is already included in branch %s -- really re-apply it?"
msgstr ""
"Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras "
"på nytt?"
-#: gitk:9550
+#: gitk:9713
msgid "Cherry-picking"
msgstr "Plockar"
-#: gitk:9559
+#: gitk:9722
#, tcl-format
msgid ""
"Cherry-pick failed because of local changes to file '%s'.\n"
"Please commit, reset or stash your changes and try again."
msgstr ""
-"Cherry-pick misslyckades på grund av lokala ändringar i filen \"%s\".\n"
+"Cherry-pick misslyckades på grund av lokala ändringar i filen ”%s”.\n"
"Checka in, återställ eller spara undan (stash) dina ändringar och försök "
"igen."
-#: gitk:9565
+#: gitk:9728
msgid ""
"Cherry-pick failed because of merge conflict.\n"
"Do you wish to run git citool to resolve it?"
@@ -1069,20 +1094,20 @@ msgstr ""
"Cherry-pick misslyckades på grund av en sammanslagningskonflikt.\n"
"Vill du köra git citool för att lösa den?"
-#: gitk:9581 gitk:9639
+#: gitk:9744 gitk:9802
msgid "No changes committed"
msgstr "Inga ändringar incheckade"
-#: gitk:9608
+#: gitk:9771
#, tcl-format
msgid "Commit %s is not included in branch %s -- really revert it?"
msgstr "Incheckningen %s finns inte på grenen %s -- vill du verkligen ångra?"
-#: gitk:9613
+#: gitk:9776
msgid "Reverting"
msgstr "Ångrar"
-#: gitk:9621
+#: gitk:9784
#, tcl-format
msgid ""
"Revert failed because of local changes to the following files:%s Please "
@@ -1092,7 +1117,7 @@ msgstr ""
"Checka in, återställ eller spara undan (stash) dina ändringar och försök "
"igen."
-#: gitk:9625
+#: gitk:9788
msgid ""
"Revert failed because of merge conflict.\n"
" Do you wish to run git citool to resolve it?"
@@ -1100,28 +1125,28 @@ msgstr ""
"Misslyckades med att ångra på grund av en sammanslagningskonflikt.\n"
" Vill du köra git citool för att lösa den?"
-#: gitk:9668
+#: gitk:9831
msgid "Confirm reset"
msgstr "Bekräfta återställning"
-#: gitk:9670
+#: gitk:9833
#, tcl-format
msgid "Reset branch %s to %s?"
msgstr "Återställa grenen %s till %s?"
-#: gitk:9672
+#: gitk:9835
msgid "Reset type:"
msgstr "Typ av återställning:"
-#: gitk:9675
+#: gitk:9838
msgid "Soft: Leave working tree and index untouched"
msgstr "Mjuk: Rör inte utcheckning och index"
-#: gitk:9678
+#: gitk:9841
msgid "Mixed: Leave working tree untouched, reset index"
msgstr "Blandad: Rör inte utcheckning, återställ index"
-#: gitk:9681
+#: gitk:9844
msgid ""
"Hard: Reset working tree and index\n"
"(discard ALL local changes)"
@@ -1129,19 +1154,24 @@ msgstr ""
"Hård: Återställ utcheckning och index\n"
"(förkastar ALLA lokala ändringar)"
-#: gitk:9698
+#: gitk:9861
msgid "Resetting"
msgstr "Återställer"
-#: gitk:9758
+#: gitk:9934
+#, tcl-format
+msgid "A local branch named %s exists already"
+msgstr "Det finns redan en lokal gren som heter %s"
+
+#: gitk:9942
msgid "Checking out"
msgstr "Checkar ut"
-#: gitk:9811
+#: gitk:10001
msgid "Cannot delete the currently checked-out branch"
msgstr "Kan inte ta bort den just nu utcheckade grenen"
-#: gitk:9817
+#: gitk:10007
#, tcl-format
msgid ""
"The commits on branch %s aren't on any other branch.\n"
@@ -1150,16 +1180,16 @@ msgstr ""
"Incheckningarna på grenen %s existerar inte på någon annan gren.\n"
"Vill du verkligen ta bort grenen %s?"
-#: gitk:9848
+#: gitk:10038
#, tcl-format
msgid "Tags and heads: %s"
msgstr "Taggar och huvuden: %s"
-#: gitk:9865
+#: gitk:10055
msgid "Filter"
msgstr "Filter"
-#: gitk:10161
+#: gitk:10356
msgid ""
"Error reading commit topology information; branch and preceding/following "
"tag information will be incomplete."
@@ -1167,201 +1197,221 @@ msgstr ""
"Fel vid läsning av information om incheckningstopologi; information om "
"grenar och föregående/senare taggar kommer inte vara komplett."
-#: gitk:11138
+#: gitk:11333
msgid "Tag"
msgstr "Tagg"
-#: gitk:11142
+#: gitk:11337
msgid "Id"
msgstr "Id"
-#: gitk:11225
+#: gitk:11420
msgid "Gitk font chooser"
msgstr "Teckensnittsväljare för Gitk"
-#: gitk:11242
+#: gitk:11437
msgid "B"
msgstr "F"
-#: gitk:11245
+#: gitk:11440
msgid "I"
msgstr "K"
-#: gitk:11363
+#: gitk:11558
msgid "Commit list display options"
msgstr "Alternativ för incheckningslistvy"
-#: gitk:11366
+#: gitk:11561
msgid "Maximum graph width (lines)"
msgstr "Maximal grafbredd (rader)"
-#: gitk:11370
+#: gitk:11565
#, no-tcl-format
msgid "Maximum graph width (% of pane)"
msgstr "Maximal grafbredd (% av ruta)"
-#: gitk:11373
+#: gitk:11568
msgid "Show local changes"
msgstr "Visa lokala ändringar"
-#: gitk:11376
+#: gitk:11571
msgid "Auto-select SHA1 (length)"
msgstr "Välj SHA1 (längd) automatiskt"
-#: gitk:11380
+#: gitk:11575
msgid "Hide remote refs"
msgstr "Dölj fjärr-referenser"
-#: gitk:11384
+#: gitk:11579
msgid "Diff display options"
msgstr "Alternativ för diffvy"
-#: gitk:11386
+#: gitk:11581
msgid "Tab spacing"
msgstr "Blanksteg för tabulatortecken"
-#: gitk:11389
+#: gitk:11584
msgid "Display nearby tags/heads"
msgstr "Visa närliggande taggar/huvuden"
-#: gitk:11392
+#: gitk:11587
msgid "Maximum # tags/heads to show"
msgstr "Maximalt antal taggar/huvuden att visa"
-#: gitk:11395
+#: gitk:11590
msgid "Limit diffs to listed paths"
msgstr "Begränsa diff till listade sökvägar"
-#: gitk:11398
+#: gitk:11593
msgid "Support per-file encodings"
msgstr "Stöd för filspecifika teckenkodningar"
-#: gitk:11404 gitk:11551
+#: gitk:11599 gitk:11766
msgid "External diff tool"
msgstr "Externt diff-verktyg"
-#: gitk:11405
+#: gitk:11600
msgid "Choose..."
msgstr "Välj..."
-#: gitk:11410
+#: gitk:11607
+msgid "Web browser"
+msgstr "Webbläsare"
+
+#: gitk:11612
msgid "General options"
msgstr "Allmänna inställningar"
-#: gitk:11413
+#: gitk:11615
msgid "Use themed widgets"
msgstr "Använd tema på fönsterelement"
-#: gitk:11415
+#: gitk:11617
msgid "(change requires restart)"
msgstr "(ändringen kräver omstart)"
-#: gitk:11417
+#: gitk:11619
msgid "(currently unavailable)"
msgstr "(för närvarande inte tillgängligt)"
-#: gitk:11428
+#: gitk:11631
msgid "Colors: press to choose"
msgstr "Färger: tryck för att välja"
-#: gitk:11431
+#: gitk:11634
msgid "Interface"
msgstr "Gränssnitt"
-#: gitk:11432
+#: gitk:11635
msgid "interface"
msgstr "gränssnitt"
-#: gitk:11435
+#: gitk:11638
msgid "Background"
msgstr "Bakgrund"
-#: gitk:11436 gitk:11466
+#: gitk:11639 gitk:11681
msgid "background"
msgstr "bakgrund"
-#: gitk:11439
+#: gitk:11642
msgid "Foreground"
msgstr "Förgrund"
-#: gitk:11440
+#: gitk:11643
msgid "foreground"
msgstr "förgrund"
-#: gitk:11443
+#: gitk:11646
msgid "Diff: old lines"
msgstr "Diff: gamla rader"
-#: gitk:11444
+#: gitk:11647
msgid "diff old lines"
msgstr "diff gamla rader"
-#: gitk:11448
+#: gitk:11651
+msgid "Diff: old lines bg"
+msgstr "Diff: gamla rader bg"
+
+#: gitk:11653
+msgid "diff old lines bg"
+msgstr "diff gamla rader bg"
+
+#: gitk:11657
msgid "Diff: new lines"
msgstr "Diff: nya rader"
-#: gitk:11449
+#: gitk:11658
msgid "diff new lines"
msgstr "diff nya rader"
-#: gitk:11453
+#: gitk:11662
+msgid "Diff: new lines bg"
+msgstr "Diff: nya rader bg"
+
+#: gitk:11664
+msgid "diff new lines bg"
+msgstr "diff nya rader bg"
+
+#: gitk:11668
msgid "Diff: hunk header"
msgstr "Diff: delhuvud"
-#: gitk:11455
+#: gitk:11670
msgid "diff hunk header"
msgstr "diff delhuvud"
-#: gitk:11459
+#: gitk:11674
msgid "Marked line bg"
msgstr "Markerad rad bakgrund"
-#: gitk:11461
+#: gitk:11676
msgid "marked line background"
msgstr "markerad rad bakgrund"
-#: gitk:11465
+#: gitk:11680
msgid "Select bg"
msgstr "Markerad bakgrund"
-#: gitk:11474
+#: gitk:11689
msgid "Fonts: press to choose"
msgstr "Teckensnitt: tryck för att välja"
-#: gitk:11476
+#: gitk:11691
msgid "Main font"
msgstr "Huvudteckensnitt"
-#: gitk:11477
+#: gitk:11692
msgid "Diff display font"
msgstr "Teckensnitt för diffvisning"
-#: gitk:11478
+#: gitk:11693
msgid "User interface font"
msgstr "Teckensnitt för användargränssnitt"
-#: gitk:11500
+#: gitk:11715
msgid "Gitk preferences"
msgstr "Inställningar för Gitk"
-#: gitk:11509
+#: gitk:11724
msgid "General"
msgstr "Allmänt"
-#: gitk:11510
+#: gitk:11725
msgid "Colors"
msgstr "Färger"
-#: gitk:11511
+#: gitk:11726
msgid "Fonts"
msgstr "Teckensnitt"
-#: gitk:11561
+#: gitk:11776
#, tcl-format
msgid "Gitk: choose color for %s"
msgstr "Gitk: välj färg för %s"
-#: gitk:12074
+#: gitk:12289
msgid ""
"Sorry, gitk cannot run with this version of Tcl/Tk.\n"
" Gitk requires at least Tcl/Tk 8.4."
@@ -1369,45 +1419,15 @@ msgstr ""
"Gitk kan tyvärr inte köra med denna version av Tcl/Tk.\n"
" Gitk kräver åtminstone Tcl/Tk 8.4."
-#: gitk:12284
+#: gitk:12507
msgid "Cannot find a git repository here."
msgstr "Hittar inget git-arkiv här."
-#: gitk:12331
+#: gitk:12554
#, tcl-format
msgid "Ambiguous argument '%s': both revision and filename"
-msgstr "Tvetydigt argument \"%s\": både revision och filnamn"
+msgstr "Tvetydigt argument ”%s”: både revision och filnamn"
-#: gitk:12343
+#: gitk:12566
msgid "Bad arguments to gitk:"
msgstr "Felaktiga argument till gitk:"
-
-#~ msgid "mc"
-#~ msgstr "mc"
-
-#~ msgid "next"
-#~ msgstr "nästa"
-
-#~ msgid "prev"
-#~ msgstr "föreg"
-
-#~ msgid "CDate"
-#~ msgstr "Skapat datum"
-
-#~ msgid "Cannot find the git directory \"%s\"."
-#~ msgstr "Hittar inte git-katalogen \"%s\"."
-
-#~ msgid "SHA1 ID: "
-#~ msgstr "SHA1-id: "
-
-#~ msgid "- stopping\n"
-#~ msgstr "- stannar\n"
-
-#~ msgid "Tag/Head %s is not known"
-#~ msgstr "Tagg/huvud %s är okänt"
-
-#~ msgid "/\t\tMove to next find hit, or redo find"
-#~ msgstr "/\t\tGå till nästa sökträff, eller sök på nytt"
-
-#~ msgid "Name"
-#~ msgstr "Namn"
diff --git a/gitweb/GITWEB-BUILD-OPTIONS.in b/gitweb/GITWEB-BUILD-OPTIONS.in
new file mode 100644
index 0000000000..41ac20654c
--- /dev/null
+++ b/gitweb/GITWEB-BUILD-OPTIONS.in
@@ -0,0 +1,24 @@
+PERL_PATH=@PERL_PATH@
+JSMIN=@JSMIN@
+CSSMIN=@CSSMIN@
+GIT_BINDIR=@GIT_BINDIR@
+GITWEB_CONFIG=@GITWEB_CONFIG@
+GITWEB_CONFIG_SYSTEM=@GITWEB_CONFIG_SYSTEM@
+GITWEB_CONFIG_COMMON=@GITWEB_CONFIG_COMMON@
+GITWEB_HOME_LINK_STR=@GITWEB_HOME_LINK_STR@
+GITWEB_SITENAME=@GITWEB_SITENAME@
+GITWEB_PROJECTROOT=@GITWEB_PROJECTROOT@
+GITWEB_PROJECT_MAXDEPTH=@GITWEB_PROJECT_MAXDEPTH@
+GITWEB_EXPORT_OK=@GITWEB_EXPORT_OK@
+GITWEB_STRICT_EXPORT=@GITWEB_STRICT_EXPORT@
+GITWEB_BASE_URL=@GITWEB_BASE_URL@
+GITWEB_LIST=@GITWEB_LIST@
+GITWEB_HOMETEXT=@GITWEB_HOMETEXT@
+GITWEB_CSS=@GITWEB_CSS@
+GITWEB_LOGO=@GITWEB_LOGO@
+GITWEB_FAVICON=@GITWEB_FAVICON@
+GITWEB_JS=@GITWEB_JS@
+GITWEB_SITE_HTML_HEAD_STRING=@GITWEB_SITE_HTML_HEAD_STRING@
+GITWEB_SITE_HEADER=@GITWEB_SITE_HEADER@
+GITWEB_SITE_FOOTER=@GITWEB_SITE_FOOTER@
+HIGHLIGHT_BIN=@HIGHLIGHT_BIN@
diff --git a/gitweb/Makefile b/gitweb/Makefile
index 3b68ab2d67..d5748e9359 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -77,48 +77,48 @@ GITWEB_JSLIB_FILES += static/js/javascript-detection.js
GITWEB_JSLIB_FILES += static/js/adjust-timezone.js
GITWEB_JSLIB_FILES += static/js/blame_incremental.js
-
-GITWEB_REPLACE = \
- -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
- -e 's|++GIT_BINDIR++|$(bindir)|g' \
- -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
- -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
- -e 's|++GITWEB_CONFIG_COMMON++|$(GITWEB_CONFIG_COMMON)|g' \
- -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
- -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
- -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
- -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
- -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
- -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
- -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
- -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
- -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
- -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
- -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
- -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
- -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
- -e 's|++GITWEB_SITE_HTML_HEAD_STRING++|$(GITWEB_SITE_HTML_HEAD_STRING)|g' \
- -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
- -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
- -e 's|++HIGHLIGHT_BIN++|$(HIGHLIGHT_BIN)|g'
-
.PHONY: FORCE
$(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS: FORCE
- @rm -f $@+
- @echo "x" '$(PERL_PATH_SQ)' $(GITWEB_REPLACE) "$(JSMIN)|$(CSSMIN)" >$@+
+ @sed -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|' \
+ -e 's|@JSMIN@|$(JSMIN)|' \
+ -e 's|@CSSMIN@|$(CSSMIN)|' \
+ -e 's|@GIT_VERSION@|$(GIT_VERSION)|' \
+ -e 's|@GIT_BINDIR@|$(bindir)|' \
+ -e 's|@GITWEB_CONFIG@|$(GITWEB_CONFIG)|' \
+ -e 's|@GITWEB_CONFIG_SYSTEM@|$(GITWEB_CONFIG_SYSTEM)|' \
+ -e 's|@GITWEB_CONFIG_COMMON@|$(GITWEB_CONFIG_COMMON)|' \
+ -e 's|@GITWEB_HOME_LINK_STR@|$(GITWEB_HOME_LINK_STR)|' \
+ -e 's|@GITWEB_SITENAME@|$(GITWEB_SITENAME)|' \
+ -e 's|@GITWEB_PROJECTROOT@|$(GITWEB_PROJECTROOT)|' \
+ -e 's|@GITWEB_PROJECT_MAXDEPTH@|$(GITWEB_PROJECT_MAXDEPTH)|' \
+ -e 's|@GITWEB_EXPORT_OK@|$(GITWEB_EXPORT_OK)|' \
+ -e 's|@GITWEB_STRICT_EXPORT@|$(GITWEB_STRICT_EXPORT)|' \
+ -e 's|@GITWEB_BASE_URL@|$(GITWEB_BASE_URL)|' \
+ -e 's|@GITWEB_LIST@|$(GITWEB_LIST)|' \
+ -e 's|@GITWEB_HOMETEXT@|$(GITWEB_HOMETEXT)|' \
+ -e 's|@GITWEB_CSS@|$(GITWEB_CSS)|' \
+ -e 's|@GITWEB_LOGO@|$(GITWEB_LOGO)|' \
+ -e 's|@GITWEB_FAVICON@|$(GITWEB_FAVICON)|' \
+ -e 's|@GITWEB_JS@|$(GITWEB_JS)|' \
+ -e 's|@GITWEB_SITE_HTML_HEAD_STRING@|$(GITWEB_SITE_HTML_HEAD_STRING)|' \
+ -e 's|@GITWEB_SITE_HEADER@|$(GITWEB_SITE_HEADER)|' \
+ -e 's|@GITWEB_SITE_FOOTER@|$(GITWEB_SITE_FOOTER)|' \
+ -e 's|@HIGHLIGHT_BIN@|$(HIGHLIGHT_BIN)|' \
+ $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS.in >"$@+"
@cmp -s $@+ $@ && rm -f $@+ || mv -f $@+ $@
+$(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)generate-gitweb-cgi.sh
$(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS
+$(MAK_DIR_GITWEB)gitweb.cgi: GIT-VERSION-FILE
$(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)gitweb.perl
$(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
- $(GITWEB_REPLACE) $< >$@+ && \
- chmod +x $@+ && \
+ $(MAK_DIR_GITWEB)generate-gitweb-cgi.sh $(MAK_DIR_GITWEB)/GITWEB-BUILD-OPTIONS ./GIT-VERSION-FILE $< $@+ && \
mv $@+ $@
+$(MAK_DIR_GITWEB)static/gitweb.js: $(MAK_DIR_GITWEB)generate-gitweb-js.sh
$(MAK_DIR_GITWEB)static/gitweb.js: $(addprefix $(MAK_DIR_GITWEB),$(GITWEB_JSLIB_FILES))
$(QUIET_GEN)$(RM) $@ $@+ && \
- cat $^ >$@+ && \
+ $(MAK_DIR_GITWEB)generate-gitweb-js.sh $@+ $^ && \
mv $@+ $@
### Installation rules
diff --git a/gitweb/generate-gitweb-cgi.sh b/gitweb/generate-gitweb-cgi.sh
new file mode 100755
index 0000000000..ede9038c33
--- /dev/null
+++ b/gitweb/generate-gitweb-cgi.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+set -e
+
+if test $# -ne 4
+then
+ echo >&2 "USAGE: $0 <GITWEB-BUILD-OPTIONS> <GIT-VERSION-FILE> <INPUT> <OUTPUT>"
+ exit 1
+fi
+
+GITWEB_BUILD_OPTIONS="$1"
+GIT_VERSION_FILE="$2"
+INPUT="$3"
+OUTPUT="$4"
+
+. "$GITWEB_BUILD_OPTIONS"
+. "$GIT_VERSION_FILE"
+
+sed -e "1s|#!/usr/bin/perl|#!$PERL_PATH|" \
+ -e "s|@PERL_PATH@|$PERL_PATH|" \
+ -e "s|@JSMIN@|$JSMIN|" \
+ -e "s|@CSSMIN@|$CSSMIN|" \
+ -e "s|@GIT_VERSION@|$GIT_VERSION|" \
+ -e "s|@GIT_BINDIR@|$GIT_BINDIR|" \
+ -e "s|@GITWEB_CONFIG@|$GITWEB_CONFIG|" \
+ -e "s|@GITWEB_CONFIG_SYSTEM@|$GITWEB_CONFIG_SYSTEM|" \
+ -e "s|@GITWEB_CONFIG_COMMON@|$GITWEB_CONFIG_COMMON|" \
+ -e "s|@GITWEB_HOME_LINK_STR@|$GITWEB_HOME_LINK_STR|" \
+ -e "s|@GITWEB_SITENAME@|$GITWEB_SITENAME|" \
+ -e "s|@GITWEB_PROJECTROOT@|$GITWEB_PROJECTROOT|" \
+ -e "s|@GITWEB_PROJECT_MAXDEPTH@|$GITWEB_PROJECT_MAXDEPTH|" \
+ -e "s|@GITWEB_EXPORT_OK@|$GITWEB_EXPORT_OK|" \
+ -e "s|@GITWEB_STRICT_EXPORT@|$GITWEB_STRICT_EXPORT|" \
+ -e "s|@GITWEB_BASE_URL@|$GITWEB_BASE_URL|" \
+ -e "s|@GITWEB_LIST@|$GITWEB_LIST|" \
+ -e "s|@GITWEB_HOMETEXT@|$GITWEB_HOMETEXT|" \
+ -e "s|@GITWEB_CSS@|$GITWEB_CSS|" \
+ -e "s|@GITWEB_LOGO@|$GITWEB_LOGO|" \
+ -e "s|@GITWEB_FAVICON@|$GITWEB_FAVICON|" \
+ -e "s|@GITWEB_JS@|$GITWEB_JS|" \
+ -e "s|@GITWEB_SITE_HTML_HEAD_STRING@|$GITWEB_SITE_HTML_HEAD_STRING|" \
+ -e "s|@GITWEB_SITE_HEADER@|$GITWEB_SITE_HEADER|" \
+ -e "s|@GITWEB_SITE_FOOTER@|$GITWEB_SITE_FOOTER|" \
+ -e "s|@HIGHLIGHT_BIN@|$HIGHLIGHT_BIN|" \
+ "$INPUT" >"$OUTPUT"
+
+chmod a+x "$OUTPUT"
diff --git a/gitweb/generate-gitweb-js.sh b/gitweb/generate-gitweb-js.sh
new file mode 100755
index 0000000000..01bb22b04b
--- /dev/null
+++ b/gitweb/generate-gitweb-js.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if test "$#" -lt 2
+then
+ echo >&2 "USAGE: $0 <OUTPUT> <INPUT>..."
+ exit 1
+fi
+
+OUTPUT="$1"
+shift
+
+cat "$@" >"$OUTPUT"
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index c4e0008d59..b5490dfecf 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -35,7 +35,7 @@ BEGIN {
CGI->compile() if $ENV{'MOD_PERL'};
}
-our $version = "++GIT_VERSION++";
+our $version = "@GIT_VERSION@";
our ($my_url, $my_uri, $base_url, $path_info, $home_link);
sub evaluate_uri {
@@ -80,46 +80,46 @@ sub evaluate_uri {
# core git executable to use
# this can just be "git" if your webserver has a sensible PATH
-our $GIT = "++GIT_BINDIR++/git";
+our $GIT = "@GIT_BINDIR@/git";
# absolute fs-path which will be prepended to the project path
#our $projectroot = "/pub/scm";
-our $projectroot = "++GITWEB_PROJECTROOT++";
+our $projectroot = "@GITWEB_PROJECTROOT@";
# fs traversing limit for getting project list
# the number is relative to the projectroot
-our $project_maxdepth = "++GITWEB_PROJECT_MAXDEPTH++";
+our $project_maxdepth = @GITWEB_PROJECT_MAXDEPTH@;
# string of the home link on top of all pages
-our $home_link_str = "++GITWEB_HOME_LINK_STR++";
+our $home_link_str = "@GITWEB_HOME_LINK_STR@";
# extra breadcrumbs preceding the home link
our @extra_breadcrumbs = ();
# name of your site or organization to appear in page titles
# replace this with something more descriptive for clearer bookmarks
-our $site_name = "++GITWEB_SITENAME++"
+our $site_name = "@GITWEB_SITENAME@"
|| ($ENV{'SERVER_NAME'} || "Untitled") . " Git";
# html snippet to include in the <head> section of each page
-our $site_html_head_string = "++GITWEB_SITE_HTML_HEAD_STRING++";
+our $site_html_head_string = "@GITWEB_SITE_HTML_HEAD_STRING@";
# filename of html text to include at top of each page
-our $site_header = "++GITWEB_SITE_HEADER++";
+our $site_header = "@GITWEB_SITE_HEADER@";
# html text to include at home page
-our $home_text = "++GITWEB_HOMETEXT++";
+our $home_text = "@GITWEB_HOMETEXT@";
# filename of html text to include at bottom of each page
-our $site_footer = "++GITWEB_SITE_FOOTER++";
+our $site_footer = "@GITWEB_SITE_FOOTER@";
# URI of stylesheets
-our @stylesheets = ("++GITWEB_CSS++");
+our @stylesheets = ("@GITWEB_CSS@");
# URI of a single stylesheet, which can be overridden in GITWEB_CONFIG.
our $stylesheet = undef;
# URI of GIT logo (72x27 size)
-our $logo = "++GITWEB_LOGO++";
+our $logo = "@GITWEB_LOGO@";
# URI of GIT favicon, assumed to be image/png type
-our $favicon = "++GITWEB_FAVICON++";
+our $favicon = "@GITWEB_FAVICON@";
# URI of gitweb.js (JavaScript code for gitweb)
-our $javascript = "++GITWEB_JS++";
+our $javascript = "@GITWEB_JS@";
# URI and label (title) of GIT logo link
#our $logo_url = "https://www.kernel.org/pub/software/scm/git/docs/";
@@ -128,7 +128,7 @@ our $logo_url = "https://git-scm.com/";
our $logo_label = "git homepage";
# source of projects list
-our $projects_list = "++GITWEB_LIST++";
+our $projects_list = "@GITWEB_LIST@";
# the width (in characters) of the projects list "Description" column
our $projects_list_description_width = 25;
@@ -147,7 +147,7 @@ our $default_projects_order = "project";
# show repository only if this file exists
# (only effective if this variable evaluates to true)
-our $export_ok = "++GITWEB_EXPORT_OK++";
+our $export_ok = "@GITWEB_EXPORT_OK@";
# don't generate age column on the projects list page
our $omit_age_column = 0;
@@ -161,11 +161,11 @@ our $omit_owner=0;
our $export_auth_hook = undef;
# only allow viewing of repositories also shown on the overview page
-our $strict_export = "++GITWEB_STRICT_EXPORT++";
+our $strict_export = "@GITWEB_STRICT_EXPORT@";
# list of git base URLs used for URL to where fetch project from,
# i.e. full URL is "$git_base_url/$project"
-our @git_base_url_list = grep { $_ ne '' } ("++GITWEB_BASE_URL++");
+our @git_base_url_list = grep { $_ ne '' } ("@GITWEB_BASE_URL@");
# default blob_plain mimetype and default charset for text/plain blob
our $default_blob_plain_mimetype = 'text/plain';
@@ -200,7 +200,7 @@ our $prevent_xss = 0;
# http://andre-simon.de/zip/download.php due to assumptions about parameters and output).
# Useful if highlight is not installed on your webserver's PATH.
# [Default: highlight]
-our $highlight_bin = "++HIGHLIGHT_BIN++";
+our $highlight_bin = "@HIGHLIGHT_BIN@";
# information about snapshot formats that gitweb is capable of serving
our %known_snapshot_formats = (
@@ -741,9 +741,9 @@ sub read_config_file {
our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM, $GITWEB_CONFIG_COMMON);
sub evaluate_gitweb_config {
- our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
- our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
- our $GITWEB_CONFIG_COMMON = $ENV{'GITWEB_CONFIG_COMMON'} || "++GITWEB_CONFIG_COMMON++";
+ our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "@GITWEB_CONFIG@";
+ our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "@GITWEB_CONFIG_SYSTEM@";
+ our $GITWEB_CONFIG_COMMON = $ENV{'GITWEB_CONFIG_COMMON'} || "@GITWEB_CONFIG_COMMON@";
# Protect against duplications of file names, to not read config twice.
# Only one of $GITWEB_CONFIG and $GITWEB_CONFIG_SYSTEM is used, so
@@ -2094,7 +2094,7 @@ sub format_log_line_html {
(
# The output of "git describe", e.g. v2.10.0-297-gf6727b0
# or hadoop-20160921-113441-20-g094fb7d
- (?<!-) # see strbuf_check_tag_ref(). Tags can't start with -
+ (?<!-) # see check_tag_ref(). Tags can't start with -
[A-Za-z0-9.-]+
(?!\.) # refs can't end with ".", see check_refname_format()
-g$regex
diff --git a/gitweb/meson.build b/gitweb/meson.build
new file mode 100644
index 0000000000..89b403dc9d
--- /dev/null
+++ b/gitweb/meson.build
@@ -0,0 +1,89 @@
+gitweb_config = configuration_data()
+gitweb_config.set_quoted('PERL_PATH', perl.full_path())
+gitweb_config.set_quoted('CSSMIN', '')
+gitweb_config.set_quoted('JSMIN', '')
+gitweb_config.set_quoted('GIT_BINDIR', get_option('prefix') / get_option('bindir'))
+gitweb_config.set_quoted('GITWEB_CONFIG', get_option('gitweb_config'))
+gitweb_config.set_quoted('GITWEB_CONFIG_SYSTEM', get_option('gitweb_config_system'))
+gitweb_config.set_quoted('GITWEB_CONFIG_COMMON', get_option('gitweb_config_common'))
+gitweb_config.set_quoted('GITWEB_HOME_LINK_STR', get_option('gitweb_home_link_str'))
+gitweb_config.set_quoted('GITWEB_SITENAME', get_option('gitweb_sitename'))
+gitweb_config.set_quoted('GITWEB_PROJECTROOT', get_option('gitweb_projectroot'))
+gitweb_config.set_quoted('GITWEB_PROJECT_MAXDEPTH', get_option('gitweb_project_maxdepth'))
+gitweb_config.set_quoted('GITWEB_EXPORT_OK', get_option('gitweb_export_ok'))
+gitweb_config.set_quoted('GITWEB_STRICT_EXPORT', get_option('gitweb_strict_export'))
+gitweb_config.set_quoted('GITWEB_BASE_URL', get_option('gitweb_base_url'))
+gitweb_config.set_quoted('GITWEB_LIST', get_option('gitweb_list'))
+gitweb_config.set_quoted('GITWEB_HOMETEXT', get_option('gitweb_hometext'))
+gitweb_config.set_quoted('GITWEB_CSS', get_option('gitweb_css'))
+gitweb_config.set_quoted('GITWEB_LOGO', get_option('gitweb_logo'))
+gitweb_config.set_quoted('GITWEB_FAVICON', get_option('gitweb_favicon'))
+gitweb_config.set_quoted('GITWEB_JS', get_option('gitweb_js'))
+gitweb_config.set_quoted('GITWEB_SITE_HTML_HEAD_STRING', get_option('gitweb_site_html_head_string'))
+gitweb_config.set_quoted('GITWEB_SITE_HEADER', get_option('gitweb_site_header'))
+gitweb_config.set_quoted('GITWEB_SITE_FOOTER', get_option('gitweb_site_footer'))
+gitweb_config.set_quoted('HIGHLIGHT_BIN', get_option('highlight_bin'))
+
+configure_file(
+ input: 'GITWEB-BUILD-OPTIONS.in',
+ output: 'GITWEB-BUILD-OPTIONS',
+ configuration: gitweb_config,
+)
+
+test_dependencies += custom_target(
+ input: 'gitweb.perl',
+ output: 'gitweb.cgi',
+ command: [
+ shell,
+ meson.current_source_dir() / 'generate-gitweb-cgi.sh',
+ meson.current_build_dir() / 'GITWEB-BUILD-OPTIONS',
+ git_version_file.full_path(),
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ install: true,
+ install_dir: get_option('datadir') / 'gitweb',
+ depends: [git_version_file],
+)
+
+javascript_files = [
+ meson.current_source_dir() / 'static/js/adjust-timezone.js',
+ meson.current_source_dir() / 'static/js/blame_incremental.js',
+ meson.current_source_dir() / 'static/js/javascript-detection.js',
+ meson.current_source_dir() / 'static/js/lib/common-lib.js',
+ meson.current_source_dir() / 'static/js/lib/cookies.js',
+ meson.current_source_dir() / 'static/js/lib/datetime.js',
+]
+
+test_dependencies += custom_target(
+ input: javascript_files,
+ output: 'gitweb.js',
+ command: [
+ shell,
+ meson.current_source_dir() / 'generate-gitweb-js.sh',
+ '@OUTPUT@',
+ ] + javascript_files,
+ install: true,
+ install_dir: get_option('datadir') / 'gitweb/static',
+)
+
+foreach asset : [
+ 'static/git-favicon.png',
+ 'static/git-logo.png',
+ 'static/gitweb.css',
+]
+ if meson.version().version_compare('>=1.3.0')
+ fs.copyfile(asset,
+ install: true,
+ install_dir: get_option('datadir') / 'gitweb' / fs.parent(asset),
+ )
+ else
+ configure_file(
+ input: asset,
+ output: fs.stem(asset),
+ copy: true,
+ install: true,
+ install_dir: get_option('datadir') / 'gitweb' / fs.parent(asset),
+ )
+ endif
+endforeach
diff --git a/hook.c b/hook.c
index a9320cb0ce..9ddbdee06d 100644
--- a/hook.c
+++ b/hook.c
@@ -39,7 +39,7 @@ const char *find_hook(struct repository *r, const char *name)
advise(_("The '%s' hook was ignored because "
"it's not set as executable.\n"
"You can disable this warning with "
- "`git config advice.ignoredHook false`."),
+ "`git config set advice.ignoredHook false`."),
path.buf);
}
}
diff --git a/http.c b/http.c
index 88bf3ba0a3..c8fc15aa11 100644
--- a/http.c
+++ b/http.c
@@ -2382,7 +2382,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
if (!tmp_idx)
return -1;
- new_pack = parse_pack_index(sha1, tmp_idx);
+ new_pack = parse_pack_index(the_repository, sha1, tmp_idx);
if (!new_pack) {
unlink(tmp_idx);
free(tmp_idx);
@@ -2524,7 +2524,7 @@ struct http_pack_request *new_direct_http_pack_request(
preq->url = url;
- odb_pack_name(&preq->tmpfile, packed_git_hash, "pack");
+ odb_pack_name(the_repository, &preq->tmpfile, packed_git_hash, "pack");
strbuf_addstr(&preq->tmpfile, ".temp");
preq->packfile = fopen(preq->tmpfile.buf, "a");
if (!preq->packfile) {
diff --git a/list-objects.c b/list-objects.c
index deacef98aa..943e62e868 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -41,7 +41,8 @@ static void show_object(struct traversal_context *ctx,
{
if (!ctx->show_object)
return;
- if (ctx->revs->unpacked && has_object_pack(&object->oid))
+ if (ctx->revs->unpacked && has_object_pack(ctx->revs->repo,
+ &object->oid))
return;
ctx->show_object(object, name, ctx->show_data);
@@ -74,7 +75,7 @@ static void process_blob(struct traversal_context *ctx,
*/
if (ctx->revs->exclude_promisor_objects &&
!repo_has_object_file(the_repository, &obj->oid) &&
- is_promisor_object(&obj->oid))
+ is_promisor_object(ctx->revs->repo, &obj->oid))
return;
pathlen = path->len;
@@ -179,7 +180,7 @@ static void process_tree(struct traversal_context *ctx,
* an incomplete list of missing objects.
*/
if (revs->exclude_promisor_objects &&
- is_promisor_object(&obj->oid))
+ is_promisor_object(revs->repo, &obj->oid))
return;
if (!revs->do_not_die_on_missing_objects)
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000000..0dccebcdf1
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,1901 @@
+# Meson build system
+# ==================
+#
+# The Meson build system is an alternative to our Makefile that you can use to
+# build, test and install Git. Using Meson results in a couple of benefits:
+#
+# - Out-of-tree builds.
+# - Better integration into IDEs.
+# - Easy-to-use autoconfiguration of available features on your system.
+#
+# To use Meson from the command line you need to have both Meson and Ninja
+# installed. Alternatively, if you do not have Python available on your system,
+# you can also use Muon instead of Meson and Samurai instead of Ninja, both of
+# which are drop-ins replacement that only depend on C.
+#
+# Basic usage
+# ===========
+#
+# In the most trivial case, you can configure, build and install Git like this:
+#
+# 1. Set up the build directory. This only needs to happen once per build
+# directory you want to have. You can also configure multiple different
+# build directories with different configurations.
+#
+# $ meson setup build/
+#
+# The build directory gets ignored by Git automatically as Meson will write
+# a ".gitignore" file into it. From hereon, we will assume that you execute
+# commands inside this build directory.
+#
+# 2. Compile Git. You can either use Meson, Ninja or Samurai to do this, so all
+# of the following invocations are equivalent:
+#
+# $ meson compile
+# $ ninja
+# $ samu
+#
+# The different invocations should ultimately not make much of a difference.
+# Using Meson also works with other generators though, like when the build
+# directory has been set up for use with Microsoft Visual Studio.
+#
+# Ninja and Samurai use multiple jobs by default, scaling with the number of
+# processor cores available. You can pass the `-jN` flag to change this.
+#
+# Meson automatically picks up ccache and sccache when these are installed
+# when setting up the build directory. You can override this behaviour when
+# setting up the build directory by setting the `CC` environment variable to
+# your desired compiler.
+#
+# 3. Execute tests. Again, you can either use Meson, Ninja or Samurai to do this:
+#
+# $ meson test
+# $ ninja test
+# $ samu test
+#
+# It is recommended to use Meson in this case though as it also provides you
+# additional features that the other build systems don't have available.
+# You can e.g. pass additional arguments to the test executables or run
+# individual tests:
+#
+# # Execute the t0000-basic integration test and t-reftable-stack unit test.
+# $ meson test t0000-basic t-reftable-stack
+#
+# # Execute all reftable unit tests.
+# $ meson test t-reftable-*
+#
+# # Execute all tests and stop with the first failure.
+# $ meson test --maxfail 1
+#
+# # Execute single test interactively such that features like `debug ()` work.
+# $ meson test -i --test-args='-ix' t1400-update-ref
+#
+# Test execution is parallelized by default and scales with the number of
+# processor cores available. You can change the number of processes by passing
+# the `-jN` flag to `meson test`.
+#
+# 4. Install the Git distribution. Again, this can be done via Meson, Ninja or
+# Samurai:
+#
+# $ meson install
+# $ ninja install
+# $ samu install
+#
+# The prefix into which Git shall be installed is defined when setting up
+# the build directory. More on that in the "Configuration" section.
+#
+# Meson supports multiple backends. The default backend generates Ninja build
+# instructions, but it also supports the generation of Microsoft Visual
+# Studio solutions as well as Xcode projects by passing the `--backend` option
+# to `meson setup`. IDEs like Eclipse and Visual Studio Code provide plugins to
+# import Meson files directly.
+#
+# Configuration
+# =============
+#
+# The exact configuration of Git is determined when setting up the build
+# directory via `meson setup`. Unless told otherwise, Meson will automatically
+# detect the availability of various bits and pieces. There are two different
+# kinds of options that can be used to further tweak the build:
+#
+# - Built-in options provided by Meson.
+#
+# - Options defined by the project in the "meson_options.txt" file.
+#
+# Both kinds of options can be inspected by running `meson configure` in the
+# build directory, which will give you a list of the current value for all
+# options.
+#
+# Options can be configured either when setting up the build directory or can
+# be changed in preexisting build directories:
+#
+# # Set up a new build directory with optimized settings that will be
+# # installed into an alternative prefix.
+# $ meson setup --buildtype release --optimization 3 --strip --prefix=/home/$USER build
+#
+# # Set up a new build directory with a higher warning level. Level 2 is
+# # mostly equivalent to setting DEVELOPER=1, level 3 and "everything"
+# # will enable even more warnings.
+# $ meson setup -Dwarning_level=2 build
+#
+# # Set up a new build directory with 'address' and 'undefined' sanitizers
+# # using Clang.
+# $ CC=clang meson setup -Db_sanitize=address,undefined build
+#
+# # Disable tests in a preexisting build directory.
+# $ meson configure -Dtests=false
+#
+# # Disable features based on Python
+# $ meson configure -Dpython=disabled
+#
+# Options have a type like booleans, choices, strings or features. Features are
+# somewhat special as they can have one of three values: enabled, disabled or
+# auto. While the first two values are self-explanatory, "auto" will enable or
+# disable the feature based on the availability of prerequisites to support it.
+# Python-based features for example will be enabled automatically when a Python
+# interpreter could be found. The default value of such features can be changed
+# via `meson setup --auto-features={enabled,disabled,auto}`, which will set the
+# value of all features with a value of "auto" to the provided one by default.
+#
+# It is also possible to store a set of configuration options in machine files.
+# This can be useful in case you regularly want to reuse the same set of options:
+#
+# [binaries]
+# c = ['clang']
+# ar = ['ar']
+#
+# [project options]
+# gettext = 'disabled'
+# default_editor = 'vim'
+#
+# [built-in options]
+# b_lto = true
+# b_sanitize = 'address,undefined'
+#
+# These machine files can be passed to `meson setup` via the `--native-file`
+# option.
+#
+# Subproject wrappers
+# ===================
+#
+# Subproject wrappers are a feature provided by Meson that allows the automatic
+# fallback to a "wrapped" dependency in case the dependency is not provided by
+# the system. For example if the system is lacking curl, then Meson will use
+# "subprojects/curl.wrap" to set up curl as a subproject and compile and link
+# the dependency into Git itself. This is especially helpful on systems like
+# Windows, where you typically don't have such dependencies installed.
+#
+# The use of subproject wrappers can be disabled by executing `meson setup`
+# with the `--wrap-mode nofallback` option.
+
+project('git', 'c',
+ meson_version: '>=0.61.0',
+ version: 'v2.47.GIT',
+)
+
+fs = import('fs')
+
+program_path = []
+# Git for Windows provides all the tools we need to build Git.
+if host_machine.system() == 'windows'
+ program_path += [ 'C:/Program Files/Git/bin', 'C:/Program Files/Git/usr/bin' ]
+endif
+
+cygpath = find_program('cygpath', dirs: program_path, required: false)
+diff = find_program('diff', dirs: program_path)
+shell = find_program('sh', dirs: program_path)
+tar = find_program('tar', dirs: program_path)
+
+script_environment = environment()
+foreach tool : ['cat', 'cut', 'grep', 'sed', 'sort', 'tr', 'uname']
+ program = find_program(tool, dirs: program_path)
+ script_environment.prepend('PATH', fs.parent(program.full_path()))
+endforeach
+
+git = find_program('git', dirs: program_path, required: false)
+if git.found()
+ script_environment.prepend('PATH', fs.parent(git.full_path()))
+endif
+
+if get_option('sane_tool_path') != ''
+ script_environment.prepend('PATH', get_option('sane_tool_path'))
+endif
+
+compiler = meson.get_compiler('c')
+
+libgit_sources = [
+ 'abspath.c',
+ 'add-interactive.c',
+ 'add-patch.c',
+ 'advice.c',
+ 'alias.c',
+ 'alloc.c',
+ 'apply.c',
+ 'archive-tar.c',
+ 'archive-zip.c',
+ 'archive.c',
+ 'attr.c',
+ 'base85.c',
+ 'bisect.c',
+ 'blame.c',
+ 'blob.c',
+ 'bloom.c',
+ 'branch.c',
+ 'bulk-checkin.c',
+ 'bundle-uri.c',
+ 'bundle.c',
+ 'cache-tree.c',
+ 'cbtree.c',
+ 'chdir-notify.c',
+ 'checkout.c',
+ 'chunk-format.c',
+ 'color.c',
+ 'column.c',
+ 'combine-diff.c',
+ 'commit-graph.c',
+ 'commit-reach.c',
+ 'commit.c',
+ 'compat/nonblock.c',
+ 'compat/obstack.c',
+ 'compat/terminal.c',
+ 'compat/zlib-uncompress2.c',
+ 'config.c',
+ 'connect.c',
+ 'connected.c',
+ 'convert.c',
+ 'copy.c',
+ 'credential.c',
+ 'csum-file.c',
+ 'ctype.c',
+ 'date.c',
+ 'decorate.c',
+ 'delta-islands.c',
+ 'diagnose.c',
+ 'diff-delta.c',
+ 'diff-merges.c',
+ 'diff-lib.c',
+ 'diff-no-index.c',
+ 'diff.c',
+ 'diffcore-break.c',
+ 'diffcore-delta.c',
+ 'diffcore-order.c',
+ 'diffcore-pickaxe.c',
+ 'diffcore-rename.c',
+ 'diffcore-rotate.c',
+ 'dir-iterator.c',
+ 'dir.c',
+ 'editor.c',
+ 'entry.c',
+ 'environment.c',
+ 'ewah/bitmap.c',
+ 'ewah/ewah_bitmap.c',
+ 'ewah/ewah_io.c',
+ 'ewah/ewah_rlw.c',
+ 'exec-cmd.c',
+ 'fetch-negotiator.c',
+ 'fetch-pack.c',
+ 'fmt-merge-msg.c',
+ 'fsck.c',
+ 'fsmonitor.c',
+ 'fsmonitor-ipc.c',
+ 'fsmonitor-settings.c',
+ 'gettext.c',
+ 'git-zlib.c',
+ 'gpg-interface.c',
+ 'graph.c',
+ 'grep.c',
+ 'hash-lookup.c',
+ 'hashmap.c',
+ 'help.c',
+ 'hex.c',
+ 'hex-ll.c',
+ 'hook.c',
+ 'ident.c',
+ 'json-writer.c',
+ 'kwset.c',
+ 'levenshtein.c',
+ 'line-log.c',
+ 'line-range.c',
+ 'linear-assignment.c',
+ 'list-objects-filter-options.c',
+ 'list-objects-filter.c',
+ 'list-objects.c',
+ 'lockfile.c',
+ 'log-tree.c',
+ 'loose.c',
+ 'ls-refs.c',
+ 'mailinfo.c',
+ 'mailmap.c',
+ 'match-trees.c',
+ 'mem-pool.c',
+ 'merge-blobs.c',
+ 'merge-ll.c',
+ 'merge-ort.c',
+ 'merge-ort-wrappers.c',
+ 'merge-recursive.c',
+ 'merge.c',
+ 'midx.c',
+ 'midx-write.c',
+ 'name-hash.c',
+ 'negotiator/default.c',
+ 'negotiator/noop.c',
+ 'negotiator/skipping.c',
+ 'notes-cache.c',
+ 'notes-merge.c',
+ 'notes-utils.c',
+ 'notes.c',
+ 'object-file-convert.c',
+ 'object-file.c',
+ 'object-name.c',
+ 'object.c',
+ 'oid-array.c',
+ 'oidmap.c',
+ 'oidset.c',
+ 'oidtree.c',
+ 'pack-bitmap-write.c',
+ 'pack-bitmap.c',
+ 'pack-check.c',
+ 'pack-mtimes.c',
+ 'pack-objects.c',
+ 'pack-revindex.c',
+ 'pack-write.c',
+ 'packfile.c',
+ 'pager.c',
+ 'parallel-checkout.c',
+ 'parse.c',
+ 'parse-options-cb.c',
+ 'parse-options.c',
+ 'patch-delta.c',
+ 'patch-ids.c',
+ 'path.c',
+ 'pathspec.c',
+ 'pkt-line.c',
+ 'preload-index.c',
+ 'pretty.c',
+ 'prio-queue.c',
+ 'progress.c',
+ 'promisor-remote.c',
+ 'prompt.c',
+ 'protocol.c',
+ 'protocol-caps.c',
+ 'prune-packed.c',
+ 'pseudo-merge.c',
+ 'quote.c',
+ 'range-diff.c',
+ 'reachable.c',
+ 'read-cache.c',
+ 'rebase-interactive.c',
+ 'rebase.c',
+ 'ref-filter.c',
+ 'reflog-walk.c',
+ 'reflog.c',
+ 'refs.c',
+ 'refs/debug.c',
+ 'refs/files-backend.c',
+ 'refs/reftable-backend.c',
+ 'refs/iterator.c',
+ 'refs/packed-backend.c',
+ 'refs/ref-cache.c',
+ 'refspec.c',
+ 'reftable/basics.c',
+ 'reftable/error.c',
+ 'reftable/block.c',
+ 'reftable/blocksource.c',
+ 'reftable/iter.c',
+ 'reftable/merged.c',
+ 'reftable/pq.c',
+ 'reftable/reader.c',
+ 'reftable/record.c',
+ 'reftable/stack.c',
+ 'reftable/system.c',
+ 'reftable/tree.c',
+ 'reftable/writer.c',
+ 'remote.c',
+ 'replace-object.c',
+ 'repo-settings.c',
+ 'repository.c',
+ 'rerere.c',
+ 'reset.c',
+ 'resolve-undo.c',
+ 'revision.c',
+ 'run-command.c',
+ 'send-pack.c',
+ 'sequencer.c',
+ 'serve.c',
+ 'server-info.c',
+ 'setup.c',
+ 'shallow.c',
+ 'sideband.c',
+ 'sigchain.c',
+ 'sparse-index.c',
+ 'split-index.c',
+ 'stable-qsort.c',
+ 'statinfo.c',
+ 'strbuf.c',
+ 'streaming.c',
+ 'string-list.c',
+ 'strmap.c',
+ 'strvec.c',
+ 'sub-process.c',
+ 'submodule-config.c',
+ 'submodule.c',
+ 'symlinks.c',
+ 'tag.c',
+ 'tempfile.c',
+ 'thread-utils.c',
+ 'tmp-objdir.c',
+ 'trace.c',
+ 'trace2.c',
+ 'trace2/tr2_cfg.c',
+ 'trace2/tr2_cmd_name.c',
+ 'trace2/tr2_ctr.c',
+ 'trace2/tr2_dst.c',
+ 'trace2/tr2_sid.c',
+ 'trace2/tr2_sysenv.c',
+ 'trace2/tr2_tbuf.c',
+ 'trace2/tr2_tgt_event.c',
+ 'trace2/tr2_tgt_normal.c',
+ 'trace2/tr2_tgt_perf.c',
+ 'trace2/tr2_tls.c',
+ 'trace2/tr2_tmr.c',
+ 'trailer.c',
+ 'transport-helper.c',
+ 'transport.c',
+ 'tree-diff.c',
+ 'tree-walk.c',
+ 'tree.c',
+ 'unpack-trees.c',
+ 'upload-pack.c',
+ 'url.c',
+ 'urlmatch.c',
+ 'usage.c',
+ 'userdiff.c',
+ 'utf8.c',
+ 'varint.c',
+ 'versioncmp.c',
+ 'walker.c',
+ 'wildmatch.c',
+ 'worktree.c',
+ 'wrapper.c',
+ 'write-or-die.c',
+ 'ws.c',
+ 'wt-status.c',
+ 'xdiff-interface.c',
+ 'xdiff/xdiffi.c',
+ 'xdiff/xemit.c',
+ 'xdiff/xhistogram.c',
+ 'xdiff/xmerge.c',
+ 'xdiff/xpatience.c',
+ 'xdiff/xprepare.c',
+ 'xdiff/xutils.c',
+]
+
+builtin_sources = [
+ 'builtin/add.c',
+ 'builtin/am.c',
+ 'builtin/annotate.c',
+ 'builtin/apply.c',
+ 'builtin/archive.c',
+ 'builtin/bisect.c',
+ 'builtin/blame.c',
+ 'builtin/branch.c',
+ 'builtin/bugreport.c',
+ 'builtin/bundle.c',
+ 'builtin/cat-file.c',
+ 'builtin/check-attr.c',
+ 'builtin/check-ignore.c',
+ 'builtin/check-mailmap.c',
+ 'builtin/check-ref-format.c',
+ 'builtin/checkout--worker.c',
+ 'builtin/checkout-index.c',
+ 'builtin/checkout.c',
+ 'builtin/clean.c',
+ 'builtin/clone.c',
+ 'builtin/column.c',
+ 'builtin/commit-graph.c',
+ 'builtin/commit-tree.c',
+ 'builtin/commit.c',
+ 'builtin/config.c',
+ 'builtin/count-objects.c',
+ 'builtin/credential-cache--daemon.c',
+ 'builtin/credential-cache.c',
+ 'builtin/credential-store.c',
+ 'builtin/credential.c',
+ 'builtin/describe.c',
+ 'builtin/diagnose.c',
+ 'builtin/diff-files.c',
+ 'builtin/diff-index.c',
+ 'builtin/diff-tree.c',
+ 'builtin/diff.c',
+ 'builtin/difftool.c',
+ 'builtin/fast-export.c',
+ 'builtin/fast-import.c',
+ 'builtin/fetch-pack.c',
+ 'builtin/fetch.c',
+ 'builtin/fmt-merge-msg.c',
+ 'builtin/for-each-ref.c',
+ 'builtin/for-each-repo.c',
+ 'builtin/fsck.c',
+ 'builtin/fsmonitor--daemon.c',
+ 'builtin/gc.c',
+ 'builtin/get-tar-commit-id.c',
+ 'builtin/grep.c',
+ 'builtin/hash-object.c',
+ 'builtin/help.c',
+ 'builtin/hook.c',
+ 'builtin/index-pack.c',
+ 'builtin/init-db.c',
+ 'builtin/interpret-trailers.c',
+ 'builtin/log.c',
+ 'builtin/ls-files.c',
+ 'builtin/ls-remote.c',
+ 'builtin/ls-tree.c',
+ 'builtin/mailinfo.c',
+ 'builtin/mailsplit.c',
+ 'builtin/merge-base.c',
+ 'builtin/merge-file.c',
+ 'builtin/merge-index.c',
+ 'builtin/merge-ours.c',
+ 'builtin/merge-recursive.c',
+ 'builtin/merge-tree.c',
+ 'builtin/merge.c',
+ 'builtin/mktag.c',
+ 'builtin/mktree.c',
+ 'builtin/multi-pack-index.c',
+ 'builtin/mv.c',
+ 'builtin/name-rev.c',
+ 'builtin/notes.c',
+ 'builtin/pack-objects.c',
+ 'builtin/pack-redundant.c',
+ 'builtin/pack-refs.c',
+ 'builtin/patch-id.c',
+ 'builtin/prune-packed.c',
+ 'builtin/prune.c',
+ 'builtin/pull.c',
+ 'builtin/push.c',
+ 'builtin/range-diff.c',
+ 'builtin/read-tree.c',
+ 'builtin/rebase.c',
+ 'builtin/receive-pack.c',
+ 'builtin/reflog.c',
+ 'builtin/refs.c',
+ 'builtin/remote-ext.c',
+ 'builtin/remote-fd.c',
+ 'builtin/remote.c',
+ 'builtin/repack.c',
+ 'builtin/replace.c',
+ 'builtin/replay.c',
+ 'builtin/rerere.c',
+ 'builtin/reset.c',
+ 'builtin/rev-list.c',
+ 'builtin/rev-parse.c',
+ 'builtin/revert.c',
+ 'builtin/rm.c',
+ 'builtin/send-pack.c',
+ 'builtin/shortlog.c',
+ 'builtin/show-branch.c',
+ 'builtin/show-index.c',
+ 'builtin/show-ref.c',
+ 'builtin/sparse-checkout.c',
+ 'builtin/stash.c',
+ 'builtin/stripspace.c',
+ 'builtin/submodule--helper.c',
+ 'builtin/symbolic-ref.c',
+ 'builtin/tag.c',
+ 'builtin/unpack-file.c',
+ 'builtin/unpack-objects.c',
+ 'builtin/update-index.c',
+ 'builtin/update-ref.c',
+ 'builtin/update-server-info.c',
+ 'builtin/upload-archive.c',
+ 'builtin/upload-pack.c',
+ 'builtin/var.c',
+ 'builtin/verify-commit.c',
+ 'builtin/verify-pack.c',
+ 'builtin/verify-tag.c',
+ 'builtin/worktree.c',
+ 'builtin/write-tree.c',
+]
+
+libgit_sources += custom_target(
+ input: 'command-list.txt',
+ output: 'command-list.h',
+ command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],
+ env: script_environment,
+)
+
+libgit_sources += custom_target(
+ output: 'config-list.h',
+ command: [
+ shell,
+ meson.current_source_dir() + '/generate-configlist.sh',
+ meson.current_source_dir(),
+ '@OUTPUT@',
+ ],
+ env: script_environment,
+)
+
+libgit_sources += custom_target(
+ input: 'Documentation/githooks.txt',
+ output: 'hook-list.h',
+ command: [
+ shell,
+ meson.current_source_dir() + '/generate-hooklist.sh',
+ meson.current_source_dir(),
+ '@OUTPUT@',
+ ],
+ env: script_environment,
+)
+
+# This contains the variables for GIT-BUILD-OPTIONS, which we use to propagate
+# build options to our tests.
+build_options_config = configuration_data()
+build_options_config.set('GIT_INTEROP_MAKE_OPTS', '')
+build_options_config.set('GIT_PERF_LARGE_REPO', '')
+build_options_config.set('GIT_PERF_MAKE_COMMAND', '')
+build_options_config.set('GIT_PERF_MAKE_OPTS', '')
+build_options_config.set('GIT_PERF_REPEAT_COUNT', '')
+build_options_config.set('GIT_PERF_REPO', '')
+build_options_config.set('GIT_TEST_CMP_USE_COPIED_CONTEXT', '')
+build_options_config.set('GIT_TEST_INDEX_VERSION', '')
+build_options_config.set('GIT_TEST_OPTS', '')
+build_options_config.set('GIT_TEST_PERL_FATAL_WARNINGS', '')
+build_options_config.set('GIT_TEST_UTF8_LOCALE', '')
+build_options_config.set_quoted('LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir')))
+build_options_config.set('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb'))
+
+if get_option('sane_tool_path') != ''
+ build_options_config.set_quoted('BROKEN_PATH_FIX', 's|^\# @BROKEN_PATH_FIX@$|git_broken_path_fix "' + get_option('sane_tool_path') + '"|')
+else
+ build_options_config.set_quoted('BROKEN_PATH_FIX', '/^\# @BROKEN_PATH_FIX@$/d')
+endif
+
+test_output_directory = get_option('test_output_directory')
+if test_output_directory == ''
+ test_output_directory = meson.project_build_root() / 'test-output'
+endif
+
+# These variables are used for building libgit.a.
+libgit_c_args = [
+ '-DBINDIR="' + get_option('bindir') + '"',
+ '-DDEFAULT_EDITOR="' + get_option('default_editor') + '"',
+ '-DDEFAULT_GIT_TEMPLATE_DIR="' + get_option('datadir') / 'git-core/templates' + '"',
+ '-DDEFAULT_HELP_FORMAT="' + get_option('default_help_format') + '"',
+ '-DDEFAULT_PAGER="' + get_option('default_pager') + '"',
+ '-DETC_GITATTRIBUTES="' + get_option('gitattributes') + '"',
+ '-DETC_GITCONFIG="' + get_option('gitconfig') + '"',
+ '-DFALLBACK_RUNTIME_PREFIX="' + get_option('prefix') + '"',
+ '-DGIT_EXEC_PATH="' + get_option('prefix') / get_option('libexecdir') / 'git-core"',
+ '-DGIT_HOST_CPU="' + host_machine.cpu_family() + '"',
+ '-DGIT_HTML_PATH="' + get_option('datadir') / 'doc/git-doc"',
+ '-DGIT_INFO_PATH="' + get_option('infodir') + '"',
+ '-DGIT_LOCALE_PATH="' + get_option('localedir') + '"',
+ '-DGIT_MAN_PATH="' + get_option('mandir') + '"',
+ '-DPAGER_ENV="' + get_option('pager_environment') + '"',
+ '-DSHELL_PATH="' + fs.as_posix(shell.full_path()) + '"',
+]
+libgit_include_directories = [ '.' ]
+libgit_dependencies = [ ]
+
+# Treat any warning level above 1 the same as we treat DEVELOPER=1 in our
+# Makefile.
+if get_option('warning_level') in ['2','3', 'everything'] and compiler.get_argument_syntax() == 'gcc'
+ foreach cflag : [
+ '-Wdeclaration-after-statement',
+ '-Wformat-security',
+ '-Wold-style-definition',
+ '-Woverflow',
+ '-Wpointer-arith',
+ '-Wstrict-prototypes',
+ '-Wunused',
+ '-Wvla',
+ '-Wwrite-strings',
+ '-fno-common',
+ '-Wtautological-constant-out-of-range-compare',
+ # If a function is public, there should be a prototype and the right
+ # header file should be included. If not, it should be static.
+ '-Wmissing-prototypes',
+ # These are disabled because we have these all over the place.
+ '-Wno-empty-body',
+ '-Wno-missing-field-initializers',
+ '-Wno-sign-compare',
+ ]
+ if compiler.has_argument(cflag)
+ libgit_c_args += cflag
+ endif
+ endforeach
+endif
+
+if get_option('b_sanitize').contains('address')
+ build_options_config.set('SANITIZE_ADDRESS', 'YesCompiledWithIt')
+else
+ build_options_config.set('SANITIZE_ADDRESS', '')
+endif
+if get_option('b_sanitize').contains('leak')
+ libgit_c_args += '-DSUPPRESS_ANNOTATED_LEAKS'
+ build_options_config.set('SANITIZE_LEAK', 'YesCompiledWithIt')
+else
+ build_options_config.set('SANITIZE_LEAK', '')
+endif
+if get_option('b_sanitize').contains('undefined')
+ libgit_c_args += '-DSHA1DC_FORCE_ALIGNED_ACCESS'
+endif
+
+executable_suffix = ''
+if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
+ executable_suffix = '.exe'
+ libgit_c_args += '-DSTRIP_EXTENSION="' + executable_suffix + '"'
+endif
+build_options_config.set_quoted('X', executable_suffix)
+
+python = import('python').find_installation('python3', required: get_option('python'))
+if python.found()
+ build_options_config.set('NO_PYTHON', '')
+else
+ libgit_c_args += '-DNO_PYTHON'
+ build_options_config.set('NO_PYTHON', '1')
+endif
+
+# Perl is used for two different things: our test harness and to provide some
+# features. It is optional if you want to neither execute tests nor use any of
+# these optional features.
+perl_required = get_option('perl')
+if get_option('tests')
+ perl_required = true
+endif
+
+# Note that we only set NO_PERL if the Perl features were disabled by the user.
+# It may not be set when we have found Perl, but only use it to run tests.
+perl = find_program('perl', version: '>=5.8.1', dirs: program_path, required: perl_required)
+perl_features_enabled = perl.found() and get_option('perl').allowed()
+if perl_features_enabled
+ build_options_config.set('NO_PERL', '')
+
+ if get_option('runtime_prefix')
+ build_options_config.set('PERL_LOCALEDIR', '')
+ else
+ build_options_config.set_quoted('PERL_LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir')))
+ endif
+
+ if get_option('perl_cpan_fallback')
+ build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
+ else
+ build_options_config.set_quoted('NO_PERL_CPAN_FALLBACKS', 'YesPlease')
+ endif
+else
+ libgit_c_args += '-DNO_PERL'
+ build_options_config.set('NO_PERL', '1')
+ build_options_config.set('PERL_LOCALEDIR', '')
+ build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
+endif
+
+zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
+if zlib.version().version_compare('<1.2.0')
+ libgit_c_args += '-DNO_DEFLATE_BOUND'
+endif
+libgit_dependencies += zlib
+
+threads = dependency('threads', required: false)
+if threads.found()
+ libgit_dependencies += threads
+ build_options_config.set('NO_PTHREADS', '')
+else
+ libgit_c_args += '-DNO_PTHREADS'
+ build_options_config.set('NO_PTHREADS', '1')
+endif
+
+msgfmt = find_program('msgfmt', dirs: program_path, required: false)
+gettext_option = get_option('gettext').disable_auto_if(not msgfmt.found())
+if not msgfmt.found() and gettext_option.enabled()
+ error('Internationalization via libintl requires msgfmt')
+endif
+
+if gettext_option.allowed() and host_machine.system() == 'darwin' and get_option('macos_use_homebrew_gettext')
+ if host_machine.cpu_family() == 'x86_64'
+ libintl_prefix = '/usr/local'
+ elif host_machine.cpu_family() == 'aarch64'
+ libintl_prefix = '/opt/homebrew'
+ else
+ error('Homebrew workaround not supported on current architecture')
+ endif
+
+ intl = compiler.find_library('intl', dirs: libintl_prefix / 'lib', required: gettext_option)
+ if intl.found()
+ intl = declare_dependency(
+ dependencies: intl,
+ include_directories: libintl_prefix / 'include',
+ )
+ endif
+else
+ intl = dependency('intl', required: gettext_option)
+endif
+if intl.found()
+ libgit_dependencies += intl
+ build_options_config.set('NO_GETTEXT', '')
+ build_options_config.set('USE_GETTEXT_SCHEME', '')
+
+ # POSIX nowadays requires `nl_langinfo()`, but some systems still don't have
+ # the function available. On such systems we instead fall back to libcharset.
+ # On native Windows systems we use our own emulation.
+ if host_machine.system() != 'windows' and not compiler.has_function('nl_langinfo')
+ libcharset = compiler.find_library('charset', required: true)
+ libgit_dependencies += libcharset
+ libgit_c_args += '-DHAVE_LIBCHARSET_H'
+ endif
+else
+ libgit_c_args += '-DNO_GETTEXT'
+ build_options_config.set('NO_GETTEXT', '1')
+ build_options_config.set('USE_GETTEXT_SCHEME', 'fallthrough')
+endif
+
+iconv = dependency('iconv', required: get_option('iconv'))
+if iconv.found()
+ libgit_dependencies += iconv
+ build_options_config.set('NO_ICONV', '')
+
+ have_old_iconv = false
+ if not compiler.compiles('''
+ #include <iconv.h>
+
+ extern size_t iconv(iconv_t cd,
+ char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ ''', name: 'old iconv interface', dependencies: [iconv])
+ libgit_c_args += '-DOLD_ICONV'
+ have_old_iconv = true
+ endif
+
+ iconv_omits_bom_source = '''#
+ #include <iconv.h>
+
+ int main(int argc, const char **argv)
+ {
+ '''
+ if have_old_iconv
+ iconv_omits_bom_source += '''
+ typedef const char *iconv_ibp;
+ '''
+ else
+ iconv_omits_bom_source += '''
+ typedef char *iconv_ibp;
+ '''
+ endif
+ iconv_omits_bom_source += '''
+ int v;
+ iconv_t conv;
+ char in[] = "a"; iconv_ibp pin = in;
+ char out[20] = ""; char *pout = out;
+ size_t isz = sizeof in;
+ size_t osz = sizeof out;
+
+ conv = iconv_open("UTF-16", "UTF-8");
+ iconv(conv, &pin, &isz, &pout, &osz);
+ iconv_close(conv);
+ v = (unsigned char)(out[0]) + (unsigned char)(out[1]);
+ return v != 0xfe + 0xff;
+ }
+ '''
+
+ if compiler.run(iconv_omits_bom_source,
+ dependencies: iconv,
+ name: 'iconv omits BOM',
+ ).returncode() != 0
+ libgit_c_args += '-DICONV_OMITS_BOM'
+ endif
+else
+ libgit_c_args += '-DNO_ICONV'
+ build_options_config.set('NO_ICONV', '1')
+endif
+
+pcre2 = dependency('libpcre2-8', required: get_option('pcre2'), default_options: ['default_library=static', 'test=false'])
+if pcre2.found()
+ libgit_dependencies += pcre2
+ libgit_c_args += '-DUSE_LIBPCRE2'
+ build_options_config.set('USE_LIBPCRE2', '1')
+else
+ build_options_config.set('USE_LIBPCRE2', '')
+endif
+
+curl = dependency('libcurl', version: '>=7.21.3', required: get_option('curl'), default_options: ['default_library=static', 'tests=disabled', 'tool=disabled'])
+use_curl_for_imap_send = false
+if curl.found()
+ if curl.version().version_compare('>=7.34.0')
+ libgit_c_args += '-DUSE_CURL_FOR_IMAP_SEND'
+ use_curl_for_imap_send = true
+ endif
+
+ libgit_dependencies += curl
+ libgit_c_args += '-DCURL_DISABLE_TYPECHECK'
+ build_options_config.set('NO_CURL', '')
+else
+ libgit_c_args += '-DNO_CURL'
+ build_options_config.set('NO_CURL', '1')
+endif
+
+expat = dependency('expat', required: get_option('expat'), default_options: ['default_library=static', 'build_tests=false'])
+if expat.found()
+ libgit_dependencies += expat
+
+ if expat.version().version_compare('<=1.2')
+ libgit_c_args += '-DEXPAT_NEEDS_XMLPARSE_H'
+ endif
+ build_options_config.set('NO_EXPAT', '')
+else
+ libgit_c_args += '-DNO_EXPAT'
+ build_options_config.set('NO_EXPAT', '1')
+endif
+
+if not compiler.has_header('sys/select.h')
+ libgit_c_args += '-DNO_SYS_SELECT_H'
+endif
+
+has_poll_h = compiler.has_header('poll.h')
+if not has_poll_h
+ libgit_c_args += '-DNO_POLL_H'
+endif
+
+has_sys_poll_h = compiler.has_header('sys/poll.h')
+if not has_sys_poll_h
+ libgit_c_args += '-DNO_SYS_POLL_H'
+endif
+
+if not has_poll_h and not has_sys_poll_h
+ libgit_c_args += '-DNO_POLL'
+ libgit_sources += 'compat/poll/poll.c'
+ libgit_include_directories += 'compat/poll'
+endif
+
+if not compiler.has_header('inttypes.h')
+ libgit_c_args += '-DNO_INTTYPES_H'
+endif
+
+if compiler.has_header('alloca.h')
+ libgit_c_args += '-DHAVE_ALLOCA_H'
+endif
+
+if compiler.has_header('sys/sysinfo.h')
+ libgit_c_args += '-DHAVE_SYSINFO'
+endif
+
+# Windows has libgen.h and a basename implementation, but we still need our own
+# implementation to threat things like drive prefixes specially.
+if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')
+ libgit_c_args += '-DNO_LIBGEN_H'
+ libgit_sources += 'compat/basename.c'
+endif
+
+if compiler.has_header('paths.h')
+ libgit_c_args += '-DHAVE_PATHS_H'
+endif
+
+if compiler.has_header('strings.h')
+ libgit_c_args += '-DHAVE_STRINGS_H'
+endif
+
+networking_dependencies = [ ]
+if host_machine.system() == 'windows'
+ winsock = compiler.find_library('ws2_32', required: false)
+ if winsock.found()
+ networking_dependencies += winsock
+ endif
+else
+ libresolv = compiler.find_library('resolv', required: false)
+ if libresolv.found()
+ networking_dependencies += libresolv
+ endif
+endif
+libgit_dependencies += networking_dependencies
+
+foreach symbol : ['inet_ntop', 'inet_pton', 'strerror']
+ if not compiler.has_function(symbol, dependencies: networking_dependencies)
+ libgit_c_args += '-DNO_' + symbol.to_upper()
+ endif
+endforeach
+
+has_ipv6 = compiler.has_function('getaddrinfo', dependencies: networking_dependencies)
+if not has_ipv6
+ libgit_c_args += '-DNO_IPV6'
+endif
+
+if not compiler.compiles('''
+ #ifdef _WIN32
+ # include <winsock2.h>
+ #else
+ # include <sys/types.h>
+ # include <sys/socket.h>
+ #endif
+
+ void func(void)
+ {
+ struct sockaddr_storage x;
+ }
+''', name: 'struct sockaddr_storage')
+ if has_ipv6
+ libgit_c_args += '-Dsockaddr_storage=sockaddr_in6'
+ else
+ libgit_c_args += '-Dsockaddr_storage=sockaddr_in'
+ endif
+endif
+
+if compiler.has_function('socket', dependencies: networking_dependencies)
+ libgit_sources += [
+ 'unix-socket.c',
+ 'unix-stream-server.c',
+ ]
+ build_options_config.set('NO_UNIX_SOCKETS', '')
+else
+ libgit_c_args += '-DNO_UNIX_SOCKETS'
+ build_options_config.set('NO_UNIX_SOCKETS', '1')
+endif
+
+if not compiler.has_function('pread')
+ libgit_c_args += '-DNO_PREAD'
+ libgit_sources += 'compat/pread.c'
+endif
+
+if host_machine.system() == 'darwin'
+ libgit_sources += 'compat/precompose_utf8.c'
+ libgit_c_args += '-DPRECOMPOSE_UNICODE'
+ libgit_c_args += '-DPROTECT_HFS_DEFAULT'
+endif
+
+# Configure general compatibility wrappers.
+if host_machine.system() == 'cygwin'
+ libgit_sources += [
+ 'compat/win32/path-utils.c',
+ ]
+elif host_machine.system() == 'windows'
+ libgit_sources += [
+ 'compat/mingw.c',
+ 'compat/winansi.c',
+ 'compat/win32/flush.c',
+ 'compat/win32/path-utils.c',
+ 'compat/win32/pthread.c',
+ 'compat/win32/syslog.c',
+ 'compat/win32/dirent.c',
+ 'compat/win32mmap.c',
+ 'compat/nedmalloc/nedmalloc.c',
+ ]
+
+ libgit_c_args += [
+ '-DDETECT_MSYS_TTY',
+ '-DENSURE_MSYSTEM_IS_SET',
+ '-DNATIVE_CRLF',
+ '-DNOGDI',
+ '-DNO_POSIX_GOODIES',
+ '-DWIN32',
+ '-D_CONSOLE',
+ '-D_CONSOLE_DETECT_MSYS_TTY',
+ '-D__USE_MINGW_ANSI_STDIO=0',
+ ]
+
+ libgit_dependencies += compiler.find_library('ntdll')
+ libgit_include_directories += 'compat/win32'
+ if compiler.get_id() == 'msvc'
+ libgit_include_directories += 'compat/vcbuild/include'
+ endif
+endif
+
+if host_machine.system() == 'linux'
+ libgit_sources += 'compat/linux/procinfo.c'
+elif host_machine.system() == 'windows'
+ libgit_sources += 'compat/win32/trace2_win32_process_info.c'
+else
+ libgit_sources += 'compat/stub/procinfo.c'
+endif
+
+if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
+ libgit_c_args += [
+ '-DUNRELIABLE_FSTAT',
+ '-DMMAP_PREVENTS_DELETE',
+ '-DOBJECT_CREATION_MODE=1',
+ ]
+endif
+
+# Configure the simple-ipc subsystem required fro the fsmonitor.
+if host_machine.system() == 'windows'
+ libgit_sources += [
+ 'compat/simple-ipc/ipc-shared.c',
+ 'compat/simple-ipc/ipc-win32.c',
+ ]
+ libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
+else
+ libgit_sources += [
+ 'compat/simple-ipc/ipc-shared.c',
+ 'compat/simple-ipc/ipc-unix-socket.c',
+ ]
+ libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
+endif
+
+fsmonitor_backend = ''
+if host_machine.system() == 'windows'
+ fsmonitor_backend = 'win32'
+elif host_machine.system() == 'darwin'
+ fsmonitor_backend = 'darwin'
+ libgit_dependencies += dependency('CoreServices')
+endif
+if fsmonitor_backend != ''
+ libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'
+ libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'
+
+ libgit_sources += [
+ 'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',
+ 'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',
+ 'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',
+ 'compat/fsmonitor/fsm-path-utils-' + fsmonitor_backend + '.c',
+ 'compat/fsmonitor/fsm-settings-' + fsmonitor_backend + '.c',
+ ]
+endif
+build_options_config.set_quoted('FSMONITOR_DAEMON_BACKEND', fsmonitor_backend)
+build_options_config.set_quoted('FSMONITOR_OS_SETTINGS', fsmonitor_backend)
+
+if not get_option('b_sanitize').contains('address') and get_option('regex').allowed() and compiler.has_header('regex.h') and compiler.get_define('REG_STARTEND', prefix: '#include <regex.h>') != ''
+ build_options_config.set('NO_REGEX', '')
+
+ if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''
+ libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'
+ libgit_sources += 'compat/regcomp_enhanced.c'
+ endif
+elif not get_option('regex').enabled()
+ libgit_c_args += [
+ '-DNO_REGEX',
+ '-DGAWK',
+ '-DNO_MBSUPPORT',
+ ]
+ build_options_config.set('NO_REGEX', '1')
+ libgit_sources += 'compat/regex/regex.c'
+ libgit_include_directories += 'compat/regex'
+else
+ error('Native regex support requested but not found')
+endif
+
+# setitimer and friends are provided by compat/mingw.c.
+if host_machine.system() != 'windows'
+ if not compiler.compiles('''
+ #include <sys/time.h>
+ void func(void)
+ {
+ struct itimerval value;
+ }
+ ''', name: 'struct itimerval')
+ libgit_c_args += '-DNO_STRUCT_ITIMERVAL'
+ libgit_c_args += '-DNO_SETITIMER'
+ elif not compiler.has_function('setitimer')
+ libgit_c_args += '-DNO_SETITIMER'
+ endif
+endif
+
+if compiler.has_member('struct stat', 'st_mtimespec.tv_nsec', prefix: '#include <sys/stat.h>')
+ libgit_c_args += '-DUSE_ST_TIMESPEC'
+elif not compiler.has_member('struct stat', 'st_mtim.tv_nsec', prefix: '#include <sys/stat.h>')
+ libgit_c_args += '-DNO_NSEC'
+endif
+
+if not compiler.has_member('struct stat', 'st_blocks', prefix: '#include <sys/stat.h>')
+ libgit_c_args += '-DNO_ST_BLOCKS_IN_STRUCT_STAT'
+endif
+
+if not compiler.has_member('struct dirent', 'd_type', prefix: '#include <dirent.h>')
+ libgit_c_args += '-DNO_D_TYPE_IN_DIRENT'
+endif
+
+if not compiler.has_member('struct passwd', 'pw_gecos', prefix: '#include <pwd.h>')
+ libgit_c_args += '-DNO_GECOS_IN_PWENT'
+endif
+
+if compiler.has_function('sync_file_range')
+ libgit_c_args += '-DHAVE_SYNC_FILE_RANGE'
+endif
+
+if not compiler.has_function('strcasestr')
+ libgit_c_args += '-DNO_STRCASESTR'
+ libgit_sources += 'compat/strcasestr.c'
+endif
+
+if not compiler.has_function('memmem')
+ libgit_c_args += '-DNO_MEMMEM'
+ libgit_sources += 'compat/memmem.c'
+endif
+
+if not compiler.has_function('strlcpy')
+ libgit_c_args += '-DNO_STRLCPY'
+ libgit_sources += 'compat/strlcpy.c'
+endif
+
+if not compiler.has_function('strdup')
+ libgit_c_args += '-DOVERRIDE_STRDUP'
+ libgit_sources += 'compat/strdup.c'
+endif
+
+if not compiler.has_function('strtoumax')
+ libgit_c_args += '-DNO_STRTOUMAX'
+ libgit_sources += [
+ 'compat/strtoumax.c',
+ 'compat/strtoimax.c',
+ ]
+endif
+
+if not compiler.has_function('strtoull')
+ libgit_c_args += '-DNO_STRTOULL'
+endif
+
+if not compiler.has_function('setenv')
+ libgit_c_args += '-DNO_SETENV'
+ libgit_sources += 'compat/setenv.c'
+endif
+
+if not compiler.has_function('qsort')
+ libgit_c_args += '-DINTERNAL_QSORT'
+endif
+libgit_sources += 'compat/qsort_s.c'
+
+# unsetenv is provided by compat/mingw.c.
+if host_machine.system() != 'windows' and not compiler.has_function('unsetenv')
+ libgit_c_args += '-DNO_UNSETENV'
+ libgit_sources += 'compat/unsetenv.c'
+endif
+
+if not compiler.has_function('mkdtemp')
+ libgit_c_args += '-DNO_MKDTEMP'
+ libgit_sources += 'compat/mkdtemp.c'
+endif
+
+if not compiler.has_function('initgroups')
+ libgit_c_args += '-DNO_INITGROUPS'
+endif
+
+if compiler.has_function('getdelim')
+ libgit_c_args += '-DHAVE_GETDELIM'
+endif
+
+if host_machine.system() == 'windows'
+ libgit_c_args += '-DUSE_WIN32_MMAP'
+elif not compiler.has_function('mmap')
+ libgit_c_args += '-DNO_MMAP'
+ libgit_sources += 'compat/mmap.c'
+endif
+
+if compiler.has_function('clock_gettime')
+ libgit_c_args += '-DHAVE_CLOCK_GETTIME'
+endif
+
+if compiler.compiles('''
+ #include <time.h>
+
+ void func(void)
+ {
+ clockid_t id = CLOCK_MONOTONIC;
+ }
+''', name: 'monotonic clock')
+ libgit_c_args += '-DHAVE_CLOCK_MONOTONIC'
+endif
+
+if not compiler.compiles('''
+ #include <inttypes.h>
+
+ void func(void)
+ {
+ uintmax_t x = 0;
+ }
+''', name: 'uintmax_t')
+ libgit_c_args += '-DNO_UINTMAX_T'
+endif
+
+has_bsd_sysctl = false
+if compiler.has_header('sys/sysctl.h')
+ if compiler.compiles('''
+ #include <stddef.h>
+ #include <sys/sysctl.h>
+
+ void func(void)
+ {
+ int val, mib[2] = { 0 };
+ size_t len = sizeof(val);
+ sysctl(mib, 2, &val, &len, NULL, 0);
+ }
+ ''', name: 'BSD sysctl')
+ libgit_c_args += '-DHAVE_BSD_SYSCTL'
+ has_bsd_sysctl = true
+ endif
+endif
+
+if not meson.is_cross_build() and compiler.run('''
+ #include <stdio.h>
+
+ int main(int argc, const char **argv)
+ {
+ FILE *f = fopen(".", "r");
+ return f ? 0 : 1;
+ }
+''', name: 'fread reads directories').returncode() == 0
+ libgit_c_args += '-DFREAD_READS_DIRECTORIES'
+ libgit_sources += 'compat/fopen.c'
+endif
+
+if not meson.is_cross_build() and fs.exists('/dev/tty')
+ libgit_c_args += '-DHAVE_DEV_TTY'
+endif
+
+https_backend = get_option('https_backend')
+
+security_framework = dependency('Security', required: https_backend == 'CommonCrypto')
+core_foundation_framework = dependency('CoreFoundation', required: security_framework.found())
+if https_backend == 'auto' and security_framework.found()
+ https_backend = 'CommonCrypto'
+endif
+
+openssl_required = https_backend == 'openssl' or get_option('sha1_backend') == 'openssl' or get_option('sha256_backend') == 'openssl'
+openssl = dependency('openssl', required: openssl_required, default_options: ['default_library=static'])
+if https_backend == 'auto' and openssl.found()
+ https_backend = 'openssl'
+endif
+
+if https_backend == 'CommonCrypto'
+ libgit_dependencies += security_framework
+ libgit_dependencies += core_foundation_framework
+ libgit_c_args += '-DAPPLE_COMMON_CRYPTO'
+elif https_backend == 'openssl'
+ libgit_dependencies += openssl
+else
+ # We either couldn't find any dependencies with 'auto' or the user requested
+ # 'none'. Both cases are benign.
+endif
+
+if https_backend != 'openssl'
+ libgit_c_args += '-DNO_OPENSSL'
+endif
+
+sha1_backend = get_option('sha1_backend')
+if sha1_backend == 'sha1dc'
+ libgit_c_args += '-DSHA1_DC'
+ libgit_c_args += '-DSHA1DC_NO_STANDARD_INCLUDES=1'
+ libgit_c_args += '-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0'
+ libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_SHA1_C="git-compat-util.h"'
+ libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h"'
+
+ libgit_sources += [
+ 'sha1dc_git.c',
+ 'sha1dc/sha1.c',
+ 'sha1dc/ubc_check.c',
+ ]
+elif sha1_backend == 'common-crypto'
+ libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL'
+ libgit_c_args += '-DSHA1_APPLE'
+ # Apple CommonCrypto requires chunking
+ libgit_c_args += '-DSHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L'
+elif sha1_backend == 'openssl'
+ libgit_c_args += '-DSHA1_OPENSSL'
+ libgit_dependencies += openssl
+elif sha1_backend == 'block'
+ libgit_c_args += '-DSHA1_BLK'
+ libgit_sources += 'block-sha1/sha1.c'
+else
+ error('Unhandled SHA1 backend ' + sha1_backend)
+endif
+
+sha256_backend = get_option('sha256_backend')
+if sha256_backend == 'openssl'
+ libgit_c_args += '-DSHA256_OPENSSL'
+ libgit_dependencies += openssl
+elif sha256_backend == 'nettle'
+ nettle = dependency('nettle')
+ libgit_dependencies += nettle
+ libgit_c_args += '-DSHA256_NETTLE'
+elif sha256_backend == 'gcrypt'
+ gcrypt = dependency('gcrypt')
+ libgit_dependencies += gcrypt
+ libgit_c_args += '-DSHA256_GCRYPT'
+elif sha256_backend == 'block'
+ libgit_c_args += '-DSHA256_BLK'
+ libgit_sources += 'sha256/block/sha256.c'
+else
+ error('Unhandled SHA256 backend ' + sha256_backend)
+endif
+
+if compiler.has_header_symbol('stdlib.h', 'arc4random_buf')
+ libgit_c_args += '-DHAVE_ARC4RANDOM'
+elif compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf')
+ libgit_c_args += '-DHAVE_ARC4RANDOM_BSD'
+elif compiler.has_function('getrandom', prefix: '#include <sys/random.h>')
+ libgit_c_args += '-DHAVE_GETRANDOM'
+elif compiler.has_function('getentropy', prefix: '#include <unistd.h>')
+ libgit_c_args += '-DHAVE_GETENTROPY'
+elif compiler.has_function('RtlGenRandom', prefix: '#include <windows.h>\n#include <ntsecapi.h>')
+ libgit_c_args += '-DHAVE_RTLGENRANDOM'
+elif openssl.found()
+ libgit_c_args += '-DHAVE_OPENSSL_CSPRNG'
+endif
+
+if get_option('runtime_prefix')
+ libgit_c_args += '-DRUNTIME_PREFIX'
+ build_options_config.set('RUNTIME_PREFIX', 'true')
+
+ if compiler.has_header('mach-o/dyld.h')
+ libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
+ endif
+
+ if has_bsd_sysctl and compiler.compiles('''
+ #include <sys/sysctl.h>
+
+ void func(void)
+ {
+ KERN_PROC_PATHNAME; KERN_PROC;
+ }
+ ''', name: 'BSD KERN_PROC_PATHNAME')
+ libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
+ endif
+
+ if host_machine.system() == 'linux'
+ libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="/proc/self/exe' + '"'
+ elif host_machine.system() == 'openbsd'
+ libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/file' + '"'
+ elif host_machine.system() == 'netbsd'
+ libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/exe' + '"'
+ endif
+
+ if host_machine.system() == 'windows' and compiler.compiles('''
+ #include <stdlib.h>
+
+ void func(void)
+ {
+ _wpgmptr;
+ }
+ ''', name: 'Win32 _wpgmptr')
+ libgit_c_args += '-DHAVE_WPGMPTR'
+ endif
+else
+ build_options_config.set('RUNTIME_PREFIX', 'false')
+endif
+
+foreach key, value : {
+ 'DIFF': diff.full_path(),
+ 'GIT_TEST_CMP': diff.full_path() + ' -u',
+ 'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl',
+ 'GIT_TEST_MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools',
+ 'GIT_TEST_POPATH': meson.project_source_root() / 'po',
+ 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates',
+ 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po',
+ 'PAGER_ENV': get_option('pager_environment'),
+ 'PERL_PATH': perl.found() ? perl.full_path() : '',
+ 'PYTHON_PATH': python.found () ? python.full_path() : '',
+ 'SHELL_PATH': shell.full_path(),
+ 'TAR': tar.full_path(),
+ 'TEST_OUTPUT_DIRECTORY': test_output_directory,
+ 'TEST_SHELL_PATH': shell.full_path(),
+}
+ if value != '' and cygpath.found()
+ value = run_command(cygpath, value, check: true).stdout().strip()
+ endif
+ build_options_config.set_quoted(key, value)
+endforeach
+
+configure_file(
+ input: 'GIT-BUILD-OPTIONS.in',
+ output: 'GIT-BUILD-OPTIONS',
+ configuration: build_options_config,
+)
+
+git_version_file = custom_target(
+ command: [
+ shell,
+ meson.current_source_dir() / 'GIT-VERSION-GEN',
+ meson.current_source_dir(),
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ input: meson.current_source_dir() / 'GIT-VERSION-FILE.in',
+ output: 'GIT-VERSION-FILE',
+ build_always_stale: true,
+)
+
+version_def_h = custom_target(
+ command: [
+ shell,
+ meson.current_source_dir() / 'GIT-VERSION-GEN',
+ meson.current_source_dir(),
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ input: meson.current_source_dir() / 'version-def.h.in',
+ output: 'version-def.h',
+ # Depend on GIT-VERSION-FILE so that we don't always try to rebuild this
+ # target for the same commit.
+ depends: [git_version_file],
+)
+
+# Build a separate library for "version.c" so that we do not have to rebuild
+# everything when the current Git commit changes.
+libgit_version_library = static_library('git-version',
+ sources: [
+ 'version.c',
+ version_def_h,
+ ],
+ c_args: libgit_c_args,
+ dependencies: libgit_dependencies,
+ include_directories: libgit_include_directories,
+)
+
+libgit_library = static_library('git',
+ sources: libgit_sources,
+ c_args: libgit_c_args,
+ link_with: libgit_version_library,
+ dependencies: libgit_dependencies,
+ include_directories: libgit_include_directories,
+)
+
+libgit = declare_dependency(
+ compile_args: libgit_c_args,
+ link_with: libgit_library,
+ dependencies: libgit_dependencies,
+ include_directories: libgit_include_directories,
+)
+
+common_main_sources = ['common-main.c']
+common_main_link_args = [ ]
+if host_machine.system() == 'windows'
+ git_rc = custom_target(
+ command: [
+ shell,
+ meson.current_source_dir() / 'GIT-VERSION-GEN',
+ meson.current_source_dir(),
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ input: meson.current_source_dir() / 'git.rc.in',
+ output: 'git.rc',
+ depends: [git_version_file],
+ )
+
+ common_main_sources += import('windows').compile_resources(git_rc,
+ include_directories: [meson.current_source_dir()],
+ )
+ if compiler.get_argument_syntax() == 'gcc'
+ common_main_link_args += [
+ '-municode',
+ '-Wl,-nxcompat',
+ '-Wl,-dynamicbase',
+ '-Wl,-pic-executable,-e,mainCRTStartup',
+ ]
+ elif compiler.get_argument_syntax() == 'msvc'
+ common_main_link_args += [
+ '/ENTRY:wmainCRTStartup',
+ 'invalidcontinue.obj',
+ ]
+ else
+ error('Unsupported compiler ' + compiler.get_id())
+ endif
+endif
+common_main_library = static_library('common-main',
+ sources: common_main_sources,
+ c_args: libgit_c_args,
+ dependencies: libgit_dependencies,
+ include_directories: libgit_include_directories,
+)
+common_main = declare_dependency(
+ link_with: common_main_library,
+ link_args: common_main_link_args,
+)
+
+bin_wrappers = [ ]
+test_dependencies = [ ]
+
+git = executable('git',
+ sources: builtin_sources + 'git.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+bin_wrappers += git
+
+test_dependencies += executable('git-daemon',
+ sources: 'daemon.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+
+test_dependencies += executable('git-sh-i18n--envsubst',
+ sources: 'sh-i18n--envsubst.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+
+bin_wrappers += executable('git-shell',
+ sources: 'shell.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+
+test_dependencies += executable('git-http-backend',
+ sources: 'http-backend.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+
+bin_wrappers += executable('scalar',
+ sources: 'scalar.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+
+if get_option('curl').enabled()
+ curl_sources = [
+ 'http.c',
+ 'http-walker.c',
+ ]
+
+ git_remote_http = executable('git-remote-http',
+ sources: curl_sources + 'remote-curl.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+ )
+ test_dependencies += git_remote_http
+
+ test_dependencies += executable('git-http-fetch',
+ sources: curl_sources + 'http-fetch.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+ )
+
+ if expat.found()
+ test_dependencies += executable('git-http-push',
+ sources: curl_sources + 'http-push.c',
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+ )
+ endif
+
+ foreach alias : [ 'git-remote-https', 'git-remote-ftp', 'git-remote-ftps' ]
+ test_dependencies += executable(alias,
+ objects: git_remote_http.extract_all_objects(recursive: false),
+ dependencies: [libgit, common_main],
+ )
+
+ install_symlink(alias + executable_suffix,
+ install_dir: get_option('libexecdir') / 'git-core',
+ pointing_to: 'git-remote-http',
+ )
+ endforeach
+endif
+
+imap_send_sources = ['imap-send.c']
+if use_curl_for_imap_send
+ imap_send_sources += curl_sources
+endif
+
+test_dependencies += executable('git-imap-send',
+ sources: imap_send_sources,
+ dependencies: [libgit, common_main],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+
+foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ]
+ bin_wrappers += executable(alias,
+ objects: git.extract_all_objects(recursive: false),
+ dependencies: [libgit, common_main],
+ )
+
+ install_symlink(alias + executable_suffix,
+ install_dir: get_option('libexecdir') / 'git-core',
+ pointing_to: 'git',
+ )
+endforeach
+
+foreach symlink : [
+ 'git',
+ 'git-receive-pack',
+ 'git-shell',
+ 'git-upload-archive',
+ 'git-upload-pack',
+ 'scalar',
+]
+ if meson.version().version_compare('>=1.3.0')
+ pointing_to = fs.relative_to(get_option('libexecdir') / 'git-core' / symlink, get_option('bindir'))
+ else
+ pointing_to = '../libexec/git-core' / symlink
+ endif
+
+ install_symlink(symlink,
+ install_dir: get_option('bindir'),
+ pointing_to: pointing_to,
+ )
+endforeach
+
+scripts_sh = [
+ 'git-difftool--helper.sh',
+ 'git-filter-branch.sh',
+ 'git-merge-octopus.sh',
+ 'git-merge-one-file.sh',
+ 'git-merge-resolve.sh',
+ 'git-mergetool--lib.sh',
+ 'git-mergetool.sh',
+ 'git-quiltimport.sh',
+ 'git-request-pull.sh',
+ 'git-sh-i18n.sh',
+ 'git-sh-setup.sh',
+ 'git-submodule.sh',
+ 'git-web--browse.sh',
+]
+if perl_features_enabled
+ scripts_sh += 'git-instaweb.sh'
+endif
+
+foreach script : scripts_sh
+ test_dependencies += custom_target(
+ input: script,
+ output: fs.stem(script),
+ command: [
+ shell,
+ meson.project_source_root() / 'generate-script.sh',
+ '@INPUT@',
+ '@OUTPUT@',
+ meson.project_build_root() / 'GIT-BUILD-OPTIONS',
+ ],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+ )
+endforeach
+
+if perl_features_enabled
+ scripts_perl = [
+ 'git-archimport.perl',
+ 'git-cvsexportcommit.perl',
+ 'git-cvsimport.perl',
+ 'git-cvsserver.perl',
+ 'git-send-email.perl',
+ 'git-svn.perl',
+ ]
+
+ pathsep = ':'
+ if host_machine.system() == 'windows'
+ pathsep = ';'
+ endif
+
+ perl_header_template = 'perl/header_templates/fixed_prefix.template.pl'
+ if get_option('runtime_prefix')
+ perl_header_template = 'perl/header_templates/runtime_prefix.template.pl'
+ endif
+
+ perl_header = configure_file(
+ input: perl_header_template,
+ output: 'GIT-PERL-HEADER',
+ configuration: {
+ 'GITEXECDIR_REL': get_option('libexecdir') / 'git-core',
+ 'PERLLIBDIR_REL': get_option('datadir') / 'perl5',
+ 'LOCALEDIR_REL': get_option('datadir') / 'locale',
+ 'INSTLIBDIR': get_option('datadir') / 'perl5',
+ 'PATHSEP': pathsep,
+ },
+ )
+
+ generate_perl_command = [
+ shell,
+ meson.project_source_root() / 'generate-perl.sh',
+ meson.project_build_root() / 'GIT-BUILD-OPTIONS',
+ git_version_file.full_path(),
+ perl_header,
+ '@INPUT@',
+ '@OUTPUT@',
+ ]
+
+ foreach script : scripts_perl
+ generated_script = custom_target(
+ input: script,
+ output: fs.stem(script),
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+ depends: [git_version_file],
+ )
+ test_dependencies += generated_script
+
+ if script == 'git-cvsserver.perl'
+ bin_wrappers += generated_script
+
+ if meson.version().version_compare('>=1.3.0')
+ pointing_to = fs.relative_to(get_option('libexecdir') / 'git-core' / fs.stem(script), get_option('bindir'))
+ else
+ pointing_to = '../libexec/git-core' / fs.stem(script)
+ endif
+
+ install_symlink(fs.stem(script),
+ install_dir: get_option('bindir'),
+ pointing_to: pointing_to,
+ )
+ endif
+ endforeach
+
+ subdir('perl')
+endif
+
+if python.found()
+ scripts_python = [
+ 'git-p4.py'
+ ]
+
+ foreach script : scripts_python
+ generated_python = custom_target(
+ input: script,
+ output: fs.stem(script),
+ command: [
+ shell,
+ meson.project_source_root() / 'generate-python.sh',
+ meson.project_build_root() / 'GIT-BUILD-OPTIONS',
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+ )
+ test_dependencies += generated_python
+ endforeach
+endif
+
+mergetools = [
+ 'mergetools/araxis',
+ 'mergetools/bc',
+ 'mergetools/codecompare',
+ 'mergetools/deltawalker',
+ 'mergetools/diffmerge',
+ 'mergetools/diffuse',
+ 'mergetools/ecmerge',
+ 'mergetools/emerge',
+ 'mergetools/examdiff',
+ 'mergetools/guiffy',
+ 'mergetools/gvimdiff',
+ 'mergetools/kdiff3',
+ 'mergetools/kompare',
+ 'mergetools/meld',
+ 'mergetools/nvimdiff',
+ 'mergetools/opendiff',
+ 'mergetools/p4merge',
+ 'mergetools/smerge',
+ 'mergetools/tkdiff',
+ 'mergetools/tortoisemerge',
+ 'mergetools/vimdiff',
+ 'mergetools/vscode',
+ 'mergetools/winmerge',
+ 'mergetools/xxdiff',
+]
+
+foreach mergetool : mergetools
+ install_data(mergetool, install_dir: get_option('libexecdir') / 'git-core' / 'mergetools')
+endforeach
+
+if intl.found()
+ subdir('po')
+endif
+subdir('contrib')
+subdir('gitweb')
+subdir('templates')
+
+# Everything but the bin-wrappers need to come before this target such that we
+# can properly set up test dependencies. The bin-wrappers themselves are set up
+# at configuration time, so these are fine.
+if get_option('tests')
+ subdir('t')
+endif
+
+subdir('bin-wrappers')
+if get_option('docs') != []
+ subdir('Documentation')
+endif
+
+summary({
+ 'curl': curl.found(),
+ 'expat': expat.found(),
+ 'gettext': intl.found(),
+ 'https': https_backend,
+ 'iconv': iconv.found(),
+ 'pcre2': pcre2.found(),
+ 'perl': perl_features_enabled,
+ 'python': python.found(),
+}, section: 'Auto-detected features')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000000..32a72139ba
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,81 @@
+# Configuration for how Git behaves at runtime.
+option('default_pager', type: 'string', value: 'less',
+ description: 'Fall-back pager.')
+option('default_editor', type: 'string', value: 'vi',
+ description: 'Fall-back editor.')
+option('gitconfig', type: 'string', value: '/etc/gitconfig',
+ description: 'Path to the global git configuration file.')
+option('gitattributes', type: 'string', value: '/etc/gitattributes',
+ description: 'Path to the global git attributes file.')
+option('pager_environment', type: 'string', value: 'LESS=FRX LV=-c',
+ description: 'Environment used when spawning the pager')
+option('perl_cpan_fallback', type: 'boolean', value: true,
+ description: 'Install bundled copies of CPAN modules that serve as a fallback in case the modules are not available on the system.')
+option('runtime_prefix', type: 'boolean', value: false,
+ description: 'Resolve ancillary tooling and support files relative to the location of the runtime binary instead of hard-coding them into the binary.')
+option('sane_tool_path', type: 'string', value: '',
+ description: 'A colon-separated list of paths to prepend to PATH if your tools in /usr/bin are broken.')
+
+# Features supported by Git.
+option('curl', type: 'feature', value: 'enabled',
+ description: 'Build helpers used to access remotes with the HTTP transport.')
+option('expat', type: 'feature', value: 'enabled',
+ description: 'Build helpers used to push to remotes with the HTTP transport.')
+option('gettext', type: 'feature', value: 'auto',
+ description: 'Build translation files.')
+option('iconv', type: 'feature', value: 'auto',
+ description: 'Support reencoding strings with different encodings.')
+option('pcre2', type: 'feature', value: 'enabled',
+ description: 'Support Perl-compatible regular expressions in e.g. git-grep(1).')
+option('perl', type: 'feature', value: 'auto',
+ description: 'Build tools written in Perl.')
+option('python', type: 'feature', value: 'auto',
+ description: 'Build tools written in Python.')
+option('regex', type: 'feature', value: 'auto',
+ description: 'Use the system-provided regex library instead of the bundled one.')
+
+# Backends.
+option('https_backend', type: 'combo', value: 'auto', choices: ['auto', 'openssl', 'CommonCrypto', 'none'],
+ description: 'The HTTPS backend to use when connecting to remotes.')
+option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'common-crypto'], value: 'sha1dc',
+ description: 'The backend used for hashing objects with the SHA1 object format')
+option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block',
+ description: 'The backend used for hashing objects with the SHA256 object format')
+
+# Build tweaks.
+option('macos_use_homebrew_gettext', type: 'boolean', value: true,
+ description: 'Use gettext from Homebrew instead of the slightly-broken system-provided one.')
+
+# gitweb configuration.
+option('gitweb_config', type: 'string', value: 'gitweb_config.perl')
+option('gitweb_config_system', type: 'string', value: '/etc/gitweb.conf')
+option('gitweb_config_common', type: 'string', value: '/etc/gitweb-common.conf')
+option('gitweb_home_link_str', type: 'string', value: 'projects')
+option('gitweb_sitename', type: 'string', value: '')
+option('gitweb_projectroot', type: 'string', value: '/pub/git')
+option('gitweb_project_maxdepth', type: 'string', value: '2007')
+option('gitweb_export_ok', type: 'string', value: '')
+option('gitweb_strict_export', type: 'string', value: '')
+option('gitweb_base_url', type: 'string', value: '')
+option('gitweb_list', type: 'string', value: '')
+option('gitweb_hometext', type: 'string', value: 'indextext.html')
+option('gitweb_css', type: 'string', value: 'static/gitweb.css')
+option('gitweb_logo', type: 'string', value: 'static/git-logo.png')
+option('gitweb_favicon', type: 'string', value: 'static/git-favicon.png')
+option('gitweb_js', type: 'string', value: 'static/gitweb.js')
+option('gitweb_site_html_head_string', type: 'string', value: '')
+option('gitweb_site_header', type: 'string', value: '')
+option('gitweb_site_footer', type: 'string', value: '')
+option('highlight_bin', type: 'string', value: 'highlight')
+
+# Documentation.
+option('docs', type: 'array', choices: ['man', 'html'], value: [],
+ description: 'Which documenattion formats to build and install.')
+option('default_help_format', type: 'combo', choices: ['man', 'html'], value: 'man',
+ description: 'Default format used when executing git-help(1).')
+
+# Testing.
+option('tests', type: 'boolean', value: true,
+ description: 'Enable building tests. This requires Perl, but is separate from the "perl" option such that you can build tests without Perl features enabled.')
+option('test_output_directory', type: 'string',
+ description: 'Path to the directory used to store test outputs')
diff --git a/midx-write.c b/midx-write.c
index f1a6f83bae..0066594fa6 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
@@ -36,13 +35,13 @@ extern void clear_incremental_midx_files_ext(const char *object_dir,
extern int cmp_idx_or_pack_name(const char *idx_or_pack_name,
const char *idx_name);
-static size_t write_midx_header(struct hashfile *f,
- unsigned char num_chunks,
+static size_t write_midx_header(const struct git_hash_algo *hash_algo,
+ struct hashfile *f, unsigned char num_chunks,
uint32_t num_packs)
{
hashwrite_be32(f, MIDX_SIGNATURE);
hashwrite_u8(f, MIDX_VERSION);
- hashwrite_u8(f, oid_version(the_hash_algo));
+ hashwrite_u8(f, oid_version(hash_algo));
hashwrite_u8(f, num_chunks);
hashwrite_u8(f, 0); /* unused */
hashwrite_be32(f, num_packs);
@@ -111,6 +110,8 @@ struct write_midx_context {
uint32_t num_multi_pack_indexes_before;
struct string_list *to_include;
+
+ struct repository *repo;
};
static int should_include_pack(const struct write_midx_context *ctx,
@@ -155,7 +156,7 @@ static void add_pack_to_midx(const char *full_path, size_t full_path_len,
return;
ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
- p = add_packed_git(full_path, full_path_len, 0);
+ p = add_packed_git(ctx->repo, full_path, full_path_len, 0);
if (!p) {
warning(_("failed to add packfile '%s'"),
full_path);
@@ -481,7 +482,7 @@ static int write_midx_oid_lookup(struct hashfile *f,
void *data)
{
struct write_midx_context *ctx = data;
- unsigned char hash_len = the_hash_algo->rawsz;
+ unsigned char hash_len = ctx->repo->hash_algo->rawsz;
struct pack_midx_entry *list = ctx->entries;
uint32_t i;
@@ -606,7 +607,7 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
uint32_t *pack_order, base_objects = 0;
uint32_t i;
- trace2_region_enter("midx", "midx_pack_order", the_repository);
+ trace2_region_enter("midx", "midx_pack_order", ctx->repo);
if (ctx->incremental && ctx->base_midx)
base_objects = ctx->base_midx->num_objects +
@@ -641,7 +642,7 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
}
free(data);
- trace2_region_leave("midx", "midx_pack_order", the_repository);
+ trace2_region_leave("midx", "midx_pack_order", ctx->repo);
return pack_order;
}
@@ -652,9 +653,10 @@ static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
struct strbuf buf = STRBUF_INIT;
char *tmp_file;
- trace2_region_enter("midx", "write_midx_reverse_index", the_repository);
+ trace2_region_enter("midx", "write_midx_reverse_index", ctx->repo);
- strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex(midx_hash));
+ strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex_algop(midx_hash,
+ ctx->repo->hash_algo));
tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr,
midx_hash, WRITE_REV);
@@ -665,7 +667,7 @@ static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
strbuf_release(&buf);
free(tmp_file);
- trace2_region_leave("midx", "write_midx_reverse_index", the_repository);
+ trace2_region_leave("midx", "write_midx_reverse_index", ctx->repo);
}
static void prepare_midx_packing_data(struct packing_data *pdata,
@@ -673,10 +675,10 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
{
uint32_t i;
- trace2_region_enter("midx", "prepare_midx_packing_data", the_repository);
+ trace2_region_enter("midx", "prepare_midx_packing_data", ctx->repo);
memset(pdata, 0, sizeof(struct packing_data));
- prepare_packing_data(the_repository, pdata);
+ prepare_packing_data(ctx->repo, pdata);
for (i = 0; i < ctx->entries_nr; i++) {
uint32_t pos = ctx->pack_order[i];
@@ -687,7 +689,7 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
ctx->info[ctx->pack_perm[from->pack_int_id]].p);
}
- trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
+ trace2_region_leave("midx", "prepare_midx_packing_data", ctx->repo);
}
static int add_ref_to_pending(const char *refname, const char *referent UNUSED,
@@ -703,7 +705,7 @@ static int add_ref_to_pending(const char *refname, const char *referent UNUSED,
return 0;
}
- if (!peel_iterated_oid(the_repository, oid, &peeled))
+ if (!peel_iterated_oid(revs->repo, oid, &peeled))
oid = &peeled;
object = parse_object_or_die(oid, refname);
@@ -761,7 +763,7 @@ static int read_refs_snapshot(const char *refs_snapshot,
hex = &buf.buf[1];
}
- if (parse_oid_hex(hex, &oid, &end) < 0)
+ if (parse_oid_hex_algop(hex, &oid, &end, revs->repo->hash_algo) < 0)
die(_("could not parse line: %s"), buf.buf);
if (*end)
die(_("malformed line: %s"), buf.buf);
@@ -777,6 +779,7 @@ static int read_refs_snapshot(const char *refs_snapshot,
strbuf_release(&buf);
return 0;
}
+
static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr_p,
const char *refs_snapshot,
struct write_midx_context *ctx)
@@ -784,17 +787,16 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
struct rev_info revs;
struct bitmap_commit_cb cb = {0};
- trace2_region_enter("midx", "find_commits_for_midx_bitmap",
- the_repository);
+ trace2_region_enter("midx", "find_commits_for_midx_bitmap", ctx->repo);
cb.ctx = ctx;
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(ctx->repo, &revs, NULL);
if (refs_snapshot) {
read_refs_snapshot(refs_snapshot, &revs);
} else {
setup_revisions(0, NULL, &revs, NULL);
- refs_for_each_ref(get_main_ref_store(the_repository),
+ refs_for_each_ref(get_main_ref_store(ctx->repo),
add_ref_to_pending, &revs);
}
@@ -822,13 +824,12 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
release_revisions(&revs);
- trace2_region_leave("midx", "find_commits_for_midx_bitmap",
- the_repository);
+ trace2_region_leave("midx", "find_commits_for_midx_bitmap", ctx->repo);
return cb.commits;
}
-static int write_midx_bitmap(const char *midx_name,
+static int write_midx_bitmap(struct repository *r, const char *midx_name,
const unsigned char *midx_hash,
struct packing_data *pdata,
struct commit **commits,
@@ -841,9 +842,9 @@ static int write_midx_bitmap(const char *midx_name,
struct bitmap_writer writer;
struct pack_idx_entry **index;
char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
- hash_to_hex(midx_hash));
+ hash_to_hex_algop(midx_hash, r->hash_algo));
- trace2_region_enter("midx", "write_midx_bitmap", the_repository);
+ trace2_region_enter("midx", "write_midx_bitmap", r);
if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
options |= BITMAP_OPT_HASH_CACHE;
@@ -860,7 +861,7 @@ static int write_midx_bitmap(const char *midx_name,
for (i = 0; i < pdata->nr_objects; i++)
index[i] = &pdata->objects[i].idx;
- bitmap_writer_init(&writer, the_repository, pdata);
+ bitmap_writer_init(&writer, r, pdata);
bitmap_writer_show_progress(&writer, flags & MIDX_PROGRESS);
bitmap_writer_build_type_index(&writer, index);
@@ -893,7 +894,7 @@ cleanup:
free(bitmap_name);
bitmap_writer_free(&writer);
- trace2_region_leave("midx", "write_midx_bitmap", the_repository);
+ trace2_region_leave("midx", "write_midx_bitmap", r);
return ret;
}
@@ -945,7 +946,7 @@ static int fill_packs_from_midx(struct write_midx_context *ctx,
*/
if (flags & MIDX_WRITE_REV_INDEX ||
preferred_pack_name) {
- if (prepare_midx_pack(the_repository, m,
+ if (prepare_midx_pack(ctx->repo, m,
m->num_packs_in_base + i)) {
error(_("could not load pack"));
return 1;
@@ -992,9 +993,10 @@ static int link_midx_to_chain(struct multi_pack_index *m)
for (i = 0; i < ARRAY_SIZE(midx_exts); i++) {
const unsigned char *hash = get_midx_checksum(m);
- get_midx_filename_ext(&from, m->object_dir, hash,
- midx_exts[i].non_split);
- get_split_midx_filename_ext(&to, m->object_dir, hash,
+ get_midx_filename_ext(m->repo->hash_algo, &from, m->object_dir,
+ hash, midx_exts[i].non_split);
+ get_split_midx_filename_ext(m->repo->hash_algo, &to,
+ m->object_dir, hash,
midx_exts[i].split);
if (link(from.buf, to.buf) < 0 && errno != ENOENT) {
@@ -1013,9 +1015,8 @@ done:
return ret;
}
-static void clear_midx_files(const char *object_dir,
- const char **hashes,
- uint32_t hashes_nr,
+static void clear_midx_files(struct repository *r, const char *object_dir,
+ const char **hashes, uint32_t hashes_nr,
unsigned incremental)
{
/*
@@ -1040,7 +1041,7 @@ static void clear_midx_files(const char *object_dir,
}
if (incremental)
- get_midx_filename(&buf, object_dir);
+ get_midx_filename(r->hash_algo, &buf, object_dir);
else
get_midx_chain_filename(&buf, object_dir);
@@ -1050,7 +1051,7 @@ static void clear_midx_files(const char *object_dir,
strbuf_release(&buf);
}
-static int write_midx_internal(const char *object_dir,
+static int write_midx_internal(struct repository *r, const char *object_dir,
struct string_list *packs_to_include,
struct string_list *packs_to_drop,
const char *preferred_pack_name,
@@ -1071,7 +1072,9 @@ static int write_midx_internal(const char *object_dir,
const char **keep_hashes = NULL;
struct chunkfile *cf;
- trace2_region_enter("midx", "write_midx_internal", the_repository);
+ trace2_region_enter("midx", "write_midx_internal", r);
+
+ ctx.repo = r;
ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL);
if (ctx.incremental && (flags & MIDX_WRITE_BITMAP))
@@ -1082,14 +1085,13 @@ static int write_midx_internal(const char *object_dir,
"%s/pack/multi-pack-index.d/tmp_midx_XXXXXX",
object_dir);
else
- get_midx_filename(&midx_name, object_dir);
+ get_midx_filename(r->hash_algo, &midx_name, object_dir);
if (safe_create_leading_directories(midx_name.buf))
die_errno(_("unable to create leading directories of %s"),
midx_name.buf);
if (!packs_to_include || ctx.incremental) {
- struct multi_pack_index *m = lookup_multi_pack_index(the_repository,
- object_dir);
+ struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
if (m && !midx_checksum_valid(m)) {
warning(_("ignoring existing multi-pack-index; checksum mismatch"));
m = NULL;
@@ -1352,7 +1354,7 @@ static int write_midx_internal(const char *object_dir,
add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE,
write_midx_oid_fanout);
add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP,
- st_mult(ctx.entries_nr, the_hash_algo->rawsz),
+ st_mult(ctx.entries_nr, r->hash_algo->rawsz),
write_midx_oid_lookup);
add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS,
st_mult(ctx.entries_nr, MIDX_CHUNK_OFFSET_WIDTH),
@@ -1374,7 +1376,8 @@ static int write_midx_internal(const char *object_dir,
write_midx_bitmapped_packs);
}
- write_midx_header(f, get_num_chunks(cf), ctx.nr - dropped_packs);
+ write_midx_header(r->hash_algo, f, get_num_chunks(cf),
+ ctx.nr - dropped_packs);
write_chunkfile(cf, &ctx);
finalize_hashfile(f, midx_hash, FSYNC_COMPONENT_PACK_METADATA,
@@ -1406,7 +1409,7 @@ static int write_midx_internal(const char *object_dir,
FREE_AND_NULL(ctx.entries);
ctx.entries_nr = 0;
- if (write_midx_bitmap(midx_name.buf, midx_hash, &pdata,
+ if (write_midx_bitmap(r, midx_name.buf, midx_hash, &pdata,
commits, commits_nr, ctx.pack_order,
flags) < 0) {
error(_("could not write multi-pack bitmap"));
@@ -1439,8 +1442,8 @@ static int write_midx_internal(const char *object_dir,
if (link_midx_to_chain(ctx.base_midx) < 0)
return -1;
- get_split_midx_filename_ext(&final_midx_name, object_dir,
- midx_hash, MIDX_EXT_MIDX);
+ get_split_midx_filename_ext(r->hash_algo, &final_midx_name,
+ object_dir, midx_hash, MIDX_EXT_MIDX);
if (rename_tempfile(&incr, final_midx_name.buf) < 0) {
error_errno(_("unable to rename new multi-pack-index layer"));
@@ -1450,12 +1453,13 @@ static int write_midx_internal(const char *object_dir,
strbuf_release(&final_midx_name);
keep_hashes[ctx.num_multi_pack_indexes_before] =
- xstrdup(hash_to_hex(midx_hash));
+ xstrdup(hash_to_hex_algop(midx_hash, r->hash_algo));
for (i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
uint32_t j = ctx.num_multi_pack_indexes_before - i - 1;
- keep_hashes[j] = xstrdup(hash_to_hex(get_midx_checksum(m)));
+ keep_hashes[j] = xstrdup(hash_to_hex_algop(get_midx_checksum(m),
+ r->hash_algo));
m = m->base_midx;
}
@@ -1463,16 +1467,16 @@ static int write_midx_internal(const char *object_dir,
fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]);
} else {
keep_hashes[ctx.num_multi_pack_indexes_before] =
- xstrdup(hash_to_hex(midx_hash));
+ xstrdup(hash_to_hex_algop(midx_hash, r->hash_algo));
}
if (ctx.m || ctx.base_midx)
- close_object_store(the_repository->objects);
+ close_object_store(ctx.repo->objects);
if (commit_lock_file(&lk) < 0)
die_errno(_("could not write multi-pack-index"));
- clear_midx_files(object_dir, keep_hashes,
+ clear_midx_files(r, object_dir, keep_hashes,
ctx.num_multi_pack_indexes_before + 1,
ctx.incremental);
@@ -1496,27 +1500,26 @@ cleanup:
}
strbuf_release(&midx_name);
- trace2_region_leave("midx", "write_midx_internal", the_repository);
+ trace2_region_leave("midx", "write_midx_internal", r);
return result;
}
-int write_midx_file(const char *object_dir,
+int write_midx_file(struct repository *r, const char *object_dir,
const char *preferred_pack_name,
- const char *refs_snapshot,
- unsigned flags)
+ const char *refs_snapshot, unsigned flags)
{
- return write_midx_internal(object_dir, NULL, NULL, preferred_pack_name,
- refs_snapshot, flags);
+ return write_midx_internal(r, object_dir, NULL, NULL,
+ preferred_pack_name, refs_snapshot,
+ flags);
}
-int write_midx_file_only(const char *object_dir,
+int write_midx_file_only(struct repository *r, const char *object_dir,
struct string_list *packs_to_include,
const char *preferred_pack_name,
- const char *refs_snapshot,
- unsigned flags)
+ const char *refs_snapshot, unsigned flags)
{
- return write_midx_internal(object_dir, packs_to_include, NULL,
+ return write_midx_internal(r, object_dir, packs_to_include, NULL,
preferred_pack_name, refs_snapshot, flags);
}
@@ -1573,7 +1576,8 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
free(count);
if (packs_to_drop.nr)
- result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, NULL, flags);
+ result = write_midx_internal(r, object_dir, NULL,
+ &packs_to_drop, NULL, NULL, flags);
string_list_clear(&packs_to_drop, 0);
@@ -1770,7 +1774,8 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
goto cleanup;
}
- result = write_midx_internal(object_dir, NULL, NULL, NULL, NULL, flags);
+ result = write_midx_internal(r, object_dir, NULL, NULL, NULL, NULL,
+ flags);
cleanup:
free(include_pack);
diff --git a/midx.c b/midx.c
index 504e03327a..f8a75cafd4 100644
--- a/midx.c
+++ b/midx.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
@@ -26,20 +25,22 @@ int cmp_idx_or_pack_name(const char *idx_or_pack_name,
const unsigned char *get_midx_checksum(struct multi_pack_index *m)
{
- return m->data + m->data_len - the_hash_algo->rawsz;
+ return m->data + m->data_len - m->repo->hash_algo->rawsz;
}
-void get_midx_filename(struct strbuf *out, const char *object_dir)
+void get_midx_filename(const struct git_hash_algo *hash_algo,
+ struct strbuf *out, const char *object_dir)
{
- get_midx_filename_ext(out, object_dir, NULL, NULL);
+ get_midx_filename_ext(hash_algo, out, object_dir, NULL, NULL);
}
-void get_midx_filename_ext(struct strbuf *out, const char *object_dir,
+void get_midx_filename_ext(const struct git_hash_algo *hash_algo,
+ struct strbuf *out, const char *object_dir,
const unsigned char *hash, const char *ext)
{
strbuf_addf(out, "%s/pack/multi-pack-index", object_dir);
if (ext)
- strbuf_addf(out, "-%s.%s", hash_to_hex(hash), ext);
+ strbuf_addf(out, "-%s.%s", hash_to_hex_algop(hash, hash_algo), ext);
}
static int midx_read_oid_fanout(const unsigned char *chunk_start,
@@ -93,9 +94,8 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
return 0;
}
-#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
-
-static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir,
+static struct multi_pack_index *load_multi_pack_index_one(struct repository *r,
+ const char *object_dir,
const char *midx_name,
int local)
{
@@ -120,7 +120,7 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir
midx_size = xsize_t(st.st_size);
- if (midx_size < MIDX_MIN_SIZE) {
+ if (midx_size < (MIDX_HEADER_SIZE + r->hash_algo->rawsz)) {
error(_("multi-pack-index file %s is too small"), midx_name);
goto cleanup_fail;
}
@@ -132,6 +132,7 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir
m->data = midx_map;
m->data_len = midx_size;
m->local = local;
+ m->repo = r;
m->signature = get_be32(m->data);
if (m->signature != MIDX_SIGNATURE)
@@ -144,12 +145,12 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir
m->version);
hash_version = m->data[MIDX_BYTE_HASH_VERSION];
- if (hash_version != oid_version(the_hash_algo)) {
+ if (hash_version != oid_version(r->hash_algo)) {
error(_("multi-pack-index hash version %u does not match version %u"),
- hash_version, oid_version(the_hash_algo));
+ hash_version, oid_version(r->hash_algo));
goto cleanup_fail;
}
- m->hash_len = the_hash_algo->rawsz;
+ m->hash_len = r->hash_algo->rawsz;
m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS];
@@ -206,8 +207,8 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir
m->pack_names[i]);
}
- trace2_data_intmax("midx", the_repository, "load/num_packs", m->num_packs);
- trace2_data_intmax("midx", the_repository, "load/num_objects", m->num_objects);
+ trace2_data_intmax("midx", r, "load/num_packs", m->num_packs);
+ trace2_data_intmax("midx", r, "load/num_objects", m->num_objects);
free_chunkfile(cf);
return m;
@@ -233,15 +234,18 @@ void get_midx_chain_filename(struct strbuf *buf, const char *object_dir)
strbuf_addstr(buf, "/multi-pack-index-chain");
}
-void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+void get_split_midx_filename_ext(const struct git_hash_algo *hash_algo,
+ struct strbuf *buf, const char *object_dir,
const unsigned char *hash, const char *ext)
{
get_midx_chain_dirname(buf, object_dir);
- strbuf_addf(buf, "/multi-pack-index-%s.%s", hash_to_hex(hash), ext);
+ strbuf_addf(buf, "/multi-pack-index-%s.%s",
+ hash_to_hex_algop(hash, hash_algo), ext);
}
-static int open_multi_pack_index_chain(const char *chain_file,
- int *fd, struct stat *st)
+static int open_multi_pack_index_chain(const struct git_hash_algo *hash_algo,
+ const char *chain_file, int *fd,
+ struct stat *st)
{
*fd = git_open(chain_file);
if (*fd < 0)
@@ -250,7 +254,7 @@ static int open_multi_pack_index_chain(const char *chain_file,
close(*fd);
return 0;
}
- if (st->st_size < the_hash_algo->hexsz) {
+ if (st->st_size < hash_algo->hexsz) {
close(*fd);
if (!st->st_size) {
/* treat empty files the same as missing */
@@ -292,7 +296,8 @@ static int add_midx_to_chain(struct multi_pack_index *midx,
return 1;
}
-static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
+static struct multi_pack_index *load_midx_chain_fd_st(struct repository *r,
+ const char *object_dir,
int local,
int fd, struct stat *st,
int *incomplete_chain)
@@ -303,7 +308,7 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
uint32_t i, count;
FILE *fp = xfdopen(fd, "r");
- count = st->st_size / (the_hash_algo->hexsz + 1);
+ count = st->st_size / (r->hash_algo->hexsz + 1);
for (i = 0; i < count; i++) {
struct multi_pack_index *m;
@@ -312,7 +317,7 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
if (strbuf_getline_lf(&buf, fp) == EOF)
break;
- if (get_oid_hex(buf.buf, &layer)) {
+ if (get_oid_hex_algop(buf.buf, &layer, r->hash_algo)) {
warning(_("invalid multi-pack-index chain: line '%s' "
"not a hash"),
buf.buf);
@@ -323,9 +328,9 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
valid = 0;
strbuf_reset(&buf);
- get_split_midx_filename_ext(&buf, object_dir, layer.hash,
- MIDX_EXT_MIDX);
- m = load_multi_pack_index_one(object_dir, buf.buf, local);
+ get_split_midx_filename_ext(r->hash_algo, &buf, object_dir,
+ layer.hash, MIDX_EXT_MIDX);
+ m = load_multi_pack_index_one(r, object_dir, buf.buf, local);
if (m) {
if (add_midx_to_chain(m, midx_chain)) {
@@ -348,7 +353,8 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
return midx_chain;
}
-static struct multi_pack_index *load_multi_pack_index_chain(const char *object_dir,
+static struct multi_pack_index *load_multi_pack_index_chain(struct repository *r,
+ const char *object_dir,
int local)
{
struct strbuf chain_file = STRBUF_INIT;
@@ -357,10 +363,10 @@ static struct multi_pack_index *load_multi_pack_index_chain(const char *object_d
struct multi_pack_index *m = NULL;
get_midx_chain_filename(&chain_file, object_dir);
- if (open_multi_pack_index_chain(chain_file.buf, &fd, &st)) {
+ if (open_multi_pack_index_chain(r->hash_algo, chain_file.buf, &fd, &st)) {
int incomplete;
/* ownership of fd is taken over by load function */
- m = load_midx_chain_fd_st(object_dir, local, fd, &st,
+ m = load_midx_chain_fd_st(r, object_dir, local, fd, &st,
&incomplete);
}
@@ -368,17 +374,19 @@ static struct multi_pack_index *load_multi_pack_index_chain(const char *object_d
return m;
}
-struct multi_pack_index *load_multi_pack_index(const char *object_dir,
+struct multi_pack_index *load_multi_pack_index(struct repository *r,
+ const char *object_dir,
int local)
{
struct strbuf midx_name = STRBUF_INIT;
struct multi_pack_index *m;
- get_midx_filename(&midx_name, object_dir);
+ get_midx_filename(r->hash_algo, &midx_name, object_dir);
- m = load_multi_pack_index_one(object_dir, midx_name.buf, local);
+ m = load_multi_pack_index_one(r, object_dir,
+ midx_name.buf, local);
if (!m)
- m = load_multi_pack_index_chain(object_dir, local);
+ m = load_multi_pack_index_chain(r, object_dir, local);
strbuf_release(&midx_name);
@@ -465,7 +473,7 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m,
strhash(key.buf), key.buf,
struct packed_git, packmap_ent);
if (!p) {
- p = add_packed_git(pack_name.buf, pack_name.len, m->local);
+ p = add_packed_git(r, pack_name.buf, pack_name.len, m->local);
if (p) {
install_packed_git(r, p);
list_add_tail(&p->mru, &r->objects->packed_git_mru);
@@ -520,7 +528,7 @@ int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
uint32_t *result)
{
int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout,
- m->chunk_oid_lookup, the_hash_algo->rawsz,
+ m->chunk_oid_lookup, m->repo->hash_algo->rawsz,
result);
if (result)
*result += m->num_objects_in_base;
@@ -551,7 +559,7 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid,
n = midx_for_object(&m, n);
oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n),
- the_repository->hash_algo);
+ m->repo->hash_algo);
return oid;
}
@@ -722,7 +730,7 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i
if (!strcmp(object_dir, m_search->object_dir))
return 1;
- m = load_multi_pack_index(object_dir, local);
+ m = load_multi_pack_index(r, object_dir, local);
if (m) {
struct multi_pack_index *mp = r->objects->multi_pack_index;
@@ -816,7 +824,7 @@ void clear_midx_file(struct repository *r)
{
struct strbuf midx = STRBUF_INIT;
- get_midx_filename(&midx, r->objects->odb->path);
+ get_midx_filename(r->hash_algo, &midx, r->objects->odb->path);
if (r->objects && r->objects->multi_pack_index) {
close_midx(r->objects->multi_pack_index);
@@ -876,7 +884,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
struct pair_pos_vs_id *pairs = NULL;
uint32_t i;
struct progress *progress = NULL;
- struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+ struct multi_pack_index *m = load_multi_pack_index(r, object_dir, 1);
struct multi_pack_index *curr;
verify_midx_error = 0;
@@ -885,7 +893,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
struct stat sb;
struct strbuf filename = STRBUF_INIT;
- get_midx_filename(&filename, object_dir);
+ get_midx_filename(r->hash_algo, &filename, object_dir);
if (!stat(filename.buf, &sb)) {
error(_("multi-pack-index file exists, but failed to parse"));
diff --git a/midx.h b/midx.h
index 42d4f8d149..9d1374cbd5 100644
--- a/midx.h
+++ b/midx.h
@@ -7,6 +7,7 @@ struct object_id;
struct pack_entry;
struct repository;
struct bitmapped_pack;
+struct git_hash_algo;
#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
#define MIDX_VERSION 1
@@ -71,6 +72,9 @@ struct multi_pack_index {
const char **pack_names;
struct packed_git **packs;
+
+ struct repository *repo;
+
char object_dir[FLEX_ARRAY];
};
@@ -86,15 +90,20 @@ struct multi_pack_index {
#define MIDX_EXT_MIDX "midx"
const unsigned char *get_midx_checksum(struct multi_pack_index *m);
-void get_midx_filename(struct strbuf *out, const char *object_dir);
-void get_midx_filename_ext(struct strbuf *out, const char *object_dir,
+void get_midx_filename(const struct git_hash_algo *hash_algo,
+ struct strbuf *out, const char *object_dir);
+void get_midx_filename_ext(const struct git_hash_algo *hash_algo,
+ struct strbuf *out, const char *object_dir,
const unsigned char *hash, const char *ext);
void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir);
void get_midx_chain_filename(struct strbuf *buf, const char *object_dir);
-void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+void get_split_midx_filename_ext(const struct git_hash_algo *hash_algo,
+ struct strbuf *buf, const char *object_dir,
const unsigned char *hash, const char *ext);
-struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local);
+struct multi_pack_index *load_multi_pack_index(struct repository *r,
+ const char *object_dir,
+ int local);
int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id);
struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
uint32_t pack_int_id);
@@ -120,15 +129,13 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i
* Variant of write_midx_file which writes a MIDX containing only the packs
* specified in packs_to_include.
*/
-int write_midx_file(const char *object_dir,
- const char *preferred_pack_name,
- const char *refs_snapshot,
+int write_midx_file(struct repository *r, const char *object_dir,
+ const char *preferred_pack_name, const char *refs_snapshot,
unsigned flags);
-int write_midx_file_only(const char *object_dir,
+int write_midx_file_only(struct repository *r, const char *object_dir,
struct string_list *packs_to_include,
const char *preferred_pack_name,
- const char *refs_snapshot,
- unsigned flags);
+ const char *refs_snapshot, unsigned flags);
void clear_midx_file(struct repository *r);
int verify_midx_file(struct repository *r, const char *object_dir, unsigned flags);
int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags);
diff --git a/object-name.c b/object-name.c
index d396778efc..88d1313028 100644
--- a/object-name.c
+++ b/object-name.c
@@ -953,7 +953,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
"\n"
"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
"examine these refs and maybe delete them. Turn this message off by\n"
- "running \"git config advice.objectNameWarning false\"");
+ "running \"git config set advice.objectNameWarning false\"");
struct object_id tmp_oid;
char *real_ref = NULL;
int refs_found = 0;
@@ -1402,7 +1402,7 @@ static int get_oid_oneline(struct repository *r,
const char *prefix, struct object_id *oid,
const struct commit_list *list)
{
- struct commit_list *copy = NULL;
+ struct commit_list *copy = NULL, **copy_tail = &copy;
const struct commit_list *l;
int found = 0;
int negative = 0;
@@ -1424,7 +1424,7 @@ static int get_oid_oneline(struct repository *r,
for (l = list; l; l = l->next) {
l->item->object.flags |= ONELINE_SEEN;
- commit_list_insert(l->item, &copy);
+ copy_tail = &commit_list_insert(l->item, copy_tail)->next;
}
while (copy) {
const char *p, *buf;
@@ -1735,42 +1735,6 @@ int repo_interpret_branch_name(struct repository *r,
return -1;
}
-void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed)
-{
- int len = strlen(name);
- struct interpret_branch_name_options options = {
- .allowed = allowed
- };
- int used = repo_interpret_branch_name(the_repository, name, len, sb,
- &options);
-
- if (used < 0)
- used = 0;
- strbuf_add(sb, name + used, len - used);
-}
-
-int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
-{
- if (startup_info->have_repository)
- strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL);
- else
- strbuf_addstr(sb, name);
-
- /*
- * This splice must be done even if we end up rejecting the
- * name; builtin/branch.c::copy_or_rename_branch() still wants
- * to see what the name expanded to so that "branch -m" can be
- * used as a tool to correct earlier mistakes.
- */
- strbuf_splice(sb, 0, 0, "refs/heads/", 11);
-
- if (*name == '-' ||
- !strcmp(sb->buf, "refs/heads/HEAD"))
- return -1;
-
- return check_refname_format(sb->buf, 0);
-}
-
void object_context_release(struct object_context *ctx)
{
free(ctx->path);
diff --git a/object-store-ll.h b/object-store-ll.h
index 53b8e693b1..cd3bd5bd99 100644
--- a/object-store-ll.h
+++ b/object-store-ll.h
@@ -10,6 +10,7 @@
struct oidmap;
struct oidtree;
struct strbuf;
+struct repository;
struct object_directory {
struct object_directory *next;
@@ -135,6 +136,10 @@ struct packed_git {
*/
const uint32_t *mtimes_map;
size_t mtimes_size;
+
+ /* repo denotes the repository this packfile belongs to */
+ struct repository *repo;
+
/* something like ".git/objects/pack/xxxxx.pack" */
char pack_name[FLEX_ARRAY]; /* more */
};
@@ -545,7 +550,7 @@ typedef int each_packed_object_fn(const struct object_id *oid,
int for_each_object_in_pack(struct packed_git *p,
each_packed_object_fn, void *data,
enum for_each_object_flags flags);
-int for_each_packed_object(each_packed_object_fn, void *,
- enum for_each_object_flags flags);
+int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
+ void *data, enum for_each_object_flags flags);
#endif /* OBJECT_STORE_LL_H */
diff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore
index a877c11f42..f2d74de457 100644
--- a/oss-fuzz/.gitignore
+++ b/oss-fuzz/.gitignore
@@ -1,5 +1,8 @@
fuzz-commit-graph
fuzz-config
+fuzz-credential-from-url-gently
fuzz-date
fuzz-pack-headers
fuzz-pack-idx
+fuzz-parse-attr-line
+fuzz-url-decode-mem
diff --git a/oss-fuzz/fuzz-credential-from-url-gently.c b/oss-fuzz/fuzz-credential-from-url-gently.c
new file mode 100644
index 0000000000..c872f9ad2d
--- /dev/null
+++ b/oss-fuzz/fuzz-credential-from-url-gently.c
@@ -0,0 +1,32 @@
+#include "git-compat-util.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include "credential.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ struct credential c;
+ char *buf;
+
+ buf = malloc(size + 1);
+ if (!buf)
+ return 0;
+
+ memcpy(buf, data, size);
+ buf[size] = 0;
+
+ // start fuzzing
+ credential_init(&c);
+ credential_from_url_gently(&c, buf, 1);
+
+ // cleanup
+ credential_clear(&c);
+ free(buf);
+
+ return 0;
+}
diff --git a/oss-fuzz/fuzz-parse-attr-line.c b/oss-fuzz/fuzz-parse-attr-line.c
new file mode 100644
index 0000000000..e0e4bc6358
--- /dev/null
+++ b/oss-fuzz/fuzz-parse-attr-line.c
@@ -0,0 +1,41 @@
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "attr.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ struct match_attr *res;
+ char *buf;
+
+ buf = malloc(size + 1);
+ if (!buf)
+ return 0;
+
+ memcpy(buf, data, size);
+ buf[size] = 0;
+
+ res = parse_attr_line(buf, "dummy", 0, 0);
+
+ if (res) {
+ int j;
+ for (j = 0; j < res->num_attr; j++) {
+ const char *setto = res->state[j].setto;
+ if (ATTR_TRUE(setto) || ATTR_FALSE(setto) ||
+ ATTR_UNSET(setto))
+ ;
+ else
+ free((char *)setto);
+ }
+ free(res);
+ }
+ free(buf);
+
+ return 0;
+}
diff --git a/oss-fuzz/fuzz-url-decode-mem.c b/oss-fuzz/fuzz-url-decode-mem.c
new file mode 100644
index 0000000000..2342aa993b
--- /dev/null
+++ b/oss-fuzz/fuzz-url-decode-mem.c
@@ -0,0 +1,43 @@
+#include "git-compat-util.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include "url.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ char *buf;
+ char *r;
+ const char *pbuf;
+
+ buf = malloc(size + 1);
+ if (!buf)
+ return 0;
+
+ memcpy(buf, data, size);
+ buf[size] = 0;
+
+ // start fuzzing
+ r = url_decode(buf);
+ free(r);
+
+ r = url_percent_decode(buf);
+ free(r);
+
+ pbuf = (const char*) buf;
+ r = url_decode_parameter_name(&pbuf);
+ free(r);
+
+ pbuf = (const char*) buf;
+ r = url_decode_parameter_value(&pbuf);
+ free(r);
+
+ // cleanup
+ free(buf);
+
+ return 0;
+}
diff --git a/pack-bitmap.c b/pack-bitmap.c
index bbcf7e9401..bceb6da042 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
@@ -178,12 +177,21 @@ static uint32_t bitmap_num_objects(struct bitmap_index *index)
return index->pack->num_objects;
}
+static struct repository *bitmap_repo(struct bitmap_index *bitmap_git)
+{
+ if (bitmap_is_midx(bitmap_git))
+ return bitmap_git->midx->repo;
+ return bitmap_git->pack->repo;
+}
+
static int load_bitmap_header(struct bitmap_index *index)
{
struct bitmap_disk_header *header = (void *)index->map;
- size_t header_size = sizeof(*header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz;
+ const struct git_hash_algo *hash_algo = bitmap_repo(index)->hash_algo;
- if (index->map_size < header_size + the_hash_algo->rawsz)
+ size_t header_size = sizeof(*header) - GIT_MAX_RAWSZ + hash_algo->rawsz;
+
+ if (index->map_size < header_size + hash_algo->rawsz)
return error(_("corrupted bitmap index (too small)"));
if (memcmp(header->magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)) != 0)
@@ -197,7 +205,7 @@ static int load_bitmap_header(struct bitmap_index *index)
{
uint32_t flags = ntohs(header->options);
size_t cache_size = st_mult(bitmap_num_objects(index), sizeof(uint32_t));
- unsigned char *index_end = index->map + index->map_size - the_hash_algo->rawsz;
+ unsigned char *index_end = index->map + index->map_size - hash_algo->rawsz;
if ((flags & BITMAP_OPT_FULL_DAG) == 0)
BUG("unsupported options for bitmap index file "
@@ -369,8 +377,8 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
char *midx_bitmap_filename(struct multi_pack_index *midx)
{
struct strbuf buf = STRBUF_INIT;
- get_midx_filename_ext(&buf, midx->object_dir, get_midx_checksum(midx),
- MIDX_EXT_BITMAP);
+ get_midx_filename_ext(midx->repo->hash_algo, &buf, midx->object_dir,
+ get_midx_checksum(midx), MIDX_EXT_BITMAP);
return strbuf_detach(&buf, NULL);
}
@@ -409,8 +417,8 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
if (bitmap_git->pack || bitmap_git->midx) {
struct strbuf buf = STRBUF_INIT;
- get_midx_filename(&buf, midx->object_dir);
- trace2_data_string("bitmap", the_repository,
+ get_midx_filename(midx->repo->hash_algo, &buf, midx->object_dir);
+ trace2_data_string("bitmap", bitmap_repo(bitmap_git),
"ignoring extra midx bitmap file", buf.buf);
close(fd);
strbuf_release(&buf);
@@ -428,7 +436,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
goto cleanup;
if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum,
- the_repository->hash_algo)) {
+ bitmap_repo(bitmap_git)->hash_algo)) {
error(_("checksum doesn't match in MIDX and bitmap"));
goto cleanup;
}
@@ -439,7 +447,9 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
}
for (i = 0; i < bitmap_git->midx->num_packs; i++) {
- if (prepare_midx_pack(the_repository, bitmap_git->midx, i)) {
+ if (prepare_midx_pack(bitmap_repo(bitmap_git),
+ bitmap_git->midx,
+ i)) {
warning(_("could not open pack %s"),
bitmap_git->midx->pack_names[i]);
goto cleanup;
@@ -493,8 +503,9 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
}
if (bitmap_git->pack || bitmap_git->midx) {
- trace2_data_string("bitmap", the_repository,
- "ignoring extra bitmap file", packfile->pack_name);
+ trace2_data_string("bitmap", bitmap_repo(bitmap_git),
+ "ignoring extra bitmap file",
+ packfile->pack_name);
close(fd);
return -1;
}
@@ -519,8 +530,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
return -1;
}
- trace2_data_string("bitmap", the_repository, "opened bitmap file",
- packfile->pack_name);
+ trace2_data_string("bitmap", bitmap_repo(bitmap_git),
+ "opened bitmap file", packfile->pack_name);
return 0;
}
@@ -650,7 +661,7 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx)
{
- struct repository *r = the_repository;
+ struct repository *r = midx->repo;
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(r, bitmap_git))
@@ -1214,6 +1225,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
{
struct bitmap_boundary_cb cb;
struct object_list *root;
+ struct repository *repo;
unsigned int i;
unsigned int tmp_blobs, tmp_trees, tmp_tags;
int any_missing = 0;
@@ -1223,6 +1235,8 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
cb.base = bitmap_new();
object_array_init(&cb.boundary);
+ repo = bitmap_repo(bitmap_git);
+
revs->ignore_missing_links = 1;
if (bitmap_git->pseudo_merges.nr) {
@@ -1281,19 +1295,19 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
* revision walk to (a) OR in any bitmaps that are UNINTERESTING
* between the tips and boundary, and (b) record the boundary.
*/
- trace2_region_enter("pack-bitmap", "boundary-prepare", the_repository);
+ trace2_region_enter("pack-bitmap", "boundary-prepare", repo);
if (prepare_revision_walk(revs))
die("revision walk setup failed");
- trace2_region_leave("pack-bitmap", "boundary-prepare", the_repository);
+ trace2_region_leave("pack-bitmap", "boundary-prepare", repo);
- trace2_region_enter("pack-bitmap", "boundary-traverse", the_repository);
+ trace2_region_enter("pack-bitmap", "boundary-traverse", repo);
revs->boundary = 1;
traverse_commit_list_filtered(revs,
show_boundary_commit,
show_boundary_object,
&cb, NULL);
revs->boundary = 0;
- trace2_region_leave("pack-bitmap", "boundary-traverse", the_repository);
+ trace2_region_leave("pack-bitmap", "boundary-traverse", repo);
revs->blob_objects = tmp_blobs;
revs->tree_objects = tmp_trees;
@@ -1305,7 +1319,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
/*
* Then add the boundary commit(s) as fill-in traversal tips.
*/
- trace2_region_enter("pack-bitmap", "boundary-fill-in", the_repository);
+ trace2_region_enter("pack-bitmap", "boundary-fill-in", repo);
for (i = 0; i < cb.boundary.nr; i++) {
struct object *obj = cb.boundary.objects[i].item;
if (bitmap_walk_contains(bitmap_git, cb.base, &obj->oid))
@@ -1315,7 +1329,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
}
if (revs->pending.nr)
cb.base = fill_in_bitmap(bitmap_git, revs, cb.base, NULL);
- trace2_region_leave("pack-bitmap", "boundary-fill-in", the_repository);
+ trace2_region_leave("pack-bitmap", "boundary-fill-in", repo);
cleanup:
object_array_clear(&cb.boundary);
@@ -1719,7 +1733,8 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
ofs = pack_pos_to_offset(pack, pos);
}
- if (packed_object_info(the_repository, pack, ofs, &oi) < 0) {
+ if (packed_object_info(bitmap_repo(bitmap_git), pack, ofs,
+ &oi) < 0) {
struct object_id oid;
nth_bitmap_object_oid(bitmap_git, &oid,
pack_pos_to_index(pack, pos));
@@ -1728,7 +1743,8 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
} else {
struct eindex *eindex = &bitmap_git->ext_index;
struct object *obj = eindex->objects[pos - bitmap_num_objects(bitmap_git)];
- if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
+ if (oid_object_info_extended(bitmap_repo(bitmap_git), &obj->oid,
+ &oi, 0) < 0)
die(_("unable to get size of %s"), oid_to_hex(&obj->oid));
}
@@ -1890,7 +1906,8 @@ static void filter_packed_objects_from_bitmap(struct bitmap_index *bitmap_git,
bitmap_unset(result, i);
for (i = 0; i < eindex->count; ++i) {
- if (has_object_pack(&eindex->objects[i]->oid))
+ if (has_object_pack(bitmap_repo(bitmap_git),
+ &eindex->objects[i]->oid))
bitmap_unset(result, objects_nr + i);
}
}
@@ -1908,6 +1925,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
struct bitmap *haves_bitmap = NULL;
struct bitmap_index *bitmap_git;
+ struct repository *repo;
/*
* We can't do pathspec limiting with bitmaps, because we don't know
@@ -1981,18 +1999,20 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
if (!use_boundary_traversal)
object_array_clear(&revs->pending);
+ repo = bitmap_repo(bitmap_git);
+
if (haves) {
if (use_boundary_traversal) {
- trace2_region_enter("pack-bitmap", "haves/boundary", the_repository);
+ trace2_region_enter("pack-bitmap", "haves/boundary", repo);
haves_bitmap = find_boundary_objects(bitmap_git, revs, haves);
- trace2_region_leave("pack-bitmap", "haves/boundary", the_repository);
+ trace2_region_leave("pack-bitmap", "haves/boundary", repo);
} else {
- trace2_region_enter("pack-bitmap", "haves/classic", the_repository);
+ trace2_region_enter("pack-bitmap", "haves/classic", repo);
revs->ignore_missing_links = 1;
haves_bitmap = find_objects(bitmap_git, revs, haves, NULL);
reset_revision_walk();
revs->ignore_missing_links = 0;
- trace2_region_leave("pack-bitmap", "haves/classic", the_repository);
+ trace2_region_leave("pack-bitmap", "haves/classic", repo);
}
if (!haves_bitmap)
@@ -2026,17 +2046,17 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
object_list_free(&wants);
object_list_free(&haves);
- trace2_data_intmax("bitmap", the_repository, "pseudo_merges_satisfied",
+ trace2_data_intmax("bitmap", repo, "pseudo_merges_satisfied",
pseudo_merges_satisfied_nr);
- trace2_data_intmax("bitmap", the_repository, "pseudo_merges_cascades",
+ trace2_data_intmax("bitmap", repo, "pseudo_merges_cascades",
pseudo_merges_cascades_nr);
- trace2_data_intmax("bitmap", the_repository, "bitmap/hits",
+ trace2_data_intmax("bitmap", repo, "bitmap/hits",
existing_bitmaps_hits_nr);
- trace2_data_intmax("bitmap", the_repository, "bitmap/misses",
+ trace2_data_intmax("bitmap", repo, "bitmap/misses",
existing_bitmaps_misses_nr);
- trace2_data_intmax("bitmap", the_repository, "bitmap/roots_with_bitmap",
+ trace2_data_intmax("bitmap", repo, "bitmap/roots_with_bitmap",
roots_with_bitmaps_nr);
- trace2_data_intmax("bitmap", the_repository, "bitmap/roots_without_bitmap",
+ trace2_data_intmax("bitmap", repo, "bitmap/roots_without_bitmap",
roots_without_bitmaps_nr);
return bitmap_git;
@@ -2257,7 +2277,7 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
struct bitmap **reuse_out,
int multi_pack_reuse)
{
- struct repository *r = the_repository;
+ struct repository *r = bitmap_repo(bitmap_git);
struct bitmapped_pack *packs = NULL;
struct bitmap *result = bitmap_git->result;
struct bitmap *reuse;
@@ -2793,7 +2813,7 @@ int rebuild_bitmap(const uint32_t *reposition,
uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
struct packing_data *mapping)
{
- struct repository *r = the_repository;
+ struct repository *r = bitmap_repo(bitmap_git);
uint32_t i, num_objects;
uint32_t *reposition;
@@ -2949,7 +2969,8 @@ static off_t get_disk_usage_for_extended(struct bitmap_index *bitmap_git)
st_add(bitmap_num_objects(bitmap_git), i)))
continue;
- if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
+ if (oid_object_info_extended(bitmap_repo(bitmap_git), &obj->oid,
+ &oi, 0) < 0)
die(_("unable to get disk usage of '%s'"),
oid_to_hex(&obj->oid));
diff --git a/pack-objects.h b/pack-objects.h
index b9898a4e64..3f6f504203 100644
--- a/pack-objects.h
+++ b/pack-objects.h
@@ -7,7 +7,8 @@
struct repository;
-#define DEFAULT_DELTA_CACHE_SIZE (256 * 1024 * 1024)
+#define DEFAULT_DELTA_CACHE_SIZE (256 * 1024 * 1024)
+#define DEFAULT_DELTA_BASE_CACHE_LIMIT (96 * 1024 * 1024)
#define OE_DFS_STATE_BITS 2
#define OE_DEPTH_BITS 12
diff --git a/pack-revindex.c b/pack-revindex.c
index 22d3c23464..d3832478d9 100644
--- a/pack-revindex.c
+++ b/pack-revindex.c
@@ -383,7 +383,7 @@ int load_midx_revindex(struct multi_pack_index *m)
trace2_data_string("load_midx_revindex", the_repository,
"source", "rev");
- get_midx_filename_ext(&revindex_name, m->object_dir,
+ get_midx_filename_ext(m->repo->hash_algo, &revindex_name, m->object_dir,
get_midx_checksum(m), MIDX_EXT_REV);
ret = load_revindex_from_disk(revindex_name.buf,
diff --git a/pack-write.c b/pack-write.c
index 8c7dfddc5a..98a8c0e785 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -21,6 +21,7 @@ void reset_pack_idx_option(struct pack_idx_option *opts)
memset(opts, 0, sizeof(*opts));
opts->version = 2;
opts->off32_limit = 0x7fffffff;
+ opts->delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT;
}
static int sha1_compare(const void *_a, const void *_b)
diff --git a/pack.h b/pack.h
index 02bbdfb19c..a8da040629 100644
--- a/pack.h
+++ b/pack.h
@@ -58,6 +58,8 @@ struct pack_idx_option {
*/
int anomaly_alloc, anomaly_nr;
uint32_t *anomaly;
+
+ size_t delta_base_cache_limit;
};
void reset_pack_idx_option(struct pack_idx_option *);
diff --git a/packfile.c b/packfile.c
index f38c207fb6..cc7ab6403a 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
@@ -26,13 +25,12 @@
#include "pack-revindex.h"
#include "promisor-remote.h"
-char *odb_pack_name(struct strbuf *buf,
- const unsigned char *hash,
- const char *ext)
+char *odb_pack_name(struct repository *r, struct strbuf *buf,
+ const unsigned char *hash, const char *ext)
{
strbuf_reset(buf);
- strbuf_addf(buf, "%s/pack/pack-%s.%s", repo_get_object_directory(the_repository),
- hash_to_hex(hash), ext);
+ strbuf_addf(buf, "%s/pack/pack-%s.%s", repo_get_object_directory(r),
+ hash_to_hex_algop(hash, r->hash_algo), ext);
return buf->buf;
}
@@ -48,15 +46,15 @@ static size_t pack_mapped;
#define SZ_FMT PRIuMAX
static inline uintmax_t sz_fmt(size_t s) { return s; }
-void pack_report(void)
+void pack_report(struct repository *repo)
{
fprintf(stderr,
"pack_report: getpagesize() = %10" SZ_FMT "\n"
"pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n"
"pack_report: core.packedGitLimit = %10" SZ_FMT "\n",
sz_fmt(getpagesize()),
- sz_fmt(packed_git_window_size),
- sz_fmt(packed_git_limit));
+ sz_fmt(repo->settings.packed_git_window_size),
+ sz_fmt(repo->settings.packed_git_limit));
fprintf(stderr,
"pack_report: pack_used_ctr = %10u\n"
"pack_report: pack_mmap_calls = %10u\n"
@@ -80,7 +78,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
size_t idx_size;
int fd = git_open(path), ret;
struct stat st;
- const unsigned int hashsz = the_hash_algo->rawsz;
+ const unsigned int hashsz = p->repo->hash_algo->rawsz;
if (fd < 0)
return -1;
@@ -218,11 +216,12 @@ uint32_t get_pack_fanout(struct packed_git *p, uint32_t value)
return ntohl(level1_ofs[value]);
}
-static struct packed_git *alloc_packed_git(int extra)
+static struct packed_git *alloc_packed_git(struct repository *r, int extra)
{
struct packed_git *p = xmalloc(st_add(sizeof(*p), extra));
memset(p, 0, sizeof(*p));
p->pack_fd = -1;
+ p->repo = r;
return p;
}
@@ -234,15 +233,16 @@ static char *pack_path_from_idx(const char *idx_path)
return xstrfmt("%.*s.pack", (int)len, idx_path);
}
-struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
+struct packed_git *parse_pack_index(struct repository *r, unsigned char *sha1,
+ const char *idx_path)
{
char *path = pack_path_from_idx(idx_path);
size_t alloc = st_add(strlen(path), 1);
- struct packed_git *p = alloc_packed_git(alloc);
+ struct packed_git *p = alloc_packed_git(r, alloc);
memcpy(p->pack_name, path, alloc); /* includes NUL */
free(path);
- hashcpy(p->hash, sha1, the_repository->hash_algo);
+ hashcpy(p->hash, sha1, p->repo->hash_algo);
if (check_packed_git_idx(idx_path, p)) {
free(p);
return NULL;
@@ -277,7 +277,7 @@ static int unuse_one_window(struct packed_git *current)
if (current)
scan_windows(current, &lru_p, &lru_w, &lru_l);
- for (p = the_repository->objects->packed_git; p; p = p->next)
+ for (p = current->repo->objects->packed_git; p; p = p->next)
scan_windows(p, &lru_p, &lru_w, &lru_l);
if (lru_p) {
munmap(lru_w->base, lru_w->len);
@@ -459,13 +459,13 @@ static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struc
*accept_windows_inuse = has_windows_inuse;
}
-static int close_one_pack(void)
+static int close_one_pack(struct repository *r)
{
struct packed_git *p, *lru_p = NULL;
struct pack_window *mru_w = NULL;
int accept_windows_inuse = 1;
- for (p = the_repository->objects->packed_git; p; p = p->next) {
+ for (p = r->objects->packed_git; p; p = p->next) {
if (p->pack_fd == -1)
continue;
find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
@@ -539,7 +539,7 @@ static int open_packed_git_1(struct packed_git *p)
unsigned char hash[GIT_MAX_RAWSZ];
unsigned char *idx_hash;
ssize_t read_result;
- const unsigned hashsz = the_hash_algo->rawsz;
+ const unsigned hashsz = p->repo->hash_algo->rawsz;
if (open_pack_index(p))
return error("packfile %s index unavailable", p->pack_name);
@@ -554,7 +554,7 @@ static int open_packed_git_1(struct packed_git *p)
pack_max_fds = 1;
}
- while (pack_max_fds <= pack_open_fds && close_one_pack())
+ while (pack_max_fds <= pack_open_fds && close_one_pack(p->repo))
; /* nothing */
p->pack_fd = git_open(p->pack_name);
@@ -596,7 +596,7 @@ static int open_packed_git_1(struct packed_git *p)
if (read_result != hashsz)
return error("packfile %s signature is unavailable", p->pack_name);
idx_hash = ((unsigned char *)p->index_data) + p->index_size - hashsz * 2;
- if (!hasheq(hash, idx_hash, the_repository->hash_algo))
+ if (!hasheq(hash, idx_hash, p->repo->hash_algo))
return error("packfile %s does not match index", p->pack_name);
return 0;
}
@@ -609,7 +609,8 @@ static int open_packed_git(struct packed_git *p)
return -1;
}
-static int in_window(struct pack_window *win, off_t offset)
+static int in_window(struct repository *r, struct pack_window *win,
+ off_t offset)
{
/* We must promise at least one full hash after the
* offset is available from this window, otherwise the offset
@@ -619,7 +620,7 @@ static int in_window(struct pack_window *win, off_t offset)
*/
off_t win_off = win->offset;
return win_off <= offset
- && (offset + the_hash_algo->rawsz) <= (win_off + win->len);
+ && (offset + r->hash_algo->rawsz) <= (win_off + win->len);
}
unsigned char *use_pack(struct packed_git *p,
@@ -636,21 +637,28 @@ unsigned char *use_pack(struct packed_git *p,
*/
if (!p->pack_size && p->pack_fd == -1 && open_packed_git(p))
die("packfile %s cannot be accessed", p->pack_name);
- if (offset > (p->pack_size - the_hash_algo->rawsz))
+ if (offset > (p->pack_size - p->repo->hash_algo->rawsz))
die("offset beyond end of packfile (truncated pack?)");
if (offset < 0)
die(_("offset before end of packfile (broken .idx?)"));
- if (!win || !in_window(win, offset)) {
+ if (!win || !in_window(p->repo, win, offset)) {
if (win)
win->inuse_cnt--;
for (win = p->windows; win; win = win->next) {
- if (in_window(win, offset))
+ if (in_window(p->repo, win, offset))
break;
}
if (!win) {
- size_t window_align = packed_git_window_size / 2;
+ size_t window_align;
off_t len;
+ struct repo_settings *settings;
+
+ /* lazy load the settings in case it hasn't been setup */
+ prepare_repo_settings(p->repo);
+ settings = &p->repo->settings;
+
+ window_align = settings->packed_git_window_size / 2;
if (p->pack_fd == -1 && open_packed_git(p))
die("packfile %s cannot be accessed", p->pack_name);
@@ -658,11 +666,12 @@ unsigned char *use_pack(struct packed_git *p,
CALLOC_ARRAY(win, 1);
win->offset = (offset / window_align) * window_align;
len = p->pack_size - win->offset;
- if (len > packed_git_window_size)
- len = packed_git_window_size;
+ if (len > settings->packed_git_window_size)
+ len = settings->packed_git_window_size;
win->len = (size_t)len;
pack_mapped += win->len;
- while (packed_git_limit < pack_mapped
+
+ while (settings->packed_git_limit < pack_mapped
&& unuse_one_window(p))
; /* nothing */
win->base = xmmap_gently(NULL, win->len,
@@ -704,11 +713,13 @@ void unuse_pack(struct pack_window **w_cursor)
}
}
-struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
+struct packed_git *add_packed_git(struct repository *r, const char *path,
+ size_t path_len, int local)
{
struct stat st;
size_t alloc;
struct packed_git *p;
+ struct object_id oid;
/*
* Make sure a corresponding .pack file exists and that
@@ -722,7 +733,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
* the use xsnprintf double-checks that)
*/
alloc = st_add3(path_len, strlen(".promisor"), 1);
- p = alloc_packed_git(alloc);
+ p = alloc_packed_git(r, alloc);
memcpy(p->pack_name, path, path_len);
xsnprintf(p->pack_name + path_len, alloc - path_len, ".keep");
@@ -749,9 +760,13 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
p->pack_size = st.st_size;
p->pack_local = local;
p->mtime = st.st_mtime;
- if (path_len < the_hash_algo->hexsz ||
- get_hash_hex(path + path_len - the_hash_algo->hexsz, p->hash))
- hashclr(p->hash, the_repository->hash_algo);
+ if (path_len < r->hash_algo->hexsz ||
+ get_oid_hex_algop(path + path_len - r->hash_algo->hexsz, &oid,
+ r->hash_algo))
+ hashclr(p->hash, r->hash_algo);
+ else
+ hashcpy(p->hash, oid.hash, r->hash_algo);
+
return p;
}
@@ -878,7 +893,7 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
/* Don't reopen a pack we already have. */
if (!hashmap_get(&data->r->objects->pack_map, &hent, pack_name)) {
- p = add_packed_git(full_name, full_name_len, data->local);
+ p = add_packed_git(data->r, full_name, full_name_len, data->local);
if (p)
install_packed_git(data->r, p);
}
@@ -1241,9 +1256,9 @@ off_t get_delta_base(struct packed_git *p,
} else if (type == OBJ_REF_DELTA) {
/* The base entry _must_ be in the same pack */
struct object_id oid;
- oidread(&oid, base_info, the_repository->hash_algo);
+ oidread(&oid, base_info, p->repo->hash_algo);
base_offset = find_pack_entry_one(&oid, p);
- *curpos += the_hash_algo->rawsz;
+ *curpos += p->repo->hash_algo->rawsz;
} else
die("I am totally screwed");
return base_offset;
@@ -1264,7 +1279,7 @@ static int get_delta_base_oid(struct packed_git *p,
{
if (type == OBJ_REF_DELTA) {
unsigned char *base = use_pack(p, w_curs, curpos, NULL);
- oidread(oid, base, the_repository->hash_algo);
+ oidread(oid, base, p->repo->hash_algo);
return 0;
} else if (type == OBJ_OFS_DELTA) {
uint32_t base_pos;
@@ -1489,7 +1504,9 @@ void clear_delta_base_cache(void)
}
static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
- void *base, unsigned long base_size, enum object_type type)
+ void *base, unsigned long base_size,
+ unsigned long delta_base_cache_limit,
+ enum object_type type)
{
struct delta_base_cache_entry *ent;
struct list_head *lru, *tmp;
@@ -1606,7 +1623,7 @@ int packed_object_info(struct repository *r, struct packed_git *p,
goto out;
}
} else
- oidclr(oi->delta_base_oid, the_repository->hash_algo);
+ oidclr(oi->delta_base_oid, p->repo->hash_algo);
}
oi->whence = in_delta_base_cache(p, obj_offset) ? OI_DBCACHED :
@@ -1691,6 +1708,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
int delta_stack_nr = 0, delta_stack_alloc = UNPACK_ENTRY_STACK_PREALLOC;
int base_from_cache = 0;
+ prepare_repo_settings(p->repo);
+
write_pack_access_log(p, obj_offset);
/* PHASE 1: drill down to the innermost base object */
@@ -1871,7 +1890,9 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
* before we are done using it.
*/
if (!external_base)
- add_delta_base_cache(p, base_obj_offset, base, base_size, type);
+ add_delta_base_cache(p, base_obj_offset, base, base_size,
+ p->repo->settings.delta_base_cache_limit,
+ type);
free(delta_data);
free(external_base);
@@ -1895,7 +1916,7 @@ int bsearch_pack(const struct object_id *oid, const struct packed_git *p, uint32
{
const unsigned char *index_fanout = p->index_data;
const unsigned char *index_lookup;
- const unsigned int hashsz = the_hash_algo->rawsz;
+ const unsigned int hashsz = p->repo->hash_algo->rawsz;
int index_lookup_width;
if (!index_fanout)
@@ -1920,7 +1941,7 @@ int nth_packed_object_id(struct object_id *oid,
uint32_t n)
{
const unsigned char *index = p->index_data;
- const unsigned int hashsz = the_hash_algo->rawsz;
+ const unsigned int hashsz = p->repo->hash_algo->rawsz;
if (!index) {
if (open_pack_index(p))
return -1;
@@ -1931,11 +1952,10 @@ int nth_packed_object_id(struct object_id *oid,
index += 4 * 256;
if (p->index_version == 1) {
oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4),
- the_repository->hash_algo);
+ p->repo->hash_algo);
} else {
index += 8;
- oidread(oid, index + st_mult(hashsz, n),
- the_repository->hash_algo);
+ oidread(oid, index + st_mult(hashsz, n), p->repo->hash_algo);
}
return 0;
}
@@ -1957,7 +1977,7 @@ void check_pack_index_ptr(const struct packed_git *p, const void *vptr)
off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
{
const unsigned char *index = p->index_data;
- const unsigned int hashsz = the_hash_algo->rawsz;
+ const unsigned int hashsz = p->repo->hash_algo->rawsz;
index += 4 * 256;
if (p->index_version == 1) {
return ntohl(*((uint32_t *)(index + st_mult(hashsz + 4, n))));
@@ -2137,16 +2157,17 @@ int find_kept_pack_entry(struct repository *r,
return 0;
}
-int has_object_pack(const struct object_id *oid)
+int has_object_pack(struct repository *r, const struct object_id *oid)
{
struct pack_entry e;
- return find_pack_entry(the_repository, oid, &e);
+ return find_pack_entry(r, oid, &e);
}
-int has_object_kept_pack(const struct object_id *oid, unsigned flags)
+int has_object_kept_pack(struct repository *r, const struct object_id *oid,
+ unsigned flags)
{
struct pack_entry e;
- return find_kept_pack_entry(the_repository, oid, flags, &e);
+ return find_kept_pack_entry(r, oid, flags, &e);
}
int for_each_object_in_pack(struct packed_git *p,
@@ -2157,7 +2178,7 @@ int for_each_object_in_pack(struct packed_git *p,
int r = 0;
if (flags & FOR_EACH_OBJECT_PACK_ORDER) {
- if (load_pack_revindex(the_repository, p))
+ if (load_pack_revindex(p->repo, p))
return -1;
}
@@ -2193,15 +2214,14 @@ int for_each_object_in_pack(struct packed_git *p,
return r;
}
-int for_each_packed_object(each_packed_object_fn cb, void *data,
- enum for_each_object_flags flags)
+int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
+ void *data, enum for_each_object_flags flags)
{
struct packed_git *p;
int r = 0;
int pack_errors = 0;
- prepare_packed_git(the_repository);
- for (p = get_all_packs(the_repository); p; p = p->next) {
+ for (p = get_all_packs(repo); p; p = p->next) {
if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
continue;
if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
@@ -2225,7 +2245,7 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
}
static int add_promisor_object(const struct object_id *oid,
- struct packed_git *pack UNUSED,
+ struct packed_git *pack,
uint32_t pos UNUSED,
void *set_)
{
@@ -2233,12 +2253,12 @@ static int add_promisor_object(const struct object_id *oid,
struct object *obj;
int we_parsed_object;
- obj = lookup_object(the_repository, oid);
+ obj = lookup_object(pack->repo, oid);
if (obj && obj->parsed) {
we_parsed_object = 0;
} else {
we_parsed_object = 1;
- obj = parse_object(the_repository, oid);
+ obj = parse_object(pack->repo, oid);
}
if (!obj)
@@ -2279,14 +2299,14 @@ static int add_promisor_object(const struct object_id *oid,
return 0;
}
-int is_promisor_object(const struct object_id *oid)
+int is_promisor_object(struct repository *r, const struct object_id *oid)
{
static struct oidset promisor_objects;
static int promisor_objects_prepared;
if (!promisor_objects_prepared) {
- if (repo_has_promisor_remote(the_repository)) {
- for_each_packed_object(add_promisor_object,
+ if (repo_has_promisor_remote(r)) {
+ for_each_packed_object(r, add_promisor_object,
&promisor_objects,
FOR_EACH_OBJECT_PROMISOR_ONLY |
FOR_EACH_OBJECT_PACK_ORDER);
diff --git a/packfile.h b/packfile.h
index 08f88a7ff5..58104fa009 100644
--- a/packfile.h
+++ b/packfile.h
@@ -29,7 +29,8 @@ struct pack_entry {
*
* Example: odb_pack_name(out, sha1, "idx") => ".git/objects/pack/pack-1234..idx"
*/
-char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const char *ext);
+char *odb_pack_name(struct repository *r, struct strbuf *buf,
+ const unsigned char *hash, const char *ext);
/*
* Return the basename of the packfile, omitting any containing directory
@@ -46,7 +47,8 @@ const char *pack_basename(struct packed_git *p);
* and does not add the resulting packed_git struct to the internal list of
* packs. You probably want add_packed_git() instead.
*/
-struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
+struct packed_git *parse_pack_index(struct repository *r, unsigned char *sha1,
+ const char *idx_path);
typedef void each_file_in_pack_dir_fn(const char *full_path, size_t full_path_len,
const char *file_name, void *data);
@@ -87,7 +89,7 @@ unsigned long repo_approximate_object_count(struct repository *r);
struct packed_git *find_oid_pack(const struct object_id *oid,
struct packed_git *packs);
-void pack_report(void);
+void pack_report(struct repository *repo);
/*
* mmap the index file for the specified packfile (if it is not
@@ -113,7 +115,8 @@ void close_pack(struct packed_git *);
void close_object_store(struct raw_object_store *o);
void unuse_pack(struct pack_window **);
void clear_delta_base_cache(void);
-struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
+struct packed_git *add_packed_git(struct repository *r, const char *path,
+ size_t path_len, int local);
/*
* Unlink the .pack and associated extension files.
@@ -190,14 +193,15 @@ const struct packed_git *has_packed_and_bad(struct repository *, const struct ob
int find_pack_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e);
int find_kept_pack_entry(struct repository *r, const struct object_id *oid, unsigned flags, struct pack_entry *e);
-int has_object_pack(const struct object_id *oid);
-int has_object_kept_pack(const struct object_id *oid, unsigned flags);
+int has_object_pack(struct repository *r, const struct object_id *oid);
+int has_object_kept_pack(struct repository *r, const struct object_id *oid,
+ unsigned flags);
/*
* Return 1 if an object in a promisor packfile is or refers to the given
* object, 0 otherwise.
*/
-int is_promisor_object(const struct object_id *oid);
+int is_promisor_object(struct repository *r, const struct object_id *oid);
/*
* Expose a function for fuzz testing.
diff --git a/path.c b/path.c
index b4be7581aa..07964f5d32 100644
--- a/path.c
+++ b/path.c
@@ -684,7 +684,7 @@ return_null:
* links. User relative paths are also returned as they are given,
* except DWIM suffixing.
*/
-const char *enter_repo(const char *path, int strict)
+const char *enter_repo(const char *path, unsigned flags)
{
static struct strbuf validated_path = STRBUF_INIT;
static struct strbuf used_path = STRBUF_INIT;
@@ -692,7 +692,7 @@ const char *enter_repo(const char *path, int strict)
if (!path)
return NULL;
- if (!strict) {
+ if (!(flags & ENTER_REPO_STRICT)) {
static const char *suffix[] = {
"/.git", "", ".git/.git", ".git", NULL,
};
@@ -736,7 +736,8 @@ const char *enter_repo(const char *path, int strict)
if (!suffix[i])
return NULL;
gitfile = read_gitfile(used_path.buf);
- die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
+ if (!(flags & ENTER_REPO_ANY_OWNER_OK))
+ die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
if (gitfile) {
strbuf_reset(&used_path);
strbuf_addstr(&used_path, gitfile);
@@ -747,7 +748,8 @@ const char *enter_repo(const char *path, int strict)
}
else {
const char *gitfile = read_gitfile(path);
- die_upon_dubious_ownership(gitfile, NULL, path);
+ if (!(flags & ENTER_REPO_ANY_OWNER_OK))
+ die_upon_dubious_ownership(gitfile, NULL, path);
if (gitfile)
path = gitfile;
if (chdir(path))
diff --git a/path.h b/path.h
index e91d19fff6..5f6c85e5f8 100644
--- a/path.h
+++ b/path.h
@@ -156,7 +156,22 @@ int calc_shared_perm(int mode);
int adjust_shared_perm(const char *path);
char *interpolate_path(const char *path, int real_home);
-const char *enter_repo(const char *path, int strict);
+
+/* The bits are as follows:
+ *
+ * - ENTER_REPO_STRICT: callers that require exact paths (as opposed
+ * to allowing known suffixes like ".git", ".git/.git" to be
+ * omitted) can set this bit.
+ *
+ * - ENTER_REPO_ANY_OWNER_OK: callers that are willing to run without
+ * ownership check can set this bit.
+ */
+enum {
+ ENTER_REPO_STRICT = (1<<0),
+ ENTER_REPO_ANY_OWNER_OK = (1<<1),
+};
+
+const char *enter_repo(const char *path, unsigned flags);
const char *remove_leading_path(const char *in, const char *prefix);
const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
diff --git a/perl/FromCPAN/Mail/meson.build b/perl/FromCPAN/Mail/meson.build
new file mode 100644
index 0000000000..129cff161c
--- /dev/null
+++ b/perl/FromCPAN/Mail/meson.build
@@ -0,0 +1,7 @@
+test_dependencies += custom_target(
+ input: 'Address.pm',
+ output: 'Address.pm',
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5/FromCPAN/Mail',
+)
diff --git a/perl/FromCPAN/meson.build b/perl/FromCPAN/meson.build
new file mode 100644
index 0000000000..4e7ea909df
--- /dev/null
+++ b/perl/FromCPAN/meson.build
@@ -0,0 +1,9 @@
+test_dependencies += custom_target(
+ input: 'Error.pm',
+ output: 'Error.pm',
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5/FromCPAN',
+)
+
+subdir('Mail')
diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm
index ab46edb608..162230af81 100644
--- a/perl/Git/I18N.pm
+++ b/perl/Git/I18N.pm
@@ -20,14 +20,14 @@ our @EXPORT_OK = @EXPORT;
# this "'@@' [...] '@@'" pattern.
use constant NO_GETTEXT_STR => '@@' . 'NO_GETTEXT' . '@@';
use constant NO_GETTEXT => (
- q[@@NO_GETTEXT@@] ne ''
+ q[@NO_GETTEXT@] ne ''
and
- q[@@NO_GETTEXT@@] ne NO_GETTEXT_STR
+ q[@NO_GETTEXT@] ne NO_GETTEXT_STR
);
sub __bootstrap_locale_messages {
our $TEXTDOMAIN = 'git';
- our $TEXTDOMAINDIR ||= $ENV{GIT_TEXTDOMAINDIR} || '@@LOCALEDIR@@';
+ our $TEXTDOMAINDIR ||= $ENV{GIT_TEXTDOMAINDIR} || '@LOCALEDIR@';
die "NO_GETTEXT=" . NO_GETTEXT_STR if NO_GETTEXT;
require POSIX;
diff --git a/perl/Git/LoadCPAN.pm b/perl/Git/LoadCPAN.pm
index 61254fddbb..92d63c71d2 100644
--- a/perl/Git/LoadCPAN.pm
+++ b/perl/Git/LoadCPAN.pm
@@ -31,11 +31,11 @@ C<git.git> repository. Use it for anything else at your peril!
# Makefile, and allows for detecting whether the module is loaded from
# perl/Git as opposed to perl/build/Git, which is useful for one-off
# testing without having Error.pm et al installed.
-use constant NO_PERL_CPAN_FALLBACKS_STR => '@@' . 'NO_PERL_CPAN_FALLBACKS' . '@@';
+use constant NO_PERL_CPAN_FALLBACKS_STR => '@' . 'NO_PERL_CPAN_FALLBACKS' . '@';
use constant NO_PERL_CPAN_FALLBACKS => (
- q[@@NO_PERL_CPAN_FALLBACKS@@] ne ''
+ q[@NO_PERL_CPAN_FALLBACKS@] ne ''
and
- q[@@NO_PERL_CPAN_FALLBACKS@@] ne NO_PERL_CPAN_FALLBACKS_STR
+ q[@NO_PERL_CPAN_FALLBACKS@] ne NO_PERL_CPAN_FALLBACKS_STR
);
sub import {
diff --git a/perl/Git/LoadCPAN/Mail/meson.build b/perl/Git/LoadCPAN/Mail/meson.build
new file mode 100644
index 0000000000..7da5b37adb
--- /dev/null
+++ b/perl/Git/LoadCPAN/Mail/meson.build
@@ -0,0 +1,7 @@
+test_dependencies += custom_target(
+ input: 'Address.pm',
+ output: 'Address.pm',
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5/Git/LoadCPAN/Mail',
+)
diff --git a/perl/Git/LoadCPAN/meson.build b/perl/Git/LoadCPAN/meson.build
new file mode 100644
index 0000000000..9468c073ae
--- /dev/null
+++ b/perl/Git/LoadCPAN/meson.build
@@ -0,0 +1,9 @@
+test_dependencies += custom_target(
+ input: 'Error.pm',
+ output: 'Error.pm',
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5/Git/LoadCPAN',
+)
+
+subdir('Mail')
diff --git a/perl/Git/SVN/Memoize/meson.build b/perl/Git/SVN/Memoize/meson.build
new file mode 100644
index 0000000000..515ab3dd92
--- /dev/null
+++ b/perl/Git/SVN/Memoize/meson.build
@@ -0,0 +1,7 @@
+test_dependencies += custom_target(
+ input: 'YAML.pm',
+ output: 'YAML.pm',
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5/Git/SVN',
+)
diff --git a/perl/Git/SVN/meson.build b/perl/Git/SVN/meson.build
new file mode 100644
index 0000000000..8338531041
--- /dev/null
+++ b/perl/Git/SVN/meson.build
@@ -0,0 +1,20 @@
+foreach source : [
+ 'Editor.pm',
+ 'Fetcher.pm',
+ 'GlobSpec.pm',
+ 'Log.pm',
+ 'Migration.pm',
+ 'Prompt.pm',
+ 'Ra.pm',
+ 'Utils.pm',
+]
+ test_dependencies += custom_target(
+ input: source,
+ output: source,
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5/Git/SVN',
+ )
+endforeach
+
+subdir('Memoize')
diff --git a/perl/Git/meson.build b/perl/Git/meson.build
new file mode 100644
index 0000000000..259209d730
--- /dev/null
+++ b/perl/Git/meson.build
@@ -0,0 +1,18 @@
+foreach source : [
+ 'I18N.pm',
+ 'IndexInfo.pm',
+ 'LoadCPAN.pm',
+ 'Packet.pm',
+ 'SVN.pm',
+]
+ test_dependencies += custom_target(
+ input: source,
+ output: source,
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5/Git',
+ )
+endforeach
+
+subdir('LoadCPAN')
+subdir('SVN')
diff --git a/perl/header_templates/fixed_prefix.template.pl b/perl/header_templates/fixed_prefix.template.pl
index 857b4391a4..d571ca5cde 100644
--- a/perl/header_templates/fixed_prefix.template.pl
+++ b/perl/header_templates/fixed_prefix.template.pl
@@ -1 +1 @@
-use lib (split(/@@PATHSEP@@/, $ENV{GITPERLLIB} || '@@INSTLIBDIR@@'));
+use lib (split(/@PATHSEP@/, $ENV{GITPERLLIB} || '@INSTLIBDIR@'));
diff --git a/perl/header_templates/runtime_prefix.template.pl b/perl/header_templates/runtime_prefix.template.pl
index 9d28b3d863..e6f8e661a1 100644
--- a/perl/header_templates/runtime_prefix.template.pl
+++ b/perl/header_templates/runtime_prefix.template.pl
@@ -3,7 +3,7 @@
# This finds our Git::* libraries relative to the script's runtime path.
sub __git_system_path {
my ($relpath) = @_;
- my $gitexecdir_relative = '@@GITEXECDIR_REL@@';
+ my $gitexecdir_relative = '@GITEXECDIR_REL@';
# GIT_EXEC_PATH is supplied by `git` or the test suite.
my $exec_path;
@@ -24,11 +24,11 @@ sub __git_system_path {
}
BEGIN {
- use lib split /@@PATHSEP@@/,
+ use lib split /@PATHSEP@/,
(
$ENV{GITPERLLIB} ||
do {
- my $perllibdir = __git_system_path('@@PERLLIBDIR_REL@@');
+ my $perllibdir = __git_system_path('@PERLLIBDIR_REL@');
(-e $perllibdir) || die("Invalid system path ($relpath): $path");
$perllibdir;
}
@@ -36,7 +36,7 @@ BEGIN {
# Export the system locale directory to the I18N module. The locale directory
# is only installed if NO_GETTEXT is set.
- $Git::I18N::TEXTDOMAINDIR = __git_system_path('@@LOCALEDIR_REL@@');
+ $Git::I18N::TEXTDOMAINDIR = __git_system_path('@LOCALEDIR_REL@');
}
# END RUNTIME_PREFIX generated code.
diff --git a/perl/meson.build b/perl/meson.build
new file mode 100644
index 0000000000..c22d6f8a1a
--- /dev/null
+++ b/perl/meson.build
@@ -0,0 +1,12 @@
+test_dependencies += custom_target(
+ input: 'Git.pm',
+ output: 'Git.pm',
+ command: generate_perl_command,
+ install: true,
+ install_dir: get_option('datadir') / 'perl5',
+)
+
+subdir('Git')
+if get_option('perl_cpan_fallback')
+ subdir('FromCPAN')
+endif
diff --git a/po/meson.build b/po/meson.build
new file mode 100644
index 0000000000..d7154b6395
--- /dev/null
+++ b/po/meson.build
@@ -0,0 +1,27 @@
+i18n = import('i18n')
+
+translations = i18n.gettext('git',
+ languages: [
+ 'bg',
+ 'ca',
+ 'de',
+ 'el',
+ 'es',
+ 'fr',
+ 'id',
+ 'is',
+ 'it',
+ 'ko',
+ 'pl',
+ 'pt_PT',
+ 'ru',
+ 'sv',
+ 'tr',
+ 'uk',
+ 'vi',
+ 'zh_CN',
+ 'zh_TW',
+ ],
+ install: true,
+)
+test_dependencies += translations[0]
diff --git a/promisor-remote.c b/promisor-remote.c
index 9345ae3db2..c714f4f007 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -283,7 +283,7 @@ void promisor_remote_get_direct(struct repository *repo,
}
for (i = 0; i < remaining_nr; i++) {
- if (is_promisor_object(&remaining_oids[i]))
+ if (is_promisor_object(repo, &remaining_oids[i]))
die(_("could not fetch %s from promisor remote"),
oid_to_hex(&remaining_oids[i]));
}
diff --git a/prune-packed.c b/prune-packed.c
index 2bb99c29df..d1c65ab10e 100644
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -24,7 +24,7 @@ static int prune_object(const struct object_id *oid, const char *path,
{
int *opts = data;
- if (!has_object_pack(oid))
+ if (!has_object_pack(the_repository, oid))
return 0;
if (*opts & PRUNE_PACKED_DRY_RUN)
diff --git a/reachable.c b/reachable.c
index 3e9b3dd0a4..ecf7ccf504 100644
--- a/reachable.c
+++ b/reachable.c
@@ -239,7 +239,7 @@ static int want_recent_object(struct recent_data *data,
const struct object_id *oid)
{
if (data->ignore_in_core_kept_packs &&
- has_object_kept_pack(oid, IN_CORE_KEEP_PACKS))
+ has_object_kept_pack(data->revs->repo, oid, IN_CORE_KEEP_PACKS))
return 0;
return 1;
}
@@ -324,7 +324,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
if (ignore_in_core_kept_packs)
flags |= FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS;
- r = for_each_packed_object(add_recent_packed, &data, flags);
+ r = for_each_packed_object(revs->repo, add_recent_packed, &data, flags);
done:
oidset_clear(&data.extra_recent_oids);
diff --git a/refs.c b/refs.c
index 02fb4b7cb2..7dd5e9fa33 100644
--- a/refs.c
+++ b/refs.c
@@ -699,6 +699,53 @@ static char *substitute_branch_name(struct repository *r,
return NULL;
}
+void copy_branchname(struct strbuf *sb, const char *name, unsigned allowed)
+{
+ int len = strlen(name);
+ struct interpret_branch_name_options options = {
+ .allowed = allowed
+ };
+ int used = repo_interpret_branch_name(the_repository, name, len, sb,
+ &options);
+
+ if (used < 0)
+ used = 0;
+ strbuf_add(sb, name + used, len - used);
+}
+
+int check_branch_ref(struct strbuf *sb, const char *name)
+{
+ if (startup_info->have_repository)
+ copy_branchname(sb, name, INTERPRET_BRANCH_LOCAL);
+ else
+ strbuf_addstr(sb, name);
+
+ /*
+ * This splice must be done even if we end up rejecting the
+ * name; builtin/branch.c::copy_or_rename_branch() still wants
+ * to see what the name expanded to so that "branch -m" can be
+ * used as a tool to correct earlier mistakes.
+ */
+ strbuf_splice(sb, 0, 0, "refs/heads/", 11);
+
+ if (*name == '-' ||
+ !strcmp(sb->buf, "refs/heads/HEAD"))
+ return -1;
+
+ return check_refname_format(sb->buf, 0);
+}
+
+int check_tag_ref(struct strbuf *sb, const char *name)
+{
+ if (name[0] == '-' || !strcmp(name, "HEAD"))
+ return -1;
+
+ strbuf_reset(sb);
+ strbuf_addf(sb, "refs/tags/%s", name);
+
+ return check_refname_format(sb->buf, 0);
+}
+
int repo_dwim_ref(struct repository *r, const char *str, int len,
struct object_id *oid, char **ref, int nonfatal_dangling_mark)
{
@@ -2121,19 +2168,53 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct
int refs_update_symref(struct ref_store *refs, const char *ref,
const char *target, const char *logmsg)
{
+ return refs_update_symref_extended(refs, ref, target, logmsg, NULL, 0);
+}
+
+int refs_update_symref_extended(struct ref_store *refs, const char *ref,
+ const char *target, const char *logmsg,
+ struct strbuf *referent, int create_only)
+{
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
- int ret = 0;
+ int ret = 0, prepret = 0;
transaction = ref_store_transaction_begin(refs, 0, &err);
- if (!transaction ||
- ref_transaction_update(transaction, ref, NULL, NULL,
- target, NULL, REF_NO_DEREF,
- logmsg, &err) ||
- ref_transaction_commit(transaction, &err)) {
+ if (!transaction) {
+ error_return:
ret = error("%s", err.buf);
+ goto cleanup;
+ }
+ if (create_only) {
+ if (ref_transaction_create(transaction, ref, NULL, target,
+ REF_NO_DEREF, logmsg, &err))
+ goto error_return;
+ prepret = ref_transaction_prepare(transaction, &err);
+ if (prepret && prepret != TRANSACTION_CREATE_EXISTS)
+ goto error_return;
+ } else {
+ if (ref_transaction_update(transaction, ref, NULL, NULL,
+ target, NULL, REF_NO_DEREF,
+ logmsg, &err) ||
+ ref_transaction_prepare(transaction, &err))
+ goto error_return;
+ }
+
+ if (referent && refs_read_symbolic_ref(refs, ref, referent) == NOT_A_SYMREF) {
+ struct object_id oid;
+ if (!refs_read_ref(refs, ref, &oid)) {
+ strbuf_addstr(referent, oid_to_hex(&oid));
+ ret = NOT_A_SYMREF;
+ }
}
+ if (prepret == TRANSACTION_CREATE_EXISTS)
+ goto cleanup;
+
+ if (ref_transaction_commit(transaction, &err))
+ goto error_return;
+
+cleanup:
strbuf_release(&err);
if (transaction)
ref_transaction_free(transaction);
@@ -2947,4 +3028,3 @@ int ref_update_expects_existing_old_ref(struct ref_update *update)
return (update->flags & REF_HAVE_OLD) &&
(!is_null_oid(&update->old_oid) || update->old_target);
}
-
diff --git a/refs.h b/refs.h
index a5bedf48cf..09be47afbe 100644
--- a/refs.h
+++ b/refs.h
@@ -83,6 +83,17 @@ int refs_read_ref_full(struct ref_store *refs, const char *refname,
int refs_read_ref(struct ref_store *refs, const char *refname, struct object_id *oid);
+#define NOT_A_SYMREF -2
+
+/*
+ * Read the symbolic ref named "refname" and write its immediate referent into
+ * the provided buffer. Referent is left empty if "refname" is not a symbolic
+ * ref. It does not resolve the symbolic reference recursively in case the
+ * target is also a symbolic ref.
+ *
+ * Returns 0 on success, -2 if the "refname" is not a symbolic ref,
+ * -1 otherwise.
+ */
int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
struct strbuf *referent);
@@ -184,6 +195,35 @@ int repo_dwim_log(struct repository *r, const char *str, int len, struct object_
char *repo_default_branch_name(struct repository *r, int quiet);
/*
+ * Copy "name" to "sb", expanding any special @-marks as handled by
+ * repo_interpret_branch_name(). The result is a non-qualified branch name
+ * (so "foo" or "origin/master" instead of "refs/heads/foo" or
+ * "refs/remotes/origin/master").
+ *
+ * Note that the resulting name may not be a syntactically valid refname.
+ *
+ * If "allowed" is non-zero, restrict the set of allowed expansions. See
+ * repo_interpret_branch_name() for details.
+ */
+void copy_branchname(struct strbuf *sb, const char *name,
+ unsigned allowed);
+
+/*
+ * Like copy_branchname() above, but confirm that the result is
+ * syntactically valid to be used as a local branch name in refs/heads/.
+ *
+ * The return value is "0" if the result is valid, and "-1" otherwise.
+ */
+int check_branch_ref(struct strbuf *sb, const char *name);
+
+/*
+ * Similar for a tag name in refs/tags/.
+ *
+ * The return value is "0" if the result is valid, and "-1" otherwise.
+ */
+int check_tag_ref(struct strbuf *sb, const char *name);
+
+/*
* A ref_transaction represents a collection of reference updates that
* should succeed or fail together.
*
@@ -575,6 +615,10 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
int refs_update_symref(struct ref_store *refs, const char *refname,
const char *target, const char *logmsg);
+int refs_update_symref_extended(struct ref_store *refs, const char *refname,
+ const char *target, const char *logmsg,
+ struct strbuf *referent, int create_only);
+
enum action_on_err {
UPDATE_REFS_MSG_ON_ERR,
UPDATE_REFS_DIE_ON_ERR,
@@ -776,8 +820,10 @@ int ref_transaction_verify(struct ref_transaction *transaction,
/* Naming conflict (for example, the ref names A and A/B conflict). */
#define TRANSACTION_NAME_CONFLICT -1
+/* When only creation was requested, but the ref already exists. */
+#define TRANSACTION_CREATE_EXISTS -2
/* All other errors. */
-#define TRANSACTION_GENERIC_ERROR -2
+#define TRANSACTION_GENERIC_ERROR -3
/*
* Perform the preparatory stages of committing `transaction`. Acquire
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 14aaf8cffc..467fe347fa 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -599,10 +599,9 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn
unsigned int type;
ret = read_ref_internal(ref_store, refname, &oid, referent, &type, &failure_errno, 1);
- if (ret)
- return ret;
-
- return !(type & REF_ISSYMREF);
+ if (!ret && !(type & REF_ISSYMREF))
+ return NOT_A_SYMREF;
+ return ret;
}
int parse_loose_ref_contents(const struct git_hash_algo *algop,
@@ -2510,14 +2509,18 @@ static int split_symref_update(struct ref_update *update,
static int check_old_oid(struct ref_update *update, struct object_id *oid,
struct strbuf *err)
{
+ int ret = TRANSACTION_GENERIC_ERROR;
+
if (!(update->flags & REF_HAVE_OLD) ||
oideq(oid, &update->old_oid))
return 0;
- if (is_null_oid(&update->old_oid))
+ if (is_null_oid(&update->old_oid)) {
strbuf_addf(err, "cannot lock ref '%s': "
"reference already exists",
ref_update_original_update_refname(update));
+ ret = TRANSACTION_CREATE_EXISTS;
+ }
else if (is_null_oid(oid))
strbuf_addf(err, "cannot lock ref '%s': "
"reference is missing but expected %s",
@@ -2530,7 +2533,7 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
oid_to_hex(oid),
oid_to_hex(&update->old_oid));
- return -1;
+ return ret;
}
/*
@@ -2610,9 +2613,11 @@ static int lock_ref_for_update(struct files_ref_store *refs,
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
- } else if (check_old_oid(update, &lock->old_oid, err)) {
- ret = TRANSACTION_GENERIC_ERROR;
- goto out;
+ } else {
+ ret = check_old_oid(update, &lock->old_oid, err);
+ if (ret) {
+ goto out;
+ }
}
} else {
/*
@@ -2643,9 +2648,11 @@ static int lock_ref_for_update(struct files_ref_store *refs,
update->old_target);
ret = TRANSACTION_GENERIC_ERROR;
goto out;
- } else if (check_old_oid(update, &lock->old_oid, err)) {
- ret = TRANSACTION_GENERIC_ERROR;
- goto out;
+ } else {
+ ret = check_old_oid(update, &lock->old_oid, err);
+ if (ret) {
+ goto out;
+ }
}
/*
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 58aa56d1b2..66e66e0fc1 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -674,6 +674,11 @@ struct ref_storage_be {
ref_iterator_begin_fn *iterator_begin;
read_raw_ref_fn *read_raw_ref;
+
+ /*
+ * Please refer to `refs_read_symbolic_ref()` for the expected
+ * behaviour.
+ */
read_symbolic_ref_fn *read_symbolic_ref;
reflog_iterator_begin_fn *reflog_iterator_begin;
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 647ef9b05b..8a2a5b847c 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -15,6 +15,7 @@
#include "../object.h"
#include "../path.h"
#include "../refs.h"
+#include "../reftable/reftable-basics.h"
#include "../reftable/reftable-stack.h"
#include "../reftable/reftable-record.h"
#include "../reftable/reftable-error.h"
@@ -23,6 +24,7 @@
#include "../setup.h"
#include "../strmap.h"
#include "../trace2.h"
+#include "../write-or-die.h"
#include "parse.h"
#include "refs-internal.h"
@@ -32,24 +34,111 @@
*/
#define REF_UPDATE_VIA_HEAD (1 << 8)
+struct reftable_backend {
+ struct reftable_stack *stack;
+ struct reftable_iterator it;
+};
+
+static void reftable_backend_on_reload(void *payload)
+{
+ struct reftable_backend *be = payload;
+ reftable_iterator_destroy(&be->it);
+}
+
+static int reftable_backend_init(struct reftable_backend *be,
+ const char *path,
+ const struct reftable_write_options *_opts)
+{
+ struct reftable_write_options opts = *_opts;
+ opts.on_reload = reftable_backend_on_reload;
+ opts.on_reload_payload = be;
+ return reftable_new_stack(&be->stack, path, &opts);
+}
+
+static void reftable_backend_release(struct reftable_backend *be)
+{
+ reftable_stack_destroy(be->stack);
+ be->stack = NULL;
+ reftable_iterator_destroy(&be->it);
+}
+
+static int reftable_backend_read_ref(struct reftable_backend *be,
+ const char *refname,
+ struct object_id *oid,
+ struct strbuf *referent,
+ unsigned int *type)
+{
+ struct reftable_ref_record ref = {0};
+ int ret;
+
+ if (!be->it.ops) {
+ ret = reftable_stack_init_ref_iterator(be->stack, &be->it);
+ if (ret)
+ goto done;
+ }
+
+ ret = reftable_iterator_seek_ref(&be->it, refname);
+ if (ret)
+ goto done;
+
+ ret = reftable_iterator_next_ref(&be->it, &ref);
+ if (ret)
+ goto done;
+
+ if (strcmp(ref.refname, refname)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (ref.value_type == REFTABLE_REF_SYMREF) {
+ strbuf_reset(referent);
+ strbuf_addstr(referent, ref.value.symref);
+ *type |= REF_ISSYMREF;
+ } else if (reftable_ref_record_val1(&ref)) {
+ unsigned int hash_id;
+
+ switch (reftable_stack_hash_id(be->stack)) {
+ case REFTABLE_HASH_SHA1:
+ hash_id = GIT_HASH_SHA1;
+ break;
+ case REFTABLE_HASH_SHA256:
+ hash_id = GIT_HASH_SHA256;
+ break;
+ default:
+ BUG("unhandled hash ID %d", reftable_stack_hash_id(be->stack));
+ }
+
+ oidread(oid, reftable_ref_record_val1(&ref),
+ &hash_algos[hash_id]);
+ } else {
+ /* We got a tombstone, which should not happen. */
+ BUG("unhandled reference value type %d", ref.value_type);
+ }
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ reftable_ref_record_release(&ref);
+ return ret;
+}
+
struct reftable_ref_store {
struct ref_store base;
/*
- * The main stack refers to the common dir and thus contains common
+ * The main backend refers to the common dir and thus contains common
* refs as well as refs of the main repository.
*/
- struct reftable_stack *main_stack;
+ struct reftable_backend main_backend;
/*
- * The worktree stack refers to the gitdir in case the refdb is opened
+ * The worktree backend refers to the gitdir in case the refdb is opened
* via a worktree. It thus contains the per-worktree refs.
*/
- struct reftable_stack *worktree_stack;
+ struct reftable_backend worktree_backend;
/*
- * Map of worktree stacks by their respective worktree names. The map
+ * Map of worktree backends by their respective worktree names. The map
* is populated lazily when we try to resolve `worktrees/$worktree` refs.
*/
- struct strmap worktree_stacks;
+ struct strmap worktree_backends;
struct reftable_write_options write_options;
unsigned int store_flags;
@@ -95,21 +184,25 @@ static struct reftable_ref_store *reftable_be_downcast(struct ref_store *ref_sto
* like `worktrees/$worktree/refs/heads/foo` as worktree stacks will store
* those references in their normalized form.
*/
-static struct reftable_stack *stack_for(struct reftable_ref_store *store,
- const char *refname,
- const char **rewritten_ref)
+static int backend_for(struct reftable_backend **out,
+ struct reftable_ref_store *store,
+ const char *refname,
+ const char **rewritten_ref,
+ int reload)
{
+ struct reftable_backend *be;
const char *wtname;
int wtname_len;
- if (!refname)
- return store->main_stack;
+ if (!refname) {
+ be = &store->main_backend;
+ goto out;
+ }
switch (parse_worktree_ref(refname, &wtname, &wtname_len, rewritten_ref)) {
case REF_WORKTREE_OTHER: {
static struct strbuf wtname_buf = STRBUF_INIT;
struct strbuf wt_dir = STRBUF_INIT;
- struct reftable_stack *stack;
/*
* We're using a static buffer here so that we don't need to
@@ -123,40 +216,55 @@ static struct reftable_stack *stack_for(struct reftable_ref_store *store,
/*
* There is an edge case here: when the worktree references the
* current worktree, then we set up the stack once via
- * `worktree_stacks` and once via `worktree_stack`. This is
+ * `worktree_backends` and once via `worktree_backend`. This is
* wasteful, but in the reading case it shouldn't matter. And
* in the writing case we would notice that the stack is locked
* already and error out when trying to write a reference via
* both stacks.
*/
- stack = strmap_get(&store->worktree_stacks, wtname_buf.buf);
- if (!stack) {
+ be = strmap_get(&store->worktree_backends, wtname_buf.buf);
+ if (!be) {
strbuf_addf(&wt_dir, "%s/worktrees/%s/reftable",
store->base.repo->commondir, wtname_buf.buf);
- store->err = reftable_new_stack(&stack, wt_dir.buf,
- &store->write_options);
+ CALLOC_ARRAY(be, 1);
+ store->err = reftable_backend_init(be, wt_dir.buf,
+ &store->write_options);
assert(store->err != REFTABLE_API_ERROR);
- strmap_put(&store->worktree_stacks, wtname_buf.buf, stack);
+
+ strmap_put(&store->worktree_backends, wtname_buf.buf, be);
}
strbuf_release(&wt_dir);
- return stack;
+ goto out;
}
case REF_WORKTREE_CURRENT:
/*
* If there is no worktree stack then we're currently in the
* main worktree. We thus return the main stack in that case.
*/
- if (!store->worktree_stack)
- return store->main_stack;
- return store->worktree_stack;
+ if (!store->worktree_backend.stack)
+ be = &store->main_backend;
+ else
+ be = &store->worktree_backend;
+ goto out;
case REF_WORKTREE_MAIN:
case REF_WORKTREE_SHARED:
- return store->main_stack;
+ be = &store->main_backend;
+ goto out;
default:
BUG("unhandled worktree reference type");
}
+
+out:
+ if (reload) {
+ int ret = reftable_stack_reload(be->stack);
+ if (ret)
+ return ret;
+ }
+ *out = be;
+
+ return 0;
}
static int should_write_log(struct reftable_ref_store *refs, const char *refname)
@@ -205,38 +313,6 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru
log->value.update.tz_offset = sign * atoi(tz_begin);
}
-static int read_ref_without_reload(struct reftable_ref_store *refs,
- struct reftable_stack *stack,
- const char *refname,
- struct object_id *oid,
- struct strbuf *referent,
- unsigned int *type)
-{
- struct reftable_ref_record ref = {0};
- int ret;
-
- ret = reftable_stack_read_ref(stack, refname, &ref);
- if (ret)
- goto done;
-
- if (ref.value_type == REFTABLE_REF_SYMREF) {
- strbuf_reset(referent);
- strbuf_addstr(referent, ref.value.symref);
- *type |= REF_ISSYMREF;
- } else if (reftable_ref_record_val1(&ref)) {
- oidread(oid, reftable_ref_record_val1(&ref),
- refs->base.repo->hash_algo);
- } else {
- /* We got a tombstone, which should not happen. */
- BUG("unhandled reference value type %d", ref.value_type);
- }
-
-done:
- assert(ret != REFTABLE_API_ERROR);
- reftable_ref_record_release(&ref);
- return ret;
-}
-
static int reftable_be_config(const char *var, const char *value,
const struct config_context *ctx,
void *_opts)
@@ -272,6 +348,11 @@ static int reftable_be_config(const char *var, const char *value,
return 0;
}
+static int reftable_be_fsync(int fd)
+{
+ return fsync_component(FSYNC_COMPONENT_REFERENCE, fd);
+}
+
static struct ref_store *reftable_be_init(struct repository *repo,
const char *gitdir,
unsigned int store_flags)
@@ -285,15 +366,25 @@ static struct ref_store *reftable_be_init(struct repository *repo,
umask(mask);
base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
- strmap_init(&refs->worktree_stacks);
+ strmap_init(&refs->worktree_backends);
refs->store_flags = store_flags;
refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
- refs->write_options.hash_id = repo->hash_algo->format_id;
+ switch (repo->hash_algo->format_id) {
+ case GIT_SHA1_FORMAT_ID:
+ refs->write_options.hash_id = REFTABLE_HASH_SHA1;
+ break;
+ case GIT_SHA256_FORMAT_ID:
+ refs->write_options.hash_id = REFTABLE_HASH_SHA256;
+ break;
+ default:
+ BUG("unknown hash algorithm %d", repo->hash_algo->format_id);
+ }
refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
refs->write_options.disable_auto_compact =
!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
refs->write_options.lock_timeout_ms = 100;
+ refs->write_options.fsync = reftable_be_fsync;
git_config(reftable_be_config, &refs->write_options);
@@ -320,8 +411,8 @@ static struct ref_store *reftable_be_init(struct repository *repo,
strbuf_realpath(&path, gitdir, 0);
}
strbuf_addstr(&path, "/reftable");
- refs->err = reftable_new_stack(&refs->main_stack, path.buf,
- &refs->write_options);
+ refs->err = reftable_backend_init(&refs->main_backend, path.buf,
+ &refs->write_options);
if (refs->err)
goto done;
@@ -337,8 +428,8 @@ static struct ref_store *reftable_be_init(struct repository *repo,
strbuf_reset(&path);
strbuf_addf(&path, "%s/reftable", gitdir);
- refs->err = reftable_new_stack(&refs->worktree_stack, path.buf,
- &refs->write_options);
+ refs->err = reftable_backend_init(&refs->worktree_backend, path.buf,
+ &refs->write_options);
if (refs->err)
goto done;
}
@@ -357,19 +448,17 @@ static void reftable_be_release(struct ref_store *ref_store)
struct strmap_entry *entry;
struct hashmap_iter iter;
- if (refs->main_stack) {
- reftable_stack_destroy(refs->main_stack);
- refs->main_stack = NULL;
- }
+ if (refs->main_backend.stack)
+ reftable_backend_release(&refs->main_backend);
+ if (refs->worktree_backend.stack)
+ reftable_backend_release(&refs->worktree_backend);
- if (refs->worktree_stack) {
- reftable_stack_destroy(refs->worktree_stack);
- refs->worktree_stack = NULL;
+ strmap_for_each_entry(&refs->worktree_backends, &iter, entry) {
+ struct reftable_backend *be = entry->value;
+ reftable_backend_release(be);
+ free(be);
}
-
- strmap_for_each_entry(&refs->worktree_stacks, &iter, entry)
- reftable_stack_destroy(entry->value);
- strmap_clear(&refs->worktree_stacks, 0);
+ strmap_clear(&refs->worktree_backends, 0);
}
static int reftable_be_create_on_disk(struct ref_store *ref_store,
@@ -764,7 +853,7 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
required_flags |= REF_STORE_ODB;
refs = reftable_be_downcast(ref_store, required_flags, "ref_iterator_begin");
- main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix,
+ main_iter = ref_iterator_for_stack(refs, refs->main_backend.stack, prefix,
exclude_patterns, flags);
/*
@@ -772,14 +861,14 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
* right now. If we aren't, then we return the common reftable
* iterator, only.
*/
- if (!refs->worktree_stack)
+ if (!refs->worktree_backend.stack)
return &main_iter->base;
/*
* Otherwise we merge both the common and the per-worktree refs into a
* single iterator.
*/
- worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix,
+ worktree_iter = ref_iterator_for_stack(refs, refs->worktree_backend.stack, prefix,
exclude_patterns, flags);
return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
ref_iterator_select, NULL);
@@ -794,17 +883,17 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_backend *be;
int ret;
if (refs->err < 0)
return refs->err;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&be, refs, refname, &refname, 1);
if (ret)
return ret;
- ret = read_ref_without_reload(refs, stack, refname, oid, referent, type);
+ ret = reftable_backend_read_ref(be, refname, oid, referent, type);
if (ret < 0)
return ret;
if (ret > 0) {
@@ -821,21 +910,22 @@ static int reftable_be_read_symbolic_ref(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_READ, "read_symbolic_ref");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
- struct reftable_ref_record ref = {0};
+ struct reftable_backend *be;
+ struct object_id oid;
+ unsigned int type = 0;
int ret;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&be, refs, refname, &refname, 1);
if (ret)
return ret;
- ret = reftable_stack_read_ref(stack, refname, &ref);
- if (ret == 0 && ref.value_type == REFTABLE_REF_SYMREF)
- strbuf_addstr(referent, ref.value.symref);
- else
+ ret = reftable_backend_read_ref(be, refname, &oid, referent, &type);
+ if (ret)
ret = -1;
-
- reftable_ref_record_release(&ref);
+ else if (type == REF_ISSYMREF)
+ ; /* happy */
+ else
+ ret = NOT_A_SYMREF;
return ret;
}
@@ -846,7 +936,7 @@ struct reftable_transaction_update {
struct write_transaction_table_arg {
struct reftable_ref_store *refs;
- struct reftable_stack *stack;
+ struct reftable_backend *be;
struct reftable_addition *addition;
struct reftable_transaction_update *updates;
size_t updates_nr;
@@ -881,27 +971,37 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
struct ref_update *update,
struct strbuf *err)
{
- struct reftable_stack *stack = stack_for(refs, update->refname, NULL);
struct write_transaction_table_arg *arg = NULL;
+ struct reftable_backend *be;
size_t i;
int ret;
/*
+ * This function gets called in a loop, and we don't want to repeatedly
+ * reload the stack for every single ref update. Instead, we manually
+ * reload further down in the case where we haven't yet prepared the
+ * specific `reftable_backend`.
+ */
+ ret = backend_for(&be, refs, update->refname, NULL, 0);
+ if (ret)
+ return ret;
+
+ /*
* Search for a preexisting stack update. If there is one then we add
* the update to it, otherwise we set up a new stack update.
*/
for (i = 0; !arg && i < tx_data->args_nr; i++)
- if (tx_data->args[i].stack == stack)
+ if (tx_data->args[i].be == be)
arg = &tx_data->args[i];
if (!arg) {
struct reftable_addition *addition;
- ret = reftable_stack_reload(stack);
+ ret = reftable_stack_reload(be->stack);
if (ret)
return ret;
- ret = reftable_stack_new_addition(&addition, stack,
+ ret = reftable_stack_new_addition(&addition, be->stack,
REFTABLE_STACK_NEW_ADDITION_RELOAD);
if (ret) {
if (ret == REFTABLE_LOCK_ERROR)
@@ -913,7 +1013,7 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
tx_data->args_alloc);
arg = &tx_data->args[tx_data->args_nr++];
arg->refs = refs;
- arg->stack = stack;
+ arg->be = be;
arg->addition = addition;
arg->updates = NULL;
arg->updates_nr = 0;
@@ -968,6 +1068,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
struct strbuf referent = STRBUF_INIT, head_referent = STRBUF_INIT;
struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
struct reftable_transaction_data *tx_data = NULL;
+ struct reftable_backend *be;
struct object_id head_oid;
unsigned int head_type = 0;
size_t i;
@@ -1014,8 +1115,23 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
goto done;
}
- ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD",
- &head_oid, &head_referent, &head_type);
+ /*
+ * TODO: it's dubious whether we should reload the stack that "HEAD"
+ * belongs to or not. In theory, it may happen that we only modify
+ * stacks which are _not_ part of the "HEAD" stack. In that case we
+ * wouldn't have prepared any transaction for its stack and would not
+ * have reloaded it, which may mean that it is stale.
+ *
+ * On the other hand, reloading that stack without locking it feels
+ * wrong, too, as the value of "HEAD" could be modified concurrently at
+ * any point in time.
+ */
+ ret = backend_for(&be, refs, "HEAD", NULL, 0);
+ if (ret)
+ goto done;
+
+ ret = reftable_backend_read_ref(be, "HEAD", &head_oid,
+ &head_referent, &head_type);
if (ret < 0)
goto done;
ret = 0;
@@ -1023,10 +1139,18 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
for (i = 0; i < transaction->nr; i++) {
struct ref_update *u = transaction->updates[i];
struct object_id current_oid = {0};
- struct reftable_stack *stack;
const char *rewritten_ref;
- stack = stack_for(refs, u->refname, &rewritten_ref);
+ /*
+ * There is no need to reload the respective backends here as
+ * we have already reloaded them when preparing the transaction
+ * update. And given that the stacks have been locked there
+ * shouldn't have been any concurrent modifications of the
+ * stack.
+ */
+ ret = backend_for(&be, refs, u->refname, &rewritten_ref, 0);
+ if (ret)
+ goto done;
/* Verify that the new object ID is valid. */
if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) &&
@@ -1082,8 +1206,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
string_list_insert(&affected_refnames, new_update->refname);
}
- ret = read_ref_without_reload(refs, stack, rewritten_ref,
- &current_oid, &referent, &u->type);
+ ret = reftable_backend_read_ref(be, rewritten_ref,
+ &current_oid, &referent, &u->type);
if (ret < 0)
goto done;
if (ret > 0 && !ref_update_expects_existing_old_ref(u)) {
@@ -1208,10 +1332,13 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
goto done;
}
} else if ((u->flags & REF_HAVE_OLD) && !oideq(&current_oid, &u->old_oid)) {
- if (is_null_oid(&u->old_oid))
+ ret = TRANSACTION_NAME_CONFLICT;
+ if (is_null_oid(&u->old_oid)) {
strbuf_addf(err, _("cannot lock ref '%s': "
"reference already exists"),
ref_update_original_update_refname(u));
+ ret = TRANSACTION_CREATE_EXISTS;
+ }
else if (is_null_oid(&current_oid))
strbuf_addf(err, _("cannot lock ref '%s': "
"reference is missing but expected %s"),
@@ -1223,7 +1350,6 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
ref_update_original_update_refname(u),
oid_to_hex(&current_oid),
oid_to_hex(&u->old_oid));
- ret = -1;
goto done;
}
@@ -1286,7 +1412,7 @@ static int transaction_update_cmp(const void *a, const void *b)
static int write_transaction_table(struct reftable_writer *writer, void *cb_data)
{
struct write_transaction_table_arg *arg = cb_data;
- uint64_t ts = reftable_stack_next_update_index(arg->stack);
+ uint64_t ts = reftable_stack_next_update_index(arg->be->stack);
struct reftable_log_record *logs = NULL;
struct ident_split committer_ident = {0};
size_t logs_nr = 0, logs_alloc = 0, i;
@@ -1322,7 +1448,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
struct reftable_log_record log = {0};
struct reftable_iterator it = {0};
- ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ ret = reftable_stack_init_log_iterator(arg->be->stack, &it);
if (ret < 0)
goto done;
@@ -1503,9 +1629,9 @@ static int reftable_be_pack_refs(struct ref_store *ref_store,
if (refs->err)
return refs->err;
- stack = refs->worktree_stack;
+ stack = refs->worktree_backend.stack;
if (!stack)
- stack = refs->main_stack;
+ stack = refs->main_backend.stack;
if (opts->flags & PACK_REFS_AUTO)
ret = reftable_stack_auto_compact(stack);
@@ -1536,7 +1662,7 @@ struct write_create_symref_arg {
struct write_copy_arg {
struct reftable_ref_store *refs;
- struct reftable_stack *stack;
+ struct reftable_backend *be;
const char *oldname;
const char *newname;
const char *logmsg;
@@ -1561,7 +1687,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
if (split_ident_line(&committer_ident, committer_info, strlen(committer_info)))
BUG("failed splitting committer info");
- if (reftable_stack_read_ref(arg->stack, arg->oldname, &old_ref)) {
+ if (reftable_stack_read_ref(arg->be->stack, arg->oldname, &old_ref)) {
ret = error(_("refname %s not found"), arg->oldname);
goto done;
}
@@ -1600,7 +1726,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
* the old branch and the creation of the new branch, and we cannot do
* two changes to a reflog in a single update.
*/
- deletion_ts = creation_ts = reftable_stack_next_update_index(arg->stack);
+ deletion_ts = creation_ts = reftable_stack_next_update_index(arg->be->stack);
if (arg->delete_old)
creation_ts++;
reftable_writer_set_limits(writer, deletion_ts, creation_ts);
@@ -1643,8 +1769,8 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
logs_nr++;
- ret = read_ref_without_reload(arg->refs, arg->stack, "HEAD", &head_oid,
- &head_referent, &head_type);
+ ret = reftable_backend_read_ref(arg->be, "HEAD", &head_oid,
+ &head_referent, &head_type);
if (ret < 0)
goto done;
append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname);
@@ -1687,7 +1813,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
* copy over all log entries from the old reflog. Last but not least,
* when renaming we also have to delete all the old reflog entries.
*/
- ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ ret = reftable_stack_init_log_iterator(arg->be->stack, &it);
if (ret < 0)
goto done;
@@ -1760,10 +1886,8 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
- struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname);
struct write_copy_arg arg = {
.refs = refs,
- .stack = stack,
.oldname = oldrefname,
.newname = newrefname,
.logmsg = logmsg,
@@ -1775,10 +1899,10 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
if (ret < 0)
goto done;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
if (ret)
goto done;
- ret = reftable_stack_add(stack, &write_copy_table, &arg);
+ ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
done:
assert(ret != REFTABLE_API_ERROR);
@@ -1792,10 +1916,8 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_WRITE, "copy_ref");
- struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname);
struct write_copy_arg arg = {
.refs = refs,
- .stack = stack,
.oldname = oldrefname,
.newname = newrefname,
.logmsg = logmsg,
@@ -1806,10 +1928,10 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
if (ret < 0)
goto done;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
if (ret)
goto done;
- ret = reftable_stack_add(stack, &write_copy_table, &arg);
+ ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
done:
assert(ret != REFTABLE_API_ERROR);
@@ -1930,11 +2052,11 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store *
reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_iterator_begin");
struct reftable_reflog_iterator *main_iter, *worktree_iter;
- main_iter = reflog_iterator_for_stack(refs, refs->main_stack);
- if (!refs->worktree_stack)
+ main_iter = reflog_iterator_for_stack(refs, refs->main_backend.stack);
+ if (!refs->worktree_backend.stack)
return &main_iter->base;
- worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_stack);
+ worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_backend.stack);
return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
ref_iterator_select, NULL);
@@ -1973,15 +2095,23 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent_reverse");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
struct reftable_log_record log = {0};
struct reftable_iterator it = {0};
+ struct reftable_backend *be;
int ret;
if (refs->err < 0)
return refs->err;
- ret = reftable_stack_init_log_iterator(stack, &it);
+ /*
+ * TODO: we should adapt this callsite to reload the stack. There is no
+ * obvious reason why we shouldn't.
+ */
+ ret = backend_for(&be, refs, refname, &refname, 0);
+ if (ret)
+ goto done;
+
+ ret = reftable_stack_init_log_iterator(be->stack, &it);
if (ret < 0)
goto done;
@@ -2013,16 +2143,24 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
struct reftable_log_record *logs = NULL;
struct reftable_iterator it = {0};
+ struct reftable_backend *be;
size_t logs_alloc = 0, logs_nr = 0, i;
int ret;
if (refs->err < 0)
return refs->err;
- ret = reftable_stack_init_log_iterator(stack, &it);
+ /*
+ * TODO: we should adapt this callsite to reload the stack. There is no
+ * obvious reason why we shouldn't.
+ */
+ ret = backend_for(&be, refs, refname, &refname, 0);
+ if (ret)
+ goto done;
+
+ ret = reftable_stack_init_log_iterator(be->stack, &it);
if (ret < 0)
goto done;
@@ -2062,20 +2200,20 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_exists");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
struct reftable_log_record log = {0};
struct reftable_iterator it = {0};
+ struct reftable_backend *be;
int ret;
ret = refs->err;
if (ret < 0)
goto done;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&be, refs, refname, &refname, 1);
if (ret < 0)
goto done;
- ret = reftable_stack_init_log_iterator(stack, &it);
+ ret = reftable_stack_init_log_iterator(be->stack, &it);
if (ret < 0)
goto done;
@@ -2147,10 +2285,9 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_WRITE, "create_reflog");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_backend *be;
struct write_reflog_existence_arg arg = {
.refs = refs,
- .stack = stack,
.refname = refname,
};
int ret;
@@ -2159,11 +2296,12 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
if (ret < 0)
goto done;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&be, refs, refname, &refname, 1);
if (ret)
goto done;
+ arg.stack = be->stack;
- ret = reftable_stack_add(stack, &write_reflog_existence_table, &arg);
+ ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg);
done:
return ret;
@@ -2221,17 +2359,18 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_WRITE, "delete_reflog");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_backend *be;
struct write_reflog_delete_arg arg = {
- .stack = stack,
.refname = refname,
};
int ret;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&be, refs, refname, &refname, 1);
if (ret)
return ret;
- ret = reftable_stack_add(stack, &write_reflog_delete_table, &arg);
+ arg.stack = be->stack;
+
+ ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg);
assert(ret != REFTABLE_API_ERROR);
return ret;
@@ -2330,26 +2469,27 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
*/
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_WRITE, "reflog_expire");
- struct reftable_stack *stack = stack_for(refs, refname, &refname);
struct reftable_log_record *logs = NULL;
struct reftable_log_record *rewritten = NULL;
- struct reftable_ref_record ref_record = {0};
struct reftable_iterator it = {0};
struct reftable_addition *add = NULL;
struct reflog_expiry_arg arg = {0};
+ struct reftable_backend *be;
struct object_id oid = {0};
+ struct strbuf referent = STRBUF_INIT;
uint8_t *last_hash = NULL;
size_t logs_nr = 0, logs_alloc = 0, i;
+ unsigned int type = 0;
int ret;
if (refs->err < 0)
return refs->err;
- ret = reftable_stack_reload(stack);
+ ret = backend_for(&be, refs, refname, &refname, 1);
if (ret < 0)
goto done;
- ret = reftable_stack_init_log_iterator(stack, &it);
+ ret = reftable_stack_init_log_iterator(be->stack, &it);
if (ret < 0)
goto done;
@@ -2357,16 +2497,13 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0)
goto done;
- ret = reftable_stack_new_addition(&add, stack, 0);
+ ret = reftable_stack_new_addition(&add, be->stack, 0);
if (ret < 0)
goto done;
- ret = reftable_stack_read_ref(stack, refname, &ref_record);
+ ret = reftable_backend_read_ref(be, refname, &oid, &referent, &type);
if (ret < 0)
goto done;
- if (reftable_ref_record_val1(&ref_record))
- oidread(&oid, reftable_ref_record_val1(&ref_record),
- ref_store->repo->hash_algo);
prepare_fn(refname, &oid, policy_cb_data);
while (1) {
@@ -2433,15 +2570,14 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
}
}
- if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash &&
- reftable_ref_record_val1(&ref_record))
+ if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash && !is_null_oid(&oid))
oidread(&arg.update_oid, last_hash, ref_store->repo->hash_algo);
arg.refs = refs;
arg.records = rewritten;
arg.len = logs_nr;
- arg.stack = stack,
- arg.refname = refname,
+ arg.stack = be->stack;
+ arg.refname = refname;
ret = reftable_addition_add(add, &write_reflog_expiry_table, &arg);
if (ret < 0)
@@ -2459,11 +2595,11 @@ done:
cleanup_fn(policy_cb_data);
assert(ret != REFTABLE_API_ERROR);
- reftable_ref_record_release(&ref_record);
reftable_iterator_destroy(&it);
reftable_addition_destroy(add);
for (i = 0; i < logs_nr; i++)
reftable_log_record_release(&logs[i]);
+ strbuf_release(&referent);
free(logs);
free(rewritten);
return ret;
diff --git a/reftable/basics.c b/reftable/basics.c
index bc4fcc9144..70b1091d14 100644
--- a/reftable/basics.c
+++ b/reftable/basics.c
@@ -17,6 +17,8 @@ static void (*reftable_free_ptr)(void *);
void *reftable_malloc(size_t sz)
{
+ if (!sz)
+ return NULL;
if (reftable_malloc_ptr)
return (*reftable_malloc_ptr)(sz);
return malloc(sz);
@@ -24,6 +26,11 @@ void *reftable_malloc(size_t sz)
void *reftable_realloc(void *p, size_t sz)
{
+ if (!sz) {
+ reftable_free(p);
+ return NULL;
+ }
+
if (reftable_realloc_ptr)
return (*reftable_realloc_ptr)(p, sz);
return realloc(p, sz);
@@ -271,14 +278,15 @@ int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b)
return p;
}
-int hash_size(uint32_t id)
+int hash_size(enum reftable_hash id)
{
+ if (!id)
+ return REFTABLE_HASH_SIZE_SHA1;
switch (id) {
- case 0:
- case GIT_SHA1_FORMAT_ID:
- return GIT_SHA1_RAWSZ;
- case GIT_SHA256_FORMAT_ID:
- return GIT_SHA256_RAWSZ;
+ case REFTABLE_HASH_SHA1:
+ return REFTABLE_HASH_SIZE_SHA1;
+ case REFTABLE_HASH_SHA256:
+ return REFTABLE_HASH_SIZE_SHA256;
}
abort();
}
diff --git a/reftable/basics.h b/reftable/basics.h
index 7aa46d7c30..36beda2c25 100644
--- a/reftable/basics.h
+++ b/reftable/basics.h
@@ -148,6 +148,14 @@ char *reftable_strdup(const char *str);
/* Find the longest shared prefix size of `a` and `b` */
int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b);
-int hash_size(uint32_t id);
+int hash_size(enum reftable_hash id);
+
+/*
+ * Format IDs that identify the hash function used by a reftable. Note that
+ * these constants end up on disk and thus mustn't change. The format IDs are
+ * "sha1" and "s256" in big endian, respectively.
+ */
+#define REFTABLE_FORMAT_ID_SHA1 ((uint32_t) 0x73686131)
+#define REFTABLE_FORMAT_ID_SHA256 ((uint32_t) 0x73323536)
#endif
diff --git a/reftable/merged.c b/reftable/merged.c
index 514d6facf4..e72b39e178 100644
--- a/reftable/merged.c
+++ b/reftable/merged.c
@@ -66,6 +66,8 @@ static int merged_iter_seek(struct merged_iter *mi, struct reftable_record *want
int err;
mi->advance_index = -1;
+ while (!merged_iter_pqueue_is_empty(mi->pq))
+ merged_iter_pqueue_remove(&mi->pq);
for (size_t i = 0; i < mi->subiters_len; i++) {
err = iterator_seek(&mi->subiters[i].iter, want);
@@ -181,7 +183,7 @@ static void iterator_from_merged_iter(struct reftable_iterator *it,
int reftable_merged_table_new(struct reftable_merged_table **dest,
struct reftable_reader **readers, size_t n,
- uint32_t hash_id)
+ enum reftable_hash hash_id)
{
struct reftable_merged_table *m = NULL;
uint64_t last_max = 0;
@@ -238,14 +240,16 @@ int merged_table_init_iter(struct reftable_merged_table *mt,
struct reftable_iterator *it,
uint8_t typ)
{
- struct merged_subiter *subiters;
+ struct merged_subiter *subiters = NULL;
struct merged_iter *mi = NULL;
int ret;
- REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len);
- if (!subiters) {
- ret = REFTABLE_OUT_OF_MEMORY_ERROR;
- goto out;
+ if (mt->readers_len) {
+ REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len);
+ if (!subiters) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
}
for (size_t i = 0; i < mt->readers_len; i++) {
@@ -293,7 +297,7 @@ int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
return merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
}
-uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
+enum reftable_hash reftable_merged_table_hash_id(struct reftable_merged_table *mt)
{
return mt->hash_id;
}
diff --git a/reftable/merged.h b/reftable/merged.h
index 89bd0c4b35..0b7d939e92 100644
--- a/reftable/merged.h
+++ b/reftable/merged.h
@@ -10,11 +10,12 @@ https://developers.google.com/open-source/licenses/bsd
#define MERGED_H
#include "system.h"
+#include "reftable-basics.h"
struct reftable_merged_table {
struct reftable_reader **readers;
size_t readers_len;
- uint32_t hash_id;
+ enum reftable_hash hash_id;
/* If unset, produce deletions. This is useful for compaction. For the
* full stack, deletions should be produced. */
diff --git a/reftable/reader.c b/reftable/reader.c
index 90dc950b57..ea82955c9b 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -67,7 +67,7 @@ static int reader_get_block(struct reftable_reader *r,
return block_source_read_block(&r->source, dest, off, sz);
}
-uint32_t reftable_reader_hash_id(struct reftable_reader *r)
+enum reftable_hash reftable_reader_hash_id(struct reftable_reader *r)
{
return r->hash_id;
}
@@ -107,18 +107,20 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer,
f += 8;
if (r->version == 1) {
- r->hash_id = GIT_SHA1_FORMAT_ID;
+ r->hash_id = REFTABLE_HASH_SHA1;
} else {
- r->hash_id = get_be32(f);
- switch (r->hash_id) {
- case GIT_SHA1_FORMAT_ID:
+ switch (get_be32(f)) {
+ case REFTABLE_FORMAT_ID_SHA1:
+ r->hash_id = REFTABLE_HASH_SHA1;
break;
- case GIT_SHA256_FORMAT_ID:
+ case REFTABLE_FORMAT_ID_SHA256:
+ r->hash_id = REFTABLE_HASH_SHA256;
break;
default:
err = REFTABLE_FORMAT_ERROR;
goto done;
}
+
f += 4;
}
diff --git a/reftable/reader.h b/reftable/reader.h
index 010fbfe851..d2b48a4849 100644
--- a/reftable/reader.h
+++ b/reftable/reader.h
@@ -37,8 +37,8 @@ struct reftable_reader {
/* Size of the file, excluding the footer. */
uint64_t size;
- /* 'sha1' for SHA1, 's256' for SHA-256 */
- uint32_t hash_id;
+ /* The hash function used for ref records. */
+ enum reftable_hash hash_id;
uint32_t block_size;
uint64_t min_update_index;
diff --git a/reftable/reftable-basics.h b/reftable/reftable-basics.h
index 6e8e636b71..e0397ed583 100644
--- a/reftable/reftable-basics.h
+++ b/reftable/reftable-basics.h
@@ -11,6 +11,19 @@
#include <stddef.h>
+/*
+ * Hash functions understood by the reftable library. Note that the values are
+ * arbitrary and somewhat random such that we can easily detect cases where the
+ * hash hasn't been properly set up.
+ */
+enum reftable_hash {
+ REFTABLE_HASH_SHA1 = 89,
+ REFTABLE_HASH_SHA256 = 247,
+};
+#define REFTABLE_HASH_SIZE_SHA1 20
+#define REFTABLE_HASH_SIZE_SHA256 32
+#define REFTABLE_HASH_SIZE_MAX REFTABLE_HASH_SIZE_SHA256
+
/* Overrides the functions to use for memory management. */
void reftable_set_alloc(void *(*malloc)(size_t),
void *(*realloc)(void *, size_t), void (*free)(void *));
diff --git a/reftable/reftable-merged.h b/reftable/reftable-merged.h
index a970d5dd89..f2d01c3ef8 100644
--- a/reftable/reftable-merged.h
+++ b/reftable/reftable-merged.h
@@ -34,7 +34,7 @@ struct reftable_reader;
*/
int reftable_merged_table_new(struct reftable_merged_table **dest,
struct reftable_reader **readers, size_t n,
- uint32_t hash_id);
+ enum reftable_hash hash_id);
/* Initialize a merged table iterator for reading refs. */
int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
@@ -56,6 +56,6 @@ reftable_merged_table_min_update_index(struct reftable_merged_table *mt);
void reftable_merged_table_free(struct reftable_merged_table *m);
/* return the hash ID of the merged table. */
-uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
+enum reftable_hash reftable_merged_table_hash_id(struct reftable_merged_table *m);
#endif
diff --git a/reftable/reftable-reader.h b/reftable/reftable-reader.h
index 6a2d0b693f..0085fbb903 100644
--- a/reftable/reftable-reader.h
+++ b/reftable/reftable-reader.h
@@ -54,7 +54,7 @@ int reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it);
/* returns the hash ID used in this table. */
-uint32_t reftable_reader_hash_id(struct reftable_reader *r);
+enum reftable_hash reftable_reader_hash_id(struct reftable_reader *r);
/* return an iterator for the refs pointing to `oid`. */
int reftable_reader_refs_for(struct reftable_reader *r,
diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h
index 2d42463c58..ddd48eb579 100644
--- a/reftable/reftable-record.h
+++ b/reftable/reftable-record.h
@@ -9,7 +9,7 @@ https://developers.google.com/open-source/licenses/bsd
#ifndef REFTABLE_RECORD_H
#define REFTABLE_RECORD_H
-#include "hash.h"
+#include "reftable-basics.h"
#include <stdint.h>
/*
@@ -40,10 +40,10 @@ struct reftable_ref_record {
#define REFTABLE_NR_REF_VALUETYPES 4
} value_type;
union {
- unsigned char val1[GIT_MAX_RAWSZ];
+ unsigned char val1[REFTABLE_HASH_SIZE_MAX];
struct {
- unsigned char value[GIT_MAX_RAWSZ]; /* first hash */
- unsigned char target_value[GIT_MAX_RAWSZ]; /* second hash */
+ unsigned char value[REFTABLE_HASH_SIZE_MAX]; /* first hash */
+ unsigned char target_value[REFTABLE_HASH_SIZE_MAX]; /* second hash */
} val2;
char *symref; /* referent, malloced 0-terminated string */
} value;
@@ -85,8 +85,8 @@ struct reftable_log_record {
union {
struct {
- unsigned char new_hash[GIT_MAX_RAWSZ];
- unsigned char old_hash[GIT_MAX_RAWSZ];
+ unsigned char new_hash[REFTABLE_HASH_SIZE_MAX];
+ unsigned char old_hash[REFTABLE_HASH_SIZE_MAX];
char *name;
char *email;
uint64_t time;
diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h
index 54787f2ef5..ae14270ea7 100644
--- a/reftable/reftable-stack.h
+++ b/reftable/reftable-stack.h
@@ -149,4 +149,7 @@ struct reftable_compaction_stats {
struct reftable_compaction_stats *
reftable_stack_compaction_stats(struct reftable_stack *st);
+/* Return the hash of the stack. */
+enum reftable_hash reftable_stack_hash_id(struct reftable_stack *st);
+
#endif
diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h
index e4fc953788..5f9afa620b 100644
--- a/reftable/reftable-writer.h
+++ b/reftable/reftable-writer.h
@@ -33,7 +33,7 @@ struct reftable_write_options {
/* 4-byte identifier ("sha1", "s256") of the hash.
* Defaults to SHA1 if unset
*/
- uint32_t hash_id;
+ enum reftable_hash hash_id;
/* Default mode for creating files. If unset, use 0666 (+umask) */
unsigned int default_permissions;
@@ -62,6 +62,21 @@ struct reftable_write_options {
* negative value will cause us to block indefinitely.
*/
long lock_timeout_ms;
+
+ /*
+ * Optional callback used to fsync files to disk. Falls back to using
+ * fsync(3P) when unset.
+ */
+ int (*fsync)(int fd);
+
+ /*
+ * Callback function to execute whenever the stack is being reloaded.
+ * This can be used e.g. to discard cached information that relies on
+ * the old stack's data. The payload data will be passed as argument to
+ * the callback.
+ */
+ void (*on_reload)(void *payload);
+ void *on_reload_payload;
};
/* reftable_block_stats holds statistics for a single block type */
diff --git a/reftable/stack.c b/reftable/stack.c
index c33979536e..634f0c5425 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -8,7 +8,6 @@ https://developers.google.com/open-source/licenses/bsd
#include "stack.h"
-#include "../write-or-die.h"
#include "system.h"
#include "constants.h"
#include "merged.h"
@@ -17,7 +16,6 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable-record.h"
#include "reftable-merged.h"
#include "writer.h"
-#include "tempfile.h"
static int stack_try_add(struct reftable_stack *st,
int (*write_table)(struct reftable_writer *wr,
@@ -43,17 +41,28 @@ static int stack_filename(struct reftable_buf *dest, struct reftable_stack *st,
return 0;
}
-static ssize_t reftable_fd_write(void *arg, const void *data, size_t sz)
+static int stack_fsync(const struct reftable_write_options *opts, int fd)
{
- int *fdp = (int *)arg;
- return write_in_full(*fdp, data, sz);
+ if (opts->fsync)
+ return opts->fsync(fd);
+ return fsync(fd);
}
-static int reftable_fd_flush(void *arg)
+struct fd_writer {
+ const struct reftable_write_options *opts;
+ int fd;
+};
+
+static ssize_t fd_writer_write(void *arg, const void *data, size_t sz)
{
- int *fdp = (int *)arg;
+ struct fd_writer *writer = arg;
+ return write_in_full(writer->fd, data, sz);
+}
- return fsync_component(FSYNC_COMPONENT_REFERENCE, *fdp);
+static int fd_writer_flush(void *arg)
+{
+ struct fd_writer *writer = arg;
+ return stack_fsync(writer->opts, writer->fd);
}
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
@@ -73,7 +82,7 @@ int reftable_new_stack(struct reftable_stack **dest, const char *dir,
if (_opts)
opts = *_opts;
if (opts.hash_id == 0)
- opts.hash_id = GIT_SHA1_FORMAT_ID;
+ opts.hash_id = REFTABLE_HASH_SHA1;
*dest = NULL;
@@ -261,9 +270,9 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
int reuse_open)
{
size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
- struct reftable_reader **cur;
+ struct reftable_reader **cur = NULL;
struct reftable_reader **reused = NULL;
- struct reftable_reader **new_readers;
+ struct reftable_reader **new_readers = NULL;
size_t reused_len = 0, reused_alloc = 0, names_len;
size_t new_readers_len = 0;
struct reftable_merged_table *new_merged = NULL;
@@ -271,18 +280,22 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
int err = 0;
size_t i;
- cur = stack_copy_readers(st, cur_len);
- if (!cur) {
- err = REFTABLE_OUT_OF_MEMORY_ERROR;
- goto done;
+ if (cur_len) {
+ cur = stack_copy_readers(st, cur_len);
+ if (!cur) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
}
names_len = names_length(names);
- new_readers = reftable_calloc(names_len, sizeof(*new_readers));
- if (!new_readers) {
- err = REFTABLE_OUT_OF_MEMORY_ERROR;
- goto done;
+ if (names_len) {
+ new_readers = reftable_calloc(names_len, sizeof(*new_readers));
+ if (!new_readers) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
}
while (*names) {
@@ -539,6 +552,10 @@ out:
close(fd);
free_names(names);
free_names(names_after);
+
+ if (st->opts.on_reload)
+ st->opts.on_reload(st->opts.on_reload_payload);
+
return err;
}
@@ -648,7 +665,7 @@ static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max)
}
struct reftable_addition {
- struct lock_file tables_list_lock;
+ struct reftable_flock tables_list_lock;
struct reftable_stack *stack;
char **new_tables;
@@ -667,10 +684,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
add->stack = st;
- err = hold_lock_file_for_update_timeout(&add->tables_list_lock,
- st->list_file,
- LOCK_NO_DEREF,
- st->opts.lock_timeout_ms);
+ err = flock_acquire(&add->tables_list_lock, st->list_file,
+ st->opts.lock_timeout_ms);
if (err < 0) {
if (errno == EEXIST) {
err = REFTABLE_LOCK_ERROR;
@@ -680,7 +695,7 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
goto done;
}
if (st->opts.default_permissions) {
- if (chmod(get_lock_file_path(&add->tables_list_lock),
+ if (chmod(add->tables_list_lock.path,
st->opts.default_permissions) < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -724,7 +739,7 @@ static void reftable_addition_close(struct reftable_addition *add)
add->new_tables_len = 0;
add->new_tables_cap = 0;
- rollback_lock_file(&add->tables_list_lock);
+ flock_release(&add->tables_list_lock);
reftable_buf_release(&nm);
}
@@ -740,7 +755,6 @@ void reftable_addition_destroy(struct reftable_addition *add)
int reftable_addition_commit(struct reftable_addition *add)
{
struct reftable_buf table_list = REFTABLE_BUF_INIT;
- int lock_file_fd = get_lock_file_fd(&add->tables_list_lock);
int err = 0;
size_t i;
@@ -758,20 +772,20 @@ int reftable_addition_commit(struct reftable_addition *add)
goto done;
}
- err = write_in_full(lock_file_fd, table_list.buf, table_list.len);
+ err = write_in_full(add->tables_list_lock.fd, table_list.buf, table_list.len);
reftable_buf_release(&table_list);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
- err = fsync_component(FSYNC_COMPONENT_REFERENCE, lock_file_fd);
+ err = stack_fsync(&add->stack->opts, add->tables_list_lock.fd);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
- err = commit_lock_file(&add->tables_list_lock);
+ err = flock_commit(&add->tables_list_lock);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -857,9 +871,11 @@ int reftable_addition_add(struct reftable_addition *add,
struct reftable_buf tab_file_name = REFTABLE_BUF_INIT;
struct reftable_buf next_name = REFTABLE_BUF_INIT;
struct reftable_writer *wr = NULL;
- struct tempfile *tab_file = NULL;
+ struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
+ struct fd_writer writer = {
+ .opts = &add->stack->opts,
+ };
int err = 0;
- int tab_fd;
reftable_buf_reset(&next_name);
@@ -875,22 +891,20 @@ int reftable_addition_add(struct reftable_addition *add,
if (err < 0)
goto done;
- tab_file = mks_tempfile(temp_tab_file_name.buf);
- if (!tab_file) {
- err = REFTABLE_IO_ERROR;
+ err = tmpfile_from_pattern(&tab_file, temp_tab_file_name.buf);
+ if (err < 0)
goto done;
- }
if (add->stack->opts.default_permissions) {
- if (chmod(get_tempfile_path(tab_file),
+ if (chmod(tab_file.path,
add->stack->opts.default_permissions)) {
err = REFTABLE_IO_ERROR;
goto done;
}
}
- tab_fd = get_tempfile_fd(tab_file);
- err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
- &tab_fd, &add->stack->opts);
+ writer.fd = tab_file.fd;
+ err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
+ &writer, &add->stack->opts);
if (err < 0)
goto done;
@@ -906,11 +920,9 @@ int reftable_addition_add(struct reftable_addition *add,
if (err < 0)
goto done;
- err = close_tempfile_gently(tab_file);
- if (err < 0) {
- err = REFTABLE_IO_ERROR;
+ err = tmpfile_close(&tab_file);
+ if (err < 0)
goto done;
- }
if (wr->min_update_index < add->next_update_index) {
err = REFTABLE_API_ERROR;
@@ -933,11 +945,9 @@ int reftable_addition_add(struct reftable_addition *add,
On windows, this relies on rand() picking a unique destination name.
Maybe we should do retry loop as well?
*/
- err = rename_tempfile(&tab_file, tab_file_name.buf);
- if (err < 0) {
- err = REFTABLE_IO_ERROR;
+ err = tmpfile_rename(&tab_file, tab_file_name.buf);
+ if (err < 0)
goto done;
- }
REFTABLE_ALLOC_GROW(add->new_tables, add->new_tables_len + 1,
add->new_tables_cap);
@@ -948,7 +958,7 @@ int reftable_addition_add(struct reftable_addition *add,
add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name);
done:
- delete_tempfile(&tab_file);
+ tmpfile_delete(&tab_file);
reftable_buf_release(&temp_tab_file_name);
reftable_buf_release(&tab_file_name);
reftable_buf_release(&next_name);
@@ -968,13 +978,16 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
static int stack_compact_locked(struct reftable_stack *st,
size_t first, size_t last,
struct reftable_log_expiry_config *config,
- struct tempfile **tab_file_out)
+ struct reftable_tmpfile *tab_file_out)
{
struct reftable_buf next_name = REFTABLE_BUF_INIT;
struct reftable_buf tab_file_path = REFTABLE_BUF_INIT;
struct reftable_writer *wr = NULL;
- struct tempfile *tab_file;
- int tab_fd, err = 0;
+ struct fd_writer writer= {
+ .opts = &st->opts,
+ };
+ struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
+ int err = 0;
err = format_name(&next_name, reftable_reader_min_update_index(st->readers[first]),
reftable_reader_max_update_index(st->readers[last]));
@@ -989,21 +1002,19 @@ static int stack_compact_locked(struct reftable_stack *st,
if (err < 0)
goto done;
- tab_file = mks_tempfile(tab_file_path.buf);
- if (!tab_file) {
- err = REFTABLE_IO_ERROR;
+ err = tmpfile_from_pattern(&tab_file, tab_file_path.buf);
+ if (err < 0)
goto done;
- }
- tab_fd = get_tempfile_fd(tab_file);
if (st->opts.default_permissions &&
- chmod(get_tempfile_path(tab_file), st->opts.default_permissions) < 0) {
+ chmod(tab_file.path, st->opts.default_permissions) < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
- err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
- &tab_fd, &st->opts);
+ writer.fd = tab_file.fd;
+ err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
+ &writer, &st->opts);
if (err < 0)
goto done;
@@ -1015,15 +1026,15 @@ static int stack_compact_locked(struct reftable_stack *st,
if (err < 0)
goto done;
- err = close_tempfile_gently(tab_file);
+ err = tmpfile_close(&tab_file);
if (err < 0)
goto done;
*tab_file_out = tab_file;
- tab_file = NULL;
+ tab_file = REFTABLE_TMPFILE_INIT;
done:
- delete_tempfile(&tab_file);
+ tmpfile_delete(&tab_file);
reftable_writer_free(wr);
reftable_buf_release(&next_name);
reftable_buf_release(&tab_file_path);
@@ -1154,9 +1165,9 @@ static int stack_compact_range(struct reftable_stack *st,
struct reftable_buf new_table_name = REFTABLE_BUF_INIT;
struct reftable_buf new_table_path = REFTABLE_BUF_INIT;
struct reftable_buf table_name = REFTABLE_BUF_INIT;
- struct lock_file tables_list_lock = LOCK_INIT;
- struct lock_file *table_locks = NULL;
- struct tempfile *new_table = NULL;
+ struct reftable_flock tables_list_lock = REFTABLE_FLOCK_INIT;
+ struct reftable_flock *table_locks = NULL;
+ struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT;
int is_empty_table = 0, err = 0;
size_t first_to_replace, last_to_replace;
size_t i, nlocks = 0;
@@ -1173,10 +1184,7 @@ static int stack_compact_range(struct reftable_stack *st,
* Hold the lock so that we can read "tables.list" and lock all tables
* which are part of the user-specified range.
*/
- err = hold_lock_file_for_update_timeout(&tables_list_lock,
- st->list_file,
- LOCK_NO_DEREF,
- st->opts.lock_timeout_ms);
+ err = flock_acquire(&tables_list_lock, st->list_file, st->opts.lock_timeout_ms);
if (err < 0) {
if (errno == EEXIST)
err = REFTABLE_LOCK_ERROR;
@@ -1199,19 +1207,20 @@ static int stack_compact_range(struct reftable_stack *st,
* older process is still busy compacting tables which are preexisting
* from the point of view of the newer process.
*/
- REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1);
+ REFTABLE_ALLOC_ARRAY(table_locks, last - first + 1);
if (!table_locks) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
+ for (i = 0; i < last - first + 1; i++)
+ table_locks[i] = REFTABLE_FLOCK_INIT;
for (i = last + 1; i > first; i--) {
err = stack_filename(&table_name, st, reader_name(st->readers[i - 1]));
if (err < 0)
goto done;
- err = hold_lock_file_for_update(&table_locks[nlocks],
- table_name.buf, LOCK_NO_DEREF);
+ err = flock_acquire(&table_locks[nlocks], table_name.buf, 0);
if (err < 0) {
/*
* When the table is locked already we may do a
@@ -1247,7 +1256,7 @@ static int stack_compact_range(struct reftable_stack *st,
* run into file descriptor exhaustion when we compress a lot
* of tables.
*/
- err = close_lock_file_gently(&table_locks[nlocks++]);
+ err = flock_close(&table_locks[nlocks++]);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -1259,7 +1268,7 @@ static int stack_compact_range(struct reftable_stack *st,
* "tables.list" lock while compacting the locked tables. This allows
* concurrent updates to the stack to proceed.
*/
- err = rollback_lock_file(&tables_list_lock);
+ err = flock_release(&tables_list_lock);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -1282,10 +1291,7 @@ static int stack_compact_range(struct reftable_stack *st,
* "tables.list". We'll then replace the compacted range of tables with
* the new table.
*/
- err = hold_lock_file_for_update_timeout(&tables_list_lock,
- st->list_file,
- LOCK_NO_DEREF,
- st->opts.lock_timeout_ms);
+ err = flock_acquire(&tables_list_lock, st->list_file, st->opts.lock_timeout_ms);
if (err < 0) {
if (errno == EEXIST)
err = REFTABLE_LOCK_ERROR;
@@ -1295,7 +1301,7 @@ static int stack_compact_range(struct reftable_stack *st,
}
if (st->opts.default_permissions) {
- if (chmod(get_lock_file_path(&tables_list_lock),
+ if (chmod(tables_list_lock.path,
st->opts.default_permissions) < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -1424,11 +1430,9 @@ static int stack_compact_range(struct reftable_stack *st,
if (err < 0)
goto done;
- err = rename_tempfile(&new_table, new_table_path.buf);
- if (err < 0) {
- err = REFTABLE_IO_ERROR;
+ err = tmpfile_rename(&new_table, new_table_path.buf);
+ if (err < 0)
goto done;
- }
}
/*
@@ -1452,7 +1456,7 @@ static int stack_compact_range(struct reftable_stack *st,
goto done;
}
- err = write_in_full(get_lock_file_fd(&tables_list_lock),
+ err = write_in_full(tables_list_lock.fd,
tables_list_buf.buf, tables_list_buf.len);
if (err < 0) {
err = REFTABLE_IO_ERROR;
@@ -1460,14 +1464,14 @@ static int stack_compact_range(struct reftable_stack *st,
goto done;
}
- err = fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&tables_list_lock));
+ err = stack_fsync(&st->opts, tables_list_lock.fd);
if (err < 0) {
err = REFTABLE_IO_ERROR;
unlink(new_table_path.buf);
goto done;
}
- err = commit_lock_file(&tables_list_lock);
+ err = flock_commit(&tables_list_lock);
if (err < 0) {
err = REFTABLE_IO_ERROR;
unlink(new_table_path.buf);
@@ -1488,19 +1492,24 @@ static int stack_compact_range(struct reftable_stack *st,
* readers, so it is expected that unlinking tables may fail.
*/
for (i = 0; i < nlocks; i++) {
- struct lock_file *table_lock = &table_locks[i];
- char *table_path = get_locked_file_path(table_lock);
- unlink(table_path);
- reftable_free(table_path);
+ struct reftable_flock *table_lock = &table_locks[i];
+
+ reftable_buf_reset(&table_name);
+ err = reftable_buf_add(&table_name, table_lock->path,
+ strlen(table_lock->path) - strlen(".lock"));
+ if (err)
+ continue;
+
+ unlink(table_name.buf);
}
done:
- rollback_lock_file(&tables_list_lock);
+ flock_release(&tables_list_lock);
for (i = 0; table_locks && i < nlocks; i++)
- rollback_lock_file(&table_locks[i]);
+ flock_release(&table_locks[i]);
reftable_free(table_locks);
- delete_tempfile(&new_table);
+ tmpfile_delete(&new_table);
reftable_buf_release(&new_table_name);
reftable_buf_release(&new_table_path);
reftable_buf_release(&tables_list_buf);
@@ -1603,7 +1612,7 @@ struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
{
- int version = (st->opts.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
+ int version = (st->opts.hash_id == REFTABLE_HASH_SHA1) ? 1 : 2;
int overhead = header_size(version) - 1;
uint64_t *sizes;
@@ -1622,6 +1631,9 @@ int reftable_stack_auto_compact(struct reftable_stack *st)
struct segment seg;
uint64_t *sizes;
+ if (st->merged->readers_len < 2)
+ return 0;
+
sizes = stack_table_sizes_for_compaction(st);
if (!sizes)
return REFTABLE_OUT_OF_MEMORY_ERROR;
@@ -1790,3 +1802,8 @@ done:
reftable_addition_destroy(add);
return err;
}
+
+enum reftable_hash reftable_stack_hash_id(struct reftable_stack *st)
+{
+ return reftable_merged_table_hash_id(st->merged);
+}
diff --git a/reftable/system.c b/reftable/system.c
new file mode 100644
index 0000000000..adf8e4d30b
--- /dev/null
+++ b/reftable/system.c
@@ -0,0 +1,126 @@
+#include "system.h"
+#include "basics.h"
+#include "reftable-error.h"
+#include "../lockfile.h"
+#include "../tempfile.h"
+
+int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern)
+{
+ struct tempfile *tempfile;
+
+ tempfile = mks_tempfile(pattern);
+ if (!tempfile)
+ return REFTABLE_IO_ERROR;
+
+ out->path = tempfile->filename.buf;
+ out->fd = tempfile->fd;
+ out->priv = tempfile;
+
+ return 0;
+}
+
+int tmpfile_close(struct reftable_tmpfile *t)
+{
+ struct tempfile *tempfile = t->priv;
+ int ret = close_tempfile_gently(tempfile);
+ t->fd = -1;
+ if (ret < 0)
+ return REFTABLE_IO_ERROR;
+ return 0;
+}
+
+int tmpfile_delete(struct reftable_tmpfile *t)
+{
+ struct tempfile *tempfile = t->priv;
+ int ret = delete_tempfile(&tempfile);
+ *t = REFTABLE_TMPFILE_INIT;
+ if (ret < 0)
+ return REFTABLE_IO_ERROR;
+ return 0;
+}
+
+int tmpfile_rename(struct reftable_tmpfile *t, const char *path)
+{
+ struct tempfile *tempfile = t->priv;
+ int ret = rename_tempfile(&tempfile, path);
+ *t = REFTABLE_TMPFILE_INIT;
+ if (ret < 0)
+ return REFTABLE_IO_ERROR;
+ return 0;
+}
+
+int flock_acquire(struct reftable_flock *l, const char *target_path,
+ long timeout_ms)
+{
+ struct lock_file *lockfile;
+ int err;
+
+ lockfile = reftable_malloc(sizeof(*lockfile));
+ if (!lockfile)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
+ err = hold_lock_file_for_update_timeout(lockfile, target_path, LOCK_NO_DEREF,
+ timeout_ms);
+ if (err < 0) {
+ reftable_free(lockfile);
+ if (errno == EEXIST)
+ return REFTABLE_LOCK_ERROR;
+ return -1;
+ }
+
+ l->fd = get_lock_file_fd(lockfile);
+ l->path = get_lock_file_path(lockfile);
+ l->priv = lockfile;
+
+ return 0;
+}
+
+int flock_close(struct reftable_flock *l)
+{
+ struct lock_file *lockfile = l->priv;
+ int ret;
+
+ if (!lockfile)
+ return REFTABLE_API_ERROR;
+
+ ret = close_lock_file_gently(lockfile);
+ l->fd = -1;
+ if (ret < 0)
+ return REFTABLE_IO_ERROR;
+
+ return 0;
+}
+
+int flock_release(struct reftable_flock *l)
+{
+ struct lock_file *lockfile = l->priv;
+ int ret;
+
+ if (!lockfile)
+ return 0;
+
+ ret = rollback_lock_file(lockfile);
+ reftable_free(lockfile);
+ *l = REFTABLE_FLOCK_INIT;
+ if (ret < 0)
+ return REFTABLE_IO_ERROR;
+
+ return 0;
+}
+
+int flock_commit(struct reftable_flock *l)
+{
+ struct lock_file *lockfile = l->priv;
+ int ret;
+
+ if (!lockfile)
+ return REFTABLE_API_ERROR;
+
+ ret = commit_lock_file(lockfile);
+ reftable_free(lockfile);
+ *l = REFTABLE_FLOCK_INIT;
+ if (ret < 0)
+ return REFTABLE_IO_ERROR;
+
+ return 0;
+}
diff --git a/reftable/system.h b/reftable/system.h
index d3b8a55f4b..5274eca1d0 100644
--- a/reftable/system.h
+++ b/reftable/system.h
@@ -14,11 +14,90 @@ https://developers.google.com/open-source/licenses/bsd
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
-#include "lockfile.h"
-#include "tempfile.h"
-#include "hash.h" /* hash ID, sizes.*/
-#include "dir.h" /* remove_dir_recursively, for tests.*/
-int hash_size(uint32_t id);
+/*
+ * An implementation-specific temporary file. By making this specific to the
+ * implementation it becomes possible to tie temporary files into any kind of
+ * signal or atexit handlers for cleanup on abnormal situations.
+ */
+struct reftable_tmpfile {
+ const char *path;
+ int fd;
+ void *priv;
+};
+#define REFTABLE_TMPFILE_INIT ((struct reftable_tmpfile) { .fd = -1, })
+
+/*
+ * Create a temporary file from a pattern similar to how mkstemp(3p) would.
+ * The `pattern` shall not be modified. On success, the structure at `out` has
+ * been initialized such that it is ready for use. Returns 0 on success, a
+ * reftable error code on error.
+ */
+int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern);
+
+/*
+ * Close the temporary file's file descriptor without removing the file itself.
+ * This is a no-op in case the file has already been closed beforehand. Returns
+ * 0 on success, a reftable error code on error.
+ */
+int tmpfile_close(struct reftable_tmpfile *t);
+
+/*
+ * Close the temporary file and delete it. This is a no-op in case the file has
+ * already been deleted or renamed beforehand. Returns 0 on success, a reftable
+ * error code on error.
+ */
+int tmpfile_delete(struct reftable_tmpfile *t);
+
+/*
+ * Rename the temporary file to the provided path. The temporary file must be
+ * active. Return 0 on success, a reftable error code on error. Deactivates the
+ * temporary file.
+ */
+int tmpfile_rename(struct reftable_tmpfile *t, const char *path);
+
+/*
+ * An implementation-specific file lock. Same as with `reftable_tmpfile`,
+ * making this specific to the implementation makes it possible to tie this
+ * into signal or atexit handlers such that we know to clean up stale locks on
+ * abnormal exits.
+ */
+struct reftable_flock {
+ const char *path;
+ int fd;
+ void *priv;
+};
+#define REFTABLE_FLOCK_INIT ((struct reftable_flock){ .fd = -1, })
+
+/*
+ * Acquire the lock for the given target path by exclusively creating a file
+ * with ".lock" appended to it. If that lock exists, we wait up to `timeout_ms`
+ * to acquire the lock. If `timeout_ms` is 0 we don't wait, if it is negative
+ * we block indefinitely.
+ *
+ * Retrun 0 on success, a reftable error code on error.
+ */
+int flock_acquire(struct reftable_flock *l, const char *target_path,
+ long timeout_ms);
+
+/*
+ * Close the lockfile's file descriptor without removing the lock itself. This
+ * is a no-op in case the lockfile has already been closed beforehand. Returns
+ * 0 on success, a reftable error code on error.
+ */
+int flock_close(struct reftable_flock *l);
+
+/*
+ * Release the lock by unlinking the lockfile. This is a no-op in case the
+ * lockfile has already been released or committed beforehand. Returns 0 on
+ * success, a reftable error code on error.
+ */
+int flock_release(struct reftable_flock *l);
+
+/*
+ * Commit the lock by renaming the lockfile into place. Returns 0 on success, a
+ * reftable error code on error.
+ */
+int flock_commit(struct reftable_flock *l);
#endif
diff --git a/reftable/writer.c b/reftable/writer.c
index be0fae6cb2..624e90fb53 100644
--- a/reftable/writer.c
+++ b/reftable/writer.c
@@ -79,7 +79,7 @@ static void options_set_defaults(struct reftable_write_options *opts)
}
if (opts->hash_id == 0) {
- opts->hash_id = GIT_SHA1_FORMAT_ID;
+ opts->hash_id = REFTABLE_HASH_SHA1;
}
if (opts->block_size == 0) {
opts->block_size = DEFAULT_BLOCK_SIZE;
@@ -88,7 +88,7 @@ static void options_set_defaults(struct reftable_write_options *opts)
static int writer_version(struct reftable_writer *w)
{
- return (w->opts.hash_id == 0 || w->opts.hash_id == GIT_SHA1_FORMAT_ID) ?
+ return (w->opts.hash_id == 0 || w->opts.hash_id == REFTABLE_HASH_SHA1) ?
1 :
2;
}
@@ -103,8 +103,22 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest)
put_be64(dest + 8, w->min_update_index);
put_be64(dest + 16, w->max_update_index);
if (writer_version(w) == 2) {
- put_be32(dest + 24, w->opts.hash_id);
+ uint32_t hash_id;
+
+ switch (w->opts.hash_id) {
+ case REFTABLE_HASH_SHA1:
+ hash_id = REFTABLE_FORMAT_ID_SHA1;
+ break;
+ case REFTABLE_HASH_SHA256:
+ hash_id = REFTABLE_FORMAT_ID_SHA256;
+ break;
+ default:
+ return -1;
+ }
+
+ put_be32(dest + 24, hash_id);
}
+
return header_size(writer_version(w));
}
@@ -411,6 +425,18 @@ int reftable_writer_add_log(struct reftable_writer *w,
if (log->value_type == REFTABLE_LOG_DELETION)
return reftable_writer_add_log_verbatim(w, log);
+ /*
+ * Verify only the upper limit of the update_index. Each reflog entry
+ * is tied to a specific update_index. Entries in the reflog can be
+ * replaced by adding a new entry with the same update_index,
+ * effectively canceling the old one.
+ *
+ * Consequently, reflog updates may include update_index values lower
+ * than the writer's min_update_index.
+ */
+ if (log->update_index > w->max_update_index)
+ return REFTABLE_API_ERROR;
+
if (!log->refname)
return REFTABLE_API_ERROR;
diff --git a/remote.c b/remote.c
index a6d8c15189..b80e810a90 100644
--- a/remote.c
+++ b/remote.c
@@ -515,6 +515,24 @@ static int handle_config(const char *key, const char *value,
} else if (!strcmp(subkey, "serveroption")) {
return parse_transport_option(key, value,
&remote->server_options);
+ } else if (!strcmp(subkey, "followremotehead")) {
+ const char *no_warn_branch;
+ if (!strcmp(value, "never"))
+ remote->follow_remote_head = FOLLOW_REMOTE_NEVER;
+ else if (!strcmp(value, "create"))
+ remote->follow_remote_head = FOLLOW_REMOTE_CREATE;
+ else if (!strcmp(value, "warn")) {
+ remote->follow_remote_head = FOLLOW_REMOTE_WARN;
+ remote->no_warn_branch = NULL;
+ } else if (skip_prefix(value, "warn-if-not-", &no_warn_branch)) {
+ remote->follow_remote_head = FOLLOW_REMOTE_WARN;
+ remote->no_warn_branch = no_warn_branch;
+ } else if (!strcmp(value, "always")) {
+ remote->follow_remote_head = FOLLOW_REMOTE_ALWAYS;
+ } else {
+ warning(_("unrecognized followRemoteHEAD value '%s' ignored"),
+ value);
+ }
}
return 0;
}
diff --git a/remote.h b/remote.h
index a7e5c4e07c..bda10dd5c8 100644
--- a/remote.h
+++ b/remote.h
@@ -59,6 +59,13 @@ struct remote_state {
void remote_state_clear(struct remote_state *remote_state);
struct remote_state *remote_state_new(void);
+ enum follow_remote_head_settings {
+ FOLLOW_REMOTE_NEVER = -1,
+ FOLLOW_REMOTE_CREATE = 0,
+ FOLLOW_REMOTE_WARN = 1,
+ FOLLOW_REMOTE_ALWAYS = 2,
+ };
+
struct remote {
struct hashmap_entry ent;
@@ -107,6 +114,9 @@ struct remote {
char *http_proxy_authmethod;
struct string_list server_options;
+
+ enum follow_remote_head_settings follow_remote_head;
+ const char *no_warn_branch;
};
/**
diff --git a/repo-settings.c b/repo-settings.c
index 4699b4b365..9d16d5399e 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -3,6 +3,7 @@
#include "repo-settings.h"
#include "repository.h"
#include "midx.h"
+#include "pack-objects.h"
static void repo_cfg_bool(struct repository *r, const char *key, int *dest,
int def)
@@ -26,6 +27,7 @@ void prepare_repo_settings(struct repository *r)
const char *strval;
int manyfiles;
int read_changed_paths;
+ unsigned long ulongval;
if (!r->gitdir)
BUG("Cannot add settings for uninitialized repository");
@@ -123,6 +125,22 @@ void prepare_repo_settings(struct repository *r)
* removed.
*/
r->settings.command_requires_full_index = 1;
+
+ if (!repo_config_get_ulong(r, "core.deltabasecachelimit", &ulongval))
+ r->settings.delta_base_cache_limit = ulongval;
+
+ if (!repo_config_get_ulong(r, "core.packedgitwindowsize", &ulongval)) {
+ int pgsz_x2 = getpagesize() * 2;
+
+ /* This value must be multiple of (pagesize * 2) */
+ ulongval /= pgsz_x2;
+ if (ulongval < 1)
+ ulongval = 1;
+ r->settings.packed_git_window_size = ulongval * pgsz_x2;
+ }
+
+ if (!repo_config_get_ulong(r, "core.packedgitlimit", &ulongval))
+ r->settings.packed_git_limit = ulongval;
}
enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
diff --git a/repo-settings.h b/repo-settings.h
index 51d6156a11..93ea0c3274 100644
--- a/repo-settings.h
+++ b/repo-settings.h
@@ -57,12 +57,19 @@ struct repo_settings {
int core_multi_pack_index;
int warn_ambiguous_refs; /* lazily loaded via accessor */
+
+ size_t delta_base_cache_limit;
+ size_t packed_git_window_size;
+ size_t packed_git_limit;
};
#define REPO_SETTINGS_INIT { \
.index_version = -1, \
.core_untracked_cache = UNTRACKED_CACHE_KEEP, \
.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \
.warn_ambiguous_refs = -1, \
+ .delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \
+ .packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE, \
+ .packed_git_limit = DEFAULT_PACKED_GIT_LIMIT, \
}
void prepare_repo_settings(struct repository *r);
diff --git a/repository.c b/repository.c
index f988b8ae68..1a6a62bbd0 100644
--- a/repository.c
+++ b/repository.c
@@ -283,6 +283,7 @@ int repo_init(struct repository *repo,
repo_set_compat_hash_algo(repo, format.compat_hash_algo);
repo_set_ref_storage_format(repo, format.ref_storage_format);
repo->repository_format_worktree_config = format.worktree_config;
+ repo->repository_format_relative_worktrees = format.relative_worktrees;
/* take ownership of format.partial_clone */
repo->repository_format_partial_clone = format.partial_clone;
diff --git a/repository.h b/repository.h
index 24a66a496a..c4c92b2ab9 100644
--- a/repository.h
+++ b/repository.h
@@ -150,6 +150,7 @@ struct repository {
/* Configurations */
int repository_format_worktree_config;
+ int repository_format_relative_worktrees;
/* Indicate if a repository has a different 'commondir' from 'gitdir' */
unsigned different_commondir:1;
diff --git a/revision.c b/revision.c
index a152916861..474fa1e767 100644
--- a/revision.c
+++ b/revision.c
@@ -391,7 +391,8 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
if (!object) {
if (revs->ignore_missing)
return NULL;
- if (revs->exclude_promisor_objects && is_promisor_object(oid))
+ if (revs->exclude_promisor_objects &&
+ is_promisor_object(revs->repo, oid))
return NULL;
if (revs->do_not_die_on_missing_objects) {
oidset_insert(&revs->missing_commits, oid);
@@ -433,7 +434,7 @@ static struct commit *handle_commit(struct rev_info *revs,
if (revs->ignore_missing_links || (flags & UNINTERESTING))
return NULL;
if (revs->exclude_promisor_objects &&
- is_promisor_object(&tag->tagged->oid))
+ is_promisor_object(revs->repo, &tag->tagged->oid))
return NULL;
if (revs->do_not_die_on_missing_objects && oid) {
oidset_insert(&revs->missing_commits, oid);
@@ -1212,7 +1213,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
revs->do_not_die_on_missing_objects;
if (repo_parse_commit_gently(revs->repo, p, gently) < 0) {
if (revs->exclude_promisor_objects &&
- is_promisor_object(&p->object.oid)) {
+ is_promisor_object(revs->repo, &p->object.oid)) {
if (revs->first_parent_only)
break;
continue;
@@ -3921,7 +3922,7 @@ int prepare_revision_walk(struct rev_info *revs)
revs->treesame.name = "treesame";
if (revs->exclude_promisor_objects) {
- for_each_packed_object(mark_uninteresting, revs,
+ for_each_packed_object(revs->repo, mark_uninteresting, revs,
FOR_EACH_OBJECT_PROMISOR_ONLY);
}
@@ -4109,10 +4110,10 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
{
if (commit->object.flags & SHOWN)
return commit_ignore;
- if (revs->unpacked && has_object_pack(&commit->object.oid))
+ if (revs->unpacked && has_object_pack(revs->repo, &commit->object.oid))
return commit_ignore;
if (revs->no_kept_objects) {
- if (has_object_kept_pack(&commit->object.oid,
+ if (has_object_kept_pack(revs->repo, &commit->object.oid,
revs->keep_pack_cache_flags))
return commit_ignore;
}
diff --git a/setup.c b/setup.c
index 8084465197..8a488f3e7c 100644
--- a/setup.c
+++ b/setup.c
@@ -684,6 +684,9 @@ static enum extension_result handle_extension(const char *var,
"extensions.refstorage", value);
data->ref_storage_format = format;
return EXTENSION_OK;
+ } else if (!strcmp(ext, "relativeworktrees")) {
+ data->relative_worktrees = git_config_bool(var, value);
+ return EXTENSION_OK;
}
return EXTENSION_UNKNOWN;
}
@@ -1855,6 +1858,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
repo_fmt.ref_storage_format);
the_repository->repository_format_worktree_config =
repo_fmt.worktree_config;
+ the_repository->repository_format_relative_worktrees =
+ repo_fmt.relative_worktrees;
/* take ownership of repo_fmt.partial_clone */
the_repository->repository_format_partial_clone =
repo_fmt.partial_clone;
@@ -1951,6 +1956,8 @@ void check_repository_format(struct repository_format *fmt)
fmt->ref_storage_format);
the_repository->repository_format_worktree_config =
fmt->worktree_config;
+ the_repository->repository_format_relative_worktrees =
+ fmt->relative_worktrees;
the_repository->repository_format_partial_clone =
xstrdup_or_null(fmt->partial_clone);
clear_repository_format(&repo_fmt);
@@ -2205,8 +2212,8 @@ void initialize_repository_version(int hash_algo,
enum ref_storage_format ref_storage_format,
int reinit)
{
- char repo_version_string[10];
- int repo_version = GIT_REPO_VERSION;
+ struct strbuf repo_version = STRBUF_INIT;
+ int target_version = GIT_REPO_VERSION;
/*
* Note that we initialize the repository version to 1 when the ref
@@ -2217,12 +2224,7 @@ void initialize_repository_version(int hash_algo,
*/
if (hash_algo != GIT_HASH_SHA1 ||
ref_storage_format != REF_STORAGE_FORMAT_FILES)
- repo_version = GIT_REPO_VERSION_READ;
-
- /* This forces creation of new config file */
- xsnprintf(repo_version_string, sizeof(repo_version_string),
- "%d", repo_version);
- git_config_set("core.repositoryformatversion", repo_version_string);
+ target_version = GIT_REPO_VERSION_READ;
if (hash_algo != GIT_HASH_SHA1 && hash_algo != GIT_HASH_UNKNOWN)
git_config_set("extensions.objectformat",
@@ -2235,6 +2237,25 @@ void initialize_repository_version(int hash_algo,
ref_storage_format_to_name(ref_storage_format));
else if (reinit)
git_config_set_gently("extensions.refstorage", NULL);
+
+ if (reinit) {
+ struct strbuf config = STRBUF_INIT;
+ struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
+
+ strbuf_git_common_path(&config, the_repository, "config");
+ read_repository_format(&repo_fmt, config.buf);
+
+ if (repo_fmt.v1_only_extensions.nr)
+ target_version = GIT_REPO_VERSION_READ;
+
+ strbuf_release(&config);
+ clear_repository_format(&repo_fmt);
+ }
+
+ strbuf_addf(&repo_version, "%d", target_version);
+ git_config_set("core.repositoryformatversion", repo_version.buf);
+
+ strbuf_release(&repo_version);
}
static int is_reinit(void)
@@ -2334,7 +2355,7 @@ static int create_default_files(const char *template_path,
adjust_shared_perm(repo_get_git_dir(the_repository));
}
- initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, 0);
+ initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, reinit);
/* Check filemode trustability */
path = git_path_buf(&buf, "config");
diff --git a/setup.h b/setup.h
index e496ab3e4d..18dc3b7368 100644
--- a/setup.h
+++ b/setup.h
@@ -129,6 +129,7 @@ struct repository_format {
int precious_objects;
char *partial_clone; /* value of extensions.partialclone */
int worktree_config;
+ int relative_worktrees;
int is_bare;
int hash_algo;
int compat_hash_algo;
diff --git a/strbuf.h b/strbuf.h
index 003f880ff7..4dc05b4ba7 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -637,28 +637,6 @@ static inline void strbuf_complete_line(struct strbuf *sb)
strbuf_complete(sb, '\n');
}
-/*
- * Copy "name" to "sb", expanding any special @-marks as handled by
- * repo_interpret_branch_name(). The result is a non-qualified branch name
- * (so "foo" or "origin/master" instead of "refs/heads/foo" or
- * "refs/remotes/origin/master").
- *
- * Note that the resulting name may not be a syntactically valid refname.
- *
- * If "allowed" is non-zero, restrict the set of allowed expansions. See
- * repo_interpret_branch_name() for details.
- */
-void strbuf_branchname(struct strbuf *sb, const char *name,
- unsigned allowed);
-
-/*
- * Like strbuf_branchname() above, but confirm that the result is
- * syntactically valid to be used as a local branch name in refs/heads/.
- *
- * The return value is "0" if the result is valid, and "-1" otherwise.
- */
-int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
-
typedef int (*char_predicate)(char ch);
void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,
diff --git a/strvec.c b/strvec.c
index 5cead29ba1..f8de79f557 100644
--- a/strvec.c
+++ b/strvec.c
@@ -61,16 +61,19 @@ void strvec_splice(struct strvec *array, size_t idx, size_t len,
{
if (idx + len > array->nr)
BUG("range outside of array boundary");
- if (replacement_len > len)
+ if (replacement_len > len) {
+ if (array->v == empty_strvec)
+ array->v = NULL;
ALLOC_GROW(array->v, array->nr + (replacement_len - len) + 1,
array->alloc);
+ array->v[array->nr + (replacement_len - len)] = NULL;
+ }
for (size_t i = 0; i < len; i++)
free((char *)array->v[idx + i]);
- if (replacement_len != len) {
+ if ((replacement_len != len) && array->nr)
memmove(array->v + idx + replacement_len, array->v + idx + len,
(array->nr - idx - len + 1) * sizeof(char *));
- array->nr += (replacement_len - len);
- }
+ array->nr += replacement_len - len;
for (size_t i = 0; i < replacement_len; i++)
array->v[idx + i] = xstrdup(replacement[i]);
}
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
new file mode 100644
index 0000000000..63ea916ef5
--- /dev/null
+++ b/subprojects/.gitignore
@@ -0,0 +1 @@
+/*/
diff --git a/subprojects/curl.wrap b/subprojects/curl.wrap
new file mode 100644
index 0000000000..f7e384b85c
--- /dev/null
+++ b/subprojects/curl.wrap
@@ -0,0 +1,13 @@
+[wrap-file]
+directory = curl-8.10.1
+source_url = https://github.com/curl/curl/releases/download/curl-8_10_1/curl-8.10.1.tar.xz
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/curl_8.10.1-1/curl-8.10.1.tar.xz
+source_filename = curl-8.10.1.tar.xz
+source_hash = 73a4b0e99596a09fa5924a4fb7e4b995a85fda0d18a2c02ab9cf134bebce04ee
+patch_filename = curl_8.10.1-1_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/curl_8.10.1-1/get_patch
+patch_hash = 707c28f35fc9b0e8d68c0c2800712007612f922a31da9637ce706a2159f3ddd8
+wrapdb_version = 8.10.1-1
+
+[provide]
+dependency_names = libcurl
diff --git a/subprojects/expat.wrap b/subprojects/expat.wrap
new file mode 100644
index 0000000000..2e0427dcfd
--- /dev/null
+++ b/subprojects/expat.wrap
@@ -0,0 +1,13 @@
+[wrap-file]
+directory = expat-2.6.3
+source_url = https://github.com/libexpat/libexpat/releases/download/R_2_6_3/expat-2.6.3.tar.xz
+source_filename = expat-2.6.3.tar.bz2
+source_hash = 274db254a6979bde5aad404763a704956940e465843f2a9bd9ed7af22e2c0efc
+patch_filename = expat_2.6.3-1_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.6.3-1/get_patch
+patch_hash = cf017fbe105e31428b2768360bd9be39094df4e948a1e8d1c54b6f7c76460cb1
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/expat_2.6.3-1/expat-2.6.3.tar.bz2
+wrapdb_version = 2.6.3-1
+
+[provide]
+expat = expat_dep
diff --git a/subprojects/openssl.wrap b/subprojects/openssl.wrap
new file mode 100644
index 0000000000..873d55106e
--- /dev/null
+++ b/subprojects/openssl.wrap
@@ -0,0 +1,15 @@
+[wrap-file]
+directory = openssl-3.0.8
+source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
+source_filename = openssl-3.0.8.tar.gz
+source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
+patch_filename = openssl_3.0.8-3_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-3/get_patch
+patch_hash = 300da189e106942347d61a4a4295aa2edbcf06184f8d13b4cee0bed9fb936963
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-3/openssl-3.0.8.tar.gz
+wrapdb_version = 3.0.8-3
+
+[provide]
+libcrypto = libcrypto_dep
+libssl = libssl_dep
+openssl = openssl_dep
diff --git a/subprojects/pcre2.wrap b/subprojects/pcre2.wrap
new file mode 100644
index 0000000000..7e18447254
--- /dev/null
+++ b/subprojects/pcre2.wrap
@@ -0,0 +1,16 @@
+[wrap-file]
+directory = pcre2-10.44
+source_url = https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.44/pcre2-10.44.tar.bz2
+source_filename = pcre2-10.44.tar.bz2
+source_hash = d34f02e113cf7193a1ebf2770d3ac527088d485d4e047ed10e5d217c6ef5de96
+patch_filename = pcre2_10.44-2_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/pcre2_10.44-2/get_patch
+patch_hash = 4336d422ee9043847e5e10dbbbd01940d4c9e5027f31ccdc33a7898a1ca94009
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/pcre2_10.44-2/pcre2-10.44.tar.bz2
+wrapdb_version = 10.44-2
+
+[provide]
+libpcre2-8 = libpcre2_8
+libpcre2-16 = libpcre2_16
+libpcre2-32 = libpcre2_32
+libpcre2-posix = libpcre2_posix
diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap
new file mode 100644
index 0000000000..aa14de1774
--- /dev/null
+++ b/subprojects/zlib.wrap
@@ -0,0 +1,13 @@
+[wrap-file]
+directory = zlib-1.3.1
+source_url = http://zlib.net/fossils/zlib-1.3.1.tar.gz
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/zlib_1.3.1-1/zlib-1.3.1.tar.gz
+source_filename = zlib-1.3.1.tar.gz
+source_hash = 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23
+patch_filename = zlib_1.3.1-1_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3.1-1/get_patch
+patch_hash = e79b98eb24a75392009cec6f99ca5cdca9881ff20bfa174e8b8926d5c7a47095
+wrapdb_version = 1.3.1-1
+
+[provide]
+zlib = zlib_dep
diff --git a/t/helper/meson.build b/t/helper/meson.build
new file mode 100644
index 0000000000..5e83884246
--- /dev/null
+++ b/t/helper/meson.build
@@ -0,0 +1,91 @@
+test_tool_sources = [
+ '../unit-tests/test-lib.c',
+ 'test-advise.c',
+ 'test-bitmap.c',
+ 'test-bloom.c',
+ 'test-bundle-uri.c',
+ 'test-cache-tree.c',
+ 'test-chmtime.c',
+ 'test-config.c',
+ 'test-crontab.c',
+ 'test-csprng.c',
+ 'test-date.c',
+ 'test-delete-gpgsig.c',
+ 'test-delta.c',
+ 'test-dir-iterator.c',
+ 'test-drop-caches.c',
+ 'test-dump-cache-tree.c',
+ 'test-dump-fsmonitor.c',
+ 'test-dump-split-index.c',
+ 'test-dump-untracked-cache.c',
+ 'test-env-helper.c',
+ 'test-example-tap.c',
+ 'test-find-pack.c',
+ 'test-fsmonitor-client.c',
+ 'test-genrandom.c',
+ 'test-genzeros.c',
+ 'test-getcwd.c',
+ 'test-hash-speed.c',
+ 'test-hash.c',
+ 'test-hashmap.c',
+ 'test-hexdump.c',
+ 'test-json-writer.c',
+ 'test-lazy-init-name-hash.c',
+ 'test-match-trees.c',
+ 'test-mergesort.c',
+ 'test-mktemp.c',
+ 'test-online-cpus.c',
+ 'test-pack-mtimes.c',
+ 'test-parse-options.c',
+ 'test-parse-pathspec-file.c',
+ 'test-partial-clone.c',
+ 'test-path-utils.c',
+ 'test-pcre2-config.c',
+ 'test-pkt-line.c',
+ 'test-proc-receive.c',
+ 'test-progress.c',
+ 'test-reach.c',
+ 'test-read-cache.c',
+ 'test-read-graph.c',
+ 'test-read-midx.c',
+ 'test-ref-store.c',
+ 'test-reftable.c',
+ 'test-regex.c',
+ 'test-repository.c',
+ 'test-revision-walking.c',
+ 'test-rot13-filter.c',
+ 'test-run-command.c',
+ 'test-scrap-cache-tree.c',
+ 'test-serve-v2.c',
+ 'test-sha1.c',
+ 'test-sha256.c',
+ 'test-sigchain.c',
+ 'test-simple-ipc.c',
+ 'test-string-list.c',
+ 'test-submodule-config.c',
+ 'test-submodule-nested-repo-config.c',
+ 'test-submodule.c',
+ 'test-subprocess.c',
+ 'test-tool.c',
+ 'test-trace2.c',
+ 'test-truncate.c',
+ 'test-userdiff.c',
+ 'test-wildmatch.c',
+ 'test-windows-named-pipe.c',
+ 'test-write-cache.c',
+ 'test-xml-encode.c',
+]
+
+test_tool = executable('test-tool',
+ sources: test_tool_sources,
+ dependencies: [libgit, common_main],
+)
+bin_wrappers += test_tool
+test_dependencies += test_tool
+
+test_fake_ssh = executable('test-fake-ssh',
+ sources: 'test-fake-ssh.c',
+ dependencies: [libgit, common_main],
+)
+bin_wrappers += test_fake_ssh
+test_dependencies += test_fake_ssh
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 438fb9fc61..fc63236961 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -18,7 +18,7 @@ static int read_midx_file(const char *object_dir, const char *checksum,
struct multi_pack_index *m;
setup_git_directory();
- m = load_multi_pack_index(object_dir, 1);
+ m = load_multi_pack_index(the_repository, object_dir, 1);
if (!m)
return 1;
@@ -82,7 +82,7 @@ static int read_midx_checksum(const char *object_dir)
struct multi_pack_index *m;
setup_git_directory();
- m = load_multi_pack_index(object_dir, 1);
+ m = load_multi_pack_index(the_repository, object_dir, 1);
if (!m)
return 1;
printf("%s\n", hash_to_hex(get_midx_checksum(m)));
@@ -98,7 +98,7 @@ static int read_midx_preferred_pack(const char *object_dir)
setup_git_directory();
- midx = load_multi_pack_index(object_dir, 1);
+ midx = load_multi_pack_index(the_repository, object_dir, 1);
if (!midx)
return 1;
@@ -121,7 +121,7 @@ static int read_midx_bitmapped_packs(const char *object_dir)
setup_git_directory();
- midx = load_multi_pack_index(object_dir, 1);
+ midx = load_multi_pack_index(the_repository, object_dir, 1);
if (!midx)
return 1;
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index 5c8849d115..3c72ed985b 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -156,7 +156,7 @@ int cmd__dump_reftable(int argc, const char **argv)
int opt_dump_blocks = 0;
int opt_dump_table = 0;
int opt_dump_stack = 0;
- uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
+ uint32_t opt_hash_id = REFTABLE_HASH_SHA1;
const char *arg = NULL, *argv0 = argv[0];
for (; argc > 1; argv++, argc--)
@@ -167,7 +167,7 @@ int cmd__dump_reftable(int argc, const char **argv)
else if (!strcmp("-t", argv[1]))
opt_dump_table = 1;
else if (!strcmp("-6", argv[1]))
- opt_hash_id = GIT_SHA256_FORMAT_ID;
+ opt_hash_id = REFTABLE_HASH_SHA256;
else if (!strcmp("-s", argv[1]))
opt_dump_stack = 1;
else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh
index cc6bb2cdea..7a734c6973 100644
--- a/t/lib-gettext.sh
+++ b/t/lib-gettext.sh
@@ -6,8 +6,8 @@
. ./test-lib.sh
-GIT_TEXTDOMAINDIR="$GIT_BUILD_DIR/po/build/locale"
-GIT_PO_PATH="$GIT_BUILD_DIR/po"
+GIT_TEXTDOMAINDIR="$GIT_TEST_TEXTDOMAINDIR"
+GIT_PO_PATH="$GIT_TEST_POPATH"
export GIT_TEXTDOMAINDIR GIT_PO_PATH
if test -n "$GIT_TEST_INSTALLED"
diff --git a/t/meson.build b/t/meson.build
new file mode 100644
index 0000000000..13fe854ba0
--- /dev/null
+++ b/t/meson.build
@@ -0,0 +1,1114 @@
+clar_test_suites = [
+ 'unit-tests/ctype.c',
+ 'unit-tests/strvec.c',
+]
+
+clar_sources = [
+ 'unit-tests/clar/clar.c',
+ 'unit-tests/unit-test.c',
+]
+
+clar_decls_h = custom_target(
+ input: clar_test_suites,
+ output: 'clar-decls.h',
+ command : [
+ shell,
+ meson.current_source_dir() + '/unit-tests/generate-clar-decls.sh',
+ '@OUTPUT@',
+ '@INPUT@',
+ ],
+ env: script_environment,
+)
+clar_sources += clar_decls_h
+
+clar_sources += custom_target(
+ input: clar_decls_h,
+ output: 'clar.suite',
+ command : [
+ shell,
+ meson.current_source_dir() + '/unit-tests/generate-clar-suites.sh',
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ env: script_environment,
+)
+
+clar_unit_tests = executable('unit-tests',
+ sources: clar_sources + clar_test_suites,
+ dependencies: [libgit, common_main],
+)
+test('unit-tests', clar_unit_tests)
+
+unit_test_programs = [
+ 'unit-tests/t-example-decorate.c',
+ 'unit-tests/t-hash.c',
+ 'unit-tests/t-hashmap.c',
+ 'unit-tests/t-mem-pool.c',
+ 'unit-tests/t-oid-array.c',
+ 'unit-tests/t-oidmap.c',
+ 'unit-tests/t-oidtree.c',
+ 'unit-tests/t-prio-queue.c',
+ 'unit-tests/t-reftable-basics.c',
+ 'unit-tests/t-reftable-block.c',
+ 'unit-tests/t-reftable-merged.c',
+ 'unit-tests/t-reftable-pq.c',
+ 'unit-tests/t-reftable-reader.c',
+ 'unit-tests/t-reftable-readwrite.c',
+ 'unit-tests/t-reftable-record.c',
+ 'unit-tests/t-reftable-stack.c',
+ 'unit-tests/t-reftable-tree.c',
+ 'unit-tests/t-strbuf.c',
+ 'unit-tests/t-strcmp-offset.c',
+ 'unit-tests/t-trailer.c',
+ 'unit-tests/t-urlmatch-normalization.c',
+]
+
+foreach unit_test_program : unit_test_programs
+ unit_test_name = fs.stem(unit_test_program)
+ unit_test = executable(unit_test_name,
+ sources: [
+ 'unit-tests/test-lib.c',
+ 'unit-tests/lib-oid.c',
+ 'unit-tests/lib-reftable.c',
+ unit_test_program,
+ ],
+ dependencies: [libgit, common_main],
+ )
+ test(unit_test_name, unit_test,
+ workdir: meson.current_source_dir(),
+ timeout: 0,
+ )
+endforeach
+
+subdir('helper')
+
+integration_tests = [
+ 't0000-basic.sh',
+ 't0001-init.sh',
+ 't0002-gitfile.sh',
+ 't0003-attributes.sh',
+ 't0004-unwritable.sh',
+ 't0005-signals.sh',
+ 't0006-date.sh',
+ 't0007-git-var.sh',
+ 't0008-ignores.sh',
+ 't0010-racy-git.sh',
+ 't0012-help.sh',
+ 't0013-sha1dc.sh',
+ 't0014-alias.sh',
+ 't0017-env-helper.sh',
+ 't0018-advice.sh',
+ 't0019-json-writer.sh',
+ 't0020-crlf.sh',
+ 't0021-conversion.sh',
+ 't0022-crlf-rename.sh',
+ 't0023-crlf-am.sh',
+ 't0024-crlf-archive.sh',
+ 't0025-crlf-renormalize.sh',
+ 't0026-eol-config.sh',
+ 't0027-auto-crlf.sh',
+ 't0028-working-tree-encoding.sh',
+ 't0029-core-unsetenvvars.sh',
+ 't0030-stripspace.sh',
+ 't0033-safe-directory.sh',
+ 't0034-root-safe-directory.sh',
+ 't0035-safe-bare-repository.sh',
+ 't0040-parse-options.sh',
+ 't0041-usage.sh',
+ 't0050-filesystem.sh',
+ 't0051-windows-named-pipe.sh',
+ 't0052-simple-ipc.sh',
+ 't0055-beyond-symlinks.sh',
+ 't0056-git-C.sh',
+ 't0060-path-utils.sh',
+ 't0061-run-command.sh',
+ 't0062-revision-walking.sh',
+ 't0063-string-list.sh',
+ 't0066-dir-iterator.sh',
+ 't0067-parse_pathspec_file.sh',
+ 't0068-for-each-repo.sh',
+ 't0070-fundamental.sh',
+ 't0071-sort.sh',
+ 't0080-unit-test-output.sh',
+ 't0081-find-pack.sh',
+ 't0090-cache-tree.sh',
+ 't0091-bugreport.sh',
+ 't0092-diagnose.sh',
+ 't0095-bloom.sh',
+ 't0100-previous.sh',
+ 't0101-at-syntax.sh',
+ 't0200-gettext-basic.sh',
+ 't0201-gettext-fallbacks.sh',
+ 't0202-gettext-perl.sh',
+ 't0203-gettext-setlocale-sanity.sh',
+ 't0204-gettext-reencode-sanity.sh',
+ 't0210-trace2-normal.sh',
+ 't0211-trace2-perf.sh',
+ 't0212-trace2-event.sh',
+ 't0300-credentials.sh',
+ 't0301-credential-cache.sh',
+ 't0302-credential-store.sh',
+ 't0303-credential-external.sh',
+ 't0410-partial-clone.sh',
+ 't0411-clone-from-partial.sh',
+ 't0450-txt-doc-vs-help.sh',
+ 't0500-progress-display.sh',
+ 't0600-reffiles-backend.sh',
+ 't0601-reffiles-pack-refs.sh',
+ 't0602-reffiles-fsck.sh',
+ 't0610-reftable-basics.sh',
+ 't0611-reftable-httpd.sh',
+ 't0612-reftable-jgit-compatibility.sh',
+ 't0613-reftable-write-options.sh',
+ 't1000-read-tree-m-3way.sh',
+ 't1001-read-tree-m-2way.sh',
+ 't1002-read-tree-m-u-2way.sh',
+ 't1003-read-tree-prefix.sh',
+ 't1004-read-tree-m-u-wf.sh',
+ 't1005-read-tree-reset.sh',
+ 't1006-cat-file.sh',
+ 't1007-hash-object.sh',
+ 't1008-read-tree-overlay.sh',
+ 't1009-read-tree-new-index.sh',
+ 't1010-mktree.sh',
+ 't1011-read-tree-sparse-checkout.sh',
+ 't1012-read-tree-df.sh',
+ 't1013-read-tree-submodule.sh',
+ 't1014-read-tree-confusing.sh',
+ 't1015-read-index-unmerged.sh',
+ 't1016-compatObjectFormat.sh',
+ 't1020-subdirectory.sh',
+ 't1021-rerere-in-workdir.sh',
+ 't1022-read-tree-partial-clone.sh',
+ 't1050-large.sh',
+ 't1051-large-conversion.sh',
+ 't1060-object-corruption.sh',
+ 't1090-sparse-checkout-scope.sh',
+ 't1091-sparse-checkout-builtin.sh',
+ 't1092-sparse-checkout-compatibility.sh',
+ 't1100-commit-tree-options.sh',
+ 't1300-config.sh',
+ 't1301-shared-repo.sh',
+ 't1302-repo-version.sh',
+ 't1303-wacky-config.sh',
+ 't1304-default-acl.sh',
+ 't1305-config-include.sh',
+ 't1306-xdg-files.sh',
+ 't1307-config-blob.sh',
+ 't1308-config-set.sh',
+ 't1309-early-config.sh',
+ 't1310-config-default.sh',
+ 't1350-config-hooks-path.sh',
+ 't1400-update-ref.sh',
+ 't1401-symbolic-ref.sh',
+ 't1402-check-ref-format.sh',
+ 't1403-show-ref.sh',
+ 't1404-update-ref-errors.sh',
+ 't1405-main-ref-store.sh',
+ 't1406-submodule-ref-store.sh',
+ 't1407-worktree-ref-store.sh',
+ 't1408-packed-refs.sh',
+ 't1409-avoid-packing-refs.sh',
+ 't1410-reflog.sh',
+ 't1411-reflog-show.sh',
+ 't1412-reflog-loop.sh',
+ 't1413-reflog-detach.sh',
+ 't1414-reflog-walk.sh',
+ 't1415-worktree-refs.sh',
+ 't1416-ref-transaction-hooks.sh',
+ 't1417-reflog-updateref.sh',
+ 't1418-reflog-exists.sh',
+ 't1419-exclude-refs.sh',
+ 't1420-lost-found.sh',
+ 't1430-bad-ref-name.sh',
+ 't1450-fsck.sh',
+ 't1451-fsck-buffer.sh',
+ 't1460-refs-migrate.sh',
+ 't1500-rev-parse.sh',
+ 't1501-work-tree.sh',
+ 't1502-rev-parse-parseopt.sh',
+ 't1503-rev-parse-verify.sh',
+ 't1504-ceiling-dirs.sh',
+ 't1505-rev-parse-last.sh',
+ 't1506-rev-parse-diagnosis.sh',
+ 't1507-rev-parse-upstream.sh',
+ 't1508-at-combinations.sh',
+ 't1509-root-work-tree.sh',
+ 't1510-repo-setup.sh',
+ 't1511-rev-parse-caret.sh',
+ 't1512-rev-parse-disambiguation.sh',
+ 't1513-rev-parse-prefix.sh',
+ 't1514-rev-parse-push.sh',
+ 't1515-rev-parse-outside-repo.sh',
+ 't1517-outside-repo.sh',
+ 't1600-index.sh',
+ 't1601-index-bogus.sh',
+ 't1700-split-index.sh',
+ 't1701-racy-split-index.sh',
+ 't1800-hook.sh',
+ 't2000-conflict-when-checking-files-out.sh',
+ 't2002-checkout-cache-u.sh',
+ 't2003-checkout-cache-mkdir.sh',
+ 't2004-checkout-cache-temp.sh',
+ 't2005-checkout-index-symlinks.sh',
+ 't2006-checkout-index-basic.sh',
+ 't2007-checkout-symlink.sh',
+ 't2008-checkout-subdir.sh',
+ 't2009-checkout-statinfo.sh',
+ 't2010-checkout-ambiguous.sh',
+ 't2011-checkout-invalid-head.sh',
+ 't2012-checkout-last.sh',
+ 't2013-checkout-submodule.sh',
+ 't2014-checkout-switch.sh',
+ 't2015-checkout-unborn.sh',
+ 't2016-checkout-patch.sh',
+ 't2017-checkout-orphan.sh',
+ 't2018-checkout-branch.sh',
+ 't2019-checkout-ambiguous-ref.sh',
+ 't2020-checkout-detach.sh',
+ 't2021-checkout-overwrite.sh',
+ 't2022-checkout-paths.sh',
+ 't2023-checkout-m.sh',
+ 't2024-checkout-dwim.sh',
+ 't2025-checkout-no-overlay.sh',
+ 't2026-checkout-pathspec-file.sh',
+ 't2027-checkout-track.sh',
+ 't2030-unresolve-info.sh',
+ 't2050-git-dir-relative.sh',
+ 't2060-switch.sh',
+ 't2070-restore.sh',
+ 't2071-restore-patch.sh',
+ 't2072-restore-pathspec-file.sh',
+ 't2080-parallel-checkout-basics.sh',
+ 't2081-parallel-checkout-collisions.sh',
+ 't2082-parallel-checkout-attributes.sh',
+ 't2100-update-cache-badpath.sh',
+ 't2101-update-index-reupdate.sh',
+ 't2102-update-index-symlinks.sh',
+ 't2103-update-index-ignore-missing.sh',
+ 't2104-update-index-skip-worktree.sh',
+ 't2105-update-index-gitfile.sh',
+ 't2106-update-index-assume-unchanged.sh',
+ 't2107-update-index-basic.sh',
+ 't2108-update-index-refresh-racy.sh',
+ 't2200-add-update.sh',
+ 't2201-add-update-typechange.sh',
+ 't2202-add-addremove.sh',
+ 't2203-add-intent.sh',
+ 't2204-add-ignored.sh',
+ 't2205-add-worktree-config.sh',
+ 't2300-cd-to-toplevel.sh',
+ 't2400-worktree-add.sh',
+ 't2401-worktree-prune.sh',
+ 't2402-worktree-list.sh',
+ 't2403-worktree-move.sh',
+ 't2404-worktree-config.sh',
+ 't2405-worktree-submodule.sh',
+ 't2406-worktree-repair.sh',
+ 't2407-worktree-heads.sh',
+ 't2500-untracked-overwriting.sh',
+ 't2501-cwd-empty.sh',
+ 't3000-ls-files-others.sh',
+ 't3001-ls-files-others-exclude.sh',
+ 't3002-ls-files-dashpath.sh',
+ 't3003-ls-files-exclude.sh',
+ 't3004-ls-files-basic.sh',
+ 't3005-ls-files-relative.sh',
+ 't3006-ls-files-long.sh',
+ 't3007-ls-files-recurse-submodules.sh',
+ 't3008-ls-files-lazy-init-name-hash.sh',
+ 't3009-ls-files-others-nonsubmodule.sh',
+ 't3010-ls-files-killed-modified.sh',
+ 't3011-common-prefixes-and-directory-traversal.sh',
+ 't3012-ls-files-dedup.sh',
+ 't3013-ls-files-format.sh',
+ 't3020-ls-files-error-unmatch.sh',
+ 't3040-subprojects-basic.sh',
+ 't3050-subprojects-fetch.sh',
+ 't3060-ls-files-with-tree.sh',
+ 't3070-wildmatch.sh',
+ 't3100-ls-tree-restrict.sh',
+ 't3101-ls-tree-dirname.sh',
+ 't3102-ls-tree-wildcards.sh',
+ 't3103-ls-tree-misc.sh',
+ 't3104-ls-tree-format.sh',
+ 't3105-ls-tree-output.sh',
+ 't3200-branch.sh',
+ 't3201-branch-contains.sh',
+ 't3202-show-branch.sh',
+ 't3203-branch-output.sh',
+ 't3204-branch-name-interpretation.sh',
+ 't3205-branch-color.sh',
+ 't3206-range-diff.sh',
+ 't3207-branch-submodule.sh',
+ 't3211-peel-ref.sh',
+ 't3300-funny-names.sh',
+ 't3301-notes.sh',
+ 't3302-notes-index-expensive.sh',
+ 't3303-notes-subtrees.sh',
+ 't3304-notes-mixed.sh',
+ 't3305-notes-fanout.sh',
+ 't3306-notes-prune.sh',
+ 't3307-notes-man.sh',
+ 't3308-notes-merge.sh',
+ 't3309-notes-merge-auto-resolve.sh',
+ 't3310-notes-merge-manual-resolve.sh',
+ 't3311-notes-merge-fanout.sh',
+ 't3320-notes-merge-worktrees.sh',
+ 't3321-notes-stripspace.sh',
+ 't3400-rebase.sh',
+ 't3401-rebase-and-am-rename.sh',
+ 't3402-rebase-merge.sh',
+ 't3403-rebase-skip.sh',
+ 't3404-rebase-interactive.sh',
+ 't3405-rebase-malformed.sh',
+ 't3406-rebase-message.sh',
+ 't3407-rebase-abort.sh',
+ 't3408-rebase-multi-line.sh',
+ 't3409-rebase-environ.sh',
+ 't3412-rebase-root.sh',
+ 't3413-rebase-hook.sh',
+ 't3415-rebase-autosquash.sh',
+ 't3416-rebase-onto-threedots.sh',
+ 't3417-rebase-whitespace-fix.sh',
+ 't3418-rebase-continue.sh',
+ 't3419-rebase-patch-id.sh',
+ 't3420-rebase-autostash.sh',
+ 't3421-rebase-topology-linear.sh',
+ 't3422-rebase-incompatible-options.sh',
+ 't3423-rebase-reword.sh',
+ 't3424-rebase-empty.sh',
+ 't3425-rebase-topology-merges.sh',
+ 't3426-rebase-submodule.sh',
+ 't3427-rebase-subtree.sh',
+ 't3428-rebase-signoff.sh',
+ 't3429-rebase-edit-todo.sh',
+ 't3430-rebase-merges.sh',
+ 't3431-rebase-fork-point.sh',
+ 't3432-rebase-fast-forward.sh',
+ 't3433-rebase-across-mode-change.sh',
+ 't3434-rebase-i18n.sh',
+ 't3435-rebase-gpg-sign.sh',
+ 't3436-rebase-more-options.sh',
+ 't3437-rebase-fixup-options.sh',
+ 't3438-rebase-broken-files.sh',
+ 't3500-cherry.sh',
+ 't3501-revert-cherry-pick.sh',
+ 't3502-cherry-pick-merge.sh',
+ 't3503-cherry-pick-root.sh',
+ 't3504-cherry-pick-rerere.sh',
+ 't3505-cherry-pick-empty.sh',
+ 't3506-cherry-pick-ff.sh',
+ 't3507-cherry-pick-conflict.sh',
+ 't3508-cherry-pick-many-commits.sh',
+ 't3509-cherry-pick-merge-df.sh',
+ 't3510-cherry-pick-sequence.sh',
+ 't3511-cherry-pick-x.sh',
+ 't3512-cherry-pick-submodule.sh',
+ 't3513-revert-submodule.sh',
+ 't3514-cherry-pick-revert-gpg.sh',
+ 't3600-rm.sh',
+ 't3601-rm-pathspec-file.sh',
+ 't3602-rm-sparse-checkout.sh',
+ 't3650-replay-basics.sh',
+ 't3700-add.sh',
+ 't3701-add-interactive.sh',
+ 't3702-add-edit.sh',
+ 't3703-add-magic-pathspec.sh',
+ 't3704-add-pathspec-file.sh',
+ 't3705-add-sparse-checkout.sh',
+ 't3800-mktag.sh',
+ 't3900-i18n-commit.sh',
+ 't3901-i18n-patch.sh',
+ 't3902-quoted.sh',
+ 't3903-stash.sh',
+ 't3904-stash-patch.sh',
+ 't3905-stash-include-untracked.sh',
+ 't3906-stash-submodule.sh',
+ 't3907-stash-show-config.sh',
+ 't3908-stash-in-worktree.sh',
+ 't3909-stash-pathspec-file.sh',
+ 't3910-mac-os-precompose.sh',
+ 't3920-crlf-messages.sh',
+ 't4000-diff-format.sh',
+ 't4001-diff-rename.sh',
+ 't4002-diff-basic.sh',
+ 't4003-diff-rename-1.sh',
+ 't4004-diff-rename-symlink.sh',
+ 't4005-diff-rename-2.sh',
+ 't4006-diff-mode.sh',
+ 't4007-rename-3.sh',
+ 't4008-diff-break-rewrite.sh',
+ 't4009-diff-rename-4.sh',
+ 't4010-diff-pathspec.sh',
+ 't4011-diff-symlink.sh',
+ 't4012-diff-binary.sh',
+ 't4013-diff-various.sh',
+ 't4014-format-patch.sh',
+ 't4015-diff-whitespace.sh',
+ 't4016-diff-quote.sh',
+ 't4017-diff-retval.sh',
+ 't4018-diff-funcname.sh',
+ 't4019-diff-wserror.sh',
+ 't4020-diff-external.sh',
+ 't4021-format-patch-numbered.sh',
+ 't4022-diff-rewrite.sh',
+ 't4023-diff-rename-typechange.sh',
+ 't4024-diff-optimize-common.sh',
+ 't4025-hunk-header.sh',
+ 't4026-color.sh',
+ 't4027-diff-submodule.sh',
+ 't4028-format-patch-mime-headers.sh',
+ 't4029-diff-trailing-space.sh',
+ 't4030-diff-textconv.sh',
+ 't4031-diff-rewrite-binary.sh',
+ 't4032-diff-inter-hunk-context.sh',
+ 't4033-diff-patience.sh',
+ 't4034-diff-words.sh',
+ 't4035-diff-quiet.sh',
+ 't4036-format-patch-signer-mime.sh',
+ 't4037-diff-r-t-dirs.sh',
+ 't4038-diff-combined.sh',
+ 't4039-diff-assume-unchanged.sh',
+ 't4040-whitespace-status.sh',
+ 't4041-diff-submodule-option.sh',
+ 't4042-diff-textconv-caching.sh',
+ 't4043-diff-rename-binary.sh',
+ 't4044-diff-index-unique-abbrev.sh',
+ 't4045-diff-relative.sh',
+ 't4046-diff-unmerged.sh',
+ 't4047-diff-dirstat.sh',
+ 't4048-diff-combined-binary.sh',
+ 't4049-diff-stat-count.sh',
+ 't4050-diff-histogram.sh',
+ 't4051-diff-function-context.sh',
+ 't4052-stat-output.sh',
+ 't4053-diff-no-index.sh',
+ 't4054-diff-bogus-tree.sh',
+ 't4055-diff-context.sh',
+ 't4056-diff-order.sh',
+ 't4057-diff-combined-paths.sh',
+ 't4058-diff-duplicates.sh',
+ 't4059-diff-submodule-not-initialized.sh',
+ 't4060-diff-submodule-option-diff-format.sh',
+ 't4061-diff-indent.sh',
+ 't4062-diff-pickaxe.sh',
+ 't4063-diff-blobs.sh',
+ 't4064-diff-oidfind.sh',
+ 't4065-diff-anchored.sh',
+ 't4066-diff-emit-delay.sh',
+ 't4067-diff-partial-clone.sh',
+ 't4068-diff-symmetric-merge-base.sh',
+ 't4069-remerge-diff.sh',
+ 't4100-apply-stat.sh',
+ 't4101-apply-nonl.sh',
+ 't4102-apply-rename.sh',
+ 't4103-apply-binary.sh',
+ 't4104-apply-boundary.sh',
+ 't4105-apply-fuzz.sh',
+ 't4106-apply-stdin.sh',
+ 't4107-apply-ignore-whitespace.sh',
+ 't4108-apply-threeway.sh',
+ 't4109-apply-multifrag.sh',
+ 't4110-apply-scan.sh',
+ 't4111-apply-subdir.sh',
+ 't4112-apply-renames.sh',
+ 't4113-apply-ending.sh',
+ 't4114-apply-typechange.sh',
+ 't4115-apply-symlink.sh',
+ 't4116-apply-reverse.sh',
+ 't4117-apply-reject.sh',
+ 't4118-apply-empty-context.sh',
+ 't4119-apply-config.sh',
+ 't4120-apply-popt.sh',
+ 't4121-apply-diffs.sh',
+ 't4122-apply-symlink-inside.sh',
+ 't4123-apply-shrink.sh',
+ 't4124-apply-ws-rule.sh',
+ 't4125-apply-ws-fuzz.sh',
+ 't4126-apply-empty.sh',
+ 't4127-apply-same-fn.sh',
+ 't4128-apply-root.sh',
+ 't4129-apply-samemode.sh',
+ 't4130-apply-criss-cross-rename.sh',
+ 't4131-apply-fake-ancestor.sh',
+ 't4132-apply-removal.sh',
+ 't4133-apply-filenames.sh',
+ 't4134-apply-submodule.sh',
+ 't4135-apply-weird-filenames.sh',
+ 't4136-apply-check.sh',
+ 't4137-apply-submodule.sh',
+ 't4138-apply-ws-expansion.sh',
+ 't4139-apply-escape.sh',
+ 't4140-apply-ita.sh',
+ 't4141-apply-too-large.sh',
+ 't4150-am.sh',
+ 't4151-am-abort.sh',
+ 't4152-am-subjects.sh',
+ 't4153-am-resume-override-opts.sh',
+ 't4200-rerere.sh',
+ 't4201-shortlog.sh',
+ 't4202-log.sh',
+ 't4203-mailmap.sh',
+ 't4204-patch-id.sh',
+ 't4205-log-pretty-formats.sh',
+ 't4206-log-follow-harder-copies.sh',
+ 't4207-log-decoration-colors.sh',
+ 't4208-log-magic-pathspec.sh',
+ 't4209-log-pickaxe.sh',
+ 't4210-log-i18n.sh',
+ 't4211-line-log.sh',
+ 't4212-log-corrupt.sh',
+ 't4213-log-tabexpand.sh',
+ 't4214-log-graph-octopus.sh',
+ 't4215-log-skewed-merges.sh',
+ 't4216-log-bloom.sh',
+ 't4217-log-limit.sh',
+ 't4252-am-options.sh',
+ 't4253-am-keep-cr-dos.sh',
+ 't4254-am-corrupt.sh',
+ 't4255-am-submodule.sh',
+ 't4256-am-format-flowed.sh',
+ 't4257-am-interactive.sh',
+ 't4258-am-quoted-cr.sh',
+ 't4300-merge-tree.sh',
+ 't4301-merge-tree-write-tree.sh',
+ 't5000-tar-tree.sh',
+ 't5001-archive-attr.sh',
+ 't5002-archive-attr-pattern.sh',
+ 't5003-archive-zip.sh',
+ 't5004-archive-corner-cases.sh',
+ 't5100-mailinfo.sh',
+ 't5150-request-pull.sh',
+ 't5200-update-server-info.sh',
+ 't5300-pack-object.sh',
+ 't5301-sliding-window.sh',
+ 't5302-pack-index.sh',
+ 't5303-pack-corruption-resilience.sh',
+ 't5304-prune.sh',
+ 't5305-include-tag.sh',
+ 't5306-pack-nobase.sh',
+ 't5307-pack-missing-commit.sh',
+ 't5308-pack-detect-duplicates.sh',
+ 't5309-pack-delta-cycles.sh',
+ 't5310-pack-bitmaps.sh',
+ 't5311-pack-bitmaps-shallow.sh',
+ 't5312-prune-corruption.sh',
+ 't5313-pack-bounds-checks.sh',
+ 't5314-pack-cycle-detection.sh',
+ 't5315-pack-objects-compression.sh',
+ 't5316-pack-delta-depth.sh',
+ 't5317-pack-objects-filter-objects.sh',
+ 't5318-commit-graph.sh',
+ 't5319-multi-pack-index.sh',
+ 't5320-delta-islands.sh',
+ 't5321-pack-large-objects.sh',
+ 't5322-pack-objects-sparse.sh',
+ 't5323-pack-redundant.sh',
+ 't5324-split-commit-graph.sh',
+ 't5325-reverse-index.sh',
+ 't5326-multi-pack-bitmaps.sh',
+ 't5327-multi-pack-bitmaps-rev.sh',
+ 't5328-commit-graph-64bit-time.sh',
+ 't5329-pack-objects-cruft.sh',
+ 't5330-no-lazy-fetch-with-commit-graph.sh',
+ 't5331-pack-objects-stdin.sh',
+ 't5332-multi-pack-reuse.sh',
+ 't5333-pseudo-merge-bitmaps.sh',
+ 't5334-incremental-multi-pack-index.sh',
+ 't5351-unpack-large-objects.sh',
+ 't5400-send-pack.sh',
+ 't5401-update-hooks.sh',
+ 't5402-post-merge-hook.sh',
+ 't5403-post-checkout-hook.sh',
+ 't5404-tracking-branches.sh',
+ 't5405-send-pack-rewind.sh',
+ 't5406-remote-rejects.sh',
+ 't5407-post-rewrite-hook.sh',
+ 't5408-send-pack-stdin.sh',
+ 't5409-colorize-remote-messages.sh',
+ 't5410-receive-pack-alternates.sh',
+ 't5411-proc-receive-hook.sh',
+ 't5500-fetch-pack.sh',
+ 't5501-fetch-push-alternates.sh',
+ 't5502-quickfetch.sh',
+ 't5503-tagfollow.sh',
+ 't5504-fetch-receive-strict.sh',
+ 't5505-remote.sh',
+ 't5506-remote-groups.sh',
+ 't5507-remote-environment.sh',
+ 't5509-fetch-push-namespaces.sh',
+ 't5510-fetch.sh',
+ 't5511-refspec.sh',
+ 't5512-ls-remote.sh',
+ 't5513-fetch-track.sh',
+ 't5514-fetch-multiple.sh',
+ 't5515-fetch-merge-logic.sh',
+ 't5516-fetch-push.sh',
+ 't5517-push-mirror.sh',
+ 't5518-fetch-exit-status.sh',
+ 't5519-push-alternates.sh',
+ 't5520-pull.sh',
+ 't5521-pull-options.sh',
+ 't5522-pull-symlink.sh',
+ 't5523-push-upstream.sh',
+ 't5524-pull-msg.sh',
+ 't5525-fetch-tagopt.sh',
+ 't5526-fetch-submodules.sh',
+ 't5527-fetch-odd-refs.sh',
+ 't5528-push-default.sh',
+ 't5529-push-errors.sh',
+ 't5530-upload-pack-error.sh',
+ 't5531-deep-submodule-push.sh',
+ 't5532-fetch-proxy.sh',
+ 't5533-push-cas.sh',
+ 't5534-push-signed.sh',
+ 't5535-fetch-push-symref.sh',
+ 't5536-fetch-conflicts.sh',
+ 't5537-fetch-shallow.sh',
+ 't5538-push-shallow.sh',
+ 't5539-fetch-http-shallow.sh',
+ 't5540-http-push-webdav.sh',
+ 't5541-http-push-smart.sh',
+ 't5542-push-http-shallow.sh',
+ 't5543-atomic-push.sh',
+ 't5544-pack-objects-hook.sh',
+ 't5545-push-options.sh',
+ 't5546-receive-limits.sh',
+ 't5547-push-quarantine.sh',
+ 't5548-push-porcelain.sh',
+ 't5549-fetch-push-http.sh',
+ 't5550-http-fetch-dumb.sh',
+ 't5551-http-fetch-smart.sh',
+ 't5552-skipping-fetch-negotiator.sh',
+ 't5553-set-upstream.sh',
+ 't5554-noop-fetch-negotiator.sh',
+ 't5555-http-smart-common.sh',
+ 't5557-http-get.sh',
+ 't5558-clone-bundle-uri.sh',
+ 't5559-http-fetch-smart-http2.sh',
+ 't5560-http-backend-noserver.sh',
+ 't5561-http-backend.sh',
+ 't5562-http-backend-content-length.sh',
+ 't5563-simple-http-auth.sh',
+ 't5564-http-proxy.sh',
+ 't5570-git-daemon.sh',
+ 't5571-pre-push-hook.sh',
+ 't5572-pull-submodule.sh',
+ 't5573-pull-verify-signatures.sh',
+ 't5574-fetch-output.sh',
+ 't5580-unc-paths.sh',
+ 't5581-http-curl-verbose.sh',
+ 't5582-fetch-negative-refspec.sh',
+ 't5583-push-branches.sh',
+ 't5600-clone-fail-cleanup.sh',
+ 't5601-clone.sh',
+ 't5602-clone-remote-exec.sh',
+ 't5603-clone-dirname.sh',
+ 't5604-clone-reference.sh',
+ 't5605-clone-local.sh',
+ 't5606-clone-options.sh',
+ 't5607-clone-bundle.sh',
+ 't5608-clone-2gb.sh',
+ 't5609-clone-branch.sh',
+ 't5610-clone-detached.sh',
+ 't5611-clone-config.sh',
+ 't5612-clone-refspec.sh',
+ 't5613-info-alternate.sh',
+ 't5614-clone-submodules-shallow.sh',
+ 't5615-alternate-env.sh',
+ 't5616-partial-clone.sh',
+ 't5617-clone-submodules-remote.sh',
+ 't5618-alternate-refs.sh',
+ 't5619-clone-local-ambiguous-transport.sh',
+ 't5700-protocol-v1.sh',
+ 't5701-git-serve.sh',
+ 't5702-protocol-v2.sh',
+ 't5703-upload-pack-ref-in-want.sh',
+ 't5704-protocol-violations.sh',
+ 't5705-session-id-in-capabilities.sh',
+ 't5730-protocol-v2-bundle-uri-file.sh',
+ 't5731-protocol-v2-bundle-uri-git.sh',
+ 't5732-protocol-v2-bundle-uri-http.sh',
+ 't5750-bundle-uri-parse.sh',
+ 't5801-remote-helpers.sh',
+ 't5802-connect-helper.sh',
+ 't5810-proto-disable-local.sh',
+ 't5811-proto-disable-git.sh',
+ 't5812-proto-disable-http.sh',
+ 't5813-proto-disable-ssh.sh',
+ 't5814-proto-disable-ext.sh',
+ 't5815-submodule-protos.sh',
+ 't5900-repo-selection.sh',
+ 't6000-rev-list-misc.sh',
+ 't6001-rev-list-graft.sh',
+ 't6002-rev-list-bisect.sh',
+ 't6003-rev-list-topo-order.sh',
+ 't6004-rev-list-path-optim.sh',
+ 't6005-rev-list-count.sh',
+ 't6006-rev-list-format.sh',
+ 't6007-rev-list-cherry-pick-file.sh',
+ 't6008-rev-list-submodule.sh',
+ 't6009-rev-list-parent.sh',
+ 't6010-merge-base.sh',
+ 't6011-rev-list-with-bad-commit.sh',
+ 't6012-rev-list-simplify.sh',
+ 't6013-rev-list-reverse-parents.sh',
+ 't6014-rev-list-all.sh',
+ 't6016-rev-list-graph-simplify-history.sh',
+ 't6017-rev-list-stdin.sh',
+ 't6018-rev-list-glob.sh',
+ 't6019-rev-list-ancestry-path.sh',
+ 't6020-bundle-misc.sh',
+ 't6021-rev-list-exclude-hidden.sh',
+ 't6022-rev-list-missing.sh',
+ 't6030-bisect-porcelain.sh',
+ 't6040-tracking-info.sh',
+ 't6041-bisect-submodule.sh',
+ 't6050-replace.sh',
+ 't6060-merge-index.sh',
+ 't6100-rev-list-in-order.sh',
+ 't6101-rev-parse-parents.sh',
+ 't6102-rev-list-unexpected-objects.sh',
+ 't6110-rev-list-sparse.sh',
+ 't6111-rev-list-treesame.sh',
+ 't6112-rev-list-filters-objects.sh',
+ 't6113-rev-list-bitmap-filters.sh',
+ 't6114-keep-packs.sh',
+ 't6115-rev-list-du.sh',
+ 't6120-describe.sh',
+ 't6130-pathspec-noglob.sh',
+ 't6131-pathspec-icase.sh',
+ 't6132-pathspec-exclude.sh',
+ 't6133-pathspec-rev-dwim.sh',
+ 't6134-pathspec-in-submodule.sh',
+ 't6135-pathspec-with-attrs.sh',
+ 't6136-pathspec-in-bare.sh',
+ 't6200-fmt-merge-msg.sh',
+ 't6300-for-each-ref.sh',
+ 't6301-for-each-ref-errors.sh',
+ 't6302-for-each-ref-filter.sh',
+ 't6400-merge-df.sh',
+ 't6401-merge-criss-cross.sh',
+ 't6402-merge-rename.sh',
+ 't6403-merge-file.sh',
+ 't6404-recursive-merge.sh',
+ 't6405-merge-symlinks.sh',
+ 't6406-merge-attr.sh',
+ 't6407-merge-binary.sh',
+ 't6408-merge-up-to-date.sh',
+ 't6409-merge-subtree.sh',
+ 't6411-merge-filemode.sh',
+ 't6412-merge-large-rename.sh',
+ 't6413-merge-crlf.sh',
+ 't6414-merge-rename-nocruft.sh',
+ 't6415-merge-dir-to-symlink.sh',
+ 't6416-recursive-corner-cases.sh',
+ 't6417-merge-ours-theirs.sh',
+ 't6418-merge-text-auto.sh',
+ 't6419-merge-ignorecase.sh',
+ 't6421-merge-partial-clone.sh',
+ 't6422-merge-rename-corner-cases.sh',
+ 't6423-merge-rename-directories.sh',
+ 't6424-merge-unrelated-index-changes.sh',
+ 't6425-merge-rename-delete.sh',
+ 't6426-merge-skip-unneeded-updates.sh',
+ 't6427-diff3-conflict-markers.sh',
+ 't6428-merge-conflicts-sparse.sh',
+ 't6429-merge-sequence-rename-caching.sh',
+ 't6430-merge-recursive.sh',
+ 't6431-merge-criscross.sh',
+ 't6432-merge-recursive-space-options.sh',
+ 't6433-merge-toplevel.sh',
+ 't6434-merge-recursive-rename-options.sh',
+ 't6435-merge-sparse.sh',
+ 't6436-merge-overwrite.sh',
+ 't6437-submodule-merge.sh',
+ 't6438-submodule-directory-file-conflicts.sh',
+ 't6439-merge-co-error-msgs.sh',
+ 't6500-gc.sh',
+ 't6501-freshen-objects.sh',
+ 't6600-test-reach.sh',
+ 't6700-tree-depth.sh',
+ 't7001-mv.sh',
+ 't7002-mv-sparse-checkout.sh',
+ 't7003-filter-branch.sh',
+ 't7004-tag.sh',
+ 't7005-editor.sh',
+ 't7006-pager.sh',
+ 't7007-show.sh',
+ 't7008-filter-branch-null-sha1.sh',
+ 't7010-setup.sh',
+ 't7011-skip-worktree-reading.sh',
+ 't7012-skip-worktree-writing.sh',
+ 't7030-verify-tag.sh',
+ 't7031-verify-tag-signed-ssh.sh',
+ 't7060-wtstatus.sh',
+ 't7061-wtstatus-ignore.sh',
+ 't7062-wtstatus-ignorecase.sh',
+ 't7063-status-untracked-cache.sh',
+ 't7064-wtstatus-pv2.sh',
+ 't7101-reset-empty-subdirs.sh',
+ 't7102-reset.sh',
+ 't7103-reset-bare.sh',
+ 't7104-reset-hard.sh',
+ 't7105-reset-patch.sh',
+ 't7106-reset-unborn-branch.sh',
+ 't7107-reset-pathspec-file.sh',
+ 't7110-reset-merge.sh',
+ 't7111-reset-table.sh',
+ 't7112-reset-submodule.sh',
+ 't7113-post-index-change-hook.sh',
+ 't7201-co.sh',
+ 't7300-clean.sh',
+ 't7301-clean-interactive.sh',
+ 't7400-submodule-basic.sh',
+ 't7401-submodule-summary.sh',
+ 't7402-submodule-rebase.sh',
+ 't7403-submodule-sync.sh',
+ 't7406-submodule-update.sh',
+ 't7407-submodule-foreach.sh',
+ 't7408-submodule-reference.sh',
+ 't7409-submodule-detached-work-tree.sh',
+ 't7411-submodule-config.sh',
+ 't7412-submodule-absorbgitdirs.sh',
+ 't7413-submodule-is-active.sh',
+ 't7414-submodule-mistakes.sh',
+ 't7416-submodule-dash-url.sh',
+ 't7417-submodule-path-url.sh',
+ 't7418-submodule-sparse-gitmodules.sh',
+ 't7419-submodule-set-branch.sh',
+ 't7420-submodule-set-url.sh',
+ 't7421-submodule-summary-add.sh',
+ 't7422-submodule-output.sh',
+ 't7423-submodule-symlinks.sh',
+ 't7424-submodule-mixed-ref-formats.sh',
+ 't7450-bad-git-dotfiles.sh',
+ 't7500-commit-template-squash-signoff.sh',
+ 't7501-commit-basic-functionality.sh',
+ 't7502-commit-porcelain.sh',
+ 't7503-pre-commit-and-pre-merge-commit-hooks.sh',
+ 't7504-commit-msg-hook.sh',
+ 't7505-prepare-commit-msg-hook.sh',
+ 't7506-status-submodule.sh',
+ 't7507-commit-verbose.sh',
+ 't7508-status.sh',
+ 't7509-commit-authorship.sh',
+ 't7510-signed-commit.sh',
+ 't7511-status-index.sh',
+ 't7512-status-help.sh',
+ 't7513-interpret-trailers.sh',
+ 't7514-commit-patch.sh',
+ 't7515-status-symlinks.sh',
+ 't7516-commit-races.sh',
+ 't7517-per-repo-email.sh',
+ 't7518-ident-corner-cases.sh',
+ 't7519-status-fsmonitor.sh',
+ 't7520-ignored-hook-warning.sh',
+ 't7521-ignored-mode.sh',
+ 't7524-commit-summary.sh',
+ 't7525-status-rename.sh',
+ 't7526-commit-pathspec-file.sh',
+ 't7527-builtin-fsmonitor.sh',
+ 't7528-signed-commit-ssh.sh',
+ 't7600-merge.sh',
+ 't7601-merge-pull-config.sh',
+ 't7602-merge-octopus-many.sh',
+ 't7603-merge-reduce-heads.sh',
+ 't7604-merge-custom-message.sh',
+ 't7605-merge-resolve.sh',
+ 't7606-merge-custom.sh',
+ 't7607-merge-state.sh',
+ 't7608-merge-messages.sh',
+ 't7609-mergetool--lib.sh',
+ 't7610-mergetool.sh',
+ 't7611-merge-abort.sh',
+ 't7612-merge-verify-signatures.sh',
+ 't7614-merge-signoff.sh',
+ 't7615-diff-algo-with-mergy-operations.sh',
+ 't7700-repack.sh',
+ 't7701-repack-unpack-unreachable.sh',
+ 't7702-repack-cyclic-alternate.sh',
+ 't7703-repack-geometric.sh',
+ 't7704-repack-cruft.sh',
+ 't7800-difftool.sh',
+ 't7810-grep.sh',
+ 't7811-grep-open.sh',
+ 't7812-grep-icase-non-ascii.sh',
+ 't7813-grep-icase-iso.sh',
+ 't7814-grep-recurse-submodules.sh',
+ 't7815-grep-binary.sh',
+ 't7816-grep-binary-pattern.sh',
+ 't7817-grep-sparse-checkout.sh',
+ 't7900-maintenance.sh',
+ 't8001-annotate.sh',
+ 't8002-blame.sh',
+ 't8003-blame-corner-cases.sh',
+ 't8004-blame-with-conflicts.sh',
+ 't8005-blame-i18n.sh',
+ 't8006-blame-textconv.sh',
+ 't8007-cat-file-textconv.sh',
+ 't8008-blame-formats.sh',
+ 't8009-blame-vs-topicbranches.sh',
+ 't8010-cat-file-filters.sh',
+ 't8011-blame-split-file.sh',
+ 't8012-blame-colors.sh',
+ 't8013-blame-ignore-revs.sh',
+ 't8014-blame-ignore-fuzzy.sh',
+ 't9001-send-email.sh',
+ 't9002-column.sh',
+ 't9003-help-autocorrect.sh',
+ 't9100-git-svn-basic.sh',
+ 't9101-git-svn-props.sh',
+ 't9102-git-svn-deep-rmdir.sh',
+ 't9103-git-svn-tracked-directory-removed.sh',
+ 't9104-git-svn-follow-parent.sh',
+ 't9105-git-svn-commit-diff.sh',
+ 't9106-git-svn-commit-diff-clobber.sh',
+ 't9107-git-svn-migrate.sh',
+ 't9108-git-svn-glob.sh',
+ 't9109-git-svn-multi-glob.sh',
+ 't9110-git-svn-use-svm-props.sh',
+ 't9111-git-svn-use-svnsync-props.sh',
+ 't9112-git-svn-md5less-file.sh',
+ 't9113-git-svn-dcommit-new-file.sh',
+ 't9114-git-svn-dcommit-merge.sh',
+ 't9115-git-svn-dcommit-funky-renames.sh',
+ 't9116-git-svn-log.sh',
+ 't9117-git-svn-init-clone.sh',
+ 't9118-git-svn-funky-branch-names.sh',
+ 't9119-git-svn-info.sh',
+ 't9120-git-svn-clone-with-percent-escapes.sh',
+ 't9121-git-svn-fetch-renamed-dir.sh',
+ 't9122-git-svn-author.sh',
+ 't9123-git-svn-rebuild-with-rewriteroot.sh',
+ 't9124-git-svn-dcommit-auto-props.sh',
+ 't9125-git-svn-multi-glob-branch-names.sh',
+ 't9126-git-svn-follow-deleted-readded-directory.sh',
+ 't9127-git-svn-partial-rebuild.sh',
+ 't9128-git-svn-cmd-branch.sh',
+ 't9129-git-svn-i18n-commitencoding.sh',
+ 't9130-git-svn-authors-file.sh',
+ 't9131-git-svn-empty-symlink.sh',
+ 't9132-git-svn-broken-symlink.sh',
+ 't9133-git-svn-nested-git-repo.sh',
+ 't9134-git-svn-ignore-paths.sh',
+ 't9135-git-svn-moved-branch-empty-file.sh',
+ 't9136-git-svn-recreated-branch-empty-file.sh',
+ 't9137-git-svn-dcommit-clobber-series.sh',
+ 't9138-git-svn-authors-prog.sh',
+ 't9139-git-svn-non-utf8-commitencoding.sh',
+ 't9140-git-svn-reset.sh',
+ 't9141-git-svn-multiple-branches.sh',
+ 't9142-git-svn-shallow-clone.sh',
+ 't9143-git-svn-gc.sh',
+ 't9144-git-svn-old-rev_map.sh',
+ 't9145-git-svn-master-branch.sh',
+ 't9146-git-svn-empty-dirs.sh',
+ 't9147-git-svn-include-paths.sh',
+ 't9148-git-svn-propset.sh',
+ 't9150-svk-mergetickets.sh',
+ 't9151-svn-mergeinfo.sh',
+ 't9152-svn-empty-dirs-after-gc.sh',
+ 't9153-git-svn-rewrite-uuid.sh',
+ 't9154-git-svn-fancy-glob.sh',
+ 't9155-git-svn-fetch-deleted-tag.sh',
+ 't9156-git-svn-fetch-deleted-tag-2.sh',
+ 't9157-git-svn-fetch-merge.sh',
+ 't9158-git-svn-mergeinfo.sh',
+ 't9159-git-svn-no-parent-mergeinfo.sh',
+ 't9160-git-svn-preserve-empty-dirs.sh',
+ 't9161-git-svn-mergeinfo-push.sh',
+ 't9162-git-svn-dcommit-interactive.sh',
+ 't9163-git-svn-reset-clears-caches.sh',
+ 't9164-git-svn-dcommit-concurrent.sh',
+ 't9165-git-svn-fetch-merge-branch-of-branch.sh',
+ 't9166-git-svn-fetch-merge-branch-of-branch2.sh',
+ 't9167-git-svn-cmd-branch-subproject.sh',
+ 't9168-git-svn-partially-globbed-names.sh',
+ 't9169-git-svn-dcommit-crlf.sh',
+ 't9200-git-cvsexportcommit.sh',
+ 't9210-scalar.sh',
+ 't9211-scalar-clone.sh',
+ 't9300-fast-import.sh',
+ 't9301-fast-import-notes.sh',
+ 't9302-fast-import-unpack-limit.sh',
+ 't9303-fast-import-compression.sh',
+ 't9304-fast-import-marks.sh',
+ 't9350-fast-export.sh',
+ 't9351-fast-export-anonymize.sh',
+ 't9400-git-cvsserver-server.sh',
+ 't9401-git-cvsserver-crlf.sh',
+ 't9402-git-cvsserver-refs.sh',
+ 't9500-gitweb-standalone-no-errors.sh',
+ 't9501-gitweb-standalone-http-status.sh',
+ 't9502-gitweb-standalone-parse-output.sh',
+ 't9600-cvsimport.sh',
+ 't9601-cvsimport-vendor-branch.sh',
+ 't9602-cvsimport-branches-tags.sh',
+ 't9603-cvsimport-patchsets.sh',
+ 't9604-cvsimport-timestamps.sh',
+ 't9700-perl-git.sh',
+ 't9800-git-p4-basic.sh',
+ 't9801-git-p4-branch.sh',
+ 't9802-git-p4-filetype.sh',
+ 't9803-git-p4-shell-metachars.sh',
+ 't9804-git-p4-label.sh',
+ 't9805-git-p4-skip-submit-edit.sh',
+ 't9806-git-p4-options.sh',
+ 't9807-git-p4-submit.sh',
+ 't9808-git-p4-chdir.sh',
+ 't9809-git-p4-client-view.sh',
+ 't9810-git-p4-rcs.sh',
+ 't9811-git-p4-label-import.sh',
+ 't9812-git-p4-wildcards.sh',
+ 't9813-git-p4-preserve-users.sh',
+ 't9814-git-p4-rename.sh',
+ 't9815-git-p4-submit-fail.sh',
+ 't9816-git-p4-locked.sh',
+ 't9817-git-p4-exclude.sh',
+ 't9818-git-p4-block.sh',
+ 't9819-git-p4-case-folding.sh',
+ 't9820-git-p4-editor-handling.sh',
+ 't9821-git-p4-path-variations.sh',
+ 't9822-git-p4-path-encoding.sh',
+ 't9823-git-p4-mock-lfs.sh',
+ 't9824-git-p4-git-lfs.sh',
+ 't9825-git-p4-handle-utf16-without-bom.sh',
+ 't9826-git-p4-keep-empty-commits.sh',
+ 't9827-git-p4-change-filetype.sh',
+ 't9828-git-p4-map-user.sh',
+ 't9829-git-p4-jobs.sh',
+ 't9830-git-p4-symlink-dir.sh',
+ 't9831-git-p4-triggers.sh',
+ 't9832-unshelve.sh',
+ 't9833-errors.sh',
+ 't9834-git-p4-file-dir-bug.sh',
+ 't9835-git-p4-metadata-encoding-python2.sh',
+ 't9836-git-p4-metadata-encoding-python3.sh',
+ 't9850-shell.sh',
+ 't9901-git-web--browse.sh',
+ 't9902-completion.sh',
+ 't9903-bash-prompt.sh',
+]
+
+# GIT_BUILD_DIR needs to be Unix-style without drive prefixes as it get added
+# to the PATH variable. And given that drive prefixes contain a colon we'd
+# otherwise end up with a broken PATH if we didn't convert it.
+git_build_dir = meson.project_build_root()
+if cygpath.found()
+ git_build_dir = run_command(cygpath, git_build_dir, check: true).stdout().strip()
+endif
+
+test_environment = script_environment
+test_environment.set('GIT_BUILD_DIR', git_build_dir)
+
+foreach integration_test : integration_tests
+ test(fs.stem(integration_test), shell,
+ args: [ integration_test ],
+ workdir: meson.current_source_dir(),
+ env: test_environment,
+ depends: test_dependencies + bin_wrappers,
+ timeout: 0,
+ )
+endforeach
diff --git a/t/perf/p6100-describe.sh b/t/perf/p6100-describe.sh
new file mode 100755
index 0000000000..069f91ce49
--- /dev/null
+++ b/t/perf/p6100-describe.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description='performance of git-describe'
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+# clear out old tags and give us a known state
+test_expect_success 'set up tags' '
+ git for-each-ref --format="delete %(refname)" refs/tags >to-delete &&
+ git update-ref --stdin <to-delete &&
+ new=$(git rev-list -1000 HEAD | tail -n 1) &&
+ git tag -m new new $new &&
+ old=$(git rev-list HEAD | tail -n 1) &&
+ git tag -m old old $old
+'
+
+test_perf 'describe HEAD' '
+ git describe HEAD
+'
+
+test_perf 'describe HEAD with one max candidate' '
+ git describe --candidates=1 HEAD
+'
+
+test_perf 'describe HEAD with one tag' '
+ git describe --match=new HEAD
+'
+
+test_done
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 4890dff4b2..72a0c2e7d4 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -433,6 +433,12 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
sep_git_dir_worktree () {
test_when_finished "rm -rf mainwt linkwt seprepo" &&
git init mainwt &&
+ if test "relative" = $2
+ then
+ test_config -C mainwt worktree.useRelativePaths true
+ else
+ test_config -C mainwt worktree.useRelativePaths false
+ fi
test_commit -C mainwt gumby &&
git -C mainwt worktree add --detach ../linkwt &&
git -C "$1" init --separate-git-dir ../seprepo &&
@@ -441,12 +447,20 @@ sep_git_dir_worktree () {
test_cmp expect actual
}
-test_expect_success 're-init to move gitdir with linked worktrees' '
- sep_git_dir_worktree mainwt
+test_expect_success 're-init to move gitdir with linked worktrees (absolute)' '
+ sep_git_dir_worktree mainwt absolute
+'
+
+test_expect_success 're-init to move gitdir within linked worktree (absolute)' '
+ sep_git_dir_worktree linkwt absolute
+'
+
+test_expect_success 're-init to move gitdir with linked worktrees (relative)' '
+ sep_git_dir_worktree mainwt relative
'
-test_expect_success 're-init to move gitdir within linked worktree' '
- sep_git_dir_worktree linkwt
+test_expect_success 're-init to move gitdir within linked worktree (relative)' '
+ sep_git_dir_worktree linkwt relative
'
test_expect_success MINGW '.git hidden' '
diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh
index 9a3db02fde..f68e08d0b1 100755
--- a/t/t0018-advice.sh
+++ b/t/t0018-advice.sh
@@ -10,7 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
test_expect_success 'advice should be printed when config variable is unset' '
cat >expect <<-\EOF &&
hint: This is a piece of advice
- hint: Disable this message with "git config advice.nestedTag false"
+ hint: Disable this message with "git config set advice.nestedTag false"
EOF
test-tool advise "This is a piece of advice" 2>actual &&
test_cmp expect actual
diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
index c98d501869..196fc61784 100755
--- a/t/t0411-clone-from-partial.sh
+++ b/t/t0411-clone-from-partial.sh
@@ -28,7 +28,6 @@ test_expect_success 'local clone must not fetch from promisor remote and execute
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
evil clone1 2>err &&
- test_grep "detected dubious ownership" err &&
test_grep ! "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
@@ -38,7 +37,6 @@ test_expect_success 'clone from file://... must not fetch from promisor remote a
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
"file://$(pwd)/evil" clone2 2>err &&
- test_grep "detected dubious ownership" err &&
test_grep ! "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
@@ -48,7 +46,6 @@ test_expect_success 'fetch from file://... must not fetch from promisor remote a
test_must_fail git fetch \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
"file://$(pwd)/evil" 2>err &&
- test_grep "detected dubious ownership" err &&
test_grep ! "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index bf2a90df94..58a4583088 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -309,4 +309,19 @@ test_expect_success '--short= truncates to the actual hash length' '
test_cmp expect actual
'
+test_expect_success ':/ and HEAD^{/} favor more recent matching commits' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit common-old &&
+ test_commit --no-tag common-new &&
+ git rev-parse HEAD >expect &&
+ git rev-parse :/common >actual &&
+ test_cmp expect actual &&
+ git rev-parse HEAD^{/common} >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index ba320dc417..90638fa886 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -1206,4 +1206,50 @@ test_expect_success '"add" with initialized submodule, with submodule.recurse se
git -C project-clone -c submodule.recurse worktree add ../project-5
'
+test_expect_success 'can create worktrees with relative paths' '
+ test_when_finished "git worktree remove relative" &&
+ test_config worktree.useRelativePaths false &&
+ git worktree add --relative-paths ./relative &&
+ echo "gitdir: ../.git/worktrees/relative" >expect &&
+ test_cmp expect relative/.git &&
+ echo "../../../relative/.git" >expect &&
+ test_cmp expect .git/worktrees/relative/gitdir
+'
+
+test_expect_success 'can create worktrees with absolute paths' '
+ test_config worktree.useRelativePaths true &&
+ git worktree add ./relative &&
+ echo "gitdir: ../.git/worktrees/relative" >expect &&
+ test_cmp expect relative/.git &&
+ git worktree add --no-relative-paths ./absolute &&
+ echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect &&
+ test_cmp expect absolute/.git &&
+ echo "$(pwd)/absolute/.git" >expect &&
+ test_cmp expect .git/worktrees/absolute/gitdir
+'
+
+test_expect_success 'move repo without breaking relative internal links' '
+ test_when_finished rm -rf repo moved &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ git worktree add --relative-paths wt1 &&
+ cd .. &&
+ mv repo moved &&
+ cd moved/wt1 &&
+ git worktree list >out 2>err &&
+ test_must_be_empty err
+ )
+'
+
+test_expect_success 'relative worktree sets extension config' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ git -C repo commit --allow-empty -m base &&
+ git -C repo worktree add --relative-paths ./foo &&
+ test_cmp_config -C repo 1 core.repositoryformatversion &&
+ test_cmp_config -C repo true extensions.relativeworktrees
+'
+
test_done
diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh
index aa5b42c0f7..fe671d4197 100755
--- a/t/t2401-worktree-prune.sh
+++ b/t/t2401-worktree-prune.sh
@@ -119,11 +119,12 @@ test_expect_success 'prune duplicate (main/linked)' '
! test -d .git/worktrees/wt
'
-test_expect_success 'not prune proper worktrees when run inside linked worktree' '
+test_expect_success 'not prune proper worktrees inside linked worktree with relative paths' '
test_when_finished rm -rf repo wt_ext &&
git init repo &&
(
cd repo &&
+ git config worktree.useRelativePaths true &&
echo content >file &&
git add file &&
git commit -m msg &&
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index cb125ec226..8ef1cad7f2 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -260,6 +260,7 @@ test_expect_success 'broken main worktree still at the top' '
'
test_expect_success 'linked worktrees are sorted' '
+ test_when_finished "rm -rf sorted" &&
mkdir sorted &&
git init sorted/main &&
(
@@ -279,6 +280,27 @@ test_expect_success 'linked worktrees are sorted' '
test_cmp expected sorted/main/actual
'
+test_expect_success 'linked worktrees with relative paths are shown with absolute paths' '
+ test_when_finished "rm -rf sorted" &&
+ mkdir sorted &&
+ git init sorted/main &&
+ (
+ cd sorted/main &&
+ test_tick &&
+ test_commit new &&
+ git worktree add --relative-paths ../first &&
+ git worktree add ../second &&
+ git worktree list --porcelain >out &&
+ grep ^worktree out >actual
+ ) &&
+ cat >expected <<-EOF &&
+ worktree $(pwd)/sorted/main
+ worktree $(pwd)/sorted/first
+ worktree $(pwd)/sorted/second
+ EOF
+ test_cmp expected sorted/main/actual
+'
+
test_expect_success 'worktree path when called in .git directory' '
git worktree list >list1 &&
git -C .git worktree list >list2 &&
diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh
index 08531deb5b..0bb33e8b1b 100755
--- a/t/t2403-worktree-move.sh
+++ b/t/t2403-worktree-move.sh
@@ -246,4 +246,29 @@ test_expect_success 'not remove a repo with initialized submodule' '
)
'
+test_expect_success 'move worktree with absolute path to relative path' '
+ test_config worktree.useRelativePaths false &&
+ git worktree add ./absolute &&
+ git worktree move --relative-paths absolute relative &&
+ echo "gitdir: ../.git/worktrees/absolute" >expect &&
+ test_cmp expect relative/.git &&
+ echo "../../../relative/.git" >expect &&
+ test_cmp expect .git/worktrees/absolute/gitdir &&
+ test_config worktree.useRelativePaths true &&
+ git worktree move relative relative2 &&
+ echo "gitdir: ../.git/worktrees/absolute" >expect &&
+ test_cmp expect relative2/.git &&
+ echo "../../../relative2/.git" >expect &&
+ test_cmp expect .git/worktrees/absolute/gitdir
+'
+
+test_expect_success 'move worktree with relative path to absolute path' '
+ test_config worktree.useRelativePaths true &&
+ git worktree move --no-relative-paths relative2 absolute &&
+ echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect &&
+ test_cmp expect absolute/.git &&
+ echo "$(pwd)/absolute/.git" >expect &&
+ test_cmp expect .git/worktrees/absolute/gitdir
+'
+
test_done
diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh
index bf340b8772..f5f19b3169 100755
--- a/t/t2406-worktree-repair.sh
+++ b/t/t2406-worktree-repair.sh
@@ -215,4 +215,43 @@ test_expect_success 'repair copied main and linked worktrees' '
test_cmp dup/linked.expect dup/linked/.git
'
+test_expect_success 'repair worktree with relative path with missing gitfile' '
+ test_when_finished "rm -rf main wt" &&
+ test_create_repo main &&
+ git -C main config worktree.useRelativePaths true &&
+ test_commit -C main init &&
+ git -C main worktree add --detach ../wt &&
+ rm wt/.git &&
+ test_path_is_missing wt/.git &&
+ git -C main worktree repair &&
+ echo "gitdir: ../main/.git/worktrees/wt" >expect &&
+ test_cmp expect wt/.git
+'
+
+test_expect_success 'repair absolute worktree to use relative paths' '
+ test_when_finished "rm -rf main side sidemoved" &&
+ test_create_repo main &&
+ test_commit -C main init &&
+ git -C main worktree add --detach ../side &&
+ echo "../../../../sidemoved/.git" >expect-gitdir &&
+ echo "gitdir: ../main/.git/worktrees/side" >expect-gitfile &&
+ mv side sidemoved &&
+ git -C main worktree repair --relative-paths ../sidemoved &&
+ test_cmp expect-gitdir main/.git/worktrees/side/gitdir &&
+ test_cmp expect-gitfile sidemoved/.git
+'
+
+test_expect_success 'repair relative worktree to use absolute paths' '
+ test_when_finished "rm -rf main side sidemoved" &&
+ test_create_repo main &&
+ test_commit -C main init &&
+ git -C main worktree add --relative-paths --detach ../side &&
+ echo "$(pwd)/sidemoved/.git" >expect-gitdir &&
+ echo "gitdir: $(pwd)/main/.git/worktrees/side" >expect-gitfile &&
+ mv side sidemoved &&
+ git -C main worktree repair ../sidemoved &&
+ test_cmp expect-gitdir main/.git/worktrees/side/gitdir &&
+ test_cmp expect-gitfile sidemoved/.git
+'
+
test_done
diff --git a/t/t2408-worktree-relative.sh b/t/t2408-worktree-relative.sh
deleted file mode 100755
index d51cc8c5ab..0000000000
--- a/t/t2408-worktree-relative.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-
-test_description='test worktrees linked with relative paths'
-
-. ./test-lib.sh
-
-test_expect_success 'links worktrees with relative paths' '
- test_when_finished rm -rf repo &&
- git init repo &&
- (
- cd repo &&
- test_commit initial &&
- git worktree add wt1 &&
- echo "../../../wt1/.git" >expected_gitdir &&
- cat .git/worktrees/wt1/gitdir >actual_gitdir &&
- echo "gitdir: ../.git/worktrees/wt1" >expected_git &&
- cat wt1/.git >actual_git &&
- test_cmp expected_gitdir actual_gitdir &&
- test_cmp expected_git actual_git
- )
-'
-
-test_expect_success 'move repo without breaking relative internal links' '
- test_when_finished rm -rf repo moved &&
- git init repo &&
- (
- cd repo &&
- test_commit initial &&
- git worktree add wt1 &&
- cd .. &&
- mv repo moved &&
- cd moved/wt1 &&
- git status >out 2>err &&
- test_must_be_empty err
- )
-'
-
-test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 2295db3dcb..a3a21c54cf 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -1696,7 +1696,7 @@ test_expect_success 'errors if given a bad branch name' '
cat <<-\EOF >expect &&
fatal: '\''foo..bar'\'' is not a valid branch name
hint: See `man git check-ref-format`
- hint: Disable this message with "git config advice.refSyntax false"
+ hint: Disable this message with "git config set advice.refSyntax false"
EOF
test_must_fail git branch foo..bar >actual 2>&1 &&
test_cmp expect actual
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index b11f04eb33..ecfc02062c 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -2258,20 +2258,20 @@ test_expect_success 'non-merge commands reject merge commits' '
error: ${SQ}pick${SQ} does not accept merge commits
hint: ${SQ}pick${SQ} does not take a merge commit. If you wanted to
hint: replay the merge, use ${SQ}merge -C${SQ} on the commit.
- hint: Disable this message with "git config advice.rebaseTodoError false"
+ hint: Disable this message with "git config set advice.rebaseTodoError false"
error: invalid line 1: pick $oid
error: ${SQ}reword${SQ} does not accept merge commits
hint: ${SQ}reword${SQ} does not take a merge commit. If you wanted to
hint: replay the merge and reword the commit message, use
hint: ${SQ}merge -c${SQ} on the commit
- hint: Disable this message with "git config advice.rebaseTodoError false"
+ hint: Disable this message with "git config set advice.rebaseTodoError false"
error: invalid line 2: reword $oid
error: ${SQ}edit${SQ} does not accept merge commits
hint: ${SQ}edit${SQ} does not take a merge commit. If you wanted to
hint: replay the merge, use ${SQ}merge -C${SQ} on the commit, and then
hint: ${SQ}break${SQ} to give the control back to you so that you can
hint: do ${SQ}git commit --amend && git rebase --continue${SQ}.
- hint: Disable this message with "git config advice.rebaseTodoError false"
+ hint: Disable this message with "git config set advice.rebaseTodoError false"
error: invalid line 3: edit $oid
error: cannot squash merge commit into another commit
error: invalid line 4: fixup $oid
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 9e8c51b4e2..8025a28cfd 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -177,7 +177,7 @@ test_expect_success 'advice from failed revert' '
hint: You can instead skip this commit with "git revert --skip".
hint: To abort and get back to the state before "git revert",
hint: run "git revert --abort".
- hint: Disable this message with "git config advice.mergeConflict false"
+ hint: Disable this message with "git config set advice.mergeConflict false"
EOF
test_commit --append --no-tag "double-add dream" dream dream &&
test_must_fail git revert HEAD^ 2>actual &&
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index f3947b400a..44596cb1e8 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -34,7 +34,7 @@ test_expect_success setup '
git commit --allow-empty --allow-empty-message &&
git tag empty &&
git checkout main &&
- git config advice.detachedhead false
+ git config set advice.detachedhead false
'
@@ -60,7 +60,7 @@ test_expect_success 'advice from failed cherry-pick' '
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
- hint: Disable this message with "git config advice.mergeConflict false"
+ hint: Disable this message with "git config set advice.mergeConflict false"
EOF
test_must_fail git cherry-pick picked 2>actual &&
@@ -75,7 +75,7 @@ test_expect_success 'advice from failed cherry-pick --no-commit' "
error: could not apply \$picked... picked
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
- hint: Disable this message with \"git config advice.mergeConflict false\"
+ hint: Disable this message with \"git config set advice.mergeConflict false\"
EOF
test_must_fail git cherry-pick --no-commit picked 2>actual &&
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 7eb52b12ed..66ff9db270 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -25,7 +25,7 @@ pristine_detach () {
}
test_expect_success setup '
- git config advice.detachedhead false &&
+ git config set advice.detachedhead false &&
echo unrelated >unrelated &&
git add unrelated &&
test_commit initial foo a &&
diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh
index 84a587daf3..98ef13f0a3 100755
--- a/t/t3511-cherry-pick-x.sh
+++ b/t/t3511-cherry-pick-x.sh
@@ -51,7 +51,7 @@ trailing empty lines
"
test_expect_success setup '
- git config advice.detachedhead false &&
+ git config set advice.detachedhead false &&
echo unrelated >unrelated &&
git add unrelated &&
test_commit initial foo a &&
diff --git a/t/t3602-rm-sparse-checkout.sh b/t/t3602-rm-sparse-checkout.sh
index 08580fd3dc..02c7acd617 100755
--- a/t/t3602-rm-sparse-checkout.sh
+++ b/t/t3602-rm-sparse-checkout.sh
@@ -20,7 +20,7 @@ test_expect_success 'setup' "
hint: If you intend to update such entries, try one of the following:
hint: * Use the --sparse option.
hint: * Disable or modify the sparsity rules.
- hint: Disable this message with \"git config advice.updateSparsePath false\"
+ hint: Disable this message with \"git config set advice.updateSparsePath false\"
EOF
echo b | cat sparse_error_header - >sparse_entry_b_error &&
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 4c543a1a7e..df580a5806 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -31,7 +31,7 @@ test_expect_success 'Test with no pathspecs' '
cat >expect <<-EOF &&
Nothing specified, nothing added.
hint: Maybe you wanted to say ${SQ}git add .${SQ}?
- hint: Disable this message with "git config advice.addEmptyPathspec false"
+ hint: Disable this message with "git config set advice.addEmptyPathspec false"
EOF
git add 2>actual &&
test_cmp expect actual
@@ -375,7 +375,7 @@ test_expect_success '"git add" a embedded repository' '
hint: git rm --cached inner1
hint:
hint: See "git help submodule" for more information.
- hint: Disable this message with "git config advice.addEmbeddedRepo false"
+ hint: Disable this message with "git config set advice.addEmbeddedRepo false"
warning: adding embedded git repository: inner2
EOF
test_cmp expect actual
@@ -413,7 +413,7 @@ cat >expect.err <<\EOF
The following paths are ignored by one of your .gitignore files:
ignored-file
hint: Use -f if you really want to add them.
-hint: Disable this message with "git config advice.addIgnoredFile false"
+hint: Disable this message with "git config set advice.addIgnoredFile false"
EOF
cat >expect.out <<\EOF
add 'track-this'
diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh
index 2bade9e804..53a4782267 100755
--- a/t/t3705-add-sparse-checkout.sh
+++ b/t/t3705-add-sparse-checkout.sh
@@ -54,7 +54,7 @@ test_expect_success 'setup' "
hint: If you intend to update such entries, try one of the following:
hint: * Use the --sparse option.
hint: * Disable or modify the sparsity rules.
- hint: Disable this message with \"git config advice.updateSparsePath false\"
+ hint: Disable this message with \"git config set advice.updateSparsePath false\"
EOF
echo sparse_entry | cat sparse_error_header - >sparse_entry_error &&
diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh
index ca8f999cab..c6c94aef14 100755
--- a/t/t4069-remerge-diff.sh
+++ b/t/t4069-remerge-diff.sh
@@ -352,4 +352,11 @@ test_expect_success 'remerge-diff turns off history simplification' '
test_cmp expect actual
'
+test_expect_success 'remerge-diff with --reverse' '
+ git log -1 --remerge-diff --oneline ab_resolution^ >expect &&
+ git log -1 --remerge-diff --oneline ab_resolution >>expect &&
+ git log -2 --remerge-diff --oneline ab_resolution --reverse >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index 0614511656..2e83cc820a 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -58,7 +58,8 @@ ${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \
${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B
${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \
-${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1
+${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit}, \
+${c_reset}${c_remoteBranch}other/HEAD${c_reset}${c_commit})${c_reset} A1
${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t
${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 53dbc8ce3a..8212a70be8 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -170,7 +170,7 @@ test_expect_success 'fsck with invalid or bogus skipList input' '
test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err &&
test_grep "could not open.*: does-not-exist" err &&
test_must_fail git -c fsck.skipList=.git/config -c fsck.missingEmail=ignore fsck 2>err &&
- test_grep "invalid object name: \[core\]" err
+ test_grep "invalid object name: " err
'
test_expect_success 'fsck with other accepted skipList input (comments & empty lines)' '
@@ -233,7 +233,7 @@ test_expect_success 'push with receive.fsck.skipList' '
test_grep "could not open.*: does-not-exist" err &&
git --git-dir=dst/.git config receive.fsck.skipList config &&
test_must_fail git push --porcelain dst bogus 2>err &&
- test_grep "invalid object name: \[core\]" err &&
+ test_grep "invalid object name: " err &&
git --git-dir=dst/.git config receive.fsck.skipList SKIP &&
git push --porcelain dst bogus
@@ -262,7 +262,7 @@ test_expect_success 'fetch with fetch.fsck.skipList' '
test_grep "could not open.*: does-not-exist" err &&
git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/config &&
test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec 2>err &&
- test_grep "invalid object name: \[core\]" err &&
+ test_grep "invalid object name: " err &&
git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/SKIP &&
git --git-dir=dst/.git fetch "file://$(pwd)" $refspec
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 08424e878e..519f7973e3 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -2,6 +2,9 @@
test_description='git remote porcelain-ish'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
. ./test-lib.sh
setup_repository () {
@@ -70,7 +73,7 @@ test_expect_success 'add another remote' '
cd test &&
git remote add -f second ../two &&
tokens_match "origin second" "$(git remote)" &&
- check_tracking_branch second main side another &&
+ check_tracking_branch second main side another HEAD &&
git for-each-ref "--format=%(refname)" refs/remotes |
sed -e "/^refs\/remotes\/origin\//d" \
-e "/^refs\/remotes\/second\//d" >actual &&
@@ -428,16 +431,90 @@ test_expect_success 'set-head --auto' '
)
'
+test_expect_success REFFILES 'set-head --auto failure' '
+ test_when_finished "rm -f test/.git/refs/remotes/origin/HEAD.lock" &&
+ (
+ cd test &&
+ touch .git/refs/remotes/origin/HEAD.lock &&
+ test_must_fail git remote set-head --auto origin 2>err &&
+ tail -n1 err >output &&
+ echo "error: Could not set up refs/remotes/origin/HEAD" >expect &&
+ test_cmp expect output
+ )
+'
+
+test_expect_success 'set-head --auto detects creation' '
+ (
+ cd test &&
+ git update-ref --no-deref -d refs/remotes/origin/HEAD &&
+ git remote set-head --auto origin >output &&
+ echo "${SQ}origin/HEAD${SQ} is now created and points to ${SQ}main${SQ}" >expect &&
+ test_cmp expect output
+ )
+'
+
+test_expect_success 'set-head --auto to update a non symbolic ref' '
+ (
+ cd test &&
+ git update-ref --no-deref -d refs/remotes/origin/HEAD &&
+ git update-ref refs/remotes/origin/HEAD HEAD &&
+ HEAD=$(git log --pretty="%H") &&
+ git remote set-head --auto origin >output &&
+ echo "${SQ}origin/HEAD${SQ} was detached at ${SQ}${HEAD}${SQ} and now points to ${SQ}main${SQ}" >expect &&
+ test_cmp expect output
+ )
+'
+
+test_expect_success 'set-head --auto detects no change' '
+ (
+ cd test &&
+ git remote set-head --auto origin >output &&
+ echo "${SQ}origin/HEAD${SQ} is unchanged and points to ${SQ}main${SQ}" >expect &&
+ test_cmp expect output
+ )
+'
+
+test_expect_success 'set-head --auto detects change' '
+ (
+ cd test &&
+ git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/ahead &&
+ git remote set-head --auto origin >output &&
+ echo "${SQ}origin/HEAD${SQ} has changed from ${SQ}ahead${SQ} and now points to ${SQ}main${SQ}" >expect &&
+ test_cmp expect output
+ )
+'
+
+test_expect_success 'set-head --auto detects strange ref' '
+ (
+ cd test &&
+ git symbolic-ref refs/remotes/origin/HEAD refs/heads/main &&
+ git remote set-head --auto origin >output &&
+ echo "${SQ}origin/HEAD${SQ} used to point to ${SQ}refs/heads/main${SQ} (which is not a remote branch), but now points to ${SQ}main${SQ}" >expect &&
+ test_cmp expect output
+ )
+'
+
test_expect_success 'set-head --auto has no problem w/multiple HEADs' '
(
cd test &&
git fetch two "refs/heads/*:refs/remotes/two/*" &&
git remote set-head --auto two >output 2>&1 &&
- echo "two/HEAD set to main" >expect &&
+ echo "${SQ}two/HEAD${SQ} is unchanged and points to ${SQ}main${SQ}" >expect &&
test_cmp expect output
)
'
+test_expect_success 'set-head changes followRemoteHEAD always to warn' '
+ (
+ cd test &&
+ git config set remote.origin.followRemoteHEAD "always" &&
+ git remote set-head --auto origin &&
+ git config get remote.origin.followRemoteHEAD >actual &&
+ echo "warn" >expect &&
+ test_cmp expect actual
+ )
+'
+
cat >test/expect <<\EOF
refs/remotes/origin/side2
EOF
@@ -452,6 +529,16 @@ test_expect_success 'set-head explicit' '
)
'
+test_expect_success 'set-head --auto reports change' '
+ (
+ cd test &&
+ git remote set-head origin side2 &&
+ git remote set-head --auto origin >output 2>&1 &&
+ echo "${SQ}origin/HEAD${SQ} has changed from ${SQ}side2${SQ} and now points to ${SQ}main${SQ}" >expect &&
+ test_cmp expect output
+ )
+'
+
cat >test/expect <<EOF
Pruning origin
URL: $(pwd)/one
@@ -492,6 +579,16 @@ test_expect_success 'add --mirror && prune' '
)
'
+test_expect_success 'add --mirror setting HEAD' '
+ mkdir headmirror &&
+ (
+ cd headmirror &&
+ git init --bare -b notmain &&
+ git remote add --mirror -f origin ../one &&
+ test "$(git symbolic-ref HEAD)" = "refs/heads/main"
+ )
+'
+
test_expect_success 'add --mirror=fetch' '
mkdir mirror-fetch &&
git init -b main mirror-fetch/parent &&
@@ -711,8 +808,10 @@ test_expect_success 'reject --no-no-tags' '
'
cat >one/expect <<\EOF
+ apis/HEAD -> apis/main
apis/main
apis/side
+ drosophila/HEAD -> drosophila/main
drosophila/another
drosophila/main
drosophila/side
@@ -730,11 +829,14 @@ test_expect_success 'update' '
'
cat >one/expect <<\EOF
+ drosophila/HEAD -> drosophila/main
drosophila/another
drosophila/main
drosophila/side
+ manduca/HEAD -> manduca/main
manduca/main
manduca/side
+ megaloprepus/HEAD -> megaloprepus/main
megaloprepus/main
megaloprepus/side
EOF
@@ -742,7 +844,7 @@ EOF
test_expect_success 'update with arguments' '
(
cd one &&
- for b in $(git branch -r)
+ for b in $(git branch -r | grep -v HEAD)
do
git branch -r -d $b || exit 1
done &&
@@ -774,10 +876,13 @@ test_expect_success 'update --prune' '
'
cat >one/expect <<-\EOF
+ apis/HEAD -> apis/main
apis/main
apis/side
+ manduca/HEAD -> manduca/main
manduca/main
manduca/side
+ megaloprepus/HEAD -> megaloprepus/main
megaloprepus/main
megaloprepus/side
EOF
@@ -785,7 +890,7 @@ EOF
test_expect_success 'update default' '
(
cd one &&
- for b in $(git branch -r)
+ for b in $(git branch -r | grep -v HEAD)
do
git branch -r -d $b || exit 1
done &&
@@ -797,6 +902,7 @@ test_expect_success 'update default' '
'
cat >one/expect <<\EOF
+ drosophila/HEAD -> drosophila/main
drosophila/another
drosophila/main
drosophila/side
@@ -805,7 +911,7 @@ EOF
test_expect_success 'update default (overridden, with funny whitespace)' '
(
cd one &&
- for b in $(git branch -r)
+ for b in $(git branch -r | grep -v HEAD)
do
git branch -r -d $b || exit 1
done &&
@@ -819,7 +925,7 @@ test_expect_success 'update default (overridden, with funny whitespace)' '
test_expect_success 'update (with remotes.default defined)' '
(
cd one &&
- for b in $(git branch -r)
+ for b in $(git branch -r | grep -v HEAD)
do
git branch -r -d $b || exit 1
done &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 3b3991ab86..2d9587059f 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -74,6 +74,168 @@ test_expect_success "fetch test for-merge" '
cut -f -2 .git/FETCH_HEAD >actual &&
test_cmp expected actual'
+test_expect_success "fetch test remote HEAD" '
+ cd "$D" &&
+ cd two &&
+ git fetch &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/main) &&
+ test "z$head" = "z$branch"'
+
+test_expect_success "fetch test remote HEAD change" '
+ cd "$D" &&
+ cd two &&
+ git switch -c other &&
+ git push -u origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git fetch &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/other) &&
+ test "z$head" = "z$branch"'
+
+test_expect_success "fetch test followRemoteHEAD never" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git update-ref --no-deref -d refs/remotes/origin/HEAD &&
+ git config set remote.origin.followRemoteHEAD "never" &&
+ git fetch &&
+ test_must_fail git rev-parse --verify refs/remotes/origin/HEAD
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD warn no change" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git config set remote.origin.followRemoteHEAD "warn" &&
+ git fetch >output &&
+ echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \
+ "but we have ${SQ}other${SQ} locally." >expect &&
+ test_cmp expect output &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/other) &&
+ test "z$head" = "z$branch"
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD warn create" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git update-ref --no-deref -d refs/remotes/origin/HEAD &&
+ git config set remote.origin.followRemoteHEAD "warn" &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ output=$(git fetch) &&
+ test "z" = "z$output" &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/main) &&
+ test "z$head" = "z$branch"
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD warn detached" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git update-ref --no-deref -d refs/remotes/origin/HEAD &&
+ git update-ref refs/remotes/origin/HEAD HEAD &&
+ HEAD=$(git log --pretty="%H") &&
+ git config set remote.origin.followRemoteHEAD "warn" &&
+ git fetch >output &&
+ echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \
+ "but we have a detached HEAD pointing to" \
+ "${SQ}${HEAD}${SQ} locally." >expect &&
+ test_cmp expect output
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD warn quiet" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git config set remote.origin.followRemoteHEAD "warn" &&
+ output=$(git fetch --quiet) &&
+ test "z" = "z$output" &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/other) &&
+ test "z$head" = "z$branch"
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD warn-if-not-branch branch is same" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git config set remote.origin.followRemoteHEAD "warn-if-not-main" &&
+ actual=$(git fetch) &&
+ test "z" = "z$actual" &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/other) &&
+ test "z$head" = "z$branch"
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD warn-if-not-branch branch is different" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git config set remote.origin.followRemoteHEAD "warn-if-not-some/different-branch" &&
+ git fetch >actual &&
+ echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \
+ "but we have ${SQ}other${SQ} locally." >expect &&
+ test_cmp expect actual &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/other) &&
+ test "z$head" = "z$branch"
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD always" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git config set remote.origin.followRemoteHEAD "always" &&
+ git fetch &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/main) &&
+ test "z$head" = "z$branch"
+ )
+'
+
test_expect_success 'fetch --prune on its own works as expected' '
cd "$D" &&
git clone . prune &&
@@ -164,6 +326,23 @@ test_expect_success 'fetch --prune --tags with refspec prunes based on refspec'
git rev-parse sometag
'
+test_expect_success 'fetch --tags gets tags even without a configured remote' '
+ REMOTE="$(pwd)/test_tag_1" &&
+ git init test_tag_1 &&
+ (
+ cd test_tag_1 &&
+ test_commit foo
+ ) &&
+ git init test_tag_2 &&
+ (
+ cd test_tag_2 &&
+ git fetch --tags "file://$REMOTE" &&
+ echo "foo" >expect &&
+ git tag >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success REFFILES 'fetch --prune fails to delete branches' '
cd "$D" &&
git clone . prune-fail &&
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 3a67992a7d..5930f55186 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -292,6 +292,8 @@ test_expect_success 'ls-remote with filtered symref (refname)' '
cat >expect <<-EOF &&
ref: refs/heads/main HEAD
$rev HEAD
+ ref: refs/remotes/origin/main refs/remotes/origin/HEAD
+ $rev refs/remotes/origin/HEAD
EOF
git ls-remote --symref . HEAD >actual &&
test_cmp expect actual
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index 25772c85c5..523aff6268 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -44,14 +44,17 @@ test_expect_success setup '
'
cat > test/expect << EOF
+ one/HEAD -> one/main
one/main
one/side
origin/HEAD -> origin/main
origin/main
origin/side
+ three/HEAD -> three/main
three/another
three/main
three/side
+ two/HEAD -> two/main
two/another
two/main
two/side
@@ -96,6 +99,7 @@ cat > expect << EOF
origin/HEAD -> origin/main
origin/main
origin/side
+ three/HEAD -> three/main
three/another
three/main
three/side
@@ -111,8 +115,10 @@ test_expect_success 'git fetch --multiple (but only one remote)' '
'
cat > expect << EOF
+ one/HEAD -> one/main
one/main
one/side
+ two/HEAD -> two/main
two/another
two/main
two/side
@@ -140,7 +146,7 @@ test_expect_success 'git fetch --multiple (bad remote names)' '
test_expect_success 'git fetch --all (skipFetchAll)' '
(cd test4 &&
- for b in $(git branch -r)
+ for b in $(git branch -r | grep -v HEAD)
do
git branch -r -d $b || exit 1
done &&
@@ -152,11 +158,14 @@ test_expect_success 'git fetch --all (skipFetchAll)' '
'
cat > expect << EOF
+ one/HEAD -> one/main
one/main
one/side
+ three/HEAD -> three/main
three/another
three/main
three/side
+ two/HEAD -> two/main
two/another
two/main
two/side
@@ -164,7 +173,7 @@ EOF
test_expect_success 'git fetch --multiple (ignoring skipFetchAll)' '
(cd test4 &&
- for b in $(git branch -r)
+ for b in $(git branch -r | grep -v HEAD)
do
git branch -r -d $b || exit 1
done &&
@@ -220,14 +229,17 @@ test_expect_success 'git fetch --multiple --jobs=0 picks a default' '
create_fetch_all_expect () {
cat >expect <<-\EOF
+ one/HEAD -> one/main
one/main
one/side
origin/HEAD -> origin/main
origin/main
origin/side
+ three/HEAD -> three/main
three/another
three/main
three/side
+ two/HEAD -> two/main
two/another
two/main
two/side
@@ -264,6 +276,7 @@ test_expect_success 'git fetch (fetch all remotes with fetch.all = true)' '
create_fetch_one_expect () {
cat >expect <<-\EOF
+ one/HEAD -> one/main
one/main
one/side
origin/HEAD -> origin/main
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 9d693eb57f..041d7d806f 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1394,7 +1394,8 @@ test_expect_success 'fetch follows tags by default' '
git tag -m "annotated" tag &&
git for-each-ref >tmp1 &&
sed -n "p; s|refs/heads/main$|refs/remotes/origin/main|p" tmp1 |
- sort -k 3 >../expect
+ sed -n "p; s|refs/heads/main$|refs/remotes/origin/HEAD|p" |
+ sort -k 4 >../expect
) &&
test_when_finished "rm -rf dst" &&
git init dst &&
diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh
index e2770e4541..0de8eb5b6f 100755
--- a/t/t5527-fetch-odd-refs.sh
+++ b/t/t5527-fetch-odd-refs.sh
@@ -51,7 +51,8 @@ test_expect_success LONG_REF 'fetch handles extremely long refname' '
long
main
EOF
- git for-each-ref --format="%(subject)" refs/remotes/long >actual &&
+ git for-each-ref --format="%(subject)" refs/remotes/long \
+ --exclude=refs/remotes/long/HEAD >actual &&
test_cmp expect actual
'
diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh
index fa5ca4f522..470bfb610c 100755
--- a/t/t5604-clone-reference.sh
+++ b/t/t5604-clone-reference.sh
@@ -130,7 +130,7 @@ test_expect_success 'cloning with multiple references drops duplicates' '
test_expect_success 'clone with reference from a tagged repository' '
(
- cd A && git tag -a -m tagged HEAD
+ cd A && git tag -a -m tagged foo
) &&
git clone --reference=A A I
'
@@ -155,10 +155,10 @@ test_expect_success 'fetch with incomplete alternates' '
git remote add J "file://$base_dir/J" &&
GIT_TRACE_PACKET=$U.K git fetch J
) &&
- main_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/main) &&
+ main_object=$(git -C A rev-parse --verify refs/heads/main) &&
test -s "$U.K" &&
! grep " want $main_object" "$U.K" &&
- tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) &&
+ tag_object=$(git -C A rev-parse --verify refs/tags/foo) &&
! grep " want $tag_object" "$U.K"
'
diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh
index 339d8c786f..4605703496 100755
--- a/t/t5605-clone-local.sh
+++ b/t/t5605-clone-local.sh
@@ -153,6 +153,16 @@ test_expect_success 'cloning a local path with --no-local does not hardlink' '
! repo_is_hardlinked force-nonlocal
'
+test_expect_success 'cloning a local path with --no-local from a different user succeeds' '
+ git clone --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+ --no-local a nonlocal-otheruser 2>err &&
+ ! repo_is_hardlinked nonlocal-otheruser &&
+ # Verify that this is a git repository.
+ git -C nonlocal-otheruser rev-parse --show-toplevel &&
+ ! test_grep "detected dubious ownership" err
+
+'
+
test_expect_success 'cloning locally respects "-u" for fetching refs' '
test_must_fail git clone --bare -u false a should_not_work.git
'
diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh
index 489c6570da..82e3621ec5 100755
--- a/t/t5607-clone-bundle.sh
+++ b/t/t5607-clone-bundle.sh
@@ -170,6 +170,13 @@ test_expect_success 'clone bundle with different fsckObjects configurations' '
test_must_fail git -c transfer.fsckObjects=true \
clone bundle-fsck/bad.bundle bundle-transfer-fsck 2>err &&
+ test_grep "missingEmail" err &&
+
+ git -c fetch.fsckObjects=true -c fetch.fsck.missingEmail=ignore \
+ clone bundle-fsck/bad.bundle bundle-fsck-ignore &&
+
+ test_must_fail git -c fetch.fsckObjects=true -c fetch.fsck.missingEmail=error \
+ clone bundle-fsck/bad.bundle bundle-fsck-error 2>err &&
test_grep "missingEmail" err
'
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 5d444bfe20..4ce62feaa2 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -504,6 +504,50 @@ test_expect_success 'unfiltered bundle with --objects' '
test_cmp expect actual
'
+test_expect_success 'full bundle upto annotated tag' '
+ git bundle create v2.bdl \
+ v2 &&
+
+ git bundle verify v2.bdl |
+ make_user_friendly_and_stable_output >actual &&
+
+ format_and_save_expect <<-EOF &&
+ The bundle contains this ref:
+ <TAG-2> refs/tags/v2
+ The bundle records a complete history.
+ $HASH_MESSAGE
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'clone from full bundle upto annotated tag' '
+ git clone --mirror v2.bdl tag-clone.git &&
+ git -C tag-clone.git show-ref |
+ make_user_friendly_and_stable_output >actual &&
+ cat >expect <<-\EOF &&
+ <TAG-2> refs/tags/v2
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'incremental bundle between two annotated tags' '
+ git bundle create v1-v2.bdl \
+ v1..v2 &&
+
+ git bundle verify v1-v2.bdl |
+ make_user_friendly_and_stable_output >actual &&
+
+ format_and_save_expect <<-EOF &&
+ The bundle contains this ref:
+ <TAG-2> refs/tags/v2
+ The bundle requires these 2 refs:
+ <COMMIT-E> Z
+ <COMMIT-B> Z
+ $HASH_MESSAGE
+ EOF
+ test_cmp expect actual
+'
+
for filter in "blob:none" "tree:0" "tree:1" "blob:limit=100"
do
test_expect_success "filtered bundle: $filter" '
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 79e0f19deb..3f6160d702 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -18,6 +18,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
check_describe () {
indir= &&
+ outcome=success &&
while test $# != 0
do
case "$1" in
@@ -25,6 +26,9 @@ check_describe () {
indir="$2"
shift
;;
+ --expect-failure)
+ outcome=failure
+ ;;
*)
break
;;
@@ -35,7 +39,7 @@ check_describe () {
expect="$1"
shift
describe_opts="$@"
- test_expect_success "describe $describe_opts" '
+ test_expect_${outcome} "describe $describe_opts" '
git ${indir:+ -C "$indir"} describe $describe_opts >raw &&
sed -e "s/-g[0-9a-f]*\$/-gHASH/" <raw >actual &&
echo "$expect" >expect &&
@@ -616,7 +620,7 @@ test_expect_success 'name-rev --annotate-stdin works with commitGraph' '
# B
# o
-# \
+# H \
# o-----o---o----x
# A
#
@@ -626,6 +630,7 @@ test_expect_success 'setup: describe commits with disjoint bases' '
cd disjoint1 &&
echo o >> file && git add file && git commit -m o &&
+ git tag H -a -m H &&
echo A >> file && git add file && git commit -m A &&
git tag A -a -m A &&
echo o >> file && git add file && git commit -m o &&
@@ -638,8 +643,9 @@ test_expect_success 'setup: describe commits with disjoint bases' '
'
check_describe -C disjoint1 "A-3-gHASH" HEAD
+check_describe -C disjoint1 --expect-failure "A-3-gHASH" --candidates=2 HEAD
-# B
+# H B
# o---o---o------------.
# \
# o---o---x
@@ -657,6 +663,7 @@ test_expect_success 'setup: describe commits with disjoint bases 2' '
git checkout --orphan branch &&
echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:00" git commit -m o &&
echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:01" git commit -m o &&
+ git tag H -a -m H &&
echo B >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:02" git commit -m B &&
git tag B -a -m B &&
git merge --no-ff --allow-unrelated-histories main -m x
@@ -664,6 +671,7 @@ test_expect_success 'setup: describe commits with disjoint bases 2' '
'
check_describe -C disjoint2 "B-3-gHASH" HEAD
+check_describe -C disjoint2 --expect-failure "B-3-gHASH" --candidates=2 HEAD
test_expect_success 'setup misleading taggerdates' '
GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1
@@ -707,4 +715,14 @@ test_expect_success 'describe --broken --dirty with a file with changed stat' '
)
'
+test_expect_success '--always with no refs falls back to commit hash' '
+ git rev-parse HEAD >expect &&
+ git describe --no-abbrev --always --match=no-such-tag >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--exact-match does not show --always fallback' '
+ test_must_fail git describe --exact-match --always
+'
+
test_done
diff --git a/t/t7002-mv-sparse-checkout.sh b/t/t7002-mv-sparse-checkout.sh
index 26582ae4e5..4d3f221224 100755
--- a/t/t7002-mv-sparse-checkout.sh
+++ b/t/t7002-mv-sparse-checkout.sh
@@ -32,7 +32,7 @@ test_expect_success 'setup' "
hint: If you intend to update such entries, try one of the following:
hint: * Use the --sparse option.
hint: * Disable or modify the sparsity rules.
- hint: Disable this message with \"git config advice.updateSparsePath false\"
+ hint: Disable this message with \"git config set advice.updateSparsePath false\"
EOF
cat >dirty_error_header <<-EOF &&
@@ -45,7 +45,7 @@ test_expect_success 'setup' "
hint: To correct the sparsity of these paths, do the following:
hint: * Use \"git add --sparse <paths>\" to update the index
hint: * Use \"git sparse-checkout reapply\" to apply the sparsity rules
- hint: Disable this message with \"git config advice.updateSparsePath false\"
+ hint: Disable this message with \"git config set advice.updateSparsePath false\"
EOF
"
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index b1316e62f4..10835631ca 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -91,6 +91,18 @@ test_expect_success 'creating a tag using default HEAD should succeed' '
test_must_fail git reflog exists refs/tags/mytag
'
+test_expect_success 'HEAD is forbidden as a tagname' '
+ test_when_finished "git update-ref --no-deref -d refs/tags/HEAD || :" &&
+ test_must_fail git tag HEAD &&
+ test_must_fail git tag -a -m "useless" HEAD
+'
+
+test_expect_success '"git tag" can remove a tag named HEAD' '
+ test_when_finished "git update-ref --no-deref -d refs/tags/HEAD || :" &&
+ git update-ref refs/tags/HEAD HEAD &&
+ git tag -d HEAD
+'
+
test_expect_success 'creating a tag with --create-reflog should create reflog' '
git log -1 \
--format="format:tag: tagging %h (%s, %cd)%n" \
@@ -1850,7 +1862,7 @@ test_expect_success 'recursive tagging should give advice' '
hint: already a tag. If you meant to tag the object that it points to, use:
hint:
hint: git tag -f nested annotated-v4.0^{}
- hint: Disable this message with "git config advice.nestedTag false"
+ hint: Disable this message with "git config set advice.nestedTag false"
EOF
git tag -m nested nested annotated-v4.0 2>actual &&
test_cmp expect actual
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 793da6e64e..9bcf7c0b40 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -224,7 +224,7 @@ test_expect_success 'switch to another branch while carrying a deletion' '
'
test_expect_success 'checkout to detach HEAD (with advice declined)' '
- git config advice.detachedHead false &&
+ git config set advice.detachedHead false &&
rev=$(git rev-parse --short renamer^) &&
git checkout -f renamer &&
git clean -f &&
@@ -244,7 +244,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' '
'
test_expect_success 'checkout to detach HEAD' '
- git config advice.detachedHead true &&
+ git config set advice.detachedHead true &&
rev=$(git rev-parse --short renamer^) &&
git checkout -f renamer &&
git clean -f &&
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 981488885f..d6a501d453 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -212,7 +212,7 @@ test_expect_success 'submodule add to .gitignored path fails' '
The following paths are ignored by one of your .gitignore files:
submod
hint: Use -f if you really want to add them.
- hint: Disable this message with "git config advice.addIgnoredFile false"
+ hint: Disable this message with "git config set advice.addIgnoredFile false"
EOF
# Does not use test_commit due to the ignore
echo "*" > .gitignore &&
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index f9a5c98f3f..b2070d4e39 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1699,7 +1699,7 @@ test_expect_success 'setup slow status advice' '
EOF
git add .gitignore &&
git commit -m "Add .gitignore" &&
- git config advice.statusuoption true
+ git config set advice.statusuoption true
)
'
diff --git a/t/t7609-mergetool--lib.sh b/t/t7609-mergetool--lib.sh
index 330d6d603d..e8e205707e 100755
--- a/t/t7609-mergetool--lib.sh
+++ b/t/t7609-mergetool--lib.sh
@@ -7,7 +7,7 @@ Testing basic merge tools options'
. ./test-lib.sh
test_expect_success 'mergetool --tool=vimdiff creates the expected layout' '
- . "$GIT_BUILD_DIR"/mergetools/vimdiff &&
+ . "$GIT_TEST_MERGE_TOOLS_DIR"/vimdiff &&
run_unit_tests
'
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index 22b3a85b3e..c077aba7ce 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -898,4 +898,12 @@ test_expect_success 'mergetool with guiDefault' '
git commit -m "branch1 resolved with mergetool"
'
+test_expect_success 'mergetool with non-existent tool' '
+ test_when_finished "git reset --hard" &&
+ git checkout -b test$test_count branch1 &&
+ test_must_fail git merge main &&
+ yes "" | test_must_fail git mergetool --tool=absent >out 2>&1 &&
+ test_grep "mergetool.absent.cmd not set for tool" out
+'
+
test_done
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 0ce4ba1cbe..1909aed95e 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -328,7 +328,8 @@ test_expect_success 'incremental-repack task' '
# Delete refs that have not been repacked in these packs.
git for-each-ref --format="delete %(refname)" \
- refs/prefetch refs/tags refs/remotes >refs &&
+ refs/prefetch refs/tags refs/remotes \
+ --exclude=refs/remotes/*/HEAD >refs &&
git update-ref --stdin <refs &&
# Replace the object directory with this pack layout.
diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh
index 027235d61a..a81662713e 100755
--- a/t/t9210-scalar.sh
+++ b/t/t9210-scalar.sh
@@ -150,7 +150,8 @@ test_expect_success 'scalar clone' '
"$(pwd)" &&
git for-each-ref --format="%(refname)" refs/remotes/origin/ >actual &&
- echo "refs/remotes/origin/parallel" >expect &&
+ echo "refs/remotes/origin/HEAD" >>expect &&
+ echo "refs/remotes/origin/parallel" >>expect &&
test_cmp expect actual &&
test_path_is_missing 1/2 &&
@@ -219,7 +220,7 @@ test_expect_success 'scalar reconfigure --all with includeIf.onbranch' '
done
'
- test_expect_success 'scalar reconfigure --all with detached HEADs' '
+test_expect_success 'scalar reconfigure --all with detached HEADs' '
repos="two three four" &&
for num in $repos
do
diff --git a/t/t9211-scalar-clone.sh b/t/t9211-scalar-clone.sh
index 7869f45ee6..01f71910f5 100755
--- a/t/t9211-scalar-clone.sh
+++ b/t/t9211-scalar-clone.sh
@@ -31,7 +31,7 @@ test_expect_success 'set up repository to clone' '
)
'
-cleanup_clone () {
+cleanup_clone() {
rm -rf "$1"
}
@@ -127,7 +127,7 @@ test_expect_success '--single-branch clones HEAD only' '
(
cd $enlistment/src &&
git for-each-ref refs/remotes/origin >out &&
- test_line_count = 1 out &&
+ test_line_count = 2 out &&
grep "refs/remotes/origin/base" out
) &&
@@ -141,7 +141,7 @@ test_expect_success '--no-single-branch clones all branches' '
(
cd $enlistment/src &&
git for-each-ref refs/remotes/origin >out &&
- test_line_count = 2 out &&
+ test_line_count = 3 out &&
grep "refs/remotes/origin/base" out &&
grep "refs/remotes/origin/parallel" out
) &&
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 27b2025f40..b258dbf1df 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -521,6 +521,113 @@ test_expect_success 'B: fail on invalid committer (5)' '
test_must_fail git fast-import <input
'
+test_expect_success 'B: fail on invalid file path of ..' '
+ cat >input <<-INPUT_END &&
+ blob
+ mark :1
+ data <<EOF
+ File contents
+ EOF
+
+ commit refs/heads/badpath
+ committer Name <email> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ Commit Message
+ COMMIT
+ M 100644 :1 ../invalid-path
+ INPUT_END
+
+ test_when_finished "git update-ref -d refs/heads/badpath" &&
+ test_must_fail git fast-import <input
+'
+
+test_expect_success 'B: fail on invalid file path of .' '
+ cat >input <<-INPUT_END &&
+ blob
+ mark :1
+ data <<EOF
+ File contents
+ EOF
+
+ commit refs/heads/badpath
+ committer Name <email> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ Good path
+ COMMIT
+ M 100644 :1 ok-path
+
+ commit refs/heads/badpath
+ committer Name <email> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ Bad path
+ COMMIT
+ R ok-path ./invalid-path
+ INPUT_END
+
+ test_when_finished "git update-ref -d refs/heads/badpath" &&
+ test_must_fail git fast-import <input
+'
+
+test_expect_success WINDOWS 'B: fail on invalid file path of C:' '
+ cat >input <<-INPUT_END &&
+ blob
+ mark :1
+ data <<EOF
+ File contents
+ EOF
+
+ commit refs/heads/badpath
+ committer Name <email> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ Commit Message
+ COMMIT
+ M 100644 :1 C:/invalid-path
+ INPUT_END
+
+ test_when_finished "git update-ref -d refs/heads/badpath" &&
+ test_must_fail git fast-import <input
+'
+
+test_expect_success 'B: fail on invalid file path of .git' '
+ cat >input <<-INPUT_END &&
+ blob
+ mark :1
+ data <<EOF
+ File contents
+ EOF
+
+ commit refs/heads/badpath
+ committer Name <email> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ Commit Message
+ COMMIT
+ M 100644 :1 .git/invalid-path
+ INPUT_END
+
+ test_when_finished "git update-ref -d refs/heads/badpath" &&
+ test_must_fail git fast-import <input
+'
+
+test_expect_success 'B: fail on invalid file path of .gitmodules' '
+ cat >input <<-INPUT_END &&
+ blob
+ mark :1
+ data <<EOF
+ File contents
+ EOF
+
+ commit refs/heads/badpath
+ committer Name <email> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ Commit Message
+ COMMIT
+ M 120000 :1 .gitmodules
+ INPUT_END
+
+ test_when_finished "git update-ref -d refs/heads/badpath" &&
+ test_must_fail git fast-import <input
+'
+
###
### series C
###
@@ -945,7 +1052,7 @@ test_expect_success 'L: verify internal tree sorting' '
:100644 100644 M ba
EXPECT_END
- git fast-import <input &&
+ git -c core.protectNTFS=false fast-import <input &&
GIT_PRINT_SHA1_ELLIPSIS="yes" git diff-tree --abbrev --raw L^ L >output &&
cut -d" " -f1,2,5 output >actual &&
test_cmp expect actual
@@ -3096,7 +3203,7 @@ test_path_eol_success () {
test_expect_success "S: paths at EOL with $test must work" '
test_when_finished "git branch -D S-path-eol" &&
- git fast-import --export-marks=marks.out <<-EOF >out 2>err &&
+ git -c core.protectNTFS=false fast-import --export-marks=marks.out <<-EOF >out 2>err &&
blob
mark :401
data <<BLOB
@@ -3205,7 +3312,7 @@ test_path_space_success () {
test_expect_success "S: paths before space with $test must work" '
test_when_finished "git branch -D S-path-space" &&
- git fast-import --export-marks=marks.out <<-EOF 2>err &&
+ git -c core.protectNTFS=false fast-import --export-marks=marks.out <<-EOF 2>err &&
blob
mark :401
data <<BLOB
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index aa33791b77..40427883ec 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -631,7 +631,7 @@ test_expect_success 'fast-export quotes pathnames' '
git rev-list HEAD >expect &&
git init result &&
cd result &&
- git fast-import <../export.out &&
+ git -c core.protectNTFS=false fast-import <../export.out &&
git rev-list HEAD >actual &&
test_cmp ../expect actual
)
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 932d5ad759..51bd750837 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -657,6 +657,7 @@ test_expect_success '__git_refs - simple' '
HEAD
main
matching-branch
+ other/HEAD
other/branch-in-other
other/main-in-other
matching-tag
@@ -672,6 +673,7 @@ test_expect_success '__git_refs - full refs' '
cat >expected <<-EOF &&
refs/heads/main
refs/heads/matching-branch
+ refs/remotes/other/HEAD
refs/remotes/other/branch-in-other
refs/remotes/other/main-in-other
refs/tags/matching-tag
@@ -728,6 +730,7 @@ test_expect_success '__git_refs - remote on local file system - full refs' '
test_expect_success '__git_refs - configured remote' '
cat >expected <<-EOF &&
HEAD
+ HEAD
branch-in-other
main-in-other
EOF
@@ -755,6 +758,7 @@ test_expect_success '__git_refs - configured remote - full refs' '
test_expect_success '__git_refs - configured remote - repo given on the command line' '
cat >expected <<-EOF &&
HEAD
+ HEAD
branch-in-other
main-in-other
EOF
@@ -786,6 +790,7 @@ test_expect_success '__git_refs - configured remote - full refs - repo given on
test_expect_success '__git_refs - configured remote - remote name matches a directory' '
cat >expected <<-EOF &&
HEAD
+ HEAD
branch-in-other
main-in-other
EOF
@@ -874,12 +879,14 @@ test_expect_success '__git_refs - unique remote branches for git checkout DWIMer
HEAD
main
matching-branch
+ other/HEAD
other/ambiguous
other/branch-in-other
other/main-in-other
remote/ambiguous
remote/branch-in-remote
matching-tag
+ HEAD
branch-in-other
branch-in-remote
main-in-other
@@ -903,6 +910,7 @@ test_expect_success '__git_refs - after --opt=' '
HEAD
main
matching-branch
+ other/HEAD
other/branch-in-other
other/main-in-other
matching-tag
@@ -918,6 +926,7 @@ test_expect_success '__git_refs - after --opt= - full refs' '
cat >expected <<-EOF &&
refs/heads/main
refs/heads/matching-branch
+ refs/remotes/other/HEAD
refs/remotes/other/branch-in-other
refs/remotes/other/main-in-other
refs/tags/matching-tag
@@ -934,6 +943,7 @@ test_expect_success '__git refs - excluding refs' '
^HEAD
^main
^matching-branch
+ ^other/HEAD
^other/branch-in-other
^other/main-in-other
^matching-tag
@@ -949,6 +959,7 @@ test_expect_success '__git refs - excluding full refs' '
cat >expected <<-EOF &&
^refs/heads/main
^refs/heads/matching-branch
+ ^refs/remotes/other/HEAD
^refs/remotes/other/branch-in-other
^refs/remotes/other/main-in-other
^refs/tags/matching-tag
@@ -974,6 +985,7 @@ test_expect_success '__git_refs - do not filter refs unless told so' '
main
matching-branch
matching/branch
+ other/HEAD
other/branch-in-other
other/main-in-other
other/matching/branch-in-other
@@ -1094,6 +1106,7 @@ test_expect_success '__git_complete_refs - simple' '
HEAD Z
main Z
matching-branch Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
matching-tag Z
@@ -1122,6 +1135,7 @@ test_expect_success '__git_complete_refs - matching' '
test_expect_success '__git_complete_refs - remote' '
sed -e "s/Z$//" >expected <<-EOF &&
HEAD Z
+ HEAD Z
branch-in-other Z
main-in-other Z
EOF
@@ -1138,9 +1152,11 @@ test_expect_success '__git_complete_refs - track' '
HEAD Z
main Z
matching-branch Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
matching-tag Z
+ HEAD Z
branch-in-other Z
main-in-other Z
EOF
@@ -1183,6 +1199,7 @@ test_expect_success '__git_complete_refs - suffix' '
HEAD.
main.
matching-branch.
+ other/HEAD.
other/branch-in-other.
other/main-in-other.
matching-tag.
@@ -1198,6 +1215,7 @@ test_expect_success '__git_complete_refs - suffix' '
test_expect_success '__git_complete_fetch_refspecs - simple' '
sed -e "s/Z$//" >expected <<-EOF &&
HEAD:HEAD Z
+ HEAD:HEAD Z
branch-in-other:branch-in-other Z
main-in-other:main-in-other Z
EOF
@@ -1224,6 +1242,7 @@ test_expect_success '__git_complete_fetch_refspecs - matching' '
test_expect_success '__git_complete_fetch_refspecs - prefix' '
sed -e "s/Z$//" >expected <<-EOF &&
+HEAD:HEAD Z
+ +HEAD:HEAD Z
+branch-in-other:branch-in-other Z
+main-in-other:main-in-other Z
EOF
@@ -1288,6 +1307,7 @@ test_expect_success '__git_complete_worktree_paths with -C' '
test_expect_success 'git switch - with no options, complete local branches and unique remote branch names for DWIM logic' '
test_completion "git switch " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -1434,11 +1454,13 @@ test_expect_success 'git-bisect - existing view subcommand is recognized and ena
test_expect_success 'git checkout - completes refs and unique remote branches for DWIM' '
test_completion "git checkout " <<-\EOF
HEAD Z
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1460,6 +1482,7 @@ test_expect_success 'git switch - with GIT_COMPLETION_CHECKOUT_NO_GUESS=1, compl
test_expect_success 'git switch - --guess overrides GIT_COMPLETION_CHECKOUT_NO_GUESS=1, complete local branches and unique remote names for DWIM logic' '
GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git switch --guess " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -1469,6 +1492,7 @@ test_expect_success 'git switch - --guess overrides GIT_COMPLETION_CHECKOUT_NO_G
test_expect_success 'git switch - a later --guess overrides previous --no-guess, complete local and remote unique branches for DWIM' '
test_completion "git switch --no-guess --guess " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -1489,6 +1513,7 @@ test_expect_success 'git checkout - with GIT_COMPLETION_NO_GUESS=1 only complete
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1497,11 +1522,13 @@ test_expect_success 'git checkout - with GIT_COMPLETION_NO_GUESS=1 only complete
test_expect_success 'git checkout - --guess overrides GIT_COMPLETION_NO_GUESS=1, complete refs and unique remote branches for DWIM' '
GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git checkout --guess " <<-\EOF
HEAD Z
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1513,6 +1540,7 @@ test_expect_success 'git checkout - with --no-guess, only completes refs' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1521,11 +1549,13 @@ test_expect_success 'git checkout - with --no-guess, only completes refs' '
test_expect_success 'git checkout - a later --guess overrides previous --no-guess, complete refs and unique remote branches for DWIM' '
test_completion "git checkout --no-guess --guess " <<-\EOF
HEAD Z
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1537,6 +1567,7 @@ test_expect_success 'git checkout - a later --no-guess overrides previous --gues
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1549,6 +1580,7 @@ test_expect_success 'git checkout - with checkout.guess = false, only completes
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1558,11 +1590,13 @@ test_expect_success 'git checkout - with checkout.guess = true, completes refs a
test_config checkout.guess true &&
test_completion "git checkout " <<-\EOF
HEAD Z
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1572,11 +1606,13 @@ test_expect_success 'git checkout - a later --guess overrides previous checkout.
test_config checkout.guess false &&
test_completion "git checkout --guess " <<-\EOF
HEAD Z
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1589,6 +1625,7 @@ test_expect_success 'git checkout - a later --no-guess overrides previous checko
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1600,6 +1637,7 @@ test_expect_success 'git switch - with --detach, complete all references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1611,6 +1649,7 @@ test_expect_success 'git checkout - with --detach, complete only references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1782,6 +1821,7 @@ test_expect_success 'git switch - with -d, complete all references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1793,6 +1833,7 @@ test_expect_success 'git checkout - with -d, complete only references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1800,10 +1841,12 @@ test_expect_success 'git checkout - with -d, complete only references' '
test_expect_success 'git switch - with --track, complete only remote branches' '
test_completion "git switch --track " <<-\EOF &&
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
test_completion "git switch -t " <<-\EOF
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1811,10 +1854,12 @@ test_expect_success 'git switch - with --track, complete only remote branches' '
test_expect_success 'git checkout - with --track, complete only remote branches' '
test_completion "git checkout --track " <<-\EOF &&
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
test_completion "git checkout -t " <<-\EOF
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1833,6 +1878,7 @@ test_expect_success 'git checkout - with --no-track, complete only local referen
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1844,6 +1890,7 @@ test_expect_success 'git switch - with -c, complete all references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1855,6 +1902,7 @@ test_expect_success 'git switch - with -C, complete all references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1866,6 +1914,7 @@ test_expect_success 'git switch - with -c and --track, complete all references'
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1877,6 +1926,7 @@ test_expect_success 'git switch - with -C and --track, complete all references'
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1888,6 +1938,7 @@ test_expect_success 'git switch - with -c and --no-track, complete all reference
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1899,6 +1950,7 @@ test_expect_success 'git switch - with -C and --no-track, complete all reference
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1910,6 +1962,7 @@ test_expect_success 'git checkout - with -b, complete all references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1921,6 +1974,7 @@ test_expect_success 'git checkout - with -B, complete all references' '
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1932,6 +1986,7 @@ test_expect_success 'git checkout - with -b and --track, complete all references
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1943,6 +1998,7 @@ test_expect_success 'git checkout - with -B and --track, complete all references
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1954,6 +2010,7 @@ test_expect_success 'git checkout - with -b and --no-track, complete all referen
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1965,6 +2022,7 @@ test_expect_success 'git checkout - with -B and --no-track, complete all referen
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
@@ -1972,6 +2030,7 @@ test_expect_success 'git checkout - with -B and --no-track, complete all referen
test_expect_success 'git switch - for -c, complete local branches and unique remote branches' '
test_completion "git switch -c " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -1981,6 +2040,7 @@ test_expect_success 'git switch - for -c, complete local branches and unique rem
test_expect_success 'git switch - for -C, complete local branches and unique remote branches' '
test_completion "git switch -C " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -2018,6 +2078,7 @@ test_expect_success 'git switch - for -C with --no-track, complete local branche
test_expect_success 'git checkout - for -b, complete local branches and unique remote branches' '
test_completion "git checkout -b " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -2027,6 +2088,7 @@ test_expect_success 'git checkout - for -b, complete local branches and unique r
test_expect_success 'git checkout - for -B, complete local branches and unique remote branches' '
test_completion "git checkout -B " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -2064,6 +2126,7 @@ test_expect_success 'git checkout - for -B with --no-track, complete local branc
test_expect_success 'git switch - with --orphan completes local branch names and unique remote branch names' '
test_completion "git switch --orphan " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -2079,6 +2142,7 @@ test_expect_success 'git switch - --orphan with branch already provided complete
test_expect_success 'git checkout - with --orphan completes local branch names and unique remote branch names' '
test_completion "git checkout --orphan " <<-\EOF
+ HEAD Z
branch-in-other Z
main Z
main-in-other Z
@@ -2092,6 +2156,7 @@ test_expect_success 'git checkout - --orphan with branch already provided comple
main Z
matching-branch Z
matching-tag Z
+ other/HEAD Z
other/branch-in-other Z
other/main-in-other Z
EOF
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 426036b33a..62dfcc4aaf 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -35,13 +35,7 @@ else
# needing to exist.
TEST_DIRECTORY=$(cd "$TEST_DIRECTORY" && pwd) || exit 1
fi
-if test -z "$TEST_OUTPUT_DIRECTORY"
-then
- # Similarly, override this to store the test-results subdir
- # elsewhere
- TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
-fi
-GIT_BUILD_DIR="${TEST_DIRECTORY%/t}"
+GIT_BUILD_DIR="${GIT_BUILD_DIR:-${TEST_DIRECTORY%/t}}"
if test "$TEST_DIRECTORY" = "$GIT_BUILD_DIR"
then
echo "PANIC: Running in a $TEST_DIRECTORY that doesn't end in '/t'?" >&2
@@ -92,6 +86,15 @@ export LSAN_OPTIONS
prepend_var UBSAN_OPTIONS : $GIT_SAN_OPTIONS
export UBSAN_OPTIONS
+# The TEST_OUTPUT_DIRECTORY will be overwritten via GIT-BUILD-OPTIONS. So in
+# case the caller has manually set up this variable via the environment we must
+# make sure to not overwrite that value, and thus we save it into
+# TEST_OUTPUT_DIRECTORY_OVERRIDE here.
+if test -n "$TEST_OUTPUT_DIRECTORY" && test -z "$TEST_OUTPUT_DIRECTORY_OVERRIDE"
+then
+ TEST_OUTPUT_DIRECTORY_OVERRIDE=$TEST_OUTPUT_DIRECTORY
+fi
+
if test ! -f "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
then
echo >&2 'error: GIT-BUILD-OPTIONS missing (has Git been built?).'
@@ -100,6 +103,13 @@ fi
. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
export PERL_PATH SHELL_PATH
+if test -z "$TEST_OUTPUT_DIRECTORY"
+then
+ # Similarly, override this to store the test-results subdir
+ # elsewhere
+ TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
+fi
+
# In t0000, we need to override test directories of nested testcases. In case
# the developer has TEST_OUTPUT_DIRECTORY part of his build options, then we'd
# reset this value to instead contain what the developer has specified. We thus
@@ -512,6 +522,7 @@ unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
PERF_
CURL_VERBOSE
TRACE_CURL
+ BUILD_DIR
));
my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
print join("\n", @vars);
@@ -1409,7 +1420,7 @@ else # normal case, use ../bin-wrappers only unless $with_dashes:
PATH="$GIT_BUILD_DIR:$GIT_BUILD_DIR/t/helper:$PATH"
fi
fi
-GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
+GIT_TEMPLATE_DIR="$GIT_TEST_TEMPLATE_DIR"
GIT_CONFIG_NOSYSTEM=1
GIT_ATTR_NOSYSTEM=1
GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/.."
@@ -1475,9 +1486,9 @@ then
fi
fi
-GITPERLLIB="$GIT_BUILD_DIR"/perl/build/lib
+GITPERLLIB="$GIT_TEST_GITPERLLIB"
export GITPERLLIB
-test -d "$GIT_BUILD_DIR"/templates/blt || {
+test -d "$GIT_TEMPLATE_DIR" || {
BAIL_OUT "You haven't built things yet, have you?"
}
diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c
index 7bc742e4f7..8a69612266 100644
--- a/t/unit-tests/lib-reftable.c
+++ b/t/unit-tests/lib-reftable.c
@@ -4,8 +4,9 @@
#include "test-lib.h"
#include "reftable/constants.h"
#include "reftable/writer.h"
+#include "strbuf.h"
-void t_reftable_set_hash(uint8_t *p, int i, uint32_t id)
+void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id)
{
memset(p, (uint8_t)i, hash_size(id));
}
@@ -84,7 +85,7 @@ void t_reftable_write_to_buf(struct reftable_buf *buf,
size_t off = i * (opts.block_size ? opts.block_size
: DEFAULT_BLOCK_SIZE);
if (!off)
- off = header_size(opts.hash_id == GIT_SHA256_FORMAT_ID ? 2 : 1);
+ off = header_size(opts.hash_id == REFTABLE_HASH_SHA256 ? 2 : 1);
check_char(buf->buf[off], ==, 'r');
}
diff --git a/t/unit-tests/lib-reftable.h b/t/unit-tests/lib-reftable.h
index d4950fed3d..e4c360fa7e 100644
--- a/t/unit-tests/lib-reftable.h
+++ b/t/unit-tests/lib-reftable.h
@@ -6,7 +6,7 @@
struct reftable_buf;
-void t_reftable_set_hash(uint8_t *p, int i, uint32_t id);
+void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id);
struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf,
struct reftable_write_options *opts);
diff --git a/t/unit-tests/strvec.c b/t/unit-tests/strvec.c
index 855b602337..e66b7bbfae 100644
--- a/t/unit-tests/strvec.c
+++ b/t/unit-tests/strvec.c
@@ -88,6 +88,16 @@ void test_strvec__pushv(void)
strvec_clear(&vec);
}
+void test_strvec__splice_just_initialized_strvec(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char *replacement[] = { "foo" };
+
+ strvec_splice(&vec, 0, 0, replacement, ARRAY_SIZE(replacement));
+ check_strvec(&vec, "foo", NULL);
+ strvec_clear(&vec);
+}
+
void test_strvec__splice_with_same_size_replacement(void)
{
struct strvec vec = STRVEC_INIT;
diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c
index f9af907117..22040aeefa 100644
--- a/t/unit-tests/t-reftable-block.c
+++ b/t/unit-tests/t-reftable-block.c
@@ -11,6 +11,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable/blocksource.h"
#include "reftable/constants.h"
#include "reftable/reftable-error.h"
+#include "strbuf.h"
static void t_ref_block_read_write(void)
{
@@ -36,7 +37,7 @@ static void t_ref_block_read_write(void)
block.len = block_size;
block_source_from_buf(&block.source ,&buf);
ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
- header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret);
rec.u.ref.refname = (char *) "";
@@ -47,7 +48,7 @@ static void t_ref_block_read_write(void)
for (i = 0; i < N; i++) {
rec.u.ref.refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
rec.u.ref.value_type = REFTABLE_REF_VAL1;
- memset(rec.u.ref.value.val1, i, GIT_SHA1_RAWSZ);
+ memset(rec.u.ref.value.val1, i, REFTABLE_HASH_SIZE_SHA1);
recs[i] = rec;
ret = block_writer_add(&bw, &rec);
@@ -61,7 +62,7 @@ static void t_ref_block_read_write(void)
block_writer_release(&bw);
- block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+ block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);
block_iter_seek_start(&it, &br);
@@ -72,7 +73,7 @@ static void t_ref_block_read_write(void)
check_int(i, ==, N);
break;
}
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
}
for (i = 0; i < N; i++) {
@@ -85,7 +86,7 @@ static void t_ref_block_read_write(void)
ret = block_iter_next(&it, &rec);
check_int(ret, ==, 0);
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
want.len--;
ret = block_iter_seek_key(&it, &br, &want);
@@ -93,7 +94,7 @@ static void t_ref_block_read_write(void)
ret = block_iter_next(&it, &rec);
check_int(ret, ==, 0);
- check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1));
}
block_reader_release(&br);
@@ -130,7 +131,7 @@ static void t_log_block_read_write(void)
block.len = block_size;
block_source_from_buf(&block.source ,&buf);
ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
- header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret);
for (i = 0; i < N; i++) {
@@ -150,7 +151,7 @@ static void t_log_block_read_write(void)
block_writer_release(&bw);
- block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+ block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);
block_iter_seek_start(&it, &br);
@@ -161,7 +162,7 @@ static void t_log_block_read_write(void)
check_int(i, ==, N);
break;
}
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
}
for (i = 0; i < N; i++) {
@@ -175,7 +176,7 @@ static void t_log_block_read_write(void)
ret = block_iter_next(&it, &rec);
check_int(ret, ==, 0);
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
want.len--;
ret = block_iter_seek_key(&it, &br, &want);
@@ -183,7 +184,7 @@ static void t_log_block_read_write(void)
ret = block_iter_next(&it, &rec);
check_int(ret, ==, 0);
- check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1));
}
block_reader_release(&br);
@@ -220,7 +221,7 @@ static void t_obj_block_read_write(void)
block.len = block_size;
block_source_from_buf(&block.source, &buf);
ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
- header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret);
for (i = 0; i < N; i++) {
@@ -242,7 +243,7 @@ static void t_obj_block_read_write(void)
block_writer_release(&bw);
- block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+ block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);
block_iter_seek_start(&it, &br);
@@ -253,7 +254,7 @@ static void t_obj_block_read_write(void)
check_int(i, ==, N);
break;
}
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
}
for (i = 0; i < N; i++) {
@@ -266,7 +267,7 @@ static void t_obj_block_read_write(void)
ret = block_iter_next(&it, &rec);
check_int(ret, ==, 0);
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
}
block_reader_release(&br);
@@ -304,7 +305,7 @@ static void t_index_block_read_write(void)
block.len = block_size;
block_source_from_buf(&block.source, &buf);
ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
- header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret);
for (i = 0; i < N; i++) {
@@ -326,7 +327,7 @@ static void t_index_block_read_write(void)
block_writer_release(&bw);
- block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+ block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);
block_iter_seek_start(&it, &br);
@@ -337,7 +338,7 @@ static void t_index_block_read_write(void)
check_int(i, ==, N);
break;
}
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
}
for (i = 0; i < N; i++) {
@@ -350,7 +351,7 @@ static void t_index_block_read_write(void)
ret = block_iter_next(&it, &rec);
check_int(ret, ==, 0);
- check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
want.len--;
ret = block_iter_seek_key(&it, &br, &want);
@@ -358,7 +359,7 @@ static void t_index_block_read_write(void)
ret = block_iter_next(&it, &rec);
check_int(ret, ==, 0);
- check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1));
}
block_reader_release(&br);
diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c
index 4c25ee5334..a12bd0e1a3 100644
--- a/t/unit-tests/t-reftable-merged.c
+++ b/t/unit-tests/t-reftable-merged.c
@@ -42,7 +42,7 @@ merged_table_from_records(struct reftable_ref_record **refs,
check(!err);
}
- err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
+ err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1);
check(!err);
return mt;
}
@@ -91,7 +91,7 @@ static void t_merged_single_record(void)
err = reftable_iterator_next_ref(&it, &ref);
check(!err);
- check(reftable_ref_record_equal(&r2[0], &ref, GIT_SHA1_RAWSZ));
+ check(reftable_ref_record_equal(&r2[0], &ref, REFTABLE_HASH_SIZE_SHA1));
reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
readers_destroy(readers, 3);
@@ -168,7 +168,7 @@ static void t_merged_refs(void)
check(!err);
err = reftable_iterator_seek_ref(&it, "a");
check(!err);
- check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
+ check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1);
check_int(reftable_merged_table_min_update_index(mt), ==, 1);
check_int(reftable_merged_table_max_update_index(mt), ==, 3);
@@ -186,7 +186,7 @@ static void t_merged_refs(void)
check_int(ARRAY_SIZE(want), ==, len);
for (i = 0; i < len; i++)
check(reftable_ref_record_equal(want[i], &out[i],
- GIT_SHA1_RAWSZ));
+ REFTABLE_HASH_SIZE_SHA1));
for (i = 0; i < len; i++)
reftable_ref_record_release(&out[i]);
reftable_free(out);
@@ -252,12 +252,12 @@ static void t_merged_seek_multiple_times(void)
err = reftable_iterator_next_ref(&it, &rec);
check(!err);
- err = reftable_ref_record_equal(&rec, &r1[1], GIT_SHA1_RAWSZ);
+ err = reftable_ref_record_equal(&rec, &r1[1], REFTABLE_HASH_SIZE_SHA1);
check(err == 1);
err = reftable_iterator_next_ref(&it, &rec);
check(!err);
- err = reftable_ref_record_equal(&rec, &r2[1], GIT_SHA1_RAWSZ);
+ err = reftable_ref_record_equal(&rec, &r2[1], REFTABLE_HASH_SIZE_SHA1);
check(err == 1);
err = reftable_iterator_next_ref(&it, &rec);
@@ -273,6 +273,78 @@ static void t_merged_seek_multiple_times(void)
reftable_free(sources);
}
+static void t_merged_seek_multiple_times_without_draining(void)
+{
+ struct reftable_ref_record r1[] = {
+ {
+ .refname = (char *) "a",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 1 },
+ },
+ {
+ .refname = (char *) "c",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 2 },
+ }
+ };
+ struct reftable_ref_record r2[] = {
+ {
+ .refname = (char *) "b",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 3 },
+ },
+ {
+ .refname = (char *) "d",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 4 },
+ },
+ };
+ struct reftable_ref_record *refs[] = {
+ r1, r2,
+ };
+ size_t sizes[] = {
+ ARRAY_SIZE(r1), ARRAY_SIZE(r2),
+ };
+ struct reftable_buf bufs[] = {
+ REFTABLE_BUF_INIT, REFTABLE_BUF_INIT,
+ };
+ struct reftable_block_source *sources = NULL;
+ struct reftable_reader **readers = NULL;
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
+ struct reftable_merged_table *mt;
+ int err;
+
+ mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2);
+ merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+
+ err = reftable_iterator_seek_ref(&it, "b");
+ check(!err);
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ err = reftable_ref_record_equal(&rec, &r2[0], REFTABLE_HASH_SIZE_SHA1);
+ check(err == 1);
+
+ err = reftable_iterator_seek_ref(&it, "a");
+ check(!err);
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ err = reftable_ref_record_equal(&rec, &r1[0], REFTABLE_HASH_SIZE_SHA1);
+ check(err == 1);
+
+ for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
+ reftable_buf_release(&bufs[i]);
+ readers_destroy(readers, ARRAY_SIZE(refs));
+ reftable_ref_record_release(&rec);
+ reftable_iterator_destroy(&it);
+ reftable_merged_table_free(mt);
+ reftable_free(sources);
+}
+
static struct reftable_merged_table *
merged_table_from_log_records(struct reftable_log_record **logs,
struct reftable_block_source **source,
@@ -300,7 +372,7 @@ merged_table_from_log_records(struct reftable_log_record **logs,
check(!err);
}
- err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
+ err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1);
check(!err);
return mt;
}
@@ -377,7 +449,7 @@ static void t_merged_logs(void)
check(!err);
err = reftable_iterator_seek_log(&it, "a");
check(!err);
- check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
+ check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1);
check_int(reftable_merged_table_min_update_index(mt), ==, 1);
check_int(reftable_merged_table_max_update_index(mt), ==, 3);
@@ -395,7 +467,7 @@ static void t_merged_logs(void)
check_int(ARRAY_SIZE(want), ==, len);
for (i = 0; i < len; i++)
check(reftable_log_record_equal(want[i], &out[i],
- GIT_SHA1_RAWSZ));
+ REFTABLE_HASH_SIZE_SHA1));
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
check(!err);
@@ -404,7 +476,7 @@ static void t_merged_logs(void)
reftable_log_record_release(&out[0]);
err = reftable_iterator_next_log(&it, &out[0]);
check(!err);
- check(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ));
+ check(reftable_log_record_equal(&out[0], &r3[0], REFTABLE_HASH_SIZE_SHA1));
reftable_iterator_destroy(&it);
for (i = 0; i < len; i++)
@@ -448,11 +520,11 @@ static void t_default_write_opts(void)
check(!err);
hash_id = reftable_reader_hash_id(rd);
- check_int(hash_id, ==, GIT_SHA1_FORMAT_ID);
+ check_int(hash_id, ==, REFTABLE_HASH_SHA1);
- err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA256_FORMAT_ID);
+ err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA256);
check_int(err, ==, REFTABLE_FORMAT_ERROR);
- err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA1_FORMAT_ID);
+ err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA1);
check(!err);
reftable_reader_decref(rd);
@@ -467,6 +539,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
TEST(t_merged_logs(), "merged table with multiple log updates for same ref");
TEST(t_merged_refs(), "merged table with multiple updates to same ref");
TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times");
+ TEST(t_merged_seek_multiple_times_without_draining(), "merged table can seek multiple times without draining");
TEST(t_merged_single_record(), "ref occurring in only one record can be fetched");
return test_done();
diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/t-reftable-pq.c
index ada4c19f18..f3f8a0cdf3 100644
--- a/t/unit-tests/t-reftable-pq.c
+++ b/t/unit-tests/t-reftable-pq.c
@@ -9,6 +9,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "test-lib.h"
#include "reftable/constants.h"
#include "reftable/pq.h"
+#include "strbuf.h"
static void merged_iter_pqueue_check(const struct merged_iter_pqueue *pq)
{
@@ -132,7 +133,7 @@ static void t_merged_iter_pqueue_top(void)
merged_iter_pqueue_check(&pq);
check(pq_entry_equal(&top, &e));
- check(reftable_record_equal(top.rec, &recs[i], GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(top.rec, &recs[i], REFTABLE_HASH_SIZE_SHA1));
for (size_t j = 0; i < pq.len; j++) {
check(pq_less(&top, &pq.heap[j]));
check_int(top.index, >, j);
diff --git a/t/unit-tests/t-reftable-reader.c b/t/unit-tests/t-reftable-reader.c
index 19cb53b641..546df6005e 100644
--- a/t/unit-tests/t-reftable-reader.c
+++ b/t/unit-tests/t-reftable-reader.c
@@ -31,7 +31,7 @@ static int t_reader_seek_once(void)
ret = reftable_iterator_next_ref(&it, &ref);
check(!ret);
- ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
+ ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1);
check_int(ret, ==, 1);
ret = reftable_iterator_next_ref(&it, &ref);
@@ -74,7 +74,7 @@ static int t_reader_reseek(void)
ret = reftable_iterator_next_ref(&it, &ref);
check(!ret);
- ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
+ ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1);
check_int(ret, ==, 1);
ret = reftable_iterator_next_ref(&it, &ref);
diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c
index d38092ff83..6b75a419b9 100644
--- a/t/unit-tests/t-reftable-readwrite.c
+++ b/t/unit-tests/t-reftable-readwrite.c
@@ -15,6 +15,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable/reader.h"
#include "reftable/reftable-error.h"
#include "reftable/reftable-writer.h"
+#include "strbuf.h"
static const int update_index = 5;
@@ -43,7 +44,7 @@ static void t_buffer(void)
}
static void write_table(char ***names, struct reftable_buf *buf, int N,
- int block_size, uint32_t hash_id)
+ int block_size, enum reftable_hash hash_id)
{
struct reftable_write_options opts = {
.block_size = block_size,
@@ -64,7 +65,7 @@ static void write_table(char ***names, struct reftable_buf *buf, int N,
refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i);
refs[i].update_index = update_index;
refs[i].value_type = REFTABLE_REF_VAL1;
- t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1);
}
for (i = 0; i < N; i++) {
@@ -72,7 +73,7 @@ static void write_table(char ***names, struct reftable_buf *buf, int N,
logs[i].update_index = update_index;
logs[i].value_type = REFTABLE_LOG_UPDATE;
t_reftable_set_hash(logs[i].value.update.new_hash, i,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
logs[i].value.update.message = (char *) "message";
}
@@ -92,7 +93,7 @@ static void t_log_buffer_size(void)
int i;
struct reftable_log_record
log = { .refname = (char *) "refs/heads/master",
- .update_index = 0xa,
+ .update_index = update_index,
.value_type = REFTABLE_LOG_UPDATE,
.value = { .update = {
.name = (char *) "Han-Wen Nienhuys",
@@ -106,7 +107,7 @@ static void t_log_buffer_size(void)
/* This tests buffer extension for log compression. Must use a random
hash, to ensure that the compressed part is larger than the original.
*/
- for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
+ for (i = 0; i < REFTABLE_HASH_SIZE_SHA1; i++) {
log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256);
log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256);
}
@@ -129,7 +130,7 @@ static void t_log_overflow(void)
int err;
struct reftable_log_record log = {
.refname = (char *) "refs/heads/master",
- .update_index = 0xa,
+ .update_index = update_index,
.value_type = REFTABLE_LOG_UPDATE,
.value = {
.update = {
@@ -153,6 +154,48 @@ static void t_log_overflow(void)
reftable_buf_release(&buf);
}
+static void t_log_write_limits(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_log_record log = {
+ .refname = (char *)"refs/head/master",
+ .update_index = 0,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value = {
+ .update = {
+ .old_hash = { 1 },
+ .new_hash = { 2 },
+ .name = (char *)"Han-Wen Nienhuys",
+ .email = (char *)"hanwen@google.com",
+ .tz_offset = 100,
+ .time = 0x5e430672,
+ },
+ },
+ };
+ int err;
+
+ reftable_writer_set_limits(w, 1, 1);
+
+ /* write with update_index (0) below set limits (1, 1) */
+ err = reftable_writer_add_log(w, &log);
+ check_int(err, ==, 0);
+
+ /* write with update_index (1) in the set limits (1, 1) */
+ log.update_index = 1;
+ err = reftable_writer_add_log(w, &log);
+ check_int(err, ==, 0);
+
+ /* write with update_index (3) above set limits (1, 1) */
+ log.update_index = 3;
+ err = reftable_writer_add_log(w, &log);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ reftable_writer_free(w);
+ reftable_buf_release(&buf);
+}
+
static void t_log_write_read(void)
{
struct reftable_write_options opts = {
@@ -193,9 +236,9 @@ static void t_log_write_read(void)
log.update_index = i;
log.value_type = REFTABLE_LOG_UPDATE;
t_reftable_set_hash(log.value.update.old_hash, i,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
t_reftable_set_hash(log.value.update.new_hash, i + 1,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
err = reftable_writer_add_log(w, &log);
check(!err);
@@ -328,7 +371,7 @@ static void t_table_read_write_sequential(void)
int err = 0;
int j = 0;
- write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
+ write_table(&names, &buf, N, 256, REFTABLE_HASH_SHA1);
block_source_from_buf(&source, &buf);
@@ -363,7 +406,7 @@ static void t_table_write_small_table(void)
char **names;
struct reftable_buf buf = REFTABLE_BUF_INIT;
int N = 1;
- write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
+ write_table(&names, &buf, N, 4096, REFTABLE_HASH_SHA1);
check_int(buf.len, <, 200);
reftable_buf_release(&buf);
free_names(names);
@@ -380,7 +423,7 @@ static void t_table_read_api(void)
struct reftable_log_record log = { 0 };
struct reftable_iterator it = { 0 };
- write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
+ write_table(&names, &buf, N, 256, REFTABLE_HASH_SHA1);
block_source_from_buf(&source, &buf);
@@ -402,7 +445,7 @@ static void t_table_read_api(void)
reftable_buf_release(&buf);
}
-static void t_table_read_write_seek(int index, int hash_id)
+static void t_table_read_write_seek(int index, enum reftable_hash hash_id)
{
char **names;
struct reftable_buf buf = REFTABLE_BUF_INIT;
@@ -469,24 +512,24 @@ static void t_table_read_write_seek(int index, int hash_id)
static void t_table_read_write_seek_linear(void)
{
- t_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
+ t_table_read_write_seek(0, REFTABLE_HASH_SHA1);
}
static void t_table_read_write_seek_linear_sha256(void)
{
- t_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
+ t_table_read_write_seek(0, REFTABLE_HASH_SHA256);
}
static void t_table_read_write_seek_index(void)
{
- t_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
+ t_table_read_write_seek(1, REFTABLE_HASH_SHA1);
}
static void t_table_refs_for(int indexed)
{
char **want_names;
int want_names_len = 0;
- uint8_t want_hash[GIT_SHA1_RAWSZ];
+ uint8_t want_hash[REFTABLE_HASH_SIZE_SHA1];
struct reftable_write_options opts = {
.block_size = 256,
@@ -502,10 +545,10 @@ static void t_table_refs_for(int indexed)
want_names = reftable_calloc(N + 1, sizeof(*want_names));
check(want_names != NULL);
- t_reftable_set_hash(want_hash, 4, GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(want_hash, 4, REFTABLE_HASH_SHA1);
for (i = 0; i < N; i++) {
- uint8_t hash[GIT_SHA1_RAWSZ];
+ uint8_t hash[REFTABLE_HASH_SIZE_SHA1];
char fill[51] = { 0 };
char name[100];
struct reftable_ref_record ref = { 0 };
@@ -519,9 +562,9 @@ static void t_table_refs_for(int indexed)
ref.value_type = REFTABLE_REF_VAL2;
t_reftable_set_hash(ref.value.val2.value, i / 4,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
t_reftable_set_hash(ref.value.val2.target_value, 3 + i / 4,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
/* 80 bytes / entry, so 3 entries per block. Yields 17
*/
@@ -529,8 +572,8 @@ static void t_table_refs_for(int indexed)
n = reftable_writer_add_ref(w, &ref);
check_int(n, ==, 0);
- if (!memcmp(ref.value.val2.value, want_hash, GIT_SHA1_RAWSZ) ||
- !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ))
+ if (!memcmp(ref.value.val2.value, want_hash, REFTABLE_HASH_SIZE_SHA1) ||
+ !memcmp(ref.value.val2.target_value, want_hash, REFTABLE_HASH_SIZE_SHA1))
want_names[want_names_len++] = xstrdup(name);
}
@@ -919,6 +962,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
TEST(t_corrupt_table_empty(), "read-write on an empty table");
TEST(t_log_buffer_size(), "buffer extension for log compression");
TEST(t_log_overflow(), "log overflow returns expected error");
+ TEST(t_log_write_limits(), "writer limits for writing log records");
TEST(t_log_write_read(), "read-write on log records");
TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error");
TEST(t_table_read_api(), "read on a table");
diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c
index eb98bf2da9..42bc64cec8 100644
--- a/t/unit-tests/t-reftable-record.c
+++ b/t/unit-tests/t-reftable-record.c
@@ -7,6 +7,7 @@
*/
#include "test-lib.h"
+#include "reftable/basics.h"
#include "reftable/constants.h"
#include "reftable/record.h"
@@ -17,10 +18,10 @@ static void t_copy(struct reftable_record *rec)
typ = reftable_record_type(rec);
reftable_record_init(&copy, typ);
- reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
+ reftable_record_copy_from(&copy, rec, REFTABLE_HASH_SIZE_SHA1);
/* do it twice to catch memory leaks */
- reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
- check(reftable_record_equal(rec, &copy, GIT_SHA1_RAWSZ));
+ reftable_record_copy_from(&copy, rec, REFTABLE_HASH_SIZE_SHA1);
+ check(reftable_record_equal(rec, &copy, REFTABLE_HASH_SIZE_SHA1));
reftable_record_release(&copy);
}
@@ -59,7 +60,7 @@ static void t_varint_roundtrip(void)
static void set_hash(uint8_t *h, int j)
{
- for (int i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++)
+ for (int i = 0; i < hash_size(REFTABLE_HASH_SHA1); i++)
h[i] = (j >> i) & 0xff;
}
@@ -84,14 +85,14 @@ static void t_reftable_ref_record_comparison(void)
},
};
- check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
check(!reftable_record_cmp(&in[0], &in[1]));
- check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1));
check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
in[1].u.ref.value_type = in[0].u.ref.value_type;
- check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
check(!reftable_record_cmp(&in[0], &in[1]));
}
@@ -155,15 +156,15 @@ static void t_reftable_ref_record_roundtrip(void)
check_int(reftable_record_is_deletion(&in), ==, i == REFTABLE_REF_DELETION);
reftable_record_key(&in, &key);
- n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
+ n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1);
check_int(n, >, 0);
/* decode into a non-zero reftable_record to test for leaks. */
- m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch);
+ m = reftable_record_decode(&out, key, i, dest, REFTABLE_HASH_SIZE_SHA1, &scratch);
check_int(n, ==, m);
check(reftable_ref_record_equal(&in.u.ref, &out.u.ref,
- GIT_SHA1_RAWSZ));
+ REFTABLE_HASH_SIZE_SHA1));
reftable_record_release(&in);
reftable_buf_release(&key);
@@ -193,15 +194,15 @@ static void t_reftable_log_record_comparison(void)
},
};
- check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
- check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
+ check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1));
check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
/* comparison should be reversed for equal keys, because
* comparison is now performed on the basis of update indices */
check_int(reftable_record_cmp(&in[0], &in[1]), <, 0);
in[1].u.log.update_index = in[0].u.log.update_index;
- check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
check(!reftable_record_cmp(&in[0], &in[1]));
}
@@ -303,15 +304,15 @@ static void t_reftable_log_record_roundtrip(void)
reftable_record_key(&rec, &key);
- n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
+ n = reftable_record_encode(&rec, dest, REFTABLE_HASH_SIZE_SHA1);
check_int(n, >=, 0);
valtype = reftable_record_val_type(&rec);
m = reftable_record_decode(&out, key, valtype, dest,
- GIT_SHA1_RAWSZ, &scratch);
+ REFTABLE_HASH_SIZE_SHA1, &scratch);
check_int(n, ==, m);
check(reftable_log_record_equal(&in[i], &out.u.log,
- GIT_SHA1_RAWSZ));
+ REFTABLE_HASH_SIZE_SHA1));
reftable_log_record_release(&in[i]);
reftable_buf_release(&key);
reftable_record_release(&out);
@@ -380,20 +381,20 @@ static void t_reftable_obj_record_comparison(void)
},
};
- check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
check(!reftable_record_cmp(&in[0], &in[1]));
- check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1));
check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
in[1].u.obj.offset_len = in[0].u.obj.offset_len;
- check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
check(!reftable_record_cmp(&in[0], &in[1]));
}
static void t_reftable_obj_record_roundtrip(void)
{
- uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 };
+ uint8_t testHash1[REFTABLE_HASH_SIZE_SHA1] = { 1, 2, 3, 4, 0 };
uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 };
struct reftable_obj_record recs[3] = {
{
@@ -435,14 +436,14 @@ static void t_reftable_obj_record_roundtrip(void)
check(!reftable_record_is_deletion(&in));
t_copy(&in);
reftable_record_key(&in, &key);
- n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
+ n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1);
check_int(n, >, 0);
extra = reftable_record_val_type(&in);
m = reftable_record_decode(&out, key, extra, dest,
- GIT_SHA1_RAWSZ, &scratch);
+ REFTABLE_HASH_SIZE_SHA1, &scratch);
check_int(n, ==, m);
- check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&in, &out, REFTABLE_HASH_SIZE_SHA1));
reftable_buf_release(&key);
reftable_record_release(&out);
}
@@ -473,14 +474,14 @@ static void t_reftable_index_record_comparison(void)
check(!reftable_buf_addstr(&in[1].u.idx.last_key, "refs/heads/master"));
check(!reftable_buf_addstr(&in[2].u.idx.last_key, "refs/heads/branch"));
- check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
check(!reftable_record_cmp(&in[0], &in[1]));
- check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1));
check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
in[1].u.idx.offset = in[0].u.idx.offset;
- check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1));
check(!reftable_record_cmp(&in[0], &in[1]));
for (size_t i = 0; i < ARRAY_SIZE(in); i++)
@@ -516,15 +517,15 @@ static void t_reftable_index_record_roundtrip(void)
check(!reftable_record_is_deletion(&in));
check(!reftable_buf_cmp(&key, &in.u.idx.last_key));
- n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
+ n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1);
check_int(n, >, 0);
extra = reftable_record_val_type(&in);
- m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ,
+ m = reftable_record_decode(&out, key, extra, dest, REFTABLE_HASH_SIZE_SHA1,
&scratch);
check_int(m, ==, n);
- check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
+ check(reftable_record_equal(&in, &out, REFTABLE_HASH_SIZE_SHA1));
reftable_record_release(&out);
reftable_buf_release(&key);
diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c
index 4377c0af1b..aeec195b2b 100644
--- a/t/unit-tests/t-reftable-stack.c
+++ b/t/unit-tests/t-reftable-stack.c
@@ -10,10 +10,13 @@ https://developers.google.com/open-source/licenses/bsd
#include "test-lib.h"
#include "lib-reftable.h"
+#include "dir.h"
#include "reftable/merged.h"
#include "reftable/reader.h"
#include "reftable/reftable-error.h"
#include "reftable/stack.h"
+#include "strbuf.h"
+#include "tempfile.h"
#include <dirent.h>
static void clear_dir(const char *dirname)
@@ -122,7 +125,7 @@ static void write_n_ref_tables(struct reftable_stack *st,
snprintf(buf, sizeof(buf), "refs/heads/branch-%04"PRIuMAX, (uintmax_t)i);
ref.refname = buf;
- t_reftable_set_hash(ref.value.val1, i, GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(ref.value.val1, i, REFTABLE_HASH_SHA1);
err = reftable_stack_add(st, &write_test_ref, &ref);
check(!err);
@@ -170,7 +173,7 @@ static void t_reftable_stack_add_one(void)
err = reftable_stack_read_ref(st, ref.refname, &dest);
check(!err);
- check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+ check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1));
check_int(st->readers_len, >, 0);
#ifndef GIT_WINDOWS_NATIVE
@@ -281,7 +284,7 @@ static void t_reftable_stack_transaction_api(void)
err = reftable_stack_read_ref(st, ref.refname, &dest);
check(!err);
check_int(REFTABLE_REF_SYMREF, ==, dest.value_type);
- check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+ check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1));
reftable_ref_record_release(&dest);
reftable_stack_destroy(st);
@@ -341,7 +344,7 @@ static void t_reftable_stack_transaction_with_reload(void)
for (size_t i = 0; i < ARRAY_SIZE(refs); i++) {
err = reftable_stack_read_ref(st2, refs[i].refname, &ref);
check(!err);
- check(reftable_ref_record_equal(&refs[i], &ref, GIT_SHA1_RAWSZ));
+ check(reftable_ref_record_equal(&refs[i], &ref, REFTABLE_HASH_SIZE_SHA1));
}
reftable_ref_record_release(&ref);
@@ -531,13 +534,13 @@ static void t_reftable_stack_add(void)
refs[i].refname = xstrdup(buf);
refs[i].update_index = i + 1;
refs[i].value_type = REFTABLE_REF_VAL1;
- t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1);
logs[i].refname = xstrdup(buf);
logs[i].update_index = N + i + 1;
logs[i].value_type = REFTABLE_LOG_UPDATE;
logs[i].value.update.email = xstrdup("identity@invalid");
- t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(logs[i].value.update.new_hash, i, REFTABLE_HASH_SHA1);
}
for (i = 0; i < N; i++) {
@@ -563,7 +566,7 @@ static void t_reftable_stack_add(void)
int err = reftable_stack_read_ref(st, refs[i].refname, &dest);
check(!err);
check(reftable_ref_record_equal(&dest, refs + i,
- GIT_SHA1_RAWSZ));
+ REFTABLE_HASH_SIZE_SHA1));
reftable_ref_record_release(&dest);
}
@@ -572,7 +575,7 @@ static void t_reftable_stack_add(void)
int err = reftable_stack_read_log(st, refs[i].refname, &dest);
check(!err);
check(reftable_log_record_equal(&dest, logs + i,
- GIT_SHA1_RAWSZ));
+ REFTABLE_HASH_SIZE_SHA1));
reftable_log_record_release(&dest);
}
@@ -623,14 +626,14 @@ static void t_reftable_stack_iterator(void)
refs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
refs[i].update_index = i + 1;
refs[i].value_type = REFTABLE_REF_VAL1;
- t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1);
logs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
logs[i].update_index = i + 1;
logs[i].value_type = REFTABLE_LOG_UPDATE;
logs[i].value.update.email = xstrdup("johndoe@invalid");
logs[i].value.update.message = xstrdup("commit\n");
- t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(logs[i].value.update.new_hash, i, REFTABLE_HASH_SHA1);
}
for (i = 0; i < N; i++) {
@@ -657,7 +660,7 @@ static void t_reftable_stack_iterator(void)
if (err > 0)
break;
check(!err);
- check(reftable_ref_record_equal(&ref, &refs[i], GIT_SHA1_RAWSZ));
+ check(reftable_ref_record_equal(&ref, &refs[i], REFTABLE_HASH_SIZE_SHA1));
reftable_ref_record_release(&ref);
}
check_int(i, ==, N);
@@ -675,7 +678,7 @@ static void t_reftable_stack_iterator(void)
if (err > 0)
break;
check(!err);
- check(reftable_log_record_equal(&log, &logs[i], GIT_SHA1_RAWSZ));
+ check(reftable_log_record_equal(&log, &logs[i], REFTABLE_HASH_SIZE_SHA1));
reftable_log_record_release(&log);
}
check_int(i, ==, N);
@@ -768,16 +771,20 @@ static void t_reftable_stack_tombstone(void)
if (i % 2 == 0) {
refs[i].value_type = REFTABLE_REF_VAL1;
t_reftable_set_hash(refs[i].value.val1, i,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
}
logs[i].refname = xstrdup(buf);
- /* update_index is part of the key. */
- logs[i].update_index = 42;
+ /*
+ * update_index is part of the key so should be constant.
+ * The value itself should be less than the writer's upper
+ * limit.
+ */
+ logs[i].update_index = 1;
if (i % 2 == 0) {
logs[i].value_type = REFTABLE_LOG_UPDATE;
t_reftable_set_hash(logs[i].value.update.new_hash, i,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
logs[i].value.update.email =
xstrdup("identity@invalid");
}
@@ -837,7 +844,7 @@ static void t_reftable_stack_hash_id(void)
.value.symref = (char *) "target",
.update_index = 1,
};
- struct reftable_write_options opts32 = { .hash_id = GIT_SHA256_FORMAT_ID };
+ struct reftable_write_options opts32 = { .hash_id = REFTABLE_HASH_SHA256 };
struct reftable_stack *st32 = NULL;
struct reftable_write_options opts_default = { 0 };
struct reftable_stack *st_default = NULL;
@@ -860,7 +867,7 @@ static void t_reftable_stack_hash_id(void)
err = reftable_stack_read_ref(st_default, "master", &dest);
check(!err);
- check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+ check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1));
reftable_ref_record_release(&dest);
reftable_stack_destroy(st);
reftable_stack_destroy(st_default);
@@ -910,7 +917,7 @@ static void t_reflog_expire(void)
logs[i].value.update.time = i;
logs[i].value.update.email = xstrdup("identity@invalid");
t_reftable_set_hash(logs[i].value.update.new_hash, i,
- GIT_SHA1_FORMAT_ID);
+ REFTABLE_HASH_SHA1);
}
for (i = 1; i <= N; i++) {
diff --git a/tag.c b/tag.c
index 332fc338e9..8d9e9e2930 100644
--- a/tag.c
+++ b/tag.c
@@ -85,7 +85,7 @@ struct object *deref_tag(struct repository *r, struct object *o, const char *war
o = NULL;
}
if (!o && warn) {
- if (last_oid && is_promisor_object(last_oid))
+ if (last_oid && is_promisor_object(r, last_oid))
return NULL;
if (!warnlen)
warnlen = strlen(warn);
diff --git a/templates/Makefile b/templates/Makefile
index 367ad00c24..bd1e9e30c1 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -29,24 +29,35 @@ all: boilerplates.made custom
# in a file direc--tory--file in the source. They will be
# just copied to the destination.
-bpsrc = $(filter-out %~,$(wildcard *--*))
-boilerplates.made : $(bpsrc)
- $(QUIET)umask 022 && ls *--* 2>/dev/null | \
- while read boilerplate; \
+TEMPLATES =
+TEMPLATES += description
+TEMPLATES += hooks/applypatch-msg.sample
+TEMPLATES += hooks/commit-msg.sample
+TEMPLATES += hooks/fsmonitor-watchman.sample
+TEMPLATES += hooks/post-update.sample
+TEMPLATES += hooks/pre-applypatch.sample
+TEMPLATES += hooks/pre-commit.sample
+TEMPLATES += hooks/pre-merge-commit.sample
+TEMPLATES += hooks/prepare-commit-msg.sample
+TEMPLATES += hooks/pre-push.sample
+TEMPLATES += hooks/pre-rebase.sample
+TEMPLATES += hooks/pre-receive.sample
+TEMPLATES += hooks/push-to-checkout.sample
+TEMPLATES += hooks/sendemail-validate.sample
+TEMPLATES += hooks/update.sample
+TEMPLATES += info/exclude
+
+boilerplates.made: $(TEMPLATES)
+ $(QUIET)umask 022 && for template in $(TEMPLATES); \
do \
- case "$$boilerplate" in *~) continue ;; esac && \
- dst=`echo "$$boilerplate" | sed -e 's|^this|.|;s|--|/|g'` && \
- dir=`expr "$$dst" : '\(.*\)/'` && \
+ dir=$$(dirname "$$template") && \
mkdir -p blt/$$dir && \
- case "$$boilerplate" in \
- *--) continue;; \
- esac && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
- -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' $$boilerplate > \
- blt/$$dst && \
- if test -x "$$boilerplate"; then rx=rx; else rx=r; fi && \
- chmod a+$$rx "blt/$$dst" || exit; \
+ -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' $$template > \
+ blt/$$template && \
+ if test -x "$$template"; then rx=rx; else rx=r; fi && \
+ chmod a+$$rx "blt/$$template" || exit; \
done && \
date >$@
diff --git a/templates/branches-- b/templates/branches--
deleted file mode 100644
index fae88709a6..0000000000
--- a/templates/branches--
+++ /dev/null
@@ -1 +0,0 @@
-: this is just to ensure the directory exists.
diff --git a/templates/this--description b/templates/description
index 498b267a8c..498b267a8c 100644
--- a/templates/this--description
+++ b/templates/description
diff --git a/templates/hooks--applypatch-msg.sample b/templates/hooks/applypatch-msg.sample
index a5d7b84a67..a5d7b84a67 100755
--- a/templates/hooks--applypatch-msg.sample
+++ b/templates/hooks/applypatch-msg.sample
diff --git a/templates/hooks--commit-msg.sample b/templates/hooks/commit-msg.sample
index b58d1184a9..b58d1184a9 100755
--- a/templates/hooks--commit-msg.sample
+++ b/templates/hooks/commit-msg.sample
diff --git a/templates/hooks--fsmonitor-watchman.sample b/templates/hooks/fsmonitor-watchman.sample
index 23e856f5de..23e856f5de 100755
--- a/templates/hooks--fsmonitor-watchman.sample
+++ b/templates/hooks/fsmonitor-watchman.sample
diff --git a/templates/hooks/meson.build b/templates/hooks/meson.build
new file mode 100644
index 0000000000..ef85e10a16
--- /dev/null
+++ b/templates/hooks/meson.build
@@ -0,0 +1,26 @@
+hooks = [
+ 'applypatch-msg.sample',
+ 'commit-msg.sample',
+ 'fsmonitor-watchman.sample',
+ 'post-update.sample',
+ 'pre-applypatch.sample',
+ 'pre-commit.sample',
+ 'pre-merge-commit.sample',
+ 'prepare-commit-msg.sample',
+ 'pre-push.sample',
+ 'pre-rebase.sample',
+ 'pre-receive.sample',
+ 'push-to-checkout.sample',
+ 'sendemail-validate.sample',
+ 'update.sample',
+]
+
+foreach hook : hooks
+ configure_file(
+ input: hook,
+ output: hook,
+ configuration: template_config,
+ install: true,
+ install_dir: get_option('datadir') / 'git-core/templates/hooks',
+ )
+endforeach
diff --git a/templates/hooks--post-update.sample b/templates/hooks/post-update.sample
index ec17ec1939..ec17ec1939 100755
--- a/templates/hooks--post-update.sample
+++ b/templates/hooks/post-update.sample
diff --git a/templates/hooks--pre-applypatch.sample b/templates/hooks/pre-applypatch.sample
index 4142082bcb..4142082bcb 100755
--- a/templates/hooks--pre-applypatch.sample
+++ b/templates/hooks/pre-applypatch.sample
diff --git a/templates/hooks--pre-commit.sample b/templates/hooks/pre-commit.sample
index 29ed5ee486..29ed5ee486 100755
--- a/templates/hooks--pre-commit.sample
+++ b/templates/hooks/pre-commit.sample
diff --git a/templates/hooks--pre-merge-commit.sample b/templates/hooks/pre-merge-commit.sample
index 399eab1924..399eab1924 100755
--- a/templates/hooks--pre-merge-commit.sample
+++ b/templates/hooks/pre-merge-commit.sample
diff --git a/templates/hooks--pre-push.sample b/templates/hooks/pre-push.sample
index 4ce688d32b..4ce688d32b 100755
--- a/templates/hooks--pre-push.sample
+++ b/templates/hooks/pre-push.sample
diff --git a/templates/hooks--pre-rebase.sample b/templates/hooks/pre-rebase.sample
index db5feab8a1..db5feab8a1 100755
--- a/templates/hooks--pre-rebase.sample
+++ b/templates/hooks/pre-rebase.sample
diff --git a/templates/hooks--pre-receive.sample b/templates/hooks/pre-receive.sample
index a1fd29ec14..a1fd29ec14 100755
--- a/templates/hooks--pre-receive.sample
+++ b/templates/hooks/pre-receive.sample
diff --git a/templates/hooks--prepare-commit-msg.sample b/templates/hooks/prepare-commit-msg.sample
index 318afe3fd8..318afe3fd8 100755
--- a/templates/hooks--prepare-commit-msg.sample
+++ b/templates/hooks/prepare-commit-msg.sample
diff --git a/templates/hooks--push-to-checkout.sample b/templates/hooks/push-to-checkout.sample
index af5a0c0018..af5a0c0018 100755
--- a/templates/hooks--push-to-checkout.sample
+++ b/templates/hooks/push-to-checkout.sample
diff --git a/templates/hooks--sendemail-validate.sample b/templates/hooks/sendemail-validate.sample
index 640bcf874d..640bcf874d 100755
--- a/templates/hooks--sendemail-validate.sample
+++ b/templates/hooks/sendemail-validate.sample
diff --git a/templates/hooks--update.sample b/templates/hooks/update.sample
index c4d426bc6e..c4d426bc6e 100755
--- a/templates/hooks--update.sample
+++ b/templates/hooks/update.sample
diff --git a/templates/info--exclude b/templates/info/exclude
index a5196d1be8..a5196d1be8 100644
--- a/templates/info--exclude
+++ b/templates/info/exclude
diff --git a/templates/info/meson.build b/templates/info/meson.build
new file mode 100644
index 0000000000..026f231385
--- /dev/null
+++ b/templates/info/meson.build
@@ -0,0 +1,7 @@
+configure_file(
+ input: 'exclude',
+ output: 'exclude',
+ configuration: template_config,
+ install: true,
+ install_dir: get_option('datadir') / 'git-core/templates/info',
+)
diff --git a/templates/meson.build b/templates/meson.build
new file mode 100644
index 0000000000..1faf9a44ce
--- /dev/null
+++ b/templates/meson.build
@@ -0,0 +1,15 @@
+template_config = configuration_data()
+template_config.set('PERL_PATH', perl.found() ? fs.as_posix(perl.full_path()) : '')
+template_config.set('SHELL_PATH', fs.as_posix(shell.full_path()))
+template_config.set('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb'))
+
+configure_file(
+ input: 'description',
+ output: 'description',
+ configuration: template_config,
+ install: true,
+ install_dir: get_option('datadir') / 'git-core/templates',
+)
+
+subdir('hooks')
+subdir('info')
diff --git a/transport.c b/transport.c
index d94ed4f98f..10d820c333 100644
--- a/transport.c
+++ b/transport.c
@@ -19,6 +19,7 @@
#include "branch.h"
#include "url.h"
#include "submodule.h"
+#include "strbuf.h"
#include "string-list.h"
#include "oid-array.h"
#include "sigchain.h"
@@ -170,12 +171,29 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
return result;
}
+static int fetch_fsck_config_cb(const char *var, const char *value,
+ const struct config_context *ctx UNUSED, void *cb)
+{
+ struct strbuf *msg_types = cb;
+ int ret;
+
+ ret = fetch_pack_fsck_config(var, value, msg_types);
+ if (ret > 0)
+ return 0;
+
+ return ret;
+}
+
static int fetch_refs_from_bundle(struct transport *transport,
int nr_heads UNUSED,
struct ref **to_fetch UNUSED)
{
+ struct unbundle_opts opts = {
+ .flags = fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0,
+ };
struct bundle_transport_data *data = transport->data;
struct strvec extra_index_pack_args = STRVEC_INIT;
+ struct strbuf msg_types = STRBUF_INIT;
int ret;
if (transport->progress)
@@ -183,12 +201,16 @@ static int fetch_refs_from_bundle(struct transport *transport,
if (!data->get_refs_from_bundle_called)
get_refs_from_bundle_inner(transport);
+
+ git_config(fetch_fsck_config_cb, &msg_types);
+ opts.fsck_msg_types = msg_types.buf;
+
ret = unbundle(the_repository, &data->header, data->fd,
- &extra_index_pack_args,
- fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0);
+ &extra_index_pack_args, &opts);
transport->hash_algo = data->header.hash_algo;
strvec_clear(&extra_index_pack_args);
+ strbuf_release(&msg_types);
return ret;
}
diff --git a/unimplemented.sh b/unimplemented.sh
index fee21d24e8..41776b279d 100644
--- a/unimplemented.sh
+++ b/unimplemented.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-echo >&2 "fatal: git was built without support for $(basename $0) (@@REASON@@)."
+echo >&2 "fatal: git was built without support for $(basename $0) (@REASON@)."
exit 128
diff --git a/version-def.h.in b/version-def.h.in
new file mode 100644
index 0000000000..347995df06
--- /dev/null
+++ b/version-def.h.in
@@ -0,0 +1,8 @@
+#ifndef VERSION_DEF_H
+#define VERSION_DEF_H
+
+#define GIT_VERSION "@GIT_VERSION@"
+#define GIT_BUILT_FROM_COMMIT "@GIT_BUILT_FROM_COMMIT@"
+#define GIT_USER_AGENT "@GIT_USER_AGENT@"
+
+#endif /* VERSION_DEF_H */
diff --git a/version.c b/version.c
index 44cd39ae26..4d763ab48d 100644
--- a/version.c
+++ b/version.c
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "version.h"
+#include "version-def.h"
#include "strbuf.h"
const char git_version_string[] = GIT_VERSION;
diff --git a/worktree.c b/worktree.c
index 86b36f5190..248bbb39d4 100644
--- a/worktree.c
+++ b/worktree.c
@@ -112,9 +112,9 @@ struct worktree *get_linked_worktree(const char *id,
strbuf_strip_suffix(&worktree_path, "/.git");
if (!is_absolute_path(worktree_path.buf)) {
- strbuf_strip_suffix(&path, "gitdir");
- strbuf_addbuf(&path, &worktree_path);
- strbuf_realpath_forgiving(&worktree_path, path.buf, 0);
+ strbuf_strip_suffix(&path, "gitdir");
+ strbuf_addbuf(&path, &worktree_path);
+ strbuf_realpath_forgiving(&worktree_path, path.buf, 0);
}
CALLOC_ARRAY(worktree, 1);
@@ -377,32 +377,28 @@ done:
return ret;
}
-void update_worktree_location(struct worktree *wt, const char *path_)
+void update_worktree_location(struct worktree *wt, const char *path_,
+ int use_relative_paths)
{
struct strbuf path = STRBUF_INIT;
- struct strbuf repo = STRBUF_INIT;
- struct strbuf file = STRBUF_INIT;
- struct strbuf tmp = STRBUF_INIT;
+ struct strbuf dotgit = STRBUF_INIT;
+ struct strbuf gitdir = STRBUF_INIT;
if (is_main_worktree(wt))
BUG("can't relocate main worktree");
- strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
+ strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
strbuf_realpath(&path, path_, 1);
+ strbuf_addf(&dotgit, "%s/.git", path.buf);
if (fspathcmp(wt->path, path.buf)) {
- strbuf_addf(&file, "%s/gitdir", repo.buf);
- write_file(file.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp));
- strbuf_reset(&file);
- strbuf_addf(&file, "%s/.git", path.buf);
- write_file(file.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
+ write_worktree_linking_files(dotgit, gitdir, use_relative_paths);
free(wt->path);
wt->path = strbuf_detach(&path, NULL);
}
strbuf_release(&path);
- strbuf_release(&repo);
- strbuf_release(&file);
- strbuf_release(&tmp);
+ strbuf_release(&dotgit);
+ strbuf_release(&gitdir);
}
int is_worktree_being_rebased(const struct worktree *wt,
@@ -578,12 +574,13 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
* pointing at <repo>/worktrees/<id>.
*/
static void repair_gitfile(struct worktree *wt,
- worktree_repair_fn fn, void *cb_data)
+ worktree_repair_fn fn, void *cb_data,
+ int use_relative_paths)
{
struct strbuf dotgit = STRBUF_INIT;
+ struct strbuf gitdir = STRBUF_INIT;
struct strbuf repo = STRBUF_INIT;
struct strbuf backlink = STRBUF_INIT;
- struct strbuf tmp = STRBUF_INIT;
char *dotgit_contents = NULL;
const char *repair = NULL;
int err;
@@ -599,6 +596,7 @@ static void repair_gitfile(struct worktree *wt,
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
strbuf_addf(&dotgit, "%s/.git", wt->path);
+ strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
if (dotgit_contents) {
@@ -616,18 +614,20 @@ static void repair_gitfile(struct worktree *wt,
repair = _(".git file broken");
else if (fspathcmp(backlink.buf, repo.buf))
repair = _(".git file incorrect");
+ else if (use_relative_paths == is_absolute_path(dotgit_contents))
+ repair = _(".git file absolute/relative path mismatch");
if (repair) {
fn(0, wt->path, repair, cb_data);
- write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, wt->path, &tmp));
+ write_worktree_linking_files(dotgit, gitdir, use_relative_paths);
}
done:
free(dotgit_contents);
strbuf_release(&repo);
strbuf_release(&dotgit);
+ strbuf_release(&gitdir);
strbuf_release(&backlink);
- strbuf_release(&tmp);
}
static void repair_noop(int iserr UNUSED,
@@ -638,7 +638,7 @@ static void repair_noop(int iserr UNUSED,
/* nothing */
}
-void repair_worktrees(worktree_repair_fn fn, void *cb_data)
+void repair_worktrees(worktree_repair_fn fn, void *cb_data, int use_relative_paths)
{
struct worktree **worktrees = get_worktrees_internal(1);
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
@@ -646,51 +646,38 @@ void repair_worktrees(worktree_repair_fn fn, void *cb_data)
if (!fn)
fn = repair_noop;
for (; *wt; wt++)
- repair_gitfile(*wt, fn, cb_data);
+ repair_gitfile(*wt, fn, cb_data, use_relative_paths);
free_worktrees(worktrees);
}
void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path)
{
- struct strbuf path = STRBUF_INIT;
- struct strbuf repo = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
struct strbuf dotgit = STRBUF_INIT;
- struct strbuf olddotgit = STRBUF_INIT;
- struct strbuf tmp = STRBUF_INIT;
+ int is_relative_path;
if (is_main_worktree(wt))
goto done;
- strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
- strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
+ strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
- if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
+ if (strbuf_read_file(&dotgit, gitdir.buf, 0) < 0)
goto done;
- strbuf_rtrim(&olddotgit);
- if (is_absolute_path(olddotgit.buf)) {
- strbuf_addbuf(&dotgit, &olddotgit);
- } else {
- strbuf_addf(&dotgit, "%s/worktrees/%s/%s", old_path, wt->id, olddotgit.buf);
+ strbuf_rtrim(&dotgit);
+ is_relative_path = ! is_absolute_path(dotgit.buf);
+ if (is_relative_path) {
+ strbuf_insertf(&dotgit, 0, "%s/worktrees/%s/", old_path, wt->id);
strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
}
if (!file_exists(dotgit.buf))
goto done;
- strbuf_addbuf(&path, &dotgit);
- strbuf_strip_suffix(&path, "/.git");
-
- write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
- write_file(gitdir.buf, "%s", relative_path(dotgit.buf, repo.buf, &tmp));
+ write_worktree_linking_files(dotgit, gitdir, is_relative_path);
done:
- strbuf_release(&path);
- strbuf_release(&repo);
strbuf_release(&gitdir);
strbuf_release(&dotgit);
- strbuf_release(&olddotgit);
- strbuf_release(&tmp);
}
void repair_worktrees_after_gitdir_move(const char *old_path)
@@ -726,8 +713,10 @@ static int is_main_worktree_path(const char *path)
* won't know which <repo>/worktrees/<id>/gitdir to repair. However, we may
* be able to infer the gitdir by manually reading /path/to/worktree/.git,
* extracting the <id>, and checking if <repo>/worktrees/<id> exists.
+ *
+ * Returns -1 on failure and strbuf.len on success.
*/
-static int infer_backlink(const char *gitfile, struct strbuf *inferred)
+static ssize_t infer_backlink(const char *gitfile, struct strbuf *inferred)
{
struct strbuf actual = STRBUF_INIT;
const char *id;
@@ -748,12 +737,11 @@ static int infer_backlink(const char *gitfile, struct strbuf *inferred)
goto error;
strbuf_release(&actual);
- return 1;
-
+ return inferred->len;
error:
strbuf_release(&actual);
strbuf_reset(inferred); /* clear invalid path */
- return 0;
+ return -1;
}
/*
@@ -761,16 +749,14 @@ error:
* the worktree's path.
*/
void repair_worktree_at_path(const char *path,
- worktree_repair_fn fn, void *cb_data)
+ worktree_repair_fn fn, void *cb_data,
+ int use_relative_paths)
{
struct strbuf dotgit = STRBUF_INIT;
- struct strbuf realdotgit = STRBUF_INIT;
struct strbuf backlink = STRBUF_INIT;
struct strbuf inferred_backlink = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
struct strbuf olddotgit = STRBUF_INIT;
- struct strbuf realolddotgit = STRBUF_INIT;
- struct strbuf tmp = STRBUF_INIT;
char *dotgit_contents = NULL;
const char *repair = NULL;
int err;
@@ -782,25 +768,25 @@ void repair_worktree_at_path(const char *path,
goto done;
strbuf_addf(&dotgit, "%s/.git", path);
- if (!strbuf_realpath(&realdotgit, dotgit.buf, 0)) {
+ if (!strbuf_realpath(&dotgit, dotgit.buf, 0)) {
fn(1, path, _("not a valid path"), cb_data);
goto done;
}
- infer_backlink(realdotgit.buf, &inferred_backlink);
+ infer_backlink(dotgit.buf, &inferred_backlink);
strbuf_realpath_forgiving(&inferred_backlink, inferred_backlink.buf, 0);
- dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
+ dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
if (dotgit_contents) {
if (is_absolute_path(dotgit_contents)) {
strbuf_addstr(&backlink, dotgit_contents);
} else {
- strbuf_addbuf(&backlink, &realdotgit);
+ strbuf_addbuf(&backlink, &dotgit);
strbuf_strip_suffix(&backlink, ".git");
strbuf_addstr(&backlink, dotgit_contents);
strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
}
} else if (err == READ_GITFILE_ERR_NOT_A_FILE) {
- fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
+ fn(1, dotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
goto done;
} else if (err == READ_GITFILE_ERR_NOT_A_REPO) {
if (inferred_backlink.len) {
@@ -813,11 +799,11 @@ void repair_worktree_at_path(const char *path,
*/
strbuf_swap(&backlink, &inferred_backlink);
} else {
- fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
+ fn(1, dotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
goto done;
}
} else {
- fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
+ fn(1, dotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
goto done;
}
@@ -839,39 +825,35 @@ void repair_worktree_at_path(const char *path,
* in the "copy" repository. In this case, point the "copy" worktree's
* .git file at the "copy" repository.
*/
- if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf)) {
+ if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf))
strbuf_swap(&backlink, &inferred_backlink);
- }
strbuf_addf(&gitdir, "%s/gitdir", backlink.buf);
if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
repair = _("gitdir unreadable");
+ else if (use_relative_paths == is_absolute_path(olddotgit.buf))
+ repair = _("gitdir absolute/relative path mismatch");
else {
strbuf_rtrim(&olddotgit);
- if (is_absolute_path(olddotgit.buf)) {
- strbuf_addbuf(&realolddotgit, &olddotgit);
- } else {
- strbuf_addf(&realolddotgit, "%s/%s", backlink.buf, olddotgit.buf);
- strbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0);
+ if (!is_absolute_path(olddotgit.buf)) {
+ strbuf_insertf(&olddotgit, 0, "%s/", backlink.buf);
+ strbuf_realpath_forgiving(&olddotgit, olddotgit.buf, 0);
}
- if (fspathcmp(realolddotgit.buf, realdotgit.buf))
+ if (fspathcmp(olddotgit.buf, dotgit.buf))
repair = _("gitdir incorrect");
}
if (repair) {
fn(0, gitdir.buf, repair, cb_data);
- write_file(gitdir.buf, "%s", relative_path(realdotgit.buf, backlink.buf, &tmp));
+ write_worktree_linking_files(dotgit, gitdir, use_relative_paths);
}
done:
free(dotgit_contents);
strbuf_release(&olddotgit);
- strbuf_release(&realolddotgit);
strbuf_release(&backlink);
strbuf_release(&inferred_backlink);
strbuf_release(&gitdir);
- strbuf_release(&realdotgit);
strbuf_release(&dotgit);
- strbuf_release(&tmp);
}
int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire)
@@ -1032,3 +1014,38 @@ cleanup:
free(main_worktree_file);
return res;
}
+
+void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir,
+ int use_relative_paths)
+{
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf repo = STRBUF_INIT;
+ struct strbuf tmp = STRBUF_INIT;
+
+ strbuf_addbuf(&path, &dotgit);
+ strbuf_strip_suffix(&path, "/.git");
+ strbuf_realpath(&path, path.buf, 1);
+ strbuf_addbuf(&repo, &gitdir);
+ strbuf_strip_suffix(&repo, "/gitdir");
+ strbuf_realpath(&repo, repo.buf, 1);
+
+ if (use_relative_paths && !the_repository->repository_format_relative_worktrees) {
+ if (upgrade_repository_format(1) < 0)
+ die(_("unable to upgrade repository format to support relative worktrees"));
+ if (git_config_set_gently("extensions.relativeWorktrees", "true"))
+ die(_("unable to set extensions.relativeWorktrees setting"));
+ the_repository->repository_format_relative_worktrees = 1;
+ }
+
+ if (use_relative_paths) {
+ write_file(gitdir.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp));
+ write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
+ } else {
+ write_file(gitdir.buf, "%s/.git", path.buf);
+ write_file(dotgit.buf, "gitdir: %s", repo.buf);
+ }
+
+ strbuf_release(&path);
+ strbuf_release(&repo);
+ strbuf_release(&tmp);
+}
diff --git a/worktree.h b/worktree.h
index e961186216..38145df80f 100644
--- a/worktree.h
+++ b/worktree.h
@@ -117,8 +117,8 @@ int validate_worktree(const struct worktree *wt,
/*
* Update worktrees/xxx/gitdir with the new path.
*/
-void update_worktree_location(struct worktree *wt,
- const char *path_);
+void update_worktree_location(struct worktree *wt, const char *path_,
+ int use_relative_paths);
typedef void (* worktree_repair_fn)(int iserr, const char *path,
const char *msg, void *cb_data);
@@ -129,7 +129,7 @@ typedef void (* worktree_repair_fn)(int iserr, const char *path,
* function, if non-NULL, is called with the path of the worktree and a
* description of the repair or error, along with the callback user-data.
*/
-void repair_worktrees(worktree_repair_fn, void *cb_data);
+void repair_worktrees(worktree_repair_fn, void *cb_data, int use_relative_paths);
/*
* Repair the linked worktrees after the gitdir has been moved.
@@ -151,7 +151,8 @@ void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path
* worktree and a description of the repair or error, along with the callback
* user-data.
*/
-void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);
+void repair_worktree_at_path(const char *, worktree_repair_fn,
+ void *cb_data, int use_relative_paths);
/*
* Free up the memory for a worktree.
@@ -215,4 +216,17 @@ void strbuf_worktree_ref(const struct worktree *wt,
*/
int init_worktree_config(struct repository *r);
+/**
+ * Write the .git file and gitdir file that links the worktree to the repository.
+ *
+ * The `dotgit` parameter is the path to the worktree's .git file, and `gitdir`
+ * is the path to the repository's `gitdir` file.
+ *
+ * Example
+ * dotgit: "/path/to/foo/.git"
+ * gitdir: "/path/to/repo/worktrees/foo/gitdir"
+ */
+void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir,
+ int use_relative_paths);
+
#endif
diff --git a/wrap-for-bin.sh b/wrap-for-bin.sh
deleted file mode 100644
index 95851b85b6..0000000000
--- a/wrap-for-bin.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-
-# wrap-for-bin.sh: Template for git executable wrapper scripts
-# to run test suite against sandbox, but with only bindir-installed
-# executables in PATH. The Makefile copies this into various
-# files in bin-wrappers, substituting
-# @@BUILD_DIR@@ and @@PROG@@.
-
-GIT_EXEC_PATH='@@BUILD_DIR@@'
-if test -n "$NO_SET_GIT_TEMPLATE_DIR"
-then
- unset GIT_TEMPLATE_DIR
-else
- GIT_TEMPLATE_DIR='@@BUILD_DIR@@/templates/blt'
- export GIT_TEMPLATE_DIR
-fi
-GITPERLLIB='@@BUILD_DIR@@/perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}"
-GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/locale'
-PATH='@@BUILD_DIR@@/bin-wrappers:'"$PATH"
-
-export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR
-
-case "$GIT_DEBUGGER" in
-'')
- exec "${GIT_EXEC_PATH}/@@PROG@@" "$@"
- ;;
-1)
- unset GIT_DEBUGGER
- exec gdb --args "${GIT_EXEC_PATH}/@@PROG@@" "$@"
- ;;
-*)
- GIT_DEBUGGER_ARGS="$GIT_DEBUGGER"
- unset GIT_DEBUGGER
- exec ${GIT_DEBUGGER_ARGS} "${GIT_EXEC_PATH}/@@PROG@@" "$@"
- ;;
-esac