mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
Merge branch 'ps/ref-peeled-tags' into kn/refs-optim-cleanup
* ps/ref-peeled-tags: (92 commits) t7004: do not chdir around in the main process ref-filter: fix stale parsed objects ref-filter: parse objects on demand ref-filter: detect broken tags when dereferencing them refs: don't store peeled object IDs for invalid tags object: add flag to `peel_object()` to verify object type refs: drop infrastructure to peel via iterators refs: drop `current_ref_iter` hack builtin/show-ref: convert to use `reference_get_peeled_oid()` ref-filter: propagate peeled object ID upload-pack: convert to use `reference_get_peeled_oid()` refs: expose peeled object ID via the iterator refs: refactor reference status flags refs: fully reset `struct ref_iterator::ref` on iteration refs: introduce `.ref` field for the base iterator refs: introduce wrapper struct for `each_ref_fn` builtin/repo: add progress meter for structure stats builtin/repo: add keyvalue and nul format for structure stats builtin/repo: add object counts in structure output builtin/repo: introduce structure subcommand ...
This commit is contained in:
@@ -100,7 +100,7 @@ Performance, Internal Implementation, Development Support etc.
|
||||
|
||||
* CodingGuidelines now spells out how bitfields are to be written.
|
||||
|
||||
* Adjust to the way newer versions of cURL selectivel enables tracing
|
||||
* Adjust to the way newer versions of cURL selectively enable tracing
|
||||
options, so that our tests can continue to work.
|
||||
(merge 1b5a6bfff3 jk/curl-global-trace-components later to maint).
|
||||
|
||||
@@ -127,6 +127,10 @@ Performance, Internal Implementation, Development Support etc.
|
||||
* Documentation for "git log --pretty" options has been updated
|
||||
to make it easier to translate.
|
||||
|
||||
* Instead of three library archives (one for git, one for reftable,
|
||||
and one for xdiff), roll everything into a single libgit.a archive.
|
||||
This would help later effort to FFI into Rust.
|
||||
|
||||
|
||||
Fixes since v2.51
|
||||
-----------------
|
||||
@@ -212,13 +216,13 @@ including security updates, are included in this release.
|
||||
name.
|
||||
(merge bcb20dda83 js/doc-gitk-history later to maint).
|
||||
|
||||
* Update the instruction to use of GGG in the MyFirstContribution
|
||||
* Update the instructions for using GGG in the MyFirstContribution
|
||||
document to say that a GitHub PR could be made against `git/git`
|
||||
instead of `gitgitgadget/git`.
|
||||
(merge 37001cdbc4 ds/doc-ggg-pr-fork-clarify later to maint).
|
||||
|
||||
* Makefile tried to run multiple "cargo build" which would not work
|
||||
very well; serialize their execution to work it around.
|
||||
very well; serialize their execution to work around this problem.
|
||||
(merge 0eeacde50e da/cargo-serialize later to maint).
|
||||
|
||||
* "git repack --path-walk" lost objects in some corner cases, which
|
||||
@@ -294,12 +298,12 @@ including security updates, are included in this release.
|
||||
updated.
|
||||
(merge 54a60e5b38 kh/you-still-use-whatchanged-fix later to maint).
|
||||
|
||||
* Clang-format update to let our control macros formatted the way we
|
||||
* Clang-format update to let our control macros be formatted the way we
|
||||
had them traditionally, e.g., "for_each_string_list_item()" without
|
||||
space before the parentheses.
|
||||
(merge 3721541d35 jt/clang-format-foreach-wo-space-before-parenthesis later to maint).
|
||||
|
||||
* A few places where an size_t value was cast to curl_off_t without
|
||||
* A few places where a size_t value was cast to curl_off_t without
|
||||
checking has been updated to use the existing helper function.
|
||||
(merge ecc5749578 js/curl-off-t-fixes later to maint).
|
||||
|
||||
@@ -329,6 +333,19 @@ including security updates, are included in this release.
|
||||
you would get from "git format-patch --notes=..." for a singleton
|
||||
patch.
|
||||
|
||||
* The code in "git add -p" and friends to iterate over hunks was
|
||||
riddled with bugs, which has been corrected.
|
||||
|
||||
* A few more things that patch authors can do to help maintainer to
|
||||
keep track of their topics better.
|
||||
(merge 1a41698841 tb/doc-submitting-patches later to maint).
|
||||
|
||||
* An earlier addition to "git diff --no-index A B" to limit the
|
||||
output with pathspec after the two directories misbehaved when
|
||||
these directories were given with a trailing slash, which has been
|
||||
corrected.
|
||||
(merge c0bec06cfe jk/diff-no-index-with-pathspec-fix later to maint).
|
||||
|
||||
* Other code cleanup, docfix, build fix, etc.
|
||||
(merge 823d537fa7 kh/doc-git-log-markup-fix later to maint).
|
||||
(merge cf7efa4f33 rj/t6137-cygwin-fix later to maint).
|
||||
@@ -359,3 +376,7 @@ including security updates, are included in this release.
|
||||
(merge 1c573a3451 en/doc-merge-tree-describe-merge-base later to maint).
|
||||
(merge 84a6bf7965 ja/doc-markup-attached-paragraph-fix later to maint).
|
||||
(merge 399694384b kh/doc-patch-id-markup-fix later to maint).
|
||||
(merge 15b8abde07 js/mingw-includes-cleanup later to maint).
|
||||
(merge 3860985105 js/unreachable-workaround-for-no-symlink-head later to maint).
|
||||
(merge b3ac6e737d kh/doc-continued-paragraph-fix later to maint).
|
||||
(merge 2cebca0582 tb/cat-file-objectmode-update later to maint).
|
||||
|
||||
@@ -579,14 +579,27 @@ line via `git format-patch --notes`.
|
||||
[[the-topic-summary]]
|
||||
*This is EXPERIMENTAL*.
|
||||
|
||||
When sending a topic, you can propose a one-paragraph summary that
|
||||
should appear in the "What's cooking" report when it is picked up to
|
||||
explain the topic. If you choose to do so, please write a 2-5 line
|
||||
paragraph that will fit well in our release notes (see many bulleted
|
||||
entries in the Documentation/RelNotes/* files for examples), and make
|
||||
it the first paragraph of the cover letter. For a single-patch
|
||||
series, use the space between the three-dash line and the diffstat, as
|
||||
described earlier.
|
||||
When sending a topic, you can optionally propose a topic name and/or a
|
||||
one-paragraph summary that should appear in the "What's cooking"
|
||||
report when it is picked up to explain the topic. If you choose to do
|
||||
so, please write a 2-5 line paragraph that will fit well in our
|
||||
release notes (see many bulleted entries in the
|
||||
Documentation/RelNotes/* files for examples), and make it the first
|
||||
(or second, if including a suggested topic name) paragraph of the
|
||||
cover letter. If suggesting a topic name, use the format
|
||||
"XX/your-topic-name", where "XX" is a stand-in for the primary
|
||||
author's initials, and "your-topic-name" is a brief, dash-delimited
|
||||
description of what your topic does. For a single-patch series, use
|
||||
the space between the three-dash line and the diffstat, as described
|
||||
earlier.
|
||||
|
||||
[[multi-series-efforts]]
|
||||
If your patch series is part of a larger effort spanning multiple
|
||||
patch series, briefly describe the broader goal, and state where the
|
||||
current series fits into that goal. If you are suggesting a topic
|
||||
name as in <<the-topic-summary, section above>>, consider
|
||||
"XX/the-broader-goal-part-one", "XX/the-broader-goal-part-two", and so
|
||||
on.
|
||||
|
||||
[[attachment]]
|
||||
Do not attach the patch as a MIME attachment, compressed or not.
|
||||
|
||||
@@ -75,8 +75,8 @@ The built-in file system monitor is currently available only on a
|
||||
limited set of supported platforms. Currently, this includes Windows
|
||||
and MacOS.
|
||||
+
|
||||
Otherwise, this variable contains the pathname of the "fsmonitor"
|
||||
hook command.
|
||||
Otherwise, this variable contains the pathname of the "fsmonitor"
|
||||
hook command.
|
||||
+
|
||||
This hook command is used to identify all files that may have changed
|
||||
since the requested date/time. This information is used to speed up
|
||||
|
||||
@@ -11,6 +11,10 @@ endif::git-stash[]
|
||||
behave as if `--index` was supplied. Defaults to false.
|
||||
ifndef::git-stash[]
|
||||
See the descriptions in linkgit:git-stash[1].
|
||||
+
|
||||
This also affects invocations of linkgit:git-stash[1] via `--autostash` from
|
||||
commands like linkgit:git-merge[1], linkgit:git-rebase[1], and
|
||||
linkgit:git-pull[1].
|
||||
endif::git-stash[]
|
||||
|
||||
`stash.showIncludeUntracked`::
|
||||
|
||||
@@ -342,10 +342,10 @@ patch::
|
||||
d - do not stage this hunk or any of the later hunks in the file
|
||||
g - select a hunk to go to
|
||||
/ - search for a hunk matching the given regex
|
||||
j - leave this hunk undecided, see next undecided hunk
|
||||
J - leave this hunk undecided, see next hunk
|
||||
k - leave this hunk undecided, see previous undecided hunk
|
||||
K - leave this hunk undecided, see previous hunk
|
||||
j - go to the next undecided hunk, roll over at the bottom
|
||||
J - go to the next hunk, roll over at the bottom
|
||||
k - go to the previous undecided hunk, roll over at the top
|
||||
K - go to the previous hunk, roll over at the top
|
||||
s - split the current hunk into smaller hunks
|
||||
e - manually edit the current hunk
|
||||
p - print the current hunk
|
||||
|
||||
@@ -117,15 +117,15 @@ OPTIONS
|
||||
|
||||
--comment <message>::
|
||||
Append a comment at the end of new or modified lines.
|
||||
|
||||
If _<message>_ begins with one or more whitespaces followed
|
||||
by "#", it is used as-is. If it begins with "#", a space is
|
||||
prepended before it is used. Otherwise, a string " # " (a
|
||||
space followed by a hash followed by a space) is prepended
|
||||
to it. And the resulting string is placed immediately after
|
||||
the value defined for the variable. The _<message>_ must
|
||||
not contain linefeed characters (no multi-line comments are
|
||||
permitted).
|
||||
+
|
||||
If _<message>_ begins with one or more whitespaces followed
|
||||
by "#", it is used as-is. If it begins with "#", a space is
|
||||
prepended before it is used. Otherwise, a string " # " (a
|
||||
space followed by a hash followed by a space) is prepended
|
||||
to it. And the resulting string is placed immediately after
|
||||
the value defined for the variable. The _<message>_ must
|
||||
not contain linefeed characters (no multi-line comments are
|
||||
permitted).
|
||||
|
||||
--all::
|
||||
With `get`, return all values for a multi-valued key.
|
||||
|
||||
@@ -9,6 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[synopsis]
|
||||
git repo info [--format=(keyvalue|nul)] [-z] [<key>...]
|
||||
git repo structure [--format=(table|keyvalue|nul)]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -43,6 +44,35 @@ supported:
|
||||
+
|
||||
`-z` is an alias for `--format=nul`.
|
||||
|
||||
`structure [--format=(table|keyvalue|nul)]`::
|
||||
Retrieve statistics about the current repository structure. The
|
||||
following kinds of information are reported:
|
||||
+
|
||||
* Reference counts categorized by type
|
||||
* Reachable object counts categorized by type
|
||||
|
||||
+
|
||||
The output format can be chosen through the flag `--format`. Three formats are
|
||||
supported:
|
||||
+
|
||||
`table`:::
|
||||
Outputs repository stats in a human-friendly table. This format may
|
||||
change and is not intended for machine parsing. This is the default
|
||||
format.
|
||||
|
||||
`keyvalue`:::
|
||||
Each line of output contains a key-value pair for a repository stat.
|
||||
The '=' character is used to delimit between the key and the value.
|
||||
Values containing "unusual" characters are quoted as explained for the
|
||||
configuration variable `core.quotePath` (see linkgit:git-config[1]).
|
||||
|
||||
`nul`:::
|
||||
Similar to `keyvalue`, but uses a NUL character to delimit between
|
||||
key-value pairs instead of a newline. Also uses a newline character as
|
||||
the delimiter between the key and value instead of '='. Unlike the
|
||||
`keyvalue` format, values containing "unusual" characters are never
|
||||
quoted.
|
||||
|
||||
INFO KEYS
|
||||
---------
|
||||
In order to obtain a set of values from `git repo info`, you should provide
|
||||
|
||||
@@ -174,13 +174,13 @@ for another option.
|
||||
|
||||
Allow oids to be input from any object format that the current
|
||||
repository supports.
|
||||
|
||||
Specifying "sha1" translates if necessary and returns a sha1 oid.
|
||||
|
||||
Specifying "sha256" translates if necessary and returns a sha256 oid.
|
||||
|
||||
Specifying "storage" translates if necessary and returns an oid in
|
||||
encoded in the storage hash algorithm.
|
||||
+
|
||||
Specifying "sha1" translates if necessary and returns a sha1 oid.
|
||||
+
|
||||
Specifying "sha256" translates if necessary and returns a sha256 oid.
|
||||
+
|
||||
Specifying "storage" translates if necessary and returns an oid in
|
||||
encoded in the storage hash algorithm.
|
||||
|
||||
Options for Objects
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -44,8 +44,8 @@ OPTIONS
|
||||
describe each commit. '<format>' can be any string accepted
|
||||
by the `--format` option of 'git log', such as '* [%h] %s'.
|
||||
(See the "PRETTY FORMATS" section of linkgit:git-log[1].)
|
||||
|
||||
Each pretty-printed commit will be rewrapped before it is shown.
|
||||
+
|
||||
Each pretty-printed commit will be rewrapped before it is shown.
|
||||
|
||||
--date=<format>::
|
||||
Show dates formatted according to the given date string. (See
|
||||
|
||||
@@ -264,34 +264,50 @@ patterns in non-cone mode has a number of shortcomings:
|
||||
inconsistent.
|
||||
|
||||
* It has edge cases where the "right" behavior is unclear. Two examples:
|
||||
|
||||
First, two users are in a subdirectory, and the first runs
|
||||
git sparse-checkout set '/toplevel-dir/*.c'
|
||||
while the second runs
|
||||
git sparse-checkout set relative-dir
|
||||
Should those arguments be transliterated into
|
||||
current/subdirectory/toplevel-dir/*.c
|
||||
and
|
||||
current/subdirectory/relative-dir
|
||||
before inserting into the sparse-checkout file? The user who typed
|
||||
the first command is probably aware that arguments to set/add are
|
||||
supposed to be patterns in non-cone mode, and probably would not be
|
||||
happy with such a transliteration. However, many gitignore-style
|
||||
patterns are just paths, which might be what the user who typed the
|
||||
second command was thinking, and they'd be upset if their argument
|
||||
wasn't transliterated.
|
||||
|
||||
Second, what should bash-completion complete on for set/add commands
|
||||
for non-cone users? If it suggests paths, is it exacerbating the
|
||||
problem above? Also, if it suggests paths, what if the user has a
|
||||
file or directory that begins with either a '!' or '#' or has a '*',
|
||||
'\', '?', '[', or ']' in its name? And if it suggests paths, will
|
||||
it complete "/pro" to "/proc" (in the root filesystem) rather than to
|
||||
"/progress.txt" in the current directory? (Note that users are
|
||||
likely to want to start paths with a leading '/' in non-cone mode,
|
||||
for the same reason that .gitignore files often have one.)
|
||||
Completing on files or directories might give nasty surprises in
|
||||
all these cases.
|
||||
+
|
||||
First, two users are in a subdirectory, and the first runs
|
||||
+
|
||||
----
|
||||
git sparse-checkout set '/toplevel-dir/*.c'
|
||||
----
|
||||
+
|
||||
while the second runs
|
||||
+
|
||||
----
|
||||
git sparse-checkout set relative-dir
|
||||
----
|
||||
+
|
||||
Should those arguments be transliterated into
|
||||
+
|
||||
----
|
||||
current/subdirectory/toplevel-dir/*.c
|
||||
----
|
||||
+
|
||||
and
|
||||
+
|
||||
----
|
||||
current/subdirectory/relative-dir
|
||||
----
|
||||
+
|
||||
before inserting into the sparse-checkout file? The user who typed
|
||||
the first command is probably aware that arguments to set/add are
|
||||
supposed to be patterns in non-cone mode, and probably would not be
|
||||
happy with such a transliteration. However, many gitignore-style
|
||||
patterns are just paths, which might be what the user who typed the
|
||||
second command was thinking, and they'd be upset if their argument
|
||||
wasn't transliterated.
|
||||
+
|
||||
Second, what should bash-completion complete on for set/add commands
|
||||
for non-cone users? If it suggests paths, is it exacerbating the
|
||||
problem above? Also, if it suggests paths, what if the user has a
|
||||
file or directory that begins with either a '!' or '#' or has a '*',
|
||||
'\', '?', '[', or ']' in its name? And if it suggests paths, will
|
||||
it complete "/pro" to "/proc" (in the root filesystem) rather than to
|
||||
"/progress.txt" in the current directory? (Note that users are
|
||||
likely to want to start paths with a leading '/' in non-cone mode,
|
||||
for the same reason that .gitignore files often have one.)
|
||||
Completing on files or directories might give nasty surprises in
|
||||
all these cases.
|
||||
|
||||
* The excessive flexibility made other extensions essentially
|
||||
impractical. `--sparse-index` is likely impossible in non-cone
|
||||
|
||||
70
Makefile
70
Makefile
@@ -927,16 +927,13 @@ export PYTHON_PATH
|
||||
TEST_SHELL_PATH = $(SHELL_PATH)
|
||||
|
||||
LIB_FILE = libgit.a
|
||||
XDIFF_LIB = xdiff/lib.a
|
||||
REFTABLE_LIB = reftable/libreftable.a
|
||||
ifdef DEBUG
|
||||
RUST_LIB = target/debug/libgitcore.a
|
||||
else
|
||||
RUST_LIB = target/release/libgitcore.a
|
||||
endif
|
||||
|
||||
# xdiff and reftable libs may in turn depend on what is in libgit.a
|
||||
GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
|
||||
GITLIBS = common-main.o $(LIB_FILE)
|
||||
EXTLIBS =
|
||||
|
||||
GIT_USER_AGENT = git/$(GIT_VERSION)
|
||||
@@ -1248,7 +1245,27 @@ LIB_OBJS += refs/iterator.o
|
||||
LIB_OBJS += refs/packed-backend.o
|
||||
LIB_OBJS += refs/ref-cache.o
|
||||
LIB_OBJS += refspec.o
|
||||
LIB_OBJS += reftable/basics.o
|
||||
LIB_OBJS += reftable/block.o
|
||||
LIB_OBJS += reftable/blocksource.o
|
||||
LIB_OBJS += reftable/error.o
|
||||
LIB_OBJS += reftable/fsck.o
|
||||
LIB_OBJS += reftable/iter.o
|
||||
LIB_OBJS += reftable/merged.o
|
||||
LIB_OBJS += reftable/pq.o
|
||||
LIB_OBJS += reftable/record.o
|
||||
LIB_OBJS += reftable/stack.o
|
||||
LIB_OBJS += reftable/system.o
|
||||
LIB_OBJS += reftable/table.o
|
||||
LIB_OBJS += reftable/tree.o
|
||||
LIB_OBJS += reftable/writer.o
|
||||
LIB_OBJS += remote.o
|
||||
LIB_OBJS += repack.o
|
||||
LIB_OBJS += repack-cruft.o
|
||||
LIB_OBJS += repack-filtered.o
|
||||
LIB_OBJS += repack-geometry.o
|
||||
LIB_OBJS += repack-midx.o
|
||||
LIB_OBJS += repack-promisor.o
|
||||
LIB_OBJS += replace-object.o
|
||||
LIB_OBJS += repo-settings.o
|
||||
LIB_OBJS += repository.o
|
||||
@@ -1322,6 +1339,13 @@ LIB_OBJS += write-or-die.o
|
||||
LIB_OBJS += ws.o
|
||||
LIB_OBJS += wt-status.o
|
||||
LIB_OBJS += xdiff-interface.o
|
||||
LIB_OBJS += xdiff/xdiffi.o
|
||||
LIB_OBJS += xdiff/xemit.o
|
||||
LIB_OBJS += xdiff/xhistogram.o
|
||||
LIB_OBJS += xdiff/xmerge.o
|
||||
LIB_OBJS += xdiff/xpatience.o
|
||||
LIB_OBJS += xdiff/xprepare.o
|
||||
LIB_OBJS += xdiff/xutils.o
|
||||
|
||||
BUILTIN_OBJS += builtin/add.o
|
||||
BUILTIN_OBJS += builtin/am.o
|
||||
@@ -2756,31 +2780,6 @@ reconfigure config.mak.autogen: config.status
|
||||
.PHONY: reconfigure # This is a convenience target.
|
||||
endif
|
||||
|
||||
XDIFF_OBJS += xdiff/xdiffi.o
|
||||
XDIFF_OBJS += xdiff/xemit.o
|
||||
XDIFF_OBJS += xdiff/xhistogram.o
|
||||
XDIFF_OBJS += xdiff/xmerge.o
|
||||
XDIFF_OBJS += xdiff/xpatience.o
|
||||
XDIFF_OBJS += xdiff/xprepare.o
|
||||
XDIFF_OBJS += xdiff/xutils.o
|
||||
.PHONY: xdiff-objs
|
||||
xdiff-objs: $(XDIFF_OBJS)
|
||||
|
||||
REFTABLE_OBJS += reftable/basics.o
|
||||
REFTABLE_OBJS += reftable/block.o
|
||||
REFTABLE_OBJS += reftable/blocksource.o
|
||||
REFTABLE_OBJS += reftable/error.o
|
||||
REFTABLE_OBJS += reftable/fsck.o
|
||||
REFTABLE_OBJS += reftable/iter.o
|
||||
REFTABLE_OBJS += reftable/merged.o
|
||||
REFTABLE_OBJS += reftable/pq.o
|
||||
REFTABLE_OBJS += reftable/record.o
|
||||
REFTABLE_OBJS += reftable/stack.o
|
||||
REFTABLE_OBJS += reftable/system.o
|
||||
REFTABLE_OBJS += reftable/table.o
|
||||
REFTABLE_OBJS += reftable/tree.o
|
||||
REFTABLE_OBJS += reftable/writer.o
|
||||
|
||||
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
|
||||
|
||||
.PHONY: test-objs
|
||||
@@ -2801,9 +2800,8 @@ OBJECTS += $(GIT_OBJS)
|
||||
OBJECTS += $(SCALAR_OBJS)
|
||||
OBJECTS += $(PROGRAM_OBJS)
|
||||
OBJECTS += $(TEST_OBJS)
|
||||
OBJECTS += $(XDIFF_OBJS)
|
||||
OBJECTS += $(FUZZ_OBJS)
|
||||
OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
|
||||
OBJECTS += $(REFTABLE_TEST_OBJS)
|
||||
OBJECTS += $(UNIT_TEST_OBJS)
|
||||
OBJECTS += $(CLAR_TEST_OBJS)
|
||||
OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
|
||||
@@ -2961,12 +2959,6 @@ $(RUST_LIB): Cargo.toml $(RUST_SOURCES)
|
||||
.PHONY: rust
|
||||
rust: $(RUST_LIB)
|
||||
|
||||
$(XDIFF_LIB): $(XDIFF_OBJS)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
$(REFTABLE_LIB): $(REFTABLE_OBJS)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
export DEFAULT_EDITOR DEFAULT_PAGER
|
||||
|
||||
Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
|
||||
@@ -3805,7 +3797,7 @@ clean: profile-clean coverage-clean cocciclean
|
||||
$(RM) git.rc git.res
|
||||
$(RM) $(OBJECTS)
|
||||
$(RM) headless-git.o
|
||||
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB)
|
||||
$(RM) $(LIB_FILE)
|
||||
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
|
||||
$(RM) $(TEST_PROGRAMS)
|
||||
$(RM) $(FUZZ_PROGRAMS)
|
||||
@@ -3999,8 +3991,6 @@ endif
|
||||
|
||||
LIBGIT_PUB_OBJS += contrib/libgit-sys/public_symbol_export.o
|
||||
LIBGIT_PUB_OBJS += libgit.a
|
||||
LIBGIT_PUB_OBJS += reftable/libreftable.a
|
||||
LIBGIT_PUB_OBJS += xdiff/lib.a
|
||||
|
||||
LIBGIT_PARTIAL_EXPORT = contrib/libgit-sys/partial_symbol_export.o
|
||||
|
||||
|
||||
75
add-patch.c
75
add-patch.c
@@ -1408,10 +1408,10 @@ static size_t display_hunks(struct add_p_state *s,
|
||||
}
|
||||
|
||||
static const char help_patch_remainder[] =
|
||||
N_("j - leave this hunk undecided, see next undecided hunk\n"
|
||||
"J - leave this hunk undecided, see next hunk\n"
|
||||
"k - leave this hunk undecided, see previous undecided hunk\n"
|
||||
"K - leave this hunk undecided, see previous hunk\n"
|
||||
N_("j - go to the next undecided hunk, roll over at the bottom\n"
|
||||
"J - go to the next hunk, roll over at the bottom\n"
|
||||
"k - go to the previous undecided hunk, roll over at the top\n"
|
||||
"K - go to the previous hunk, roll over at the top\n"
|
||||
"g - select a hunk to go to\n"
|
||||
"/ - search for a hunk matching the given regex\n"
|
||||
"s - split the current hunk into smaller hunks\n"
|
||||
@@ -1419,6 +1419,27 @@ N_("j - leave this hunk undecided, see next undecided hunk\n"
|
||||
"p - print the current hunk, 'P' to use the pager\n"
|
||||
"? - print help\n");
|
||||
|
||||
static size_t dec_mod(size_t a, size_t m)
|
||||
{
|
||||
return a > 0 ? a - 1 : m - 1;
|
||||
}
|
||||
|
||||
static size_t inc_mod(size_t a, size_t m)
|
||||
{
|
||||
return a < m - 1 ? a + 1 : 0;
|
||||
}
|
||||
|
||||
static bool get_first_undecided(const struct file_diff *file_diff, size_t *idx)
|
||||
{
|
||||
for (size_t i = 0; i < file_diff->hunk_nr; i++) {
|
||||
if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
|
||||
*idx = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int patch_update_file(struct add_p_state *s,
|
||||
struct file_diff *file_diff)
|
||||
{
|
||||
@@ -1429,15 +1450,6 @@ static int patch_update_file(struct add_p_state *s,
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
int colored = !!s->colored.len, quit = 0, use_pager = 0;
|
||||
enum prompt_mode_type prompt_mode_type;
|
||||
enum {
|
||||
ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
|
||||
ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
|
||||
ALLOW_GOTO_NEXT_HUNK = 1 << 2,
|
||||
ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3,
|
||||
ALLOW_SEARCH_AND_GOTO = 1 << 4,
|
||||
ALLOW_SPLIT = 1 << 5,
|
||||
ALLOW_EDIT = 1 << 6
|
||||
} permitted = 0;
|
||||
|
||||
/* Empty added files have no hunks */
|
||||
if (!file_diff->hunk_nr && !file_diff->added)
|
||||
@@ -1447,6 +1459,16 @@ static int patch_update_file(struct add_p_state *s,
|
||||
render_diff_header(s, file_diff, colored, &s->buf);
|
||||
fputs(s->buf.buf, stdout);
|
||||
for (;;) {
|
||||
enum {
|
||||
ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
|
||||
ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
|
||||
ALLOW_GOTO_NEXT_HUNK = 1 << 2,
|
||||
ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3,
|
||||
ALLOW_SEARCH_AND_GOTO = 1 << 4,
|
||||
ALLOW_SPLIT = 1 << 5,
|
||||
ALLOW_EDIT = 1 << 6
|
||||
} permitted = 0;
|
||||
|
||||
if (hunk_index >= file_diff->hunk_nr)
|
||||
hunk_index = 0;
|
||||
hunk = file_diff->hunk_nr
|
||||
@@ -1456,13 +1478,17 @@ static int patch_update_file(struct add_p_state *s,
|
||||
undecided_next = -1;
|
||||
|
||||
if (file_diff->hunk_nr) {
|
||||
for (i = hunk_index - 1; i >= 0; i--)
|
||||
for (i = dec_mod(hunk_index, file_diff->hunk_nr);
|
||||
i != hunk_index;
|
||||
i = dec_mod(i, file_diff->hunk_nr))
|
||||
if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
|
||||
undecided_previous = i;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
|
||||
for (i = inc_mod(hunk_index, file_diff->hunk_nr);
|
||||
i != hunk_index;
|
||||
i = inc_mod(i, file_diff->hunk_nr))
|
||||
if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
|
||||
undecided_next = i;
|
||||
break;
|
||||
@@ -1496,7 +1522,7 @@ static int patch_update_file(struct add_p_state *s,
|
||||
permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
|
||||
strbuf_addstr(&s->buf, ",k");
|
||||
}
|
||||
if (hunk_index) {
|
||||
if (file_diff->hunk_nr > 1) {
|
||||
permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
|
||||
strbuf_addstr(&s->buf, ",K");
|
||||
}
|
||||
@@ -1504,7 +1530,7 @@ static int patch_update_file(struct add_p_state *s,
|
||||
permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
|
||||
strbuf_addstr(&s->buf, ",j");
|
||||
}
|
||||
if (hunk_index + 1 < file_diff->hunk_nr) {
|
||||
if (file_diff->hunk_nr > 1) {
|
||||
permitted |= ALLOW_GOTO_NEXT_HUNK;
|
||||
strbuf_addstr(&s->buf, ",J");
|
||||
}
|
||||
@@ -1569,6 +1595,8 @@ soft_increment:
|
||||
if (hunk->use == UNDECIDED_HUNK)
|
||||
hunk->use = USE_HUNK;
|
||||
}
|
||||
if (!get_first_undecided(file_diff, &hunk_index))
|
||||
hunk_index = 0;
|
||||
} else if (hunk->use == UNDECIDED_HUNK) {
|
||||
hunk->use = USE_HUNK;
|
||||
}
|
||||
@@ -1579,6 +1607,8 @@ soft_increment:
|
||||
if (hunk->use == UNDECIDED_HUNK)
|
||||
hunk->use = SKIP_HUNK;
|
||||
}
|
||||
if (!get_first_undecided(file_diff, &hunk_index))
|
||||
hunk_index = 0;
|
||||
} else if (hunk->use == UNDECIDED_HUNK) {
|
||||
hunk->use = SKIP_HUNK;
|
||||
}
|
||||
@@ -1588,24 +1618,25 @@ soft_increment:
|
||||
}
|
||||
} else if (s->answer.buf[0] == 'K') {
|
||||
if (permitted & ALLOW_GOTO_PREVIOUS_HUNK)
|
||||
hunk_index--;
|
||||
hunk_index = dec_mod(hunk_index,
|
||||
file_diff->hunk_nr);
|
||||
else
|
||||
err(s, _("No previous hunk"));
|
||||
err(s, _("No other hunk"));
|
||||
} else if (s->answer.buf[0] == 'J') {
|
||||
if (permitted & ALLOW_GOTO_NEXT_HUNK)
|
||||
hunk_index++;
|
||||
else
|
||||
err(s, _("No next hunk"));
|
||||
err(s, _("No other hunk"));
|
||||
} else if (s->answer.buf[0] == 'k') {
|
||||
if (permitted & ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK)
|
||||
hunk_index = undecided_previous;
|
||||
else
|
||||
err(s, _("No previous hunk"));
|
||||
err(s, _("No other undecided hunk"));
|
||||
} else if (s->answer.buf[0] == 'j') {
|
||||
if (permitted & ALLOW_GOTO_NEXT_UNDECIDED_HUNK)
|
||||
hunk_index = undecided_next;
|
||||
else
|
||||
err(s, _("No next hunk"));
|
||||
err(s, _("No other undecided hunk"));
|
||||
} else if (s->answer.buf[0] == 'g') {
|
||||
char *pend;
|
||||
unsigned long response;
|
||||
|
||||
24
bisect.c
24
bisect.c
@@ -450,21 +450,20 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
|
||||
clear_commit_weight(&commit_weight);
|
||||
}
|
||||
|
||||
static int register_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags UNUSED, void *cb_data UNUSED)
|
||||
static int register_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct strbuf good_prefix = STRBUF_INIT;
|
||||
strbuf_addstr(&good_prefix, term_good);
|
||||
strbuf_addstr(&good_prefix, "-");
|
||||
|
||||
if (!strcmp(refname, term_bad)) {
|
||||
if (!strcmp(ref->name, term_bad)) {
|
||||
free(current_bad_oid);
|
||||
current_bad_oid = xmalloc(sizeof(*current_bad_oid));
|
||||
oidcpy(current_bad_oid, oid);
|
||||
} else if (starts_with(refname, good_prefix.buf)) {
|
||||
oid_array_append(&good_revs, oid);
|
||||
} else if (starts_with(refname, "skip-")) {
|
||||
oid_array_append(&skipped_revs, oid);
|
||||
oidcpy(current_bad_oid, ref->oid);
|
||||
} else if (starts_with(ref->name, good_prefix.buf)) {
|
||||
oid_array_append(&good_revs, ref->oid);
|
||||
} else if (starts_with(ref->name, "skip-")) {
|
||||
oid_array_append(&skipped_revs, ref->oid);
|
||||
}
|
||||
|
||||
strbuf_release(&good_prefix);
|
||||
@@ -1178,14 +1177,11 @@ int estimate_bisect_steps(int all)
|
||||
return (e < 3 * x) ? n : n - 1;
|
||||
}
|
||||
|
||||
static int mark_for_removal(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flag UNUSED, void *cb_data)
|
||||
static int mark_for_removal(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct string_list *refs = cb_data;
|
||||
char *ref = xstrfmt("refs/bisect%s", refname);
|
||||
string_list_append(refs, ref);
|
||||
char *bisect_ref = xstrfmt("refs/bisect%s", ref->name);
|
||||
string_list_append(refs, bisect_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -358,10 +358,7 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inc_nr(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flag UNUSED, void *cb_data)
|
||||
static int inc_nr(const struct reference *ref UNUSED, void *cb_data)
|
||||
{
|
||||
unsigned int *nr = (unsigned int *)cb_data;
|
||||
(*nr)++;
|
||||
@@ -549,12 +546,11 @@ finish:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int add_bisect_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags UNUSED, void *cb)
|
||||
static int add_bisect_ref(const struct reference *ref, void *cb)
|
||||
{
|
||||
struct add_bisect_ref_data *data = cb;
|
||||
|
||||
add_pending_oid(data->revs, refname, oid, data->object_flags);
|
||||
add_pending_oid(data->revs, ref->name, ref->oid, data->object_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1165,12 +1161,9 @@ static int bisect_visualize(struct bisect_terms *terms, int argc,
|
||||
return run_command(&cmd);
|
||||
}
|
||||
|
||||
static int get_first_good(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data)
|
||||
static int get_first_good(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
oidcpy(cb_data, oid);
|
||||
oidcpy(cb_data, ref->oid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -495,7 +495,7 @@ static void batch_object_write(const char *obj_name,
|
||||
OBJECT_INFO_LOOKUP_REPLACE);
|
||||
if (ret < 0) {
|
||||
if (data->mode == S_IFGITLINK)
|
||||
report_object_status(opt, oid_to_hex(&data->oid), &data->oid, "submodule");
|
||||
report_object_status(opt, NULL, &data->oid, "submodule");
|
||||
else
|
||||
report_object_status(opt, obj_name, &data->oid, "missing");
|
||||
return;
|
||||
|
||||
@@ -1063,11 +1063,9 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
|
||||
report_tracking(new_branch_info);
|
||||
}
|
||||
|
||||
static int add_pending_uninteresting_ref(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED, void *cb_data)
|
||||
static int add_pending_uninteresting_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
add_pending_oid(cb_data, refname, oid, UNINTERESTING);
|
||||
add_pending_oid(cb_data, ref->name, ref->oid, UNINTERESTING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -154,20 +154,19 @@ static void add_to_known_names(const char *path,
|
||||
}
|
||||
}
|
||||
|
||||
static int get_name(const char *path, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int get_name(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
int is_tag = 0;
|
||||
struct object_id peeled;
|
||||
int is_annotated, prio;
|
||||
const char *path_to_match = NULL;
|
||||
|
||||
if (skip_prefix(path, "refs/tags/", &path_to_match)) {
|
||||
if (skip_prefix(ref->name, "refs/tags/", &path_to_match)) {
|
||||
is_tag = 1;
|
||||
} else if (all) {
|
||||
if ((exclude_patterns.nr || patterns.nr) &&
|
||||
!skip_prefix(path, "refs/heads/", &path_to_match) &&
|
||||
!skip_prefix(path, "refs/remotes/", &path_to_match)) {
|
||||
!skip_prefix(ref->name, "refs/heads/", &path_to_match) &&
|
||||
!skip_prefix(ref->name, "refs/remotes/", &path_to_match)) {
|
||||
/* Only accept reference of known type if there are match/exclude patterns */
|
||||
return 0;
|
||||
}
|
||||
@@ -209,10 +208,10 @@ static int get_name(const char *path, const char *referent UNUSED, const struct
|
||||
}
|
||||
|
||||
/* Is it annotated? */
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled)) {
|
||||
is_annotated = !oideq(oid, &peeled);
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled)) {
|
||||
is_annotated = !oideq(ref->oid, &peeled);
|
||||
} else {
|
||||
oidcpy(&peeled, oid);
|
||||
oidcpy(&peeled, ref->oid);
|
||||
is_annotated = 0;
|
||||
}
|
||||
|
||||
@@ -229,7 +228,8 @@ static int get_name(const char *path, const char *referent UNUSED, const struct
|
||||
else
|
||||
prio = 0;
|
||||
|
||||
add_to_known_names(all ? path + 5 : path + 10, &peeled, prio, oid);
|
||||
add_to_known_names(all ? ref->name + 5 : ref->name + 10,
|
||||
&peeled, prio, ref->oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -289,13 +289,11 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
|
||||
return ent;
|
||||
}
|
||||
|
||||
static int add_one_refname(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag UNUSED, void *cbdata)
|
||||
static int add_one_refname(const struct reference *ref, void *cbdata)
|
||||
{
|
||||
struct hashmap *refname_map = cbdata;
|
||||
|
||||
(void) refname_hash_add(refname_map, refname, oid);
|
||||
(void) refname_hash_add(refname_map, ref->name, ref->oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1416,14 +1414,11 @@ static void set_option(struct transport *transport, const char *name, const char
|
||||
}
|
||||
|
||||
|
||||
static int add_oid(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED, void *cb_data)
|
||||
static int add_oid(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct oid_array *oids = cb_data;
|
||||
|
||||
oid_array_append(oids, oid);
|
||||
oid_array_append(oids, ref->oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -530,14 +530,13 @@ static int fsck_handle_reflog(const char *logname, void *cb_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_handle_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
obj = parse_object(the_repository, oid);
|
||||
obj = parse_object(the_repository, ref->oid);
|
||||
if (!obj) {
|
||||
if (is_promisor_object(the_repository, oid)) {
|
||||
if (is_promisor_object(the_repository, ref->oid)) {
|
||||
/*
|
||||
* Increment default_refs anyway, because this is a
|
||||
* valid ref.
|
||||
@@ -546,19 +545,19 @@ static int fsck_handle_ref(const char *refname, const char *referent UNUSED, con
|
||||
return 0;
|
||||
}
|
||||
error(_("%s: invalid sha1 pointer %s"),
|
||||
refname, oid_to_hex(oid));
|
||||
ref->name, oid_to_hex(ref->oid));
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
/* We'll continue with the rest despite the error.. */
|
||||
return 0;
|
||||
}
|
||||
if (obj->type != OBJ_COMMIT && is_branch(refname)) {
|
||||
error(_("%s: not a commit"), refname);
|
||||
if (obj->type != OBJ_COMMIT && is_branch(ref->name)) {
|
||||
error(_("%s: not a commit"), ref->name);
|
||||
errors_found |= ERROR_REFS;
|
||||
}
|
||||
default_refs++;
|
||||
obj->flags |= USED;
|
||||
fsck_put_object_name(&fsck_walk_options,
|
||||
oid, "%s", refname);
|
||||
ref->oid, "%s", ref->name);
|
||||
mark_object_reachable(obj);
|
||||
|
||||
return 0;
|
||||
@@ -580,13 +579,19 @@ static void get_default_heads(void)
|
||||
worktrees = get_worktrees();
|
||||
for (p = worktrees; *p; p++) {
|
||||
struct worktree *wt = *p;
|
||||
struct strbuf ref = STRBUF_INIT;
|
||||
struct strbuf refname = STRBUF_INIT;
|
||||
|
||||
strbuf_worktree_ref(wt, &ref, "HEAD");
|
||||
fsck_head_link(ref.buf, &head_points_at, &head_oid);
|
||||
if (head_points_at && !is_null_oid(&head_oid))
|
||||
fsck_handle_ref(ref.buf, NULL, &head_oid, 0, NULL);
|
||||
strbuf_release(&ref);
|
||||
strbuf_worktree_ref(wt, &refname, "HEAD");
|
||||
fsck_head_link(refname.buf, &head_points_at, &head_oid);
|
||||
if (head_points_at && !is_null_oid(&head_oid)) {
|
||||
struct reference ref = {
|
||||
.name = refname.buf,
|
||||
.oid = &head_oid,
|
||||
};
|
||||
|
||||
fsck_handle_ref(&ref, NULL);
|
||||
}
|
||||
strbuf_release(&refname);
|
||||
|
||||
if (include_reflogs)
|
||||
refs_for_each_reflog(get_worktree_ref_store(wt),
|
||||
|
||||
15
builtin/gc.c
15
builtin/gc.c
@@ -1100,24 +1100,21 @@ struct cg_auto_data {
|
||||
int limit;
|
||||
};
|
||||
|
||||
static int dfs_on_ref(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED,
|
||||
void *cb_data)
|
||||
static int dfs_on_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct cg_auto_data *data = (struct cg_auto_data *)cb_data;
|
||||
int result = 0;
|
||||
const struct object_id *maybe_peeled = ref->oid;
|
||||
struct object_id peeled;
|
||||
struct commit_list *stack = NULL;
|
||||
struct commit *commit;
|
||||
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled))
|
||||
oid = &peeled;
|
||||
if (odb_read_object_info(the_repository->objects, oid, NULL) != OBJ_COMMIT)
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled))
|
||||
maybe_peeled = &peeled;
|
||||
if (odb_read_object_info(the_repository->objects, maybe_peeled, NULL) != OBJ_COMMIT)
|
||||
return 0;
|
||||
|
||||
commit = lookup_commit(the_repository, oid);
|
||||
commit = lookup_commit(the_repository, maybe_peeled);
|
||||
if (!commit)
|
||||
return 0;
|
||||
if (repo_parse_commit(the_repository, commit) ||
|
||||
|
||||
@@ -156,7 +156,7 @@ int cmd_ls_remote(int argc,
|
||||
continue;
|
||||
if (!tail_match(&pattern, ref->name))
|
||||
continue;
|
||||
item = ref_array_push(&ref_array, ref->name, &ref->old_oid);
|
||||
item = ref_array_push(&ref_array, ref->name, &ref->old_oid, NULL);
|
||||
item->symref = xstrdup_or_null(ref->symref);
|
||||
}
|
||||
|
||||
|
||||
@@ -339,10 +339,9 @@ static int cmp_by_tag_and_age(const void *a_, const void *b_)
|
||||
return a->taggerdate != b->taggerdate;
|
||||
}
|
||||
|
||||
static int name_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags UNUSED, void *cb_data)
|
||||
static int name_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct object *o = parse_object(the_repository, oid);
|
||||
struct object *o = parse_object(the_repository, ref->oid);
|
||||
struct name_ref_data *data = cb_data;
|
||||
int can_abbreviate_output = data->tags_only && data->name_only;
|
||||
int deref = 0;
|
||||
@@ -350,14 +349,14 @@ static int name_ref(const char *path, const char *referent UNUSED, const struct
|
||||
struct commit *commit = NULL;
|
||||
timestamp_t taggerdate = TIME_MAX;
|
||||
|
||||
if (data->tags_only && !starts_with(path, "refs/tags/"))
|
||||
if (data->tags_only && !starts_with(ref->name, "refs/tags/"))
|
||||
return 0;
|
||||
|
||||
if (data->exclude_filters.nr) {
|
||||
struct string_list_item *item;
|
||||
|
||||
for_each_string_list_item(item, &data->exclude_filters) {
|
||||
if (subpath_matches(path, item->string) >= 0)
|
||||
if (subpath_matches(ref->name, item->string) >= 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -378,7 +377,7 @@ static int name_ref(const char *path, const char *referent UNUSED, const struct
|
||||
* shouldn't stop when seeing 'refs/tags/v1.4' matches
|
||||
* 'refs/tags/v*'. We should show it as 'v1.4'.
|
||||
*/
|
||||
switch (subpath_matches(path, item->string)) {
|
||||
switch (subpath_matches(ref->name, item->string)) {
|
||||
case -1: /* did not match */
|
||||
break;
|
||||
case 0: /* matched fully */
|
||||
@@ -406,13 +405,13 @@ static int name_ref(const char *path, const char *referent UNUSED, const struct
|
||||
}
|
||||
if (o && o->type == OBJ_COMMIT) {
|
||||
commit = (struct commit *)o;
|
||||
from_tag = starts_with(path, "refs/tags/");
|
||||
from_tag = starts_with(ref->name, "refs/tags/");
|
||||
if (taggerdate == TIME_MAX)
|
||||
taggerdate = commit->date;
|
||||
}
|
||||
|
||||
add_to_tip_table(oid, path, can_abbreviate_output, commit, taggerdate,
|
||||
from_tag, deref);
|
||||
add_to_tip_table(ref->oid, ref->name, can_abbreviate_output,
|
||||
commit, taggerdate, from_tag, deref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -831,15 +831,14 @@ static enum write_one_status write_one(struct hashfile *f,
|
||||
return WRITE_ONE_WRITTEN;
|
||||
}
|
||||
|
||||
static int mark_tagged(const char *path UNUSED, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int mark_tagged(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object_id peeled;
|
||||
struct object_entry *entry = packlist_find(&to_pack, oid);
|
||||
struct object_entry *entry = packlist_find(&to_pack, ref->oid);
|
||||
|
||||
if (entry)
|
||||
entry->tagged = 1;
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled)) {
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled)) {
|
||||
entry = packlist_find(&to_pack, &peeled);
|
||||
if (entry)
|
||||
entry->tagged = 1;
|
||||
@@ -3306,13 +3305,13 @@ static void add_tag_chain(const struct object_id *oid)
|
||||
}
|
||||
}
|
||||
|
||||
static int add_ref_tag(const char *tag UNUSED, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int add_ref_tag(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object_id peeled;
|
||||
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled) && obj_is_packed(&peeled))
|
||||
add_tag_chain(oid);
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled) &&
|
||||
obj_is_packed(&peeled))
|
||||
add_tag_chain(ref->oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4533,19 +4532,16 @@ static void record_recent_commit(struct commit *commit, void *data UNUSED)
|
||||
oid_array_append(&recent_objects, &commit->object.oid);
|
||||
}
|
||||
|
||||
static int mark_bitmap_preferred_tip(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED,
|
||||
void *data UNUSED)
|
||||
static int mark_bitmap_preferred_tip(const struct reference *ref, void *data UNUSED)
|
||||
{
|
||||
const struct object_id *maybe_peeled = ref->oid;
|
||||
struct object_id peeled;
|
||||
struct object *object;
|
||||
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled))
|
||||
oid = &peeled;
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled))
|
||||
maybe_peeled = &peeled;
|
||||
|
||||
object = parse_object_or_die(the_repository, oid, refname);
|
||||
object = parse_object_or_die(the_repository, maybe_peeled, ref->name);
|
||||
if (object->type == OBJ_COMMIT)
|
||||
object->flags |= NEEDS_BITMAP;
|
||||
|
||||
|
||||
@@ -305,13 +305,12 @@ static void show_ref(const char *path, const struct object_id *oid)
|
||||
}
|
||||
}
|
||||
|
||||
static int show_ref_cb(const char *path_full, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *data)
|
||||
static int show_ref_cb(const struct reference *ref, void *data)
|
||||
{
|
||||
struct oidset *seen = data;
|
||||
const char *path = strip_namespace(path_full);
|
||||
const char *path = strip_namespace(ref->name);
|
||||
|
||||
if (ref_is_hidden(path, path_full, &hidden_refs))
|
||||
if (ref_is_hidden(path, ref->name, &hidden_refs))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -320,13 +319,13 @@ static int show_ref_cb(const char *path_full, const char *referent UNUSED, const
|
||||
* transfer but will otherwise ignore them.
|
||||
*/
|
||||
if (!path) {
|
||||
if (oidset_insert(seen, oid))
|
||||
if (oidset_insert(seen, ref->oid))
|
||||
return 0;
|
||||
path = ".have";
|
||||
} else {
|
||||
oidset_insert(seen, oid);
|
||||
oidset_insert(seen, ref->oid);
|
||||
}
|
||||
show_ref(path, oid);
|
||||
show_ref(path, ref->oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -570,17 +570,14 @@ struct branches_for_remote {
|
||||
struct known_remotes *keep;
|
||||
};
|
||||
|
||||
static int add_branch_for_removal(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags UNUSED, void *cb_data)
|
||||
static int add_branch_for_removal(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct branches_for_remote *branches = cb_data;
|
||||
struct refspec_item refspec;
|
||||
struct known_remote *kr;
|
||||
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.dst = (char *)refname;
|
||||
refspec.dst = (char *)ref->name;
|
||||
if (remote_find_tracking(branches->remote, &refspec))
|
||||
return 0;
|
||||
free(refspec.src);
|
||||
@@ -588,7 +585,7 @@ static int add_branch_for_removal(const char *refname,
|
||||
/* don't delete a branch if another remote also uses it */
|
||||
for (kr = branches->keep->list; kr; kr = kr->next) {
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.dst = (char *)refname;
|
||||
refspec.dst = (char *)ref->name;
|
||||
if (!remote_find_tracking(kr->remote, &refspec)) {
|
||||
free(refspec.src);
|
||||
return 0;
|
||||
@@ -596,16 +593,16 @@ static int add_branch_for_removal(const char *refname,
|
||||
}
|
||||
|
||||
/* don't delete non-remote-tracking refs */
|
||||
if (!starts_with(refname, "refs/remotes/")) {
|
||||
if (!starts_with(ref->name, "refs/remotes/")) {
|
||||
/* advise user how to delete local branches */
|
||||
if (starts_with(refname, "refs/heads/"))
|
||||
if (starts_with(ref->name, "refs/heads/"))
|
||||
string_list_append(branches->skipped,
|
||||
abbrev_branch(refname));
|
||||
abbrev_branch(ref->name));
|
||||
/* silently skip over other non-remote refs */
|
||||
return 0;
|
||||
}
|
||||
|
||||
string_list_append(branches->branches, refname);
|
||||
string_list_append(branches->branches, ref->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -713,18 +710,18 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int rename_one_ref(const char *old_refname, const char *referent,
|
||||
const struct object_id *oid,
|
||||
int flags, void *cb_data)
|
||||
static int rename_one_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct strbuf new_referent = STRBUF_INIT;
|
||||
struct strbuf new_refname = STRBUF_INIT;
|
||||
struct rename_info *rename = cb_data;
|
||||
const struct object_id *oid = ref->oid;
|
||||
const char *referent = ref->target;
|
||||
int error;
|
||||
|
||||
compute_renamed_ref(rename, old_refname, &new_refname);
|
||||
compute_renamed_ref(rename, ref->name, &new_refname);
|
||||
|
||||
if (flags & REF_ISSYMREF) {
|
||||
if (ref->flags & REF_ISSYMREF) {
|
||||
/*
|
||||
* Stupidly enough `referent` is not pointing to the immediate
|
||||
* target of a symref, but it's the recursively resolved value.
|
||||
@@ -732,25 +729,25 @@ static int rename_one_ref(const char *old_refname, const char *referent,
|
||||
* unborn symrefs don't have any value for the `referent` at all.
|
||||
*/
|
||||
referent = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
|
||||
old_refname, RESOLVE_REF_NO_RECURSE,
|
||||
ref->name, RESOLVE_REF_NO_RECURSE,
|
||||
NULL, NULL);
|
||||
compute_renamed_ref(rename, referent, &new_referent);
|
||||
oid = NULL;
|
||||
}
|
||||
|
||||
error = ref_transaction_delete(rename->transaction, old_refname,
|
||||
error = ref_transaction_delete(rename->transaction, ref->name,
|
||||
oid, referent, REF_NO_DEREF, NULL, rename->err);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
|
||||
error = ref_transaction_update(rename->transaction, new_refname.buf, oid, null_oid(the_hash_algo),
|
||||
(flags & REF_ISSYMREF) ? new_referent.buf : NULL, NULL,
|
||||
(ref->flags & REF_ISSYMREF) ? new_referent.buf : NULL, NULL,
|
||||
REF_SKIP_CREATE_REFLOG | REF_NO_DEREF | REF_SKIP_OID_VERIFICATION,
|
||||
NULL, rename->err);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
|
||||
error = rename_one_reflog(old_refname, oid, rename);
|
||||
error = rename_one_reflog(ref->name, oid, rename);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
|
||||
@@ -1125,19 +1122,16 @@ static void free_remote_ref_states(struct ref_states *states)
|
||||
string_list_clear_func(&states->push, clear_push_info);
|
||||
}
|
||||
|
||||
static int append_ref_to_tracked_list(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags, void *cb_data)
|
||||
static int append_ref_to_tracked_list(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct ref_states *states = cb_data;
|
||||
struct refspec_item refspec;
|
||||
|
||||
if (flags & REF_ISSYMREF)
|
||||
if (ref->flags & REF_ISSYMREF)
|
||||
return 0;
|
||||
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.dst = (char *)refname;
|
||||
refspec.dst = (char *)ref->name;
|
||||
if (!remote_find_tracking(states->remote, &refspec)) {
|
||||
string_list_append(&states->tracked, abbrev_branch(refspec.src));
|
||||
free(refspec.src);
|
||||
|
||||
1356
builtin/repack.c
1356
builtin/repack.c
File diff suppressed because it is too large
Load Diff
@@ -47,30 +47,27 @@ struct show_data {
|
||||
enum replace_format format;
|
||||
};
|
||||
|
||||
static int show_reference(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data)
|
||||
static int show_reference(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct show_data *data = cb_data;
|
||||
|
||||
if (!wildmatch(data->pattern, refname, 0)) {
|
||||
if (!wildmatch(data->pattern, ref->name, 0)) {
|
||||
if (data->format == REPLACE_FORMAT_SHORT)
|
||||
printf("%s\n", refname);
|
||||
printf("%s\n", ref->name);
|
||||
else if (data->format == REPLACE_FORMAT_MEDIUM)
|
||||
printf("%s -> %s\n", refname, oid_to_hex(oid));
|
||||
printf("%s -> %s\n", ref->name, oid_to_hex(ref->oid));
|
||||
else { /* data->format == REPLACE_FORMAT_LONG */
|
||||
struct object_id object;
|
||||
enum object_type obj_type, repl_type;
|
||||
|
||||
if (repo_get_oid(data->repo, refname, &object))
|
||||
return error(_("failed to resolve '%s' as a valid ref"), refname);
|
||||
if (repo_get_oid(data->repo, ref->name, &object))
|
||||
return error(_("failed to resolve '%s' as a valid ref"), ref->name);
|
||||
|
||||
obj_type = odb_read_object_info(data->repo->objects, &object, NULL);
|
||||
repl_type = odb_read_object_info(data->repo->objects, oid, NULL);
|
||||
repl_type = odb_read_object_info(data->repo->objects, ref->oid, NULL);
|
||||
|
||||
printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
|
||||
oid_to_hex(oid), type_name(repl_type));
|
||||
printf("%s (%s) -> %s (%s)\n", ref->name, type_name(obj_type),
|
||||
oid_to_hex(ref->oid), type_name(repl_type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
377
builtin/repo.c
377
builtin/repo.c
@@ -3,19 +3,27 @@
|
||||
#include "builtin.h"
|
||||
#include "environment.h"
|
||||
#include "parse-options.h"
|
||||
#include "path-walk.h"
|
||||
#include "progress.h"
|
||||
#include "quote.h"
|
||||
#include "ref-filter.h"
|
||||
#include "refs.h"
|
||||
#include "revision.h"
|
||||
#include "strbuf.h"
|
||||
#include "string-list.h"
|
||||
#include "shallow.h"
|
||||
#include "utf8.h"
|
||||
|
||||
static const char *const repo_usage[] = {
|
||||
"git repo info [--format=(keyvalue|nul)] [-z] [<key>...]",
|
||||
"git repo structure [--format=(table|keyvalue|nul)]",
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
|
||||
|
||||
enum output_format {
|
||||
FORMAT_TABLE,
|
||||
FORMAT_KEYVALUE,
|
||||
FORMAT_NUL_TERMINATED,
|
||||
};
|
||||
@@ -130,14 +138,16 @@ static int parse_format_cb(const struct option *opt,
|
||||
*format = FORMAT_NUL_TERMINATED;
|
||||
else if (!strcmp(arg, "keyvalue"))
|
||||
*format = FORMAT_KEYVALUE;
|
||||
else if (!strcmp(arg, "table"))
|
||||
*format = FORMAT_TABLE;
|
||||
else
|
||||
die(_("invalid format '%s'"), arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int repo_info(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo)
|
||||
static int cmd_repo_info(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo)
|
||||
{
|
||||
enum output_format format = FORMAT_KEYVALUE;
|
||||
struct option options[] = {
|
||||
@@ -152,16 +162,377 @@ static int repo_info(int argc, const char **argv, const char *prefix,
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
|
||||
if (format != FORMAT_KEYVALUE && format != FORMAT_NUL_TERMINATED)
|
||||
die(_("unsupported output format"));
|
||||
|
||||
return print_fields(argc, argv, repo, format);
|
||||
}
|
||||
|
||||
struct ref_stats {
|
||||
size_t branches;
|
||||
size_t remotes;
|
||||
size_t tags;
|
||||
size_t others;
|
||||
};
|
||||
|
||||
struct object_stats {
|
||||
size_t tags;
|
||||
size_t commits;
|
||||
size_t trees;
|
||||
size_t blobs;
|
||||
};
|
||||
|
||||
struct repo_structure {
|
||||
struct ref_stats refs;
|
||||
struct object_stats objects;
|
||||
};
|
||||
|
||||
struct stats_table {
|
||||
struct string_list rows;
|
||||
|
||||
int name_col_width;
|
||||
int value_col_width;
|
||||
};
|
||||
|
||||
/*
|
||||
* Holds column data that gets stored for each row.
|
||||
*/
|
||||
struct stats_table_entry {
|
||||
char *value;
|
||||
};
|
||||
|
||||
static void stats_table_vaddf(struct stats_table *table,
|
||||
struct stats_table_entry *entry,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct string_list_item *item;
|
||||
char *formatted_name;
|
||||
int name_width;
|
||||
|
||||
strbuf_vaddf(&buf, format, ap);
|
||||
formatted_name = strbuf_detach(&buf, NULL);
|
||||
name_width = utf8_strwidth(formatted_name);
|
||||
|
||||
item = string_list_append_nodup(&table->rows, formatted_name);
|
||||
item->util = entry;
|
||||
|
||||
if (name_width > table->name_col_width)
|
||||
table->name_col_width = name_width;
|
||||
if (entry) {
|
||||
int value_width = utf8_strwidth(entry->value);
|
||||
if (value_width > table->value_col_width)
|
||||
table->value_col_width = value_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void stats_table_addf(struct stats_table *table, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
stats_table_vaddf(table, NULL, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void stats_table_count_addf(struct stats_table *table, size_t value,
|
||||
const char *format, ...)
|
||||
{
|
||||
struct stats_table_entry *entry;
|
||||
va_list ap;
|
||||
|
||||
CALLOC_ARRAY(entry, 1);
|
||||
entry->value = xstrfmt("%" PRIuMAX, (uintmax_t)value);
|
||||
|
||||
va_start(ap, format);
|
||||
stats_table_vaddf(table, entry, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static inline size_t get_total_reference_count(struct ref_stats *stats)
|
||||
{
|
||||
return stats->branches + stats->remotes + stats->tags + stats->others;
|
||||
}
|
||||
|
||||
static inline size_t get_total_object_count(struct object_stats *stats)
|
||||
{
|
||||
return stats->tags + stats->commits + stats->trees + stats->blobs;
|
||||
}
|
||||
|
||||
static void stats_table_setup_structure(struct stats_table *table,
|
||||
struct repo_structure *stats)
|
||||
{
|
||||
struct object_stats *objects = &stats->objects;
|
||||
struct ref_stats *refs = &stats->refs;
|
||||
size_t object_total;
|
||||
size_t ref_total;
|
||||
|
||||
ref_total = get_total_reference_count(refs);
|
||||
stats_table_addf(table, "* %s", _("References"));
|
||||
stats_table_count_addf(table, ref_total, " * %s", _("Count"));
|
||||
stats_table_count_addf(table, refs->branches, " * %s", _("Branches"));
|
||||
stats_table_count_addf(table, refs->tags, " * %s", _("Tags"));
|
||||
stats_table_count_addf(table, refs->remotes, " * %s", _("Remotes"));
|
||||
stats_table_count_addf(table, refs->others, " * %s", _("Others"));
|
||||
|
||||
object_total = get_total_object_count(objects);
|
||||
stats_table_addf(table, "");
|
||||
stats_table_addf(table, "* %s", _("Reachable objects"));
|
||||
stats_table_count_addf(table, object_total, " * %s", _("Count"));
|
||||
stats_table_count_addf(table, objects->commits, " * %s", _("Commits"));
|
||||
stats_table_count_addf(table, objects->trees, " * %s", _("Trees"));
|
||||
stats_table_count_addf(table, objects->blobs, " * %s", _("Blobs"));
|
||||
stats_table_count_addf(table, objects->tags, " * %s", _("Tags"));
|
||||
}
|
||||
|
||||
static void stats_table_print_structure(const struct stats_table *table)
|
||||
{
|
||||
const char *name_col_title = _("Repository structure");
|
||||
const char *value_col_title = _("Value");
|
||||
int name_col_width = utf8_strwidth(name_col_title);
|
||||
int value_col_width = utf8_strwidth(value_col_title);
|
||||
struct string_list_item *item;
|
||||
|
||||
if (table->name_col_width > name_col_width)
|
||||
name_col_width = table->name_col_width;
|
||||
if (table->value_col_width > value_col_width)
|
||||
value_col_width = table->value_col_width;
|
||||
|
||||
printf("| %-*s | %-*s |\n", name_col_width, name_col_title,
|
||||
value_col_width, value_col_title);
|
||||
printf("| ");
|
||||
for (int i = 0; i < name_col_width; i++)
|
||||
putchar('-');
|
||||
printf(" | ");
|
||||
for (int i = 0; i < value_col_width; i++)
|
||||
putchar('-');
|
||||
printf(" |\n");
|
||||
|
||||
for_each_string_list_item(item, &table->rows) {
|
||||
struct stats_table_entry *entry = item->util;
|
||||
const char *value = "";
|
||||
|
||||
if (entry) {
|
||||
struct stats_table_entry *entry = item->util;
|
||||
value = entry->value;
|
||||
}
|
||||
|
||||
printf("| %-*s | %*s |\n", name_col_width, item->string,
|
||||
value_col_width, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void stats_table_clear(struct stats_table *table)
|
||||
{
|
||||
struct stats_table_entry *entry;
|
||||
struct string_list_item *item;
|
||||
|
||||
for_each_string_list_item(item, &table->rows) {
|
||||
entry = item->util;
|
||||
if (entry)
|
||||
free(entry->value);
|
||||
}
|
||||
|
||||
string_list_clear(&table->rows, 1);
|
||||
}
|
||||
|
||||
static void structure_keyvalue_print(struct repo_structure *stats,
|
||||
char key_delim, char value_delim)
|
||||
{
|
||||
printf("references.branches.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->refs.branches, value_delim);
|
||||
printf("references.tags.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->refs.tags, value_delim);
|
||||
printf("references.remotes.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->refs.remotes, value_delim);
|
||||
printf("references.others.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->refs.others, value_delim);
|
||||
|
||||
printf("objects.commits.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->objects.commits, value_delim);
|
||||
printf("objects.trees.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->objects.trees, value_delim);
|
||||
printf("objects.blobs.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->objects.blobs, value_delim);
|
||||
printf("objects.tags.count%c%" PRIuMAX "%c", key_delim,
|
||||
(uintmax_t)stats->objects.tags, value_delim);
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
struct count_references_data {
|
||||
struct ref_stats *stats;
|
||||
struct rev_info *revs;
|
||||
struct progress *progress;
|
||||
};
|
||||
|
||||
static int count_references(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct count_references_data *data = cb_data;
|
||||
struct ref_stats *stats = data->stats;
|
||||
size_t ref_count;
|
||||
|
||||
switch (ref_kind_from_refname(ref->name)) {
|
||||
case FILTER_REFS_BRANCHES:
|
||||
stats->branches++;
|
||||
break;
|
||||
case FILTER_REFS_REMOTES:
|
||||
stats->remotes++;
|
||||
break;
|
||||
case FILTER_REFS_TAGS:
|
||||
stats->tags++;
|
||||
break;
|
||||
case FILTER_REFS_OTHERS:
|
||||
stats->others++;
|
||||
break;
|
||||
default:
|
||||
BUG("unexpected reference type");
|
||||
}
|
||||
|
||||
/*
|
||||
* While iterating through references for counting, also add OIDs in
|
||||
* preparation for the path walk.
|
||||
*/
|
||||
add_pending_oid(data->revs, NULL, ref->oid, 0);
|
||||
|
||||
ref_count = get_total_reference_count(stats);
|
||||
display_progress(data->progress, ref_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void structure_count_references(struct ref_stats *stats,
|
||||
struct rev_info *revs,
|
||||
struct repository *repo,
|
||||
int show_progress)
|
||||
{
|
||||
struct count_references_data data = {
|
||||
.stats = stats,
|
||||
.revs = revs,
|
||||
};
|
||||
|
||||
if (show_progress)
|
||||
data.progress = start_delayed_progress(repo,
|
||||
_("Counting references"), 0);
|
||||
|
||||
refs_for_each_ref(get_main_ref_store(repo), count_references, &data);
|
||||
stop_progress(&data.progress);
|
||||
}
|
||||
|
||||
struct count_objects_data {
|
||||
struct object_stats *stats;
|
||||
struct progress *progress;
|
||||
};
|
||||
|
||||
static int count_objects(const char *path UNUSED, struct oid_array *oids,
|
||||
enum object_type type, void *cb_data)
|
||||
{
|
||||
struct count_objects_data *data = cb_data;
|
||||
struct object_stats *stats = data->stats;
|
||||
size_t object_count;
|
||||
|
||||
switch (type) {
|
||||
case OBJ_TAG:
|
||||
stats->tags += oids->nr;
|
||||
break;
|
||||
case OBJ_COMMIT:
|
||||
stats->commits += oids->nr;
|
||||
break;
|
||||
case OBJ_TREE:
|
||||
stats->trees += oids->nr;
|
||||
break;
|
||||
case OBJ_BLOB:
|
||||
stats->blobs += oids->nr;
|
||||
break;
|
||||
default:
|
||||
BUG("invalid object type");
|
||||
}
|
||||
|
||||
object_count = get_total_object_count(stats);
|
||||
display_progress(data->progress, object_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void structure_count_objects(struct object_stats *stats,
|
||||
struct rev_info *revs,
|
||||
struct repository *repo, int show_progress)
|
||||
{
|
||||
struct path_walk_info info = PATH_WALK_INFO_INIT;
|
||||
struct count_objects_data data = {
|
||||
.stats = stats,
|
||||
};
|
||||
|
||||
info.revs = revs;
|
||||
info.path_fn = count_objects;
|
||||
info.path_fn_data = &data;
|
||||
|
||||
if (show_progress)
|
||||
data.progress = start_delayed_progress(repo, _("Counting objects"), 0);
|
||||
|
||||
walk_objects_by_path(&info);
|
||||
path_walk_info_clear(&info);
|
||||
stop_progress(&data.progress);
|
||||
}
|
||||
|
||||
static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo)
|
||||
{
|
||||
struct stats_table table = {
|
||||
.rows = STRING_LIST_INIT_DUP,
|
||||
};
|
||||
enum output_format format = FORMAT_TABLE;
|
||||
struct repo_structure stats = { 0 };
|
||||
struct rev_info revs;
|
||||
int show_progress = -1;
|
||||
struct option options[] = {
|
||||
OPT_CALLBACK_F(0, "format", &format, N_("format"),
|
||||
N_("output format"),
|
||||
PARSE_OPT_NONEG, parse_format_cb),
|
||||
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
|
||||
if (argc)
|
||||
usage(_("too many arguments"));
|
||||
|
||||
repo_init_revisions(repo, &revs, prefix);
|
||||
|
||||
if (show_progress < 0)
|
||||
show_progress = isatty(2);
|
||||
|
||||
structure_count_references(&stats.refs, &revs, repo, show_progress);
|
||||
structure_count_objects(&stats.objects, &revs, repo, show_progress);
|
||||
|
||||
switch (format) {
|
||||
case FORMAT_TABLE:
|
||||
stats_table_setup_structure(&table, &stats);
|
||||
stats_table_print_structure(&table);
|
||||
break;
|
||||
case FORMAT_KEYVALUE:
|
||||
structure_keyvalue_print(&stats, '=', '\n');
|
||||
break;
|
||||
case FORMAT_NUL_TERMINATED:
|
||||
structure_keyvalue_print(&stats, '\n', '\0');
|
||||
break;
|
||||
default:
|
||||
BUG("invalid output format");
|
||||
}
|
||||
|
||||
stats_table_clear(&table);
|
||||
release_revisions(&revs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_repo(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo)
|
||||
{
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option options[] = {
|
||||
OPT_SUBCOMMAND("info", &fn, repo_info),
|
||||
OPT_SUBCOMMAND("info", &fn, cmd_repo_info),
|
||||
OPT_SUBCOMMAND("structure", &fn, cmd_repo_structure),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
||||
@@ -217,19 +217,17 @@ static int show_default(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int show_reference(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
if (ref_excluded(&ref_excludes, refname))
|
||||
if (ref_excluded(&ref_excludes, ref->name))
|
||||
return 0;
|
||||
show_rev(NORMAL, oid, refname);
|
||||
show_rev(NORMAL, ref->oid, ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anti_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int anti_reference(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
show_rev(REVERSED, oid, refname);
|
||||
show_rev(REVERSED, ref->oid, ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -413,34 +413,32 @@ static int append_ref(const char *refname, const struct object_id *oid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int append_head_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object_id tmp;
|
||||
int ofs = 11;
|
||||
if (!starts_with(refname, "refs/heads/"))
|
||||
if (!starts_with(ref->name, "refs/heads/"))
|
||||
return 0;
|
||||
/* If both heads/foo and tags/foo exists, get_sha1 would
|
||||
* get confused.
|
||||
*/
|
||||
if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
|
||||
if (repo_get_oid(the_repository, ref->name + ofs, &tmp) || !oideq(&tmp, ref->oid))
|
||||
ofs = 5;
|
||||
return append_ref(refname + ofs, oid, 0);
|
||||
return append_ref(ref->name + ofs, ref->oid, 0);
|
||||
}
|
||||
|
||||
static int append_remote_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data UNUSED)
|
||||
static int append_remote_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object_id tmp;
|
||||
int ofs = 13;
|
||||
if (!starts_with(refname, "refs/remotes/"))
|
||||
if (!starts_with(ref->name, "refs/remotes/"))
|
||||
return 0;
|
||||
/* If both heads/foo and tags/foo exists, get_sha1 would
|
||||
* get confused.
|
||||
*/
|
||||
if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
|
||||
if (repo_get_oid(the_repository, ref->name + ofs, &tmp) || !oideq(&tmp, ref->oid))
|
||||
ofs = 5;
|
||||
return append_ref(refname + ofs, oid, 0);
|
||||
return append_ref(ref->name + ofs, ref->oid, 0);
|
||||
}
|
||||
|
||||
static int append_tag_ref(const char *refname, const struct object_id *oid,
|
||||
@@ -454,27 +452,26 @@ static int append_tag_ref(const char *refname, const struct object_id *oid,
|
||||
static const char *match_ref_pattern = NULL;
|
||||
static int match_ref_slash = 0;
|
||||
|
||||
static int append_matching_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag, void *cb_data)
|
||||
static int append_matching_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
/* we want to allow pattern hold/<asterisk> to show all
|
||||
* branches under refs/heads/hold/, and v0.99.9? to show
|
||||
* refs/tags/v0.99.9a and friends.
|
||||
*/
|
||||
const char *tail;
|
||||
int slash = count_slashes(refname);
|
||||
for (tail = refname; *tail && match_ref_slash < slash; )
|
||||
int slash = count_slashes(ref->name);
|
||||
for (tail = ref->name; *tail && match_ref_slash < slash; )
|
||||
if (*tail++ == '/')
|
||||
slash--;
|
||||
if (!*tail)
|
||||
return 0;
|
||||
if (wildmatch(match_ref_pattern, tail, 0))
|
||||
return 0;
|
||||
if (starts_with(refname, "refs/heads/"))
|
||||
return append_head_ref(refname, NULL, oid, flag, cb_data);
|
||||
if (starts_with(refname, "refs/tags/"))
|
||||
return append_tag_ref(refname, oid, flag, cb_data);
|
||||
return append_ref(refname, oid, 0);
|
||||
if (starts_with(ref->name, "refs/heads/"))
|
||||
return append_head_ref(ref, cb_data);
|
||||
if (starts_with(ref->name, "refs/tags/"))
|
||||
return append_tag_ref(ref->name, ref->oid, ref->flags, cb_data);
|
||||
return append_ref(ref->name, ref->oid, 0);
|
||||
}
|
||||
|
||||
static void snarf_refs(int head, int remotes)
|
||||
|
||||
@@ -31,31 +31,31 @@ struct show_one_options {
|
||||
};
|
||||
|
||||
static void show_one(const struct show_one_options *opts,
|
||||
const char *refname, const struct object_id *oid)
|
||||
const struct reference *ref)
|
||||
{
|
||||
const char *hex;
|
||||
struct object_id peeled;
|
||||
|
||||
if (!odb_has_object(the_repository->objects, oid,
|
||||
if (!odb_has_object(the_repository->objects, ref->oid,
|
||||
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
|
||||
die("git show-ref: bad ref %s (%s)", refname,
|
||||
oid_to_hex(oid));
|
||||
die("git show-ref: bad ref %s (%s)", ref->name,
|
||||
oid_to_hex(ref->oid));
|
||||
|
||||
if (opts->quiet)
|
||||
return;
|
||||
|
||||
hex = repo_find_unique_abbrev(the_repository, oid, opts->abbrev);
|
||||
hex = repo_find_unique_abbrev(the_repository, ref->oid, opts->abbrev);
|
||||
if (opts->hash_only)
|
||||
printf("%s\n", hex);
|
||||
else
|
||||
printf("%s %s\n", hex, refname);
|
||||
printf("%s %s\n", hex, ref->name);
|
||||
|
||||
if (!opts->deref_tags)
|
||||
return;
|
||||
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled)) {
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled)) {
|
||||
hex = repo_find_unique_abbrev(the_repository, &peeled, opts->abbrev);
|
||||
printf("%s %s^{}\n", hex, refname);
|
||||
printf("%s %s^{}\n", hex, ref->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,26 +66,25 @@ struct show_ref_data {
|
||||
int show_head;
|
||||
};
|
||||
|
||||
static int show_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cbdata)
|
||||
static int show_ref(const struct reference *ref, void *cbdata)
|
||||
{
|
||||
struct show_ref_data *data = cbdata;
|
||||
|
||||
if (data->show_head && !strcmp(refname, "HEAD"))
|
||||
if (data->show_head && !strcmp(ref->name, "HEAD"))
|
||||
goto match;
|
||||
|
||||
if (data->patterns) {
|
||||
int reflen = strlen(refname);
|
||||
int reflen = strlen(ref->name);
|
||||
const char **p = data->patterns, *m;
|
||||
while ((m = *p++) != NULL) {
|
||||
int len = strlen(m);
|
||||
if (len > reflen)
|
||||
continue;
|
||||
if (memcmp(m, refname + reflen - len, len))
|
||||
if (memcmp(m, ref->name + reflen - len, len))
|
||||
continue;
|
||||
if (len == reflen)
|
||||
goto match;
|
||||
if (refname[reflen - len - 1] == '/')
|
||||
if (ref->name[reflen - len - 1] == '/')
|
||||
goto match;
|
||||
}
|
||||
return 0;
|
||||
@@ -94,18 +93,15 @@ static int show_ref(const char *refname, const char *referent UNUSED, const stru
|
||||
match:
|
||||
data->found_match++;
|
||||
|
||||
show_one(data->show_one_opts, refname, oid);
|
||||
show_one(data->show_one_opts, ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_existing(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flag UNUSED, void *cbdata)
|
||||
static int add_existing(const struct reference *ref, void *cbdata)
|
||||
{
|
||||
struct string_list *list = (struct string_list *)cbdata;
|
||||
string_list_insert(list, refname);
|
||||
string_list_insert(list, ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -179,12 +175,18 @@ static int cmd_show_ref__verify(const struct show_one_options *show_one_opts,
|
||||
|
||||
if ((starts_with(*refs, "refs/") || refname_is_safe(*refs)) &&
|
||||
!refs_read_ref(get_main_ref_store(the_repository), *refs, &oid)) {
|
||||
show_one(show_one_opts, *refs, &oid);
|
||||
}
|
||||
else if (!show_one_opts->quiet)
|
||||
struct reference ref = {
|
||||
.name = *refs,
|
||||
.oid = &oid,
|
||||
};
|
||||
|
||||
show_one(show_one_opts, &ref);
|
||||
} else if (!show_one_opts->quiet) {
|
||||
die("'%s' - not a valid ref", *refs);
|
||||
else
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
refs++;
|
||||
}
|
||||
|
||||
|
||||
@@ -593,16 +593,12 @@ static void print_status(unsigned int flags, char state, const char *path,
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int handle_submodule_head_ref(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED,
|
||||
void *cb_data)
|
||||
static int handle_submodule_head_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct object_id *output = cb_data;
|
||||
|
||||
if (oid)
|
||||
oidcpy(output, oid);
|
||||
if (ref->oid)
|
||||
oidcpy(output, ref->oid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ static int verify_tag(const char *name, const char *ref UNUSED,
|
||||
return -1;
|
||||
|
||||
if (format->format)
|
||||
pretty_print_ref(name, oid, format);
|
||||
pretty_print_ref(name, oid, NULL, format);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ int cmd_verify_tag(int argc,
|
||||
}
|
||||
|
||||
if (format.format)
|
||||
pretty_print_ref(name, &oid, &format);
|
||||
pretty_print_ref(name, &oid, NULL, &format);
|
||||
}
|
||||
return had_error;
|
||||
}
|
||||
|
||||
@@ -635,11 +635,7 @@ static void print_preparing_worktree_line(int detach,
|
||||
*
|
||||
* Returns 0 on failure and non-zero on success.
|
||||
*/
|
||||
static int first_valid_ref(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags UNUSED,
|
||||
void *cb_data UNUSED)
|
||||
static int first_valid_ref(const struct reference *ref UNUSED, void *cb_data UNUSED)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
403
bulk-checkin.c
Normal file
403
bulk-checkin.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Google Inc.
|
||||
*/
|
||||
|
||||
#define USE_THE_REPOSITORY_VARIABLE
|
||||
|
||||
#include "git-compat-util.h"
|
||||
#include "bulk-checkin.h"
|
||||
#include "environment.h"
|
||||
#include "gettext.h"
|
||||
#include "hex.h"
|
||||
#include "lockfile.h"
|
||||
#include "repository.h"
|
||||
#include "csum-file.h"
|
||||
#include "pack.h"
|
||||
#include "strbuf.h"
|
||||
#include "tmp-objdir.h"
|
||||
#include "packfile.h"
|
||||
#include "object-file.h"
|
||||
#include "odb.h"
|
||||
|
||||
struct bulk_checkin_packfile {
|
||||
char *pack_tmp_name;
|
||||
struct hashfile *f;
|
||||
off_t offset;
|
||||
struct pack_idx_option pack_idx_opts;
|
||||
|
||||
struct pack_idx_entry **written;
|
||||
uint32_t alloc_written;
|
||||
uint32_t nr_written;
|
||||
};
|
||||
|
||||
struct odb_transaction {
|
||||
struct object_database *odb;
|
||||
|
||||
int nesting;
|
||||
struct tmp_objdir *objdir;
|
||||
struct bulk_checkin_packfile packfile;
|
||||
};
|
||||
|
||||
static void finish_tmp_packfile(struct odb_transaction *transaction,
|
||||
struct strbuf *basename,
|
||||
unsigned char hash[])
|
||||
{
|
||||
struct bulk_checkin_packfile *state = &transaction->packfile;
|
||||
struct repository *repo = transaction->odb->repo;
|
||||
char *idx_tmp_name = NULL;
|
||||
|
||||
stage_tmp_packfiles(repo, basename, state->pack_tmp_name,
|
||||
state->written, state->nr_written, NULL,
|
||||
&state->pack_idx_opts, hash, &idx_tmp_name);
|
||||
rename_tmp_packfile_idx(repo, basename, &idx_tmp_name);
|
||||
|
||||
free(idx_tmp_name);
|
||||
}
|
||||
|
||||
static void flush_bulk_checkin_packfile(struct odb_transaction *transaction)
|
||||
{
|
||||
struct bulk_checkin_packfile *state = &transaction->packfile;
|
||||
struct repository *repo = transaction->odb->repo;
|
||||
unsigned char hash[GIT_MAX_RAWSZ];
|
||||
struct strbuf packname = STRBUF_INIT;
|
||||
|
||||
if (!state->f)
|
||||
return;
|
||||
|
||||
if (state->nr_written == 0) {
|
||||
close(state->f->fd);
|
||||
free_hashfile(state->f);
|
||||
unlink(state->pack_tmp_name);
|
||||
goto clear_exit;
|
||||
} else if (state->nr_written == 1) {
|
||||
finalize_hashfile(state->f, hash, FSYNC_COMPONENT_PACK,
|
||||
CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
|
||||
} else {
|
||||
int fd = finalize_hashfile(state->f, hash, FSYNC_COMPONENT_PACK, 0);
|
||||
fixup_pack_header_footer(repo->hash_algo, fd, hash, state->pack_tmp_name,
|
||||
state->nr_written, hash,
|
||||
state->offset);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
strbuf_addf(&packname, "%s/pack/pack-%s.",
|
||||
repo_get_object_directory(transaction->odb->repo),
|
||||
hash_to_hex_algop(hash, repo->hash_algo));
|
||||
|
||||
finish_tmp_packfile(transaction, &packname, hash);
|
||||
for (uint32_t i = 0; i < state->nr_written; i++)
|
||||
free(state->written[i]);
|
||||
|
||||
clear_exit:
|
||||
free(state->pack_tmp_name);
|
||||
free(state->written);
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
||||
strbuf_release(&packname);
|
||||
/* Make objects we just wrote available to ourselves */
|
||||
odb_reprepare(repo->objects);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup after batch-mode fsync_object_files.
|
||||
*/
|
||||
static void flush_batch_fsync(struct odb_transaction *transaction)
|
||||
{
|
||||
struct strbuf temp_path = STRBUF_INIT;
|
||||
struct tempfile *temp;
|
||||
|
||||
if (!transaction->objdir)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Issue a full hardware flush against a temporary file to ensure
|
||||
* that all objects are durable before any renames occur. The code in
|
||||
* fsync_loose_object_bulk_checkin has already issued a writeout
|
||||
* request, but it has not flushed any writeback cache in the storage
|
||||
* hardware or any filesystem logs. This fsync call acts as a barrier
|
||||
* to ensure that the data in each new object file is durable before
|
||||
* the final name is visible.
|
||||
*/
|
||||
strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX",
|
||||
repo_get_object_directory(transaction->odb->repo));
|
||||
temp = xmks_tempfile(temp_path.buf);
|
||||
fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
|
||||
delete_tempfile(&temp);
|
||||
strbuf_release(&temp_path);
|
||||
|
||||
/*
|
||||
* Make the object files visible in the primary ODB after their data is
|
||||
* fully durable.
|
||||
*/
|
||||
tmp_objdir_migrate(transaction->objdir);
|
||||
transaction->objdir = NULL;
|
||||
}
|
||||
|
||||
static int already_written(struct odb_transaction *transaction,
|
||||
struct object_id *oid)
|
||||
{
|
||||
/* The object may already exist in the repository */
|
||||
if (odb_has_object(transaction->odb, oid,
|
||||
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
|
||||
return 1;
|
||||
|
||||
/* Might want to keep the list sorted */
|
||||
for (uint32_t i = 0; i < transaction->packfile.nr_written; i++)
|
||||
if (oideq(&transaction->packfile.written[i]->oid, oid))
|
||||
return 1;
|
||||
|
||||
/* This is a new object we need to keep */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the contents from fd for size bytes, streaming it to the
|
||||
* packfile in state while updating the hash in ctx. Signal a failure
|
||||
* by returning a negative value when the resulting pack would exceed
|
||||
* the pack size limit and this is not the first object in the pack,
|
||||
* so that the caller can discard what we wrote from the current pack
|
||||
* by truncating it and opening a new one. The caller will then call
|
||||
* us again after rewinding the input fd.
|
||||
*
|
||||
* The already_hashed_to pointer is kept untouched by the caller to
|
||||
* make sure we do not hash the same byte when we are called
|
||||
* again. This way, the caller does not have to checkpoint its hash
|
||||
* status before calling us just in case we ask it to call us again
|
||||
* with a new pack.
|
||||
*/
|
||||
static int stream_blob_to_pack(struct bulk_checkin_packfile *state,
|
||||
struct git_hash_ctx *ctx, off_t *already_hashed_to,
|
||||
int fd, size_t size, const char *path,
|
||||
unsigned flags)
|
||||
{
|
||||
git_zstream s;
|
||||
unsigned char ibuf[16384];
|
||||
unsigned char obuf[16384];
|
||||
unsigned hdrlen;
|
||||
int status = Z_OK;
|
||||
int write_object = (flags & INDEX_WRITE_OBJECT);
|
||||
off_t offset = 0;
|
||||
|
||||
git_deflate_init(&s, pack_compression_level);
|
||||
|
||||
hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);
|
||||
s.next_out = obuf + hdrlen;
|
||||
s.avail_out = sizeof(obuf) - hdrlen;
|
||||
|
||||
while (status != Z_STREAM_END) {
|
||||
if (size && !s.avail_in) {
|
||||
size_t rsize = size < sizeof(ibuf) ? size : sizeof(ibuf);
|
||||
ssize_t read_result = read_in_full(fd, ibuf, rsize);
|
||||
if (read_result < 0)
|
||||
die_errno("failed to read from '%s'", path);
|
||||
if ((size_t)read_result != rsize)
|
||||
die("failed to read %u bytes from '%s'",
|
||||
(unsigned)rsize, path);
|
||||
offset += rsize;
|
||||
if (*already_hashed_to < offset) {
|
||||
size_t hsize = offset - *already_hashed_to;
|
||||
if (rsize < hsize)
|
||||
hsize = rsize;
|
||||
if (hsize)
|
||||
git_hash_update(ctx, ibuf, hsize);
|
||||
*already_hashed_to = offset;
|
||||
}
|
||||
s.next_in = ibuf;
|
||||
s.avail_in = rsize;
|
||||
size -= rsize;
|
||||
}
|
||||
|
||||
status = git_deflate(&s, size ? 0 : Z_FINISH);
|
||||
|
||||
if (!s.avail_out || status == Z_STREAM_END) {
|
||||
if (write_object) {
|
||||
size_t written = s.next_out - obuf;
|
||||
|
||||
/* would we bust the size limit? */
|
||||
if (state->nr_written &&
|
||||
pack_size_limit_cfg &&
|
||||
pack_size_limit_cfg < state->offset + written) {
|
||||
git_deflate_abort(&s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hashwrite(state->f, obuf, written);
|
||||
state->offset += written;
|
||||
}
|
||||
s.next_out = obuf;
|
||||
s.avail_out = sizeof(obuf);
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
case Z_BUF_ERROR:
|
||||
case Z_STREAM_END:
|
||||
continue;
|
||||
default:
|
||||
die("unexpected deflate failure: %d", status);
|
||||
}
|
||||
}
|
||||
git_deflate_end(&s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lazily create backing packfile for the state */
|
||||
static void prepare_to_stream(struct odb_transaction *transaction,
|
||||
unsigned flags)
|
||||
{
|
||||
struct bulk_checkin_packfile *state = &transaction->packfile;
|
||||
if (!(flags & INDEX_WRITE_OBJECT) || state->f)
|
||||
return;
|
||||
|
||||
state->f = create_tmp_packfile(transaction->odb->repo,
|
||||
&state->pack_tmp_name);
|
||||
reset_pack_idx_option(&state->pack_idx_opts);
|
||||
|
||||
/* Pretend we are going to write only one object */
|
||||
state->offset = write_pack_header(state->f, 1);
|
||||
if (!state->offset)
|
||||
die_errno("unable to write pack header");
|
||||
}
|
||||
|
||||
int index_blob_bulk_checkin(struct odb_transaction *transaction,
|
||||
struct object_id *result_oid, int fd, size_t size,
|
||||
const char *path, unsigned flags)
|
||||
{
|
||||
struct bulk_checkin_packfile *state = &transaction->packfile;
|
||||
off_t seekback, already_hashed_to;
|
||||
struct git_hash_ctx ctx;
|
||||
unsigned char obuf[16384];
|
||||
unsigned header_len;
|
||||
struct hashfile_checkpoint checkpoint;
|
||||
struct pack_idx_entry *idx = NULL;
|
||||
|
||||
seekback = lseek(fd, 0, SEEK_CUR);
|
||||
if (seekback == (off_t) -1)
|
||||
return error("cannot find the current offset");
|
||||
|
||||
header_len = format_object_header((char *)obuf, sizeof(obuf),
|
||||
OBJ_BLOB, size);
|
||||
transaction->odb->repo->hash_algo->init_fn(&ctx);
|
||||
git_hash_update(&ctx, obuf, header_len);
|
||||
|
||||
/* Note: idx is non-NULL when we are writing */
|
||||
if ((flags & INDEX_WRITE_OBJECT) != 0) {
|
||||
CALLOC_ARRAY(idx, 1);
|
||||
|
||||
prepare_to_stream(transaction, flags);
|
||||
hashfile_checkpoint_init(state->f, &checkpoint);
|
||||
}
|
||||
|
||||
already_hashed_to = 0;
|
||||
|
||||
while (1) {
|
||||
prepare_to_stream(transaction, flags);
|
||||
if (idx) {
|
||||
hashfile_checkpoint(state->f, &checkpoint);
|
||||
idx->offset = state->offset;
|
||||
crc32_begin(state->f);
|
||||
}
|
||||
if (!stream_blob_to_pack(state, &ctx, &already_hashed_to,
|
||||
fd, size, path, flags))
|
||||
break;
|
||||
/*
|
||||
* Writing this object to the current pack will make
|
||||
* it too big; we need to truncate it, start a new
|
||||
* pack, and write into it.
|
||||
*/
|
||||
if (!idx)
|
||||
BUG("should not happen");
|
||||
hashfile_truncate(state->f, &checkpoint);
|
||||
state->offset = checkpoint.offset;
|
||||
flush_bulk_checkin_packfile(transaction);
|
||||
if (lseek(fd, seekback, SEEK_SET) == (off_t) -1)
|
||||
return error("cannot seek back");
|
||||
}
|
||||
git_hash_final_oid(result_oid, &ctx);
|
||||
if (!idx)
|
||||
return 0;
|
||||
|
||||
idx->crc32 = crc32_end(state->f);
|
||||
if (already_written(transaction, result_oid)) {
|
||||
hashfile_truncate(state->f, &checkpoint);
|
||||
state->offset = checkpoint.offset;
|
||||
free(idx);
|
||||
} else {
|
||||
oidcpy(&idx->oid, result_oid);
|
||||
ALLOC_GROW(state->written,
|
||||
state->nr_written + 1,
|
||||
state->alloc_written);
|
||||
state->written[state->nr_written++] = idx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void prepare_loose_object_bulk_checkin(struct odb_transaction *transaction)
|
||||
{
|
||||
/*
|
||||
* We lazily create the temporary object directory
|
||||
* the first time an object might be added, since
|
||||
* callers may not know whether any objects will be
|
||||
* added at the time they call begin_odb_transaction.
|
||||
*/
|
||||
if (!transaction || transaction->objdir)
|
||||
return;
|
||||
|
||||
transaction->objdir = tmp_objdir_create(transaction->odb->repo, "bulk-fsync");
|
||||
if (transaction->objdir)
|
||||
tmp_objdir_replace_primary_odb(transaction->objdir, 0);
|
||||
}
|
||||
|
||||
void fsync_loose_object_bulk_checkin(struct odb_transaction *transaction,
|
||||
int fd, const char *filename)
|
||||
{
|
||||
/*
|
||||
* If we have an active ODB transaction, we issue a call that
|
||||
* cleans the filesystem page cache but avoids a hardware flush
|
||||
* command. Later on we will issue a single hardware flush
|
||||
* before renaming the objects to their final names as part of
|
||||
* flush_batch_fsync.
|
||||
*/
|
||||
if (!transaction || !transaction->objdir ||
|
||||
git_fsync(fd, FSYNC_WRITEOUT_ONLY) < 0) {
|
||||
if (errno == ENOSYS)
|
||||
warning(_("core.fsyncMethod = batch is unsupported on this platform"));
|
||||
fsync_or_die(fd, filename);
|
||||
}
|
||||
}
|
||||
|
||||
struct odb_transaction *begin_odb_transaction(struct object_database *odb)
|
||||
{
|
||||
if (!odb->transaction) {
|
||||
CALLOC_ARRAY(odb->transaction, 1);
|
||||
odb->transaction->odb = odb;
|
||||
}
|
||||
|
||||
odb->transaction->nesting += 1;
|
||||
|
||||
return odb->transaction;
|
||||
}
|
||||
|
||||
void flush_odb_transaction(struct odb_transaction *transaction)
|
||||
{
|
||||
if (!transaction)
|
||||
return;
|
||||
|
||||
flush_batch_fsync(transaction);
|
||||
flush_bulk_checkin_packfile(transaction);
|
||||
}
|
||||
|
||||
void end_odb_transaction(struct odb_transaction *transaction)
|
||||
{
|
||||
if (!transaction || transaction->nesting == 0)
|
||||
BUG("Unbalanced ODB transaction nesting");
|
||||
|
||||
transaction->nesting -= 1;
|
||||
|
||||
if (transaction->nesting)
|
||||
return;
|
||||
|
||||
flush_odb_transaction(transaction);
|
||||
transaction->odb->transaction = NULL;
|
||||
free(transaction);
|
||||
}
|
||||
@@ -1851,18 +1851,16 @@ struct refs_cb_data {
|
||||
struct progress *progress;
|
||||
};
|
||||
|
||||
static int add_ref_to_set(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED, void *cb_data)
|
||||
static int add_ref_to_set(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
const struct object_id *maybe_peeled = ref->oid;
|
||||
struct object_id peeled;
|
||||
struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
|
||||
|
||||
if (!peel_iterated_oid(data->repo, oid, &peeled))
|
||||
oid = &peeled;
|
||||
if (odb_read_object_info(data->repo->objects, oid, NULL) == OBJ_COMMIT)
|
||||
oidset_insert(data->commits, oid);
|
||||
if (!reference_get_peeled_oid(data->repo, ref, &peeled))
|
||||
maybe_peeled = &peeled;
|
||||
if (odb_read_object_info(data->repo->objects, maybe_peeled, NULL) == OBJ_COMMIT)
|
||||
oidset_insert(data->commits, maybe_peeled);
|
||||
|
||||
display_progress(data->progress, oidset_size(data->commits));
|
||||
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
#define USE_THE_REPOSITORY_VARIABLE
|
||||
#define DISABLE_SIGN_COMPARE_WARNINGS
|
||||
|
||||
#include "../git-compat-util.h"
|
||||
#include "win32.h"
|
||||
#include <aclapi.h>
|
||||
#include <sddl.h>
|
||||
#include <conio.h>
|
||||
#include <wchar.h>
|
||||
#include "../strbuf.h"
|
||||
#include "../run-command.h"
|
||||
#include "../abspath.h"
|
||||
#include "../alloc.h"
|
||||
#include "win32/lazyload.h"
|
||||
#include "../config.h"
|
||||
#include "../environment.h"
|
||||
#include "../trace2.h"
|
||||
#include "../symlinks.h"
|
||||
#include "../wrapper.h"
|
||||
#include "git-compat-util.h"
|
||||
#include "abspath.h"
|
||||
#include "alloc.h"
|
||||
#include "config.h"
|
||||
#include "dir.h"
|
||||
#include "environment.h"
|
||||
#include "gettext.h"
|
||||
#include "run-command.h"
|
||||
#include "strbuf.h"
|
||||
#include "symlinks.h"
|
||||
#include "trace2.h"
|
||||
#include "win32.h"
|
||||
#include "win32/lazyload.h"
|
||||
#include "wrapper.h"
|
||||
#include <aclapi.h>
|
||||
#include <conio.h>
|
||||
#include <sddl.h>
|
||||
#define SECURITY_WIN32
|
||||
#include <sspi.h>
|
||||
#include <wchar.h>
|
||||
#include <winternl.h>
|
||||
|
||||
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056)
|
||||
|
||||
@@ -390,8 +390,7 @@ static void add_ref_to_island(kh_str_t *remote_islands, const char *island_name,
|
||||
rl->hash += sha_core;
|
||||
}
|
||||
|
||||
static int find_island_for_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags UNUSED, void *cb)
|
||||
static int find_island_for_ref(const struct reference *ref, void *cb)
|
||||
{
|
||||
struct island_load_data *ild = cb;
|
||||
|
||||
@@ -406,7 +405,7 @@ static int find_island_for_ref(const char *refname, const char *referent UNUSED,
|
||||
|
||||
/* walk backwards to get last-one-wins ordering */
|
||||
for (i = ild->nr - 1; i >= 0; i--) {
|
||||
if (!regexec(&ild->rx[i], refname,
|
||||
if (!regexec(&ild->rx[i], ref->name,
|
||||
ARRAY_SIZE(matches), matches, 0))
|
||||
break;
|
||||
}
|
||||
@@ -428,10 +427,10 @@ static int find_island_for_ref(const char *refname, const char *referent UNUSED,
|
||||
if (island_name.len)
|
||||
strbuf_addch(&island_name, '-');
|
||||
|
||||
strbuf_add(&island_name, refname + match->rm_so, match->rm_eo - match->rm_so);
|
||||
strbuf_add(&island_name, ref->name + match->rm_so, match->rm_eo - match->rm_so);
|
||||
}
|
||||
|
||||
add_ref_to_island(ild->remote_islands, island_name.buf, oid);
|
||||
add_ref_to_island(ild->remote_islands, island_name.buf, ref->oid);
|
||||
strbuf_release(&island_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,30 +21,21 @@
|
||||
|
||||
static int read_directory_contents(const char *path, struct string_list *list,
|
||||
const struct pathspec *pathspec,
|
||||
int skip)
|
||||
struct strbuf *match)
|
||||
{
|
||||
struct strbuf match = STRBUF_INIT;
|
||||
int len;
|
||||
int len = match->len;
|
||||
DIR *dir;
|
||||
struct dirent *e;
|
||||
|
||||
if (!(dir = opendir(path)))
|
||||
return error("Could not open directory %s", path);
|
||||
|
||||
if (pathspec) {
|
||||
strbuf_addstr(&match, path);
|
||||
strbuf_complete(&match, '/');
|
||||
strbuf_remove(&match, 0, skip);
|
||||
|
||||
len = match.len;
|
||||
}
|
||||
|
||||
while ((e = readdir_skip_dot_and_dotdot(dir))) {
|
||||
if (pathspec) {
|
||||
int is_dir = 0;
|
||||
|
||||
strbuf_setlen(&match, len);
|
||||
strbuf_addstr(&match, e->d_name);
|
||||
strbuf_setlen(match, len);
|
||||
strbuf_addstr(match, e->d_name);
|
||||
if (NOT_CONSTANT(DTYPE(e)) != DT_UNKNOWN) {
|
||||
is_dir = (DTYPE(e) == DT_DIR);
|
||||
} else {
|
||||
@@ -57,7 +48,7 @@ static int read_directory_contents(const char *path, struct string_list *list,
|
||||
}
|
||||
|
||||
if (!match_leading_pathspec(NULL, pathspec,
|
||||
match.buf, match.len,
|
||||
match->buf, match->len,
|
||||
0, NULL, is_dir))
|
||||
continue;
|
||||
}
|
||||
@@ -65,7 +56,7 @@ static int read_directory_contents(const char *path, struct string_list *list,
|
||||
string_list_insert(list, e->d_name);
|
||||
}
|
||||
|
||||
strbuf_release(&match);
|
||||
strbuf_setlen(match, len);
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
@@ -169,7 +160,8 @@ static struct diff_filespec *noindex_filespec(const struct git_hash_algo *algop,
|
||||
|
||||
static int queue_diff(struct diff_options *o, const struct git_hash_algo *algop,
|
||||
const char *name1, const char *name2, int recursing,
|
||||
const struct pathspec *ps, int skip1, int skip2)
|
||||
const struct pathspec *ps,
|
||||
struct strbuf *ps_match1, struct strbuf *ps_match2)
|
||||
{
|
||||
int mode1 = 0, mode2 = 0;
|
||||
enum special special1 = SPECIAL_NONE, special2 = SPECIAL_NONE;
|
||||
@@ -208,10 +200,12 @@ static int queue_diff(struct diff_options *o, const struct git_hash_algo *algop,
|
||||
struct string_list p2 = STRING_LIST_INIT_DUP;
|
||||
int i1, i2, ret = 0;
|
||||
size_t len1 = 0, len2 = 0;
|
||||
size_t match1_len = ps_match1->len;
|
||||
size_t match2_len = ps_match2->len;
|
||||
|
||||
if (name1 && read_directory_contents(name1, &p1, ps, skip1))
|
||||
if (name1 && read_directory_contents(name1, &p1, ps, ps_match1))
|
||||
return -1;
|
||||
if (name2 && read_directory_contents(name2, &p2, ps, skip2)) {
|
||||
if (name2 && read_directory_contents(name2, &p2, ps, ps_match2)) {
|
||||
string_list_clear(&p1, 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -235,6 +229,11 @@ static int queue_diff(struct diff_options *o, const struct git_hash_algo *algop,
|
||||
strbuf_setlen(&buffer1, len1);
|
||||
strbuf_setlen(&buffer2, len2);
|
||||
|
||||
if (ps) {
|
||||
strbuf_setlen(ps_match1, match1_len);
|
||||
strbuf_setlen(ps_match2, match2_len);
|
||||
}
|
||||
|
||||
if (i1 == p1.nr)
|
||||
comp = 1;
|
||||
else if (i2 == p2.nr)
|
||||
@@ -245,18 +244,28 @@ static int queue_diff(struct diff_options *o, const struct git_hash_algo *algop,
|
||||
if (comp > 0)
|
||||
n1 = NULL;
|
||||
else {
|
||||
strbuf_addstr(&buffer1, p1.items[i1++].string);
|
||||
strbuf_addstr(&buffer1, p1.items[i1].string);
|
||||
if (ps) {
|
||||
strbuf_addstr(ps_match1, p1.items[i1].string);
|
||||
strbuf_complete(ps_match1, '/');
|
||||
}
|
||||
n1 = buffer1.buf;
|
||||
i1++;
|
||||
}
|
||||
|
||||
if (comp < 0)
|
||||
n2 = NULL;
|
||||
else {
|
||||
strbuf_addstr(&buffer2, p2.items[i2++].string);
|
||||
strbuf_addstr(&buffer2, p2.items[i2].string);
|
||||
if (ps) {
|
||||
strbuf_addstr(ps_match2, p2.items[i2].string);
|
||||
strbuf_complete(ps_match2, '/');
|
||||
}
|
||||
n2 = buffer2.buf;
|
||||
i2++;
|
||||
}
|
||||
|
||||
ret = queue_diff(o, algop, n1, n2, 1, ps, skip1, skip2);
|
||||
ret = queue_diff(o, algop, n1, n2, 1, ps, ps_match1, ps_match2);
|
||||
}
|
||||
string_list_clear(&p1, 0);
|
||||
string_list_clear(&p2, 0);
|
||||
@@ -346,7 +355,8 @@ int diff_no_index(struct rev_info *revs, const struct git_hash_algo *algop,
|
||||
int implicit_no_index, int argc, const char **argv)
|
||||
{
|
||||
struct pathspec pathspec, *ps = NULL;
|
||||
int i, no_index, skip1 = 0, skip2 = 0;
|
||||
struct strbuf ps_match1 = STRBUF_INIT, ps_match2 = STRBUF_INIT;
|
||||
int i, no_index;
|
||||
int ret = 1;
|
||||
const char *paths[2];
|
||||
char *to_free[ARRAY_SIZE(paths)] = { 0 };
|
||||
@@ -387,11 +397,6 @@ int diff_no_index(struct rev_info *revs, const struct git_hash_algo *algop,
|
||||
NULL, &argv[2]);
|
||||
if (pathspec.nr)
|
||||
ps = &pathspec;
|
||||
|
||||
skip1 = strlen(paths[0]);
|
||||
skip1 += paths[0][skip1] == '/' ? 0 : 1;
|
||||
skip2 = strlen(paths[1]);
|
||||
skip2 += paths[1][skip2] == '/' ? 0 : 1;
|
||||
} else if (argc > 2) {
|
||||
warning(_("Limiting comparison with pathspecs is only "
|
||||
"supported if both paths are directories."));
|
||||
@@ -415,7 +420,7 @@ int diff_no_index(struct rev_info *revs, const struct git_hash_algo *algop,
|
||||
revs->diffopt.flags.exit_with_status = 1;
|
||||
|
||||
if (queue_diff(&revs->diffopt, algop, paths[0], paths[1], 0, ps,
|
||||
skip1, skip2))
|
||||
&ps_match1, &ps_match2))
|
||||
goto out;
|
||||
diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
|
||||
diffcore_std(&revs->diffopt);
|
||||
@@ -431,6 +436,8 @@ out:
|
||||
for (i = 0; i < ARRAY_SIZE(to_free); i++)
|
||||
free(to_free[i]);
|
||||
strbuf_release(&replacement);
|
||||
strbuf_release(&ps_match1);
|
||||
strbuf_release(&ps_match2);
|
||||
if (ps)
|
||||
clear_pathspec(ps);
|
||||
return ret;
|
||||
|
||||
16
fetch-pack.c
16
fetch-pack.c
@@ -188,13 +188,9 @@ static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rev_list_insert_ref_oid(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data)
|
||||
static int rev_list_insert_ref_oid(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
return rev_list_insert_ref(cb_data, oid);
|
||||
return rev_list_insert_ref(cb_data, ref->oid);
|
||||
}
|
||||
|
||||
enum ack_type {
|
||||
@@ -616,13 +612,9 @@ static int mark_complete(const struct object_id *oid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mark_complete_oid(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data UNUSED)
|
||||
static int mark_complete_oid(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
return mark_complete(oid);
|
||||
return mark_complete(ref->oid);
|
||||
}
|
||||
|
||||
static void mark_recent_complete_commits(struct fetch_pack_args *args,
|
||||
|
||||
10
help.c
10
help.c
@@ -851,18 +851,16 @@ struct similar_ref_cb {
|
||||
struct string_list *similar_refs;
|
||||
};
|
||||
|
||||
static int append_similar_ref(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags UNUSED, void *cb_data)
|
||||
static int append_similar_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
|
||||
char *branch = strrchr(refname, '/') + 1;
|
||||
char *branch = strrchr(ref->name, '/') + 1;
|
||||
|
||||
/* A remote branch of the same name is deemed similar */
|
||||
if (starts_with(refname, "refs/remotes/") &&
|
||||
if (starts_with(ref->name, "refs/remotes/") &&
|
||||
!strcmp(branch, cb->base_ref))
|
||||
string_list_append_nodup(cb->similar_refs,
|
||||
refs_shorten_unambiguous_ref(get_main_ref_store(the_repository), refname, 1));
|
||||
refs_shorten_unambiguous_ref(get_main_ref_store(the_repository), ref->name, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -513,18 +513,17 @@ static void run_service(const char **argv, int buffer_input)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int show_text_ref(const char *name, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data)
|
||||
static int show_text_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
const char *name_nons = strip_namespace(name);
|
||||
const char *name_nons = strip_namespace(ref->name);
|
||||
struct strbuf *buf = cb_data;
|
||||
struct object *o = parse_object(the_repository, oid);
|
||||
struct object *o = parse_object(the_repository, ref->oid);
|
||||
if (!o)
|
||||
return 0;
|
||||
|
||||
strbuf_addf(buf, "%s\t%s\n", oid_to_hex(oid), name_nons);
|
||||
strbuf_addf(buf, "%s\t%s\n", oid_to_hex(ref->oid), name_nons);
|
||||
if (o->type == OBJ_TAG) {
|
||||
o = deref_tag(the_repository, o, name, 0);
|
||||
o = deref_tag(the_repository, o, ref->name, 0);
|
||||
if (!o)
|
||||
return 0;
|
||||
strbuf_addf(buf, "%s\t%s^{}\n", oid_to_hex(&o->oid),
|
||||
@@ -569,21 +568,20 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
static int show_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag, void *cb_data)
|
||||
static int show_head_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct strbuf *buf = cb_data;
|
||||
|
||||
if (flag & REF_ISSYMREF) {
|
||||
if (ref->flags & REF_ISSYMREF) {
|
||||
const char *target = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
|
||||
refname,
|
||||
ref->name,
|
||||
RESOLVE_REF_READING,
|
||||
NULL, NULL);
|
||||
|
||||
if (target)
|
||||
strbuf_addf(buf, "ref: %s\n", strip_namespace(target));
|
||||
} else {
|
||||
strbuf_addf(buf, "%s\n", oid_to_hex(oid));
|
||||
strbuf_addf(buf, "%s\n", oid_to_hex(ref->oid));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
24
log-tree.c
24
log-tree.c
@@ -147,9 +147,7 @@ static int ref_filter_match(const char *refname,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int add_ref_decoration(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags UNUSED,
|
||||
void *cb_data)
|
||||
static int add_ref_decoration(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
int i;
|
||||
struct object *obj;
|
||||
@@ -158,16 +156,16 @@ static int add_ref_decoration(const char *refname, const char *referent UNUSED,
|
||||
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
|
||||
const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
|
||||
|
||||
if (filter && !ref_filter_match(refname, filter))
|
||||
if (filter && !ref_filter_match(ref->name, filter))
|
||||
return 0;
|
||||
|
||||
if (starts_with(refname, git_replace_ref_base)) {
|
||||
if (starts_with(ref->name, git_replace_ref_base)) {
|
||||
struct object_id original_oid;
|
||||
if (!replace_refs_enabled(the_repository))
|
||||
return 0;
|
||||
if (get_oid_hex(refname + strlen(git_replace_ref_base),
|
||||
if (get_oid_hex(ref->name + strlen(git_replace_ref_base),
|
||||
&original_oid)) {
|
||||
warning("invalid replace ref %s", refname);
|
||||
warning("invalid replace ref %s", ref->name);
|
||||
return 0;
|
||||
}
|
||||
obj = parse_object(the_repository, &original_oid);
|
||||
@@ -176,10 +174,10 @@ static int add_ref_decoration(const char *refname, const char *referent UNUSED,
|
||||
return 0;
|
||||
}
|
||||
|
||||
objtype = odb_read_object_info(the_repository->objects, oid, NULL);
|
||||
objtype = odb_read_object_info(the_repository->objects, ref->oid, NULL);
|
||||
if (objtype < 0)
|
||||
return 0;
|
||||
obj = lookup_object_by_type(the_repository, oid, objtype);
|
||||
obj = lookup_object_by_type(the_repository, ref->oid, objtype);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
|
||||
struct ref_namespace_info *info = &ref_namespace[i];
|
||||
@@ -187,24 +185,24 @@ static int add_ref_decoration(const char *refname, const char *referent UNUSED,
|
||||
if (!info->decoration)
|
||||
continue;
|
||||
if (info->exact) {
|
||||
if (!strcmp(refname, info->ref)) {
|
||||
if (!strcmp(ref->name, info->ref)) {
|
||||
deco_type = info->decoration;
|
||||
break;
|
||||
}
|
||||
} else if (starts_with(refname, info->ref)) {
|
||||
} else if (starts_with(ref->name, info->ref)) {
|
||||
deco_type = info->decoration;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
add_name_decoration(deco_type, refname, obj);
|
||||
add_name_decoration(deco_type, ref->name, obj);
|
||||
while (obj->type == OBJ_TAG) {
|
||||
if (!obj->parsed)
|
||||
parse_object(the_repository, &obj->oid);
|
||||
obj = ((struct tag *)obj)->tagged;
|
||||
if (!obj)
|
||||
break;
|
||||
add_name_decoration(DECORATION_REF_TAG, refname, obj);
|
||||
add_name_decoration(DECORATION_REF_TAG, ref->name, obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
36
ls-refs.c
36
ls-refs.c
@@ -75,42 +75,42 @@ struct ls_refs_data {
|
||||
unsigned unborn : 1;
|
||||
};
|
||||
|
||||
static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag, void *cb_data)
|
||||
static int send_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct ls_refs_data *data = cb_data;
|
||||
const char *refname_nons = strip_namespace(refname);
|
||||
const char *refname_nons = strip_namespace(ref->name);
|
||||
|
||||
strbuf_reset(&data->buf);
|
||||
|
||||
if (ref_is_hidden(refname_nons, refname, &data->hidden_refs))
|
||||
if (ref_is_hidden(refname_nons, ref->name, &data->hidden_refs))
|
||||
return 0;
|
||||
|
||||
if (!ref_match(&data->prefixes, refname_nons))
|
||||
return 0;
|
||||
|
||||
if (oid)
|
||||
strbuf_addf(&data->buf, "%s %s", oid_to_hex(oid), refname_nons);
|
||||
if (ref->oid)
|
||||
strbuf_addf(&data->buf, "%s %s", oid_to_hex(ref->oid), refname_nons);
|
||||
else
|
||||
strbuf_addf(&data->buf, "unborn %s", refname_nons);
|
||||
if (data->symrefs && flag & REF_ISSYMREF) {
|
||||
if (data->symrefs && ref->flags & REF_ISSYMREF) {
|
||||
int unused_flag;
|
||||
struct object_id unused;
|
||||
const char *symref_target = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
|
||||
refname,
|
||||
ref->name,
|
||||
0,
|
||||
&unused,
|
||||
&flag);
|
||||
&unused_flag);
|
||||
|
||||
if (!symref_target)
|
||||
die("'%s' is a symref but it is not?", refname);
|
||||
die("'%s' is a symref but it is not?", ref->name);
|
||||
|
||||
strbuf_addf(&data->buf, " symref-target:%s",
|
||||
strip_namespace(symref_target));
|
||||
}
|
||||
|
||||
if (data->peel && oid) {
|
||||
if (data->peel && ref->oid) {
|
||||
struct object_id peeled;
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled))
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled))
|
||||
strbuf_addf(&data->buf, " peeled:%s", oid_to_hex(&peeled));
|
||||
}
|
||||
|
||||
@@ -131,9 +131,17 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
|
||||
if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), namespaced.buf, 0, &oid, &flag))
|
||||
return; /* bad ref */
|
||||
oid_is_null = is_null_oid(&oid);
|
||||
|
||||
if (!oid_is_null ||
|
||||
(data->unborn && data->symrefs && (flag & REF_ISSYMREF)))
|
||||
send_ref(namespaced.buf, NULL, oid_is_null ? NULL : &oid, flag, data);
|
||||
(data->unborn && data->symrefs && (flag & REF_ISSYMREF))) {
|
||||
struct reference ref = {
|
||||
.name = namespaced.buf,
|
||||
.oid = oid_is_null ? NULL : &oid,
|
||||
.flags = flag,
|
||||
};
|
||||
|
||||
send_ref(&ref, data);
|
||||
}
|
||||
strbuf_release(&namespaced);
|
||||
}
|
||||
|
||||
|
||||
@@ -463,6 +463,12 @@ libgit_sources = [
|
||||
'reftable/tree.c',
|
||||
'reftable/writer.c',
|
||||
'remote.c',
|
||||
'repack.c',
|
||||
'repack-cruft.c',
|
||||
'repack-filtered.c',
|
||||
'repack-geometry.c',
|
||||
'repack-midx.c',
|
||||
'repack-promisor.c',
|
||||
'replace-object.c',
|
||||
'repo-settings.c',
|
||||
'repository.c',
|
||||
|
||||
17
midx-write.c
17
midx-write.c
@@ -697,28 +697,27 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
|
||||
trace2_region_leave("midx", "prepare_midx_packing_data", ctx->repo);
|
||||
}
|
||||
|
||||
static int add_ref_to_pending(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag, void *cb_data)
|
||||
static int add_ref_to_pending(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct rev_info *revs = (struct rev_info*)cb_data;
|
||||
const struct object_id *maybe_peeled = ref->oid;
|
||||
struct object_id peeled;
|
||||
struct object *object;
|
||||
|
||||
if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
|
||||
warning("symbolic ref is dangling: %s", refname);
|
||||
if ((ref->flags & REF_ISSYMREF) && (ref->flags & REF_ISBROKEN)) {
|
||||
warning("symbolic ref is dangling: %s", ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!peel_iterated_oid(revs->repo, oid, &peeled))
|
||||
oid = &peeled;
|
||||
if (!reference_get_peeled_oid(revs->repo, ref, &peeled))
|
||||
maybe_peeled = &peeled;
|
||||
|
||||
object = parse_object_or_die(revs->repo, oid, refname);
|
||||
object = parse_object_or_die(revs->repo, maybe_peeled, ref->name);
|
||||
if (object->type != OBJ_COMMIT)
|
||||
return 0;
|
||||
|
||||
add_pending_object(revs, object, "");
|
||||
if (bitmap_is_preferred_refname(revs->repo, refname))
|
||||
if (bitmap_is_preferred_refname(revs->repo, ref->name))
|
||||
object->flags |= NEEDS_BITMAP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,11 +38,10 @@ static void rev_list_push(struct negotiation_state *ns,
|
||||
}
|
||||
}
|
||||
|
||||
static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data UNUSED)
|
||||
static int clear_marks(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
|
||||
struct object *o = deref_tag(the_repository, parse_object(the_repository, ref->oid),
|
||||
ref->name, 0);
|
||||
|
||||
if (o && o->type == OBJ_COMMIT)
|
||||
clear_commit_marks((struct commit *)o,
|
||||
|
||||
@@ -75,11 +75,10 @@ static struct entry *rev_list_push(struct data *data, struct commit *commit, int
|
||||
return entry;
|
||||
}
|
||||
|
||||
static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data UNUSED)
|
||||
static int clear_marks(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
|
||||
struct object *o = deref_tag(the_repository, parse_object(the_repository, ref->oid),
|
||||
ref->name, 0);
|
||||
|
||||
if (o && o->type == OBJ_COMMIT)
|
||||
clear_commit_marks((struct commit *)o,
|
||||
|
||||
8
notes.c
8
notes.c
@@ -938,13 +938,11 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int string_list_add_one_ref(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flag UNUSED, void *cb)
|
||||
static int string_list_add_one_ref(const struct reference *ref, void *cb)
|
||||
{
|
||||
struct string_list *refs = cb;
|
||||
if (!unsorted_string_list_has_string(refs, refname))
|
||||
string_list_append(refs, refname);
|
||||
if (!unsorted_string_list_has_string(refs, ref->name))
|
||||
string_list_append(refs, ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1444,18 +1444,16 @@ struct handle_one_ref_cb {
|
||||
struct commit_list **list;
|
||||
};
|
||||
|
||||
static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data)
|
||||
static int handle_one_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct handle_one_ref_cb *cb = cb_data;
|
||||
struct commit_list **list = cb->list;
|
||||
struct object *object = parse_object(cb->repo, oid);
|
||||
struct object *object = parse_object(cb->repo, ref->oid);
|
||||
if (!object)
|
||||
return 0;
|
||||
if (object->type == OBJ_TAG) {
|
||||
object = deref_tag(cb->repo, object, path,
|
||||
strlen(path));
|
||||
object = deref_tag(cb->repo, object, ref->name,
|
||||
strlen(ref->name));
|
||||
if (!object)
|
||||
return 0;
|
||||
}
|
||||
|
||||
20
object.c
20
object.c
@@ -209,11 +209,12 @@ struct object *lookup_object_by_type(struct repository *r,
|
||||
|
||||
enum peel_status peel_object(struct repository *r,
|
||||
const struct object_id *name,
|
||||
struct object_id *oid)
|
||||
struct object_id *oid,
|
||||
unsigned flags)
|
||||
{
|
||||
struct object *o = lookup_unknown_object(r, name);
|
||||
|
||||
if (o->type == OBJ_NONE) {
|
||||
if (o->type == OBJ_NONE || flags & PEEL_OBJECT_VERIFY_OBJECT_TYPE) {
|
||||
int type = odb_read_object_info(r->objects, name, NULL);
|
||||
if (type < 0 || !object_as_type(o, type, 0))
|
||||
return PEEL_INVALID;
|
||||
@@ -222,7 +223,20 @@ enum peel_status peel_object(struct repository *r,
|
||||
if (o->type != OBJ_TAG)
|
||||
return PEEL_NON_TAG;
|
||||
|
||||
o = deref_tag_noverify(r, o);
|
||||
while (o && o->type == OBJ_TAG) {
|
||||
o = parse_object(r, &o->oid);
|
||||
if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged) {
|
||||
o = ((struct tag *)o)->tagged;
|
||||
|
||||
if (flags & PEEL_OBJECT_VERIFY_OBJECT_TYPE) {
|
||||
int type = odb_read_object_info(r->objects, &o->oid, NULL);
|
||||
if (type < 0 || !object_as_type(o, type, 0))
|
||||
return PEEL_INVALID;
|
||||
}
|
||||
} else {
|
||||
o = NULL;
|
||||
}
|
||||
}
|
||||
if (!o)
|
||||
return PEEL_INVALID;
|
||||
|
||||
|
||||
15
object.h
15
object.h
@@ -287,6 +287,17 @@ enum peel_status {
|
||||
PEEL_BROKEN = -4
|
||||
};
|
||||
|
||||
enum peel_object_flags {
|
||||
/*
|
||||
* Always verify the object type, even in the case where the looked-up
|
||||
* object already has an object type. This can be useful when the
|
||||
* stored object type may be invalid. One such case is when looking up
|
||||
* objects via tags, where we blindly trust the object type declared by
|
||||
* the tag.
|
||||
*/
|
||||
PEEL_OBJECT_VERIFY_OBJECT_TYPE = (1 << 0),
|
||||
};
|
||||
|
||||
/*
|
||||
* Peel the named object; i.e., if the object is a tag, resolve the
|
||||
* tag recursively until a non-tag is found. If successful, store the
|
||||
@@ -295,7 +306,9 @@ enum peel_status {
|
||||
* and leave oid unchanged.
|
||||
*/
|
||||
enum peel_status peel_object(struct repository *r,
|
||||
const struct object_id *name, struct object_id *oid);
|
||||
const struct object_id *name,
|
||||
struct object_id *oid,
|
||||
unsigned flags);
|
||||
|
||||
struct object_list *object_list_insert(struct object *item,
|
||||
struct object_list **list_p);
|
||||
|
||||
@@ -221,28 +221,25 @@ void load_pseudo_merges_from_config(struct repository *r,
|
||||
}
|
||||
}
|
||||
|
||||
static int find_pseudo_merge_group_for_ref(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED,
|
||||
void *_data)
|
||||
static int find_pseudo_merge_group_for_ref(const struct reference *ref, void *_data)
|
||||
{
|
||||
struct bitmap_writer *writer = _data;
|
||||
const struct object_id *maybe_peeled = ref->oid;
|
||||
struct object_id peeled;
|
||||
struct commit *c;
|
||||
uint32_t i;
|
||||
int has_bitmap;
|
||||
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled))
|
||||
oid = &peeled;
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled))
|
||||
maybe_peeled = &peeled;
|
||||
|
||||
c = lookup_commit(the_repository, oid);
|
||||
c = lookup_commit(the_repository, maybe_peeled);
|
||||
if (!c)
|
||||
return 0;
|
||||
if (!packlist_find(writer->to_pack, oid))
|
||||
if (!packlist_find(writer->to_pack, maybe_peeled))
|
||||
return 0;
|
||||
|
||||
has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, oid);
|
||||
has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, maybe_peeled);
|
||||
|
||||
for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
|
||||
struct pseudo_merge_group *group;
|
||||
@@ -252,7 +249,7 @@ static int find_pseudo_merge_group_for_ref(const char *refname,
|
||||
size_t j;
|
||||
|
||||
group = writer->pseudo_merge_groups.items[i].util;
|
||||
if (regexec(group->pattern, refname, ARRAY_SIZE(captures),
|
||||
if (regexec(group->pattern, ref->name, ARRAY_SIZE(captures),
|
||||
captures, 0))
|
||||
continue;
|
||||
|
||||
@@ -269,7 +266,7 @@ static int find_pseudo_merge_group_for_ref(const char *refname,
|
||||
if (group_name.len)
|
||||
strbuf_addch(&group_name, '-');
|
||||
|
||||
strbuf_add(&group_name, refname + match->rm_so,
|
||||
strbuf_add(&group_name, ref->name + match->rm_so,
|
||||
match->rm_eo - match->rm_so);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,18 +83,17 @@ static void add_rebase_files(struct rev_info *revs)
|
||||
free_worktrees(worktrees);
|
||||
}
|
||||
|
||||
static int add_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag, void *cb_data)
|
||||
static int add_one_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct rev_info *revs = (struct rev_info *)cb_data;
|
||||
struct object *object;
|
||||
|
||||
if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
|
||||
warning("symbolic ref is dangling: %s", path);
|
||||
if ((ref->flags & REF_ISSYMREF) && (ref->flags & REF_ISBROKEN)) {
|
||||
warning("symbolic ref is dangling: %s", ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
object = parse_object_or_die(the_repository, oid, path);
|
||||
object = parse_object_or_die(the_repository, ref->oid, ref->name);
|
||||
add_pending_object(revs, object, "");
|
||||
|
||||
return 0;
|
||||
|
||||
235
ref-filter.c
235
ref-filter.c
@@ -91,6 +91,7 @@ static struct expand_data {
|
||||
struct object_id delta_base_oid;
|
||||
void *content;
|
||||
|
||||
struct object *maybe_object;
|
||||
struct object_info info;
|
||||
} oi, oi_deref;
|
||||
|
||||
@@ -1475,11 +1476,29 @@ static void grab_common_values(struct atom_value *val, int deref, struct expand_
|
||||
}
|
||||
}
|
||||
|
||||
/* See grab_values */
|
||||
static void grab_tag_values(struct atom_value *val, int deref, struct object *obj)
|
||||
static struct object *get_or_parse_object(struct expand_data *data, const char *refname,
|
||||
struct strbuf *err, int *eaten)
|
||||
{
|
||||
if (!data->maybe_object) {
|
||||
data->maybe_object = parse_object_buffer(the_repository, &data->oid, data->type,
|
||||
data->size, data->content, eaten);
|
||||
if (!data->maybe_object) {
|
||||
strbuf_addf(err, _("parse_object_buffer failed on %s for %s"),
|
||||
oid_to_hex(&data->oid), refname);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return data->maybe_object;
|
||||
}
|
||||
|
||||
/* See grab_values */
|
||||
static int grab_tag_values(struct atom_value *val, int deref,
|
||||
struct expand_data *data, const char *refname,
|
||||
struct strbuf *err, int *eaten)
|
||||
{
|
||||
struct tag *tag = NULL;
|
||||
int i;
|
||||
struct tag *tag = (struct tag *) obj;
|
||||
|
||||
for (i = 0; i < used_atom_cnt; i++) {
|
||||
const char *name = used_atom[i].name;
|
||||
@@ -1487,6 +1506,14 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob
|
||||
struct atom_value *v = &val[i];
|
||||
if (!!deref != (*name == '*'))
|
||||
continue;
|
||||
|
||||
if (!tag) {
|
||||
tag = (struct tag *) get_or_parse_object(data, refname,
|
||||
err, eaten);
|
||||
if (!tag)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (deref)
|
||||
name++;
|
||||
if (atom_type == ATOM_TAG)
|
||||
@@ -1496,22 +1523,35 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob
|
||||
else if (atom_type == ATOM_OBJECT && tag->tagged)
|
||||
v->s = xstrdup(oid_to_hex(&tag->tagged->oid));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See grab_values */
|
||||
static void grab_commit_values(struct atom_value *val, int deref, struct object *obj)
|
||||
static int grab_commit_values(struct atom_value *val, int deref,
|
||||
struct expand_data *data, const char *refname,
|
||||
struct strbuf *err, int *eaten)
|
||||
{
|
||||
int i;
|
||||
struct commit *commit = (struct commit *) obj;
|
||||
struct commit *commit = NULL;
|
||||
|
||||
for (i = 0; i < used_atom_cnt; i++) {
|
||||
const char *name = used_atom[i].name;
|
||||
enum atom_type atom_type = used_atom[i].atom_type;
|
||||
struct atom_value *v = &val[i];
|
||||
|
||||
if (!!deref != (*name == '*'))
|
||||
continue;
|
||||
if (deref)
|
||||
name++;
|
||||
|
||||
if (!commit) {
|
||||
commit = (struct commit *) get_or_parse_object(data, refname,
|
||||
err, eaten);
|
||||
if (!commit)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (atom_type == ATOM_TREE &&
|
||||
grab_oid(name, "tree", get_commit_tree_oid(commit), v, &used_atom[i]))
|
||||
continue;
|
||||
@@ -1531,6 +1571,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object
|
||||
v->s = strbuf_detach(&s, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *find_wholine(const char *who, int wholen, const char *buf)
|
||||
@@ -1759,10 +1801,12 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
|
||||
}
|
||||
}
|
||||
|
||||
static void grab_signature(struct atom_value *val, int deref, struct object *obj)
|
||||
static int grab_signature(struct atom_value *val, int deref,
|
||||
struct expand_data *data, const char *refname,
|
||||
struct strbuf *err, int *eaten)
|
||||
{
|
||||
int i;
|
||||
struct commit *commit = (struct commit *) obj;
|
||||
struct commit *commit = NULL;
|
||||
struct signature_check sigc = { 0 };
|
||||
int signature_checked = 0;
|
||||
|
||||
@@ -1790,6 +1834,13 @@ static void grab_signature(struct atom_value *val, int deref, struct object *obj
|
||||
continue;
|
||||
|
||||
if (!signature_checked) {
|
||||
if (!commit) {
|
||||
commit = (struct commit *) get_or_parse_object(data, refname,
|
||||
err, eaten);
|
||||
if (!commit)
|
||||
return -1;
|
||||
}
|
||||
|
||||
check_commit_signature(commit, &sigc);
|
||||
signature_checked = 1;
|
||||
}
|
||||
@@ -1843,6 +1894,8 @@ static void grab_signature(struct atom_value *val, int deref, struct object *obj
|
||||
|
||||
if (signature_checked)
|
||||
signature_check_clear(&sigc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void find_subpos(const char *buf,
|
||||
@@ -1920,9 +1973,8 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
|
||||
}
|
||||
|
||||
static void grab_describe_values(struct atom_value *val, int deref,
|
||||
struct object *obj)
|
||||
struct expand_data *data)
|
||||
{
|
||||
struct commit *commit = (struct commit *)obj;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < used_atom_cnt; i++) {
|
||||
@@ -1944,7 +1996,7 @@ static void grab_describe_values(struct atom_value *val, int deref,
|
||||
cmd.git_cmd = 1;
|
||||
strvec_push(&cmd.args, "describe");
|
||||
strvec_pushv(&cmd.args, atom->u.describe_args.v);
|
||||
strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
|
||||
strvec_push(&cmd.args, oid_to_hex(&data->oid));
|
||||
if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
|
||||
error(_("failed to run 'describe'"));
|
||||
v->s = xstrdup("");
|
||||
@@ -2066,24 +2118,36 @@ static void fill_missing_values(struct atom_value *val)
|
||||
* pointed at by the ref itself; otherwise it is the object the
|
||||
* ref (which is a tag) refers to.
|
||||
*/
|
||||
static void grab_values(struct atom_value *val, int deref, struct object *obj, struct expand_data *data)
|
||||
static int grab_values(struct atom_value *val, int deref, struct expand_data *data,
|
||||
const char *refname, struct strbuf *err, int *eaten)
|
||||
{
|
||||
void *buf = data->content;
|
||||
int ret;
|
||||
|
||||
switch (obj->type) {
|
||||
switch (data->type) {
|
||||
case OBJ_TAG:
|
||||
grab_tag_values(val, deref, obj);
|
||||
ret = grab_tag_values(val, deref, data, refname, err, eaten);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
grab_sub_body_contents(val, deref, data);
|
||||
grab_person("tagger", val, deref, buf);
|
||||
grab_describe_values(val, deref, obj);
|
||||
grab_describe_values(val, deref, data);
|
||||
break;
|
||||
case OBJ_COMMIT:
|
||||
grab_commit_values(val, deref, obj);
|
||||
ret = grab_commit_values(val, deref, data, refname, err, eaten);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
grab_sub_body_contents(val, deref, data);
|
||||
grab_person("author", val, deref, buf);
|
||||
grab_person("committer", val, deref, buf);
|
||||
grab_signature(val, deref, obj);
|
||||
grab_describe_values(val, deref, obj);
|
||||
|
||||
ret = grab_signature(val, deref, data, refname, err, eaten);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
grab_describe_values(val, deref, data);
|
||||
break;
|
||||
case OBJ_TREE:
|
||||
/* grab_tree_values(val, deref, obj, buf, sz); */
|
||||
@@ -2094,8 +2158,12 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, s
|
||||
grab_sub_body_contents(val, deref, data);
|
||||
break;
|
||||
default:
|
||||
die("Eh? Object of type %d?", obj->type);
|
||||
die("Eh? Object of type %d?", data->type);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline char *copy_advance(char *dst, const char *src)
|
||||
@@ -2292,38 +2360,43 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re
|
||||
return show_ref(&atom->u.refname, ref->refname);
|
||||
}
|
||||
|
||||
static int get_object(struct ref_array_item *ref, int deref, struct object **obj,
|
||||
static int get_object(struct ref_array_item *ref, int deref,
|
||||
struct expand_data *oi, struct strbuf *err)
|
||||
{
|
||||
/* parse_object_buffer() will set eaten to 0 if free() will be needed */
|
||||
int eaten = 1;
|
||||
/* parse_object_buffer() will set eaten to 1 if free() will be needed */
|
||||
int eaten = 0;
|
||||
int ret;
|
||||
|
||||
oi->maybe_object = NULL;
|
||||
|
||||
if (oi->info.contentp) {
|
||||
/* We need to know that to use parse_object_buffer properly */
|
||||
oi->info.sizep = &oi->size;
|
||||
oi->info.typep = &oi->type;
|
||||
}
|
||||
|
||||
if (odb_read_object_info_extended(the_repository->objects, &oi->oid, &oi->info,
|
||||
OBJECT_INFO_LOOKUP_REPLACE))
|
||||
return strbuf_addf_ret(err, -1, _("missing object %s for %s"),
|
||||
oid_to_hex(&oi->oid), ref->refname);
|
||||
OBJECT_INFO_LOOKUP_REPLACE)) {
|
||||
ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
|
||||
oid_to_hex(&oi->oid), ref->refname);
|
||||
goto out;
|
||||
}
|
||||
if (oi->info.disk_sizep && oi->disk_size < 0)
|
||||
BUG("Object size is less than zero.");
|
||||
|
||||
if (oi->info.contentp) {
|
||||
*obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten);
|
||||
if (!*obj) {
|
||||
if (!eaten)
|
||||
free(oi->content);
|
||||
return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
|
||||
oid_to_hex(&oi->oid), ref->refname);
|
||||
}
|
||||
grab_values(ref->value, deref, *obj, oi);
|
||||
ret = grab_values(ref->value, deref, oi, ref->refname, err, &eaten);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
grab_common_values(ref->value, deref, oi);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (!eaten)
|
||||
free(oi->content);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
|
||||
@@ -2376,7 +2449,6 @@ static char *get_worktree_path(const struct ref_array_item *ref)
|
||||
*/
|
||||
static int populate_value(struct ref_array_item *ref, struct strbuf *err)
|
||||
{
|
||||
struct object *obj;
|
||||
int i;
|
||||
struct object_info empty = OBJECT_INFO_INIT;
|
||||
int ahead_behind_atoms = 0;
|
||||
@@ -2564,24 +2636,32 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
|
||||
|
||||
|
||||
oi.oid = ref->objectname;
|
||||
if (get_object(ref, 0, &obj, &oi, err))
|
||||
if (get_object(ref, 0, &oi, err))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* If there is no atom that wants to know about tagged
|
||||
* object, we are done.
|
||||
*/
|
||||
if (!need_tagged || (obj->type != OBJ_TAG))
|
||||
if (!need_tagged || (oi.type != OBJ_TAG))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If it is a tag object, see if we use the peeled value. If we do,
|
||||
* grab the peeled OID.
|
||||
*/
|
||||
if (need_tagged && peel_iterated_oid(the_repository, &obj->oid, &oi_deref.oid))
|
||||
die("bad tag");
|
||||
if (need_tagged) {
|
||||
if (!is_null_oid(&ref->peeled_oid)) {
|
||||
oidcpy(&oi_deref.oid, &ref->peeled_oid);
|
||||
} else if (!peel_object(the_repository, &oi.oid, &oi_deref.oid,
|
||||
PEEL_OBJECT_VERIFY_OBJECT_TYPE)) {
|
||||
/* We managed to peel the object ourselves. */
|
||||
} else {
|
||||
die("bad tag");
|
||||
}
|
||||
}
|
||||
|
||||
return get_object(ref, 1, &obj, &oi_deref, err);
|
||||
return get_object(ref, 1, &oi_deref, err);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2664,7 +2744,7 @@ static int match_name_as_path(const char **pattern, const char *refname,
|
||||
/* Return 1 if the refname matches one of the patterns, otherwise 0. */
|
||||
static int filter_pattern_match(struct ref_filter *filter, const char *refname)
|
||||
{
|
||||
if (!*filter->name_patterns)
|
||||
if (!filter->name_patterns || !*filter->name_patterns)
|
||||
return 1; /* No pattern always matches */
|
||||
if (filter->match_as_path)
|
||||
return match_name_as_path(filter->name_patterns, refname,
|
||||
@@ -2751,7 +2831,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
|
||||
return for_each_fullref_with_seek(filter, cb, cb_data, 0);
|
||||
}
|
||||
|
||||
if (!filter->name_patterns[0]) {
|
||||
if (!filter->name_patterns || !filter->name_patterns[0]) {
|
||||
/* no patterns; we have to look at everything */
|
||||
return for_each_fullref_with_seek(filter, cb, cb_data, 0);
|
||||
}
|
||||
@@ -2807,12 +2887,15 @@ static int match_points_at(struct oid_array *points_at,
|
||||
* Callers can then fill in other struct members at their leisure.
|
||||
*/
|
||||
static struct ref_array_item *new_ref_array_item(const char *refname,
|
||||
const struct object_id *oid)
|
||||
const struct object_id *oid,
|
||||
const struct object_id *peeled_oid)
|
||||
{
|
||||
struct ref_array_item *ref;
|
||||
|
||||
FLEX_ALLOC_STR(ref, refname, refname);
|
||||
oidcpy(&ref->objectname, oid);
|
||||
if (peeled_oid)
|
||||
oidcpy(&ref->peeled_oid, peeled_oid);
|
||||
ref->rest = NULL;
|
||||
|
||||
return ref;
|
||||
@@ -2826,14 +2909,15 @@ static void ref_array_append(struct ref_array *array, struct ref_array_item *ref
|
||||
|
||||
struct ref_array_item *ref_array_push(struct ref_array *array,
|
||||
const char *refname,
|
||||
const struct object_id *oid)
|
||||
const struct object_id *oid,
|
||||
const struct object_id *peeled_oid)
|
||||
{
|
||||
struct ref_array_item *ref = new_ref_array_item(refname, oid);
|
||||
struct ref_array_item *ref = new_ref_array_item(refname, oid, peeled_oid);
|
||||
ref_array_append(array, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static int ref_kind_from_refname(const char *refname)
|
||||
int ref_kind_from_refname(const char *refname)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -2871,25 +2955,25 @@ static int filter_ref_kind(struct ref_filter *filter, const char *refname)
|
||||
return ref_kind_from_refname(refname);
|
||||
}
|
||||
|
||||
static struct ref_array_item *apply_ref_filter(const char *refname, const char *referent, const struct object_id *oid,
|
||||
int flag, struct ref_filter *filter)
|
||||
static struct ref_array_item *apply_ref_filter(const struct reference *ref,
|
||||
struct ref_filter *filter)
|
||||
{
|
||||
struct ref_array_item *ref;
|
||||
struct ref_array_item *item;
|
||||
struct commit *commit = NULL;
|
||||
unsigned int kind;
|
||||
|
||||
if (flag & REF_BAD_NAME) {
|
||||
warning(_("ignoring ref with broken name %s"), refname);
|
||||
if (ref->flags & REF_BAD_NAME) {
|
||||
warning(_("ignoring ref with broken name %s"), ref->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flag & REF_ISBROKEN) {
|
||||
warning(_("ignoring broken ref %s"), refname);
|
||||
if (ref->flags & REF_ISBROKEN) {
|
||||
warning(_("ignoring broken ref %s"), ref->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
|
||||
kind = filter_ref_kind(filter, refname);
|
||||
kind = filter_ref_kind(filter, ref->name);
|
||||
|
||||
/*
|
||||
* Generally HEAD refs are printed with special description denoting a rebase,
|
||||
@@ -2902,13 +2986,13 @@ static struct ref_array_item *apply_ref_filter(const char *refname, const char *
|
||||
else if (!(kind & filter->kind))
|
||||
return NULL;
|
||||
|
||||
if (!filter_pattern_match(filter, refname))
|
||||
if (!filter_pattern_match(filter, ref->name))
|
||||
return NULL;
|
||||
|
||||
if (filter_exclude_match(filter, refname))
|
||||
if (filter_exclude_match(filter, ref->name))
|
||||
return NULL;
|
||||
|
||||
if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname))
|
||||
if (filter->points_at.nr && !match_points_at(&filter->points_at, ref->oid, ref->name))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
@@ -2918,7 +3002,7 @@ static struct ref_array_item *apply_ref_filter(const char *refname, const char *
|
||||
*/
|
||||
if (filter->reachable_from || filter->unreachable_from ||
|
||||
filter->with_commit || filter->no_commit || filter->verbose) {
|
||||
commit = lookup_commit_reference_gently(the_repository, oid, 1);
|
||||
commit = lookup_commit_reference_gently(the_repository, ref->oid, 1);
|
||||
if (!commit)
|
||||
return NULL;
|
||||
/* We perform the filtering for the '--contains' option... */
|
||||
@@ -2936,13 +3020,13 @@ static struct ref_array_item *apply_ref_filter(const char *refname, const char *
|
||||
* to do its job and the resulting list may yet to be pruned
|
||||
* by maxcount logic.
|
||||
*/
|
||||
ref = new_ref_array_item(refname, oid);
|
||||
ref->commit = commit;
|
||||
ref->flag = flag;
|
||||
ref->kind = kind;
|
||||
ref->symref = xstrdup_or_null(referent);
|
||||
item = new_ref_array_item(ref->name, ref->oid, ref->peeled_oid);
|
||||
item->commit = commit;
|
||||
item->flag = ref->flags;
|
||||
item->kind = kind;
|
||||
item->symref = xstrdup_or_null(ref->target);
|
||||
|
||||
return ref;
|
||||
return item;
|
||||
}
|
||||
|
||||
struct ref_filter_cbdata {
|
||||
@@ -2954,14 +3038,14 @@ struct ref_filter_cbdata {
|
||||
* A call-back given to for_each_ref(). Filter refs and keep them for
|
||||
* later object processing.
|
||||
*/
|
||||
static int filter_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
|
||||
static int filter_one(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct ref_filter_cbdata *ref_cbdata = cb_data;
|
||||
struct ref_array_item *ref;
|
||||
struct ref_array_item *item;
|
||||
|
||||
ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
|
||||
if (ref)
|
||||
ref_array_append(ref_cbdata->array, ref);
|
||||
item = apply_ref_filter(ref, ref_cbdata->filter);
|
||||
if (item)
|
||||
ref_array_append(ref_cbdata->array, item);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2990,17 +3074,17 @@ struct ref_filter_and_format_cbdata {
|
||||
} internal;
|
||||
};
|
||||
|
||||
static int filter_and_format_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
|
||||
static int filter_and_format_one(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct ref_filter_and_format_cbdata *ref_cbdata = cb_data;
|
||||
struct ref_array_item *ref;
|
||||
struct ref_array_item *item;
|
||||
struct strbuf output = STRBUF_INIT, err = STRBUF_INIT;
|
||||
|
||||
ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
|
||||
if (!ref)
|
||||
item = apply_ref_filter(ref, ref_cbdata->filter);
|
||||
if (!item)
|
||||
return 0;
|
||||
|
||||
if (format_ref_array_item(ref, ref_cbdata->format, &output, &err))
|
||||
if (format_ref_array_item(item, ref_cbdata->format, &output, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
if (output.len || !ref_cbdata->format->array_opts.omit_empty) {
|
||||
@@ -3010,7 +3094,7 @@ static int filter_and_format_one(const char *refname, const char *referent, cons
|
||||
|
||||
strbuf_release(&output);
|
||||
strbuf_release(&err);
|
||||
free_array_item(ref);
|
||||
free_array_item(item);
|
||||
|
||||
/*
|
||||
* Increment the running count of refs that match the filter. If
|
||||
@@ -3583,13 +3667,14 @@ void print_formatted_ref_array(struct ref_array *array, struct ref_format *forma
|
||||
}
|
||||
|
||||
void pretty_print_ref(const char *name, const struct object_id *oid,
|
||||
const struct object_id *peeled_oid,
|
||||
struct ref_format *format)
|
||||
{
|
||||
struct ref_array_item *ref_item;
|
||||
struct strbuf output = STRBUF_INIT;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
ref_item = new_ref_array_item(name, oid);
|
||||
ref_item = new_ref_array_item(name, oid, peeled_oid);
|
||||
ref_item->kind = ref_kind_from_refname(name);
|
||||
if (format_ref_array_item(ref_item, format, &output, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
@@ -41,6 +41,7 @@ enum ref_sorting_order {
|
||||
|
||||
struct ref_array_item {
|
||||
struct object_id objectname;
|
||||
struct object_id peeled_oid;
|
||||
const char *rest;
|
||||
int flag;
|
||||
unsigned int kind;
|
||||
@@ -135,6 +136,8 @@ struct ref_format {
|
||||
OPT_STRVEC(0, "exclude", &(var)->exclude, \
|
||||
N_("pattern"), N_("exclude refs which match pattern"))
|
||||
|
||||
/* Get the reference kind from the provided reference name. */
|
||||
int ref_kind_from_refname(const char *refname);
|
||||
/*
|
||||
* API for filtering a set of refs. Based on the type of refs the user
|
||||
* has requested, we iterate through those refs and apply filters
|
||||
@@ -185,6 +188,7 @@ void print_formatted_ref_array(struct ref_array *array, struct ref_format *forma
|
||||
* name must be a fully qualified refname.
|
||||
*/
|
||||
void pretty_print_ref(const char *name, const struct object_id *oid,
|
||||
const struct object_id *peeled_oid,
|
||||
struct ref_format *format);
|
||||
|
||||
/*
|
||||
@@ -193,7 +197,8 @@ void pretty_print_ref(const char *name, const struct object_id *oid,
|
||||
*/
|
||||
struct ref_array_item *ref_array_push(struct ref_array *array,
|
||||
const char *refname,
|
||||
const struct object_id *oid);
|
||||
const struct object_id *oid,
|
||||
const struct object_id *peeled_oid);
|
||||
|
||||
/*
|
||||
* If the provided format includes ahead-behind atoms, then compute the
|
||||
|
||||
9
reflog.c
9
reflog.c
@@ -423,16 +423,13 @@ int should_expire_reflog_ent_verbose(struct object_id *ooid,
|
||||
return expire;
|
||||
}
|
||||
|
||||
static int push_tip_to_list(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags, void *cb_data)
|
||||
static int push_tip_to_list(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct commit_list **list = cb_data;
|
||||
struct commit *tip_commit;
|
||||
if (flags & REF_ISSYMREF)
|
||||
if (ref->flags & REF_ISSYMREF)
|
||||
return 0;
|
||||
tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
|
||||
tip_commit = lookup_commit_reference_gently(the_repository, ref->oid, 1);
|
||||
if (!tip_commit)
|
||||
return 0;
|
||||
commit_list_insert(tip_commit, list);
|
||||
|
||||
85
refs.c
85
refs.c
@@ -426,17 +426,19 @@ int refs_ref_exists(struct ref_store *refs, const char *refname)
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static int for_each_filter_refs(const char *refname, const char *referent,
|
||||
const struct object_id *oid,
|
||||
int flags, void *data)
|
||||
static int for_each_filter_refs(const struct reference *ref, void *data)
|
||||
{
|
||||
struct for_each_ref_filter *filter = data;
|
||||
|
||||
if (wildmatch(filter->pattern, refname, 0))
|
||||
if (wildmatch(filter->pattern, ref->name, 0))
|
||||
return 0;
|
||||
if (filter->prefix)
|
||||
skip_prefix(refname, filter->prefix, &refname);
|
||||
return filter->fn(refname, referent, oid, flags, filter->cb_data);
|
||||
if (filter->prefix) {
|
||||
struct reference skipped = *ref;
|
||||
skip_prefix(skipped.name, filter->prefix, &skipped.name);
|
||||
return filter->fn(&skipped, filter->cb_data);
|
||||
} else {
|
||||
return filter->fn(ref, filter->cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
struct warn_if_dangling_data {
|
||||
@@ -447,17 +449,15 @@ struct warn_if_dangling_data {
|
||||
int dry_run;
|
||||
};
|
||||
|
||||
static int warn_if_dangling_symref(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags, void *cb_data)
|
||||
static int warn_if_dangling_symref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct warn_if_dangling_data *d = cb_data;
|
||||
const char *resolves_to, *msg;
|
||||
|
||||
if (!(flags & REF_ISSYMREF))
|
||||
if (!(ref->flags & REF_ISSYMREF))
|
||||
return 0;
|
||||
|
||||
resolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL);
|
||||
resolves_to = refs_resolve_ref_unsafe(d->refs, ref->name, 0, NULL, NULL);
|
||||
if (!resolves_to
|
||||
|| !string_list_has_string(d->refnames, resolves_to)) {
|
||||
return 0;
|
||||
@@ -466,7 +466,7 @@ static int warn_if_dangling_symref(const char *refname, const char *referent UNU
|
||||
msg = d->dry_run
|
||||
? _("%s%s will become dangling after %s is deleted\n")
|
||||
: _("%s%s has become dangling after %s was deleted\n");
|
||||
fprintf(d->fp, msg, d->indent, refname, resolves_to);
|
||||
fprintf(d->fp, msg, d->indent, ref->name, resolves_to);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -507,8 +507,15 @@ int refs_head_ref_namespaced(struct ref_store *refs, each_ref_fn fn, void *cb_da
|
||||
int flag;
|
||||
|
||||
strbuf_addf(&buf, "%sHEAD", get_git_namespace());
|
||||
if (!refs_read_ref_full(refs, buf.buf, RESOLVE_REF_READING, &oid, &flag))
|
||||
ret = fn(buf.buf, NULL, &oid, flag, cb_data);
|
||||
if (!refs_read_ref_full(refs, buf.buf, RESOLVE_REF_READING, &oid, &flag)) {
|
||||
struct reference ref = {
|
||||
.name = buf.buf,
|
||||
.oid = &oid,
|
||||
.flags = flag,
|
||||
};
|
||||
|
||||
ret = fn(&ref, cb_data);
|
||||
}
|
||||
strbuf_release(&buf);
|
||||
|
||||
return ret;
|
||||
@@ -1741,8 +1748,15 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
||||
int flag;
|
||||
|
||||
if (refs_resolve_ref_unsafe(refs, "HEAD", RESOLVE_REF_READING,
|
||||
&oid, &flag))
|
||||
return fn("HEAD", NULL, &oid, flag, cb_data);
|
||||
&oid, &flag)) {
|
||||
struct reference ref = {
|
||||
.name = "HEAD",
|
||||
.oid = &oid,
|
||||
.flags = flag,
|
||||
};
|
||||
|
||||
return fn(&ref, cb_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2310,14 +2324,16 @@ int refs_optimize(struct ref_store *refs, struct pack_refs_opts *opts)
|
||||
return refs->be->optimize(refs, opts);
|
||||
}
|
||||
|
||||
int peel_iterated_oid(struct repository *r, const struct object_id *base, struct object_id *peeled)
|
||||
int reference_get_peeled_oid(struct repository *repo,
|
||||
const struct reference *ref,
|
||||
struct object_id *peeled_oid)
|
||||
{
|
||||
if (current_ref_iter &&
|
||||
(current_ref_iter->oid == base ||
|
||||
oideq(current_ref_iter->oid, base)))
|
||||
return ref_iterator_peel(current_ref_iter, peeled);
|
||||
if (ref->peeled_oid) {
|
||||
oidcpy(peeled_oid, ref->peeled_oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return peel_object(r, base, peeled) ? -1 : 0;
|
||||
return peel_object(repo, ref->oid, peeled_oid, 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
int refs_update_symref(struct ref_store *refs, const char *ref,
|
||||
@@ -2689,7 +2705,7 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
|
||||
|
||||
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
|
||||
if (skip &&
|
||||
string_list_has_string(skip, iter->refname))
|
||||
string_list_has_string(skip, iter->ref.name))
|
||||
continue;
|
||||
|
||||
if (transaction && ref_transaction_maybe_set_rejected(
|
||||
@@ -2698,7 +2714,7 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
|
||||
continue;
|
||||
|
||||
strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
|
||||
iter->refname, refname);
|
||||
iter->ref.name, refname);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -2753,14 +2769,10 @@ struct do_for_each_reflog_help {
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static int do_for_each_reflog_helper(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags UNUSED,
|
||||
void *cb_data)
|
||||
static int do_for_each_reflog_helper(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct do_for_each_reflog_help *hp = cb_data;
|
||||
return hp->fn(refname, hp->cb_data);
|
||||
return hp->fn(ref->name, hp->cb_data);
|
||||
}
|
||||
|
||||
int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_data)
|
||||
@@ -2976,25 +2988,24 @@ struct migration_data {
|
||||
uint64_t index;
|
||||
};
|
||||
|
||||
static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags, void *cb_data)
|
||||
static int migrate_one_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct migration_data *data = cb_data;
|
||||
struct strbuf symref_target = STRBUF_INIT;
|
||||
int ret;
|
||||
|
||||
if (flags & REF_ISSYMREF) {
|
||||
ret = refs_read_symbolic_ref(data->old_refs, refname, &symref_target);
|
||||
if (ref->flags & REF_ISSYMREF) {
|
||||
ret = refs_read_symbolic_ref(data->old_refs, ref->name, &symref_target);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = ref_transaction_update(data->transaction, refname, NULL, null_oid(the_hash_algo),
|
||||
ret = ref_transaction_update(data->transaction, ref->name, NULL, null_oid(the_hash_algo),
|
||||
symref_target.buf, NULL,
|
||||
REF_SKIP_CREATE_REFLOG | REF_NO_DEREF, NULL, data->errbuf);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
} else {
|
||||
ret = ref_transaction_create(data->transaction, refname, oid, NULL,
|
||||
ret = ref_transaction_create(data->transaction, ref->name, ref->oid, NULL,
|
||||
REF_SKIP_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION,
|
||||
NULL, data->errbuf);
|
||||
if (ret < 0)
|
||||
|
||||
90
refs.h
90
refs.h
@@ -333,36 +333,74 @@ struct ref_transaction;
|
||||
* stored in ref_iterator::flags. Other bits are for internal use
|
||||
* only:
|
||||
*/
|
||||
enum reference_status {
|
||||
/* Reference is a symbolic reference. */
|
||||
REF_ISSYMREF = (1 << 0),
|
||||
|
||||
/* Reference is a symbolic reference. */
|
||||
#define REF_ISSYMREF 0x01
|
||||
/* Reference is a packed reference. */
|
||||
REF_ISPACKED = (1 << 1),
|
||||
|
||||
/* Reference is a packed reference. */
|
||||
#define REF_ISPACKED 0x02
|
||||
/*
|
||||
* Reference cannot be resolved to an object name: dangling symbolic
|
||||
* reference (directly or indirectly), corrupt reference file,
|
||||
* reference exists but name is bad, or symbolic reference refers to
|
||||
* ill-formatted reference name.
|
||||
*/
|
||||
REF_ISBROKEN = (1 << 2),
|
||||
|
||||
/*
|
||||
* Reference name is not well formed.
|
||||
*
|
||||
* See git-check-ref-format(1) for the definition of well formed ref names.
|
||||
*/
|
||||
REF_BAD_NAME = (1 << 3),
|
||||
};
|
||||
|
||||
/* A reference passed to `for_each_ref()`-style callbacks. */
|
||||
struct reference {
|
||||
/* The fully-qualified name of the reference. */
|
||||
const char *name;
|
||||
|
||||
/* The target of a symbolic ref. `NULL` for direct references. */
|
||||
const char *target;
|
||||
|
||||
/*
|
||||
* The object ID of a reference. Either the direct object ID or the
|
||||
* resolved object ID in the case of a symbolic ref. May be the zero
|
||||
* object ID in case the symbolic ref cannot be resolved.
|
||||
*/
|
||||
const struct object_id *oid;
|
||||
|
||||
/*
|
||||
* An optional peeled object ID. This field _may_ be set for tags in
|
||||
* case the peeled value is present in the backend. Please refer to
|
||||
* `reference_get_peeled_oid()`.
|
||||
*/
|
||||
const struct object_id *peeled_oid;
|
||||
|
||||
/* A bitfield of `enum reference_status` flags. */
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Reference cannot be resolved to an object name: dangling symbolic
|
||||
* reference (directly or indirectly), corrupt reference file,
|
||||
* reference exists but name is bad, or symbolic reference refers to
|
||||
* ill-formatted reference name.
|
||||
*/
|
||||
#define REF_ISBROKEN 0x04
|
||||
|
||||
/*
|
||||
* Reference name is not well formed.
|
||||
* Peel the tag to a non-tag commit. If present, this uses the peeled object ID
|
||||
* exposed by the reference backend. Otherwise, the object is peeled via the
|
||||
* object database, which is less efficient.
|
||||
*
|
||||
* See git-check-ref-format(1) for the definition of well formed ref names.
|
||||
* Return `0` if the reference could be peeled, a negative error code
|
||||
* otherwise.
|
||||
*/
|
||||
#define REF_BAD_NAME 0x08
|
||||
int reference_get_peeled_oid(struct repository *repo,
|
||||
const struct reference *ref,
|
||||
struct object_id *peeled_oid);
|
||||
|
||||
/*
|
||||
* The signature for the callback function for the for_each_*()
|
||||
* functions below. The memory pointed to by the refname and oid
|
||||
* arguments is only guaranteed to be valid for the duration of a
|
||||
* functions below. The memory pointed to by the `struct reference`
|
||||
* argument is only guaranteed to be valid for the duration of a
|
||||
* single callback invocation.
|
||||
*/
|
||||
typedef int each_ref_fn(const char *refname, const char *referent,
|
||||
const struct object_id *oid, int flags, void *cb_data);
|
||||
typedef int each_ref_fn(const struct reference *ref, void *cb_data);
|
||||
|
||||
/*
|
||||
* The following functions invoke the specified callback function for
|
||||
@@ -1251,10 +1289,6 @@ int repo_migrate_ref_storage_format(struct repository *repo,
|
||||
* to the next entry, ref_iterator_advance() aborts the iteration,
|
||||
* frees the ref_iterator, and returns ITER_ERROR.
|
||||
*
|
||||
* The reference currently being looked at can be peeled by calling
|
||||
* ref_iterator_peel(). This function is often faster than peel_ref(),
|
||||
* so it should be preferred when iterating over references.
|
||||
*
|
||||
* Putting it all together, a typical iteration looks like this:
|
||||
*
|
||||
* int ok;
|
||||
@@ -1269,9 +1303,6 @@ int repo_migrate_ref_storage_format(struct repository *repo,
|
||||
* // Access information about the current reference:
|
||||
* if (!(iter->flags & REF_ISSYMREF))
|
||||
* printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid));
|
||||
*
|
||||
* // If you need to peel the reference:
|
||||
* ref_iterator_peel(iter, &oid);
|
||||
* }
|
||||
*
|
||||
* if (ok != ITER_DONE)
|
||||
@@ -1362,13 +1393,6 @@ enum ref_iterator_seek_flag {
|
||||
int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname,
|
||||
unsigned int flags);
|
||||
|
||||
/*
|
||||
* If possible, peel the reference currently being viewed by the
|
||||
* iterator. Return 0 on success.
|
||||
*/
|
||||
int ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled);
|
||||
|
||||
/* Free the reference iterator and any associated resources. */
|
||||
void ref_iterator_free(struct ref_iterator *ref_iterator);
|
||||
|
||||
|
||||
17
refs/debug.c
17
refs/debug.c
@@ -160,11 +160,9 @@ static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
trace_printf_key(&trace_refs, "iterator_advance: (%d)\n", res);
|
||||
else
|
||||
trace_printf_key(&trace_refs, "iterator_advance: %s (0)\n",
|
||||
diter->iter->refname);
|
||||
diter->iter->ref.name);
|
||||
|
||||
diter->base.refname = diter->iter->refname;
|
||||
diter->base.oid = diter->iter->oid;
|
||||
diter->base.flags = diter->iter->flags;
|
||||
diter->base.ref = diter->iter->ref;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -179,16 +177,6 @@ static int debug_ref_iterator_seek(struct ref_iterator *ref_iterator,
|
||||
return res;
|
||||
}
|
||||
|
||||
static int debug_ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
struct debug_ref_iterator *diter =
|
||||
(struct debug_ref_iterator *)ref_iterator;
|
||||
int res = diter->iter->vtable->peel(diter->iter, peeled);
|
||||
trace_printf_key(&trace_refs, "iterator_peel: %s: %d\n", diter->iter->refname, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void debug_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct debug_ref_iterator *diter =
|
||||
@@ -200,7 +188,6 @@ static void debug_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable debug_ref_iterator_vtable = {
|
||||
.advance = debug_ref_iterator_advance,
|
||||
.seek = debug_ref_iterator_seek,
|
||||
.peel = debug_ref_iterator_peel,
|
||||
.release = debug_ref_iterator_release,
|
||||
};
|
||||
|
||||
|
||||
@@ -961,26 +961,23 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
|
||||
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
|
||||
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
|
||||
parse_worktree_ref(iter->iter0->refname, NULL, NULL,
|
||||
parse_worktree_ref(iter->iter0->ref.name, NULL, NULL,
|
||||
NULL) != REF_WORKTREE_CURRENT)
|
||||
continue;
|
||||
|
||||
if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
|
||||
(iter->iter0->flags & REF_ISSYMREF) &&
|
||||
(iter->iter0->flags & REF_ISBROKEN))
|
||||
(iter->iter0->ref.flags & REF_ISSYMREF) &&
|
||||
(iter->iter0->ref.flags & REF_ISBROKEN))
|
||||
continue;
|
||||
|
||||
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
|
||||
!ref_resolves_to_object(iter->iter0->refname,
|
||||
!ref_resolves_to_object(iter->iter0->ref.name,
|
||||
iter->repo,
|
||||
iter->iter0->oid,
|
||||
iter->iter0->flags))
|
||||
iter->iter0->ref.oid,
|
||||
iter->iter0->ref.flags))
|
||||
continue;
|
||||
|
||||
iter->base.refname = iter->iter0->refname;
|
||||
iter->base.oid = iter->iter0->oid;
|
||||
iter->base.flags = iter->iter0->flags;
|
||||
iter->base.referent = iter->iter0->referent;
|
||||
iter->base.ref = iter->iter0->ref;
|
||||
|
||||
return ITER_OK;
|
||||
}
|
||||
@@ -996,15 +993,6 @@ static int files_ref_iterator_seek(struct ref_iterator *ref_iterator,
|
||||
return ref_iterator_seek(iter->iter0, refname, flags);
|
||||
}
|
||||
|
||||
static int files_ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
struct files_ref_iterator *iter =
|
||||
(struct files_ref_iterator *)ref_iterator;
|
||||
|
||||
return ref_iterator_peel(iter->iter0, peeled);
|
||||
}
|
||||
|
||||
static void files_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct files_ref_iterator *iter =
|
||||
@@ -1015,7 +1003,6 @@ static void files_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable files_ref_iterator_vtable = {
|
||||
.advance = files_ref_iterator_advance,
|
||||
.seek = files_ref_iterator_seek,
|
||||
.peel = files_ref_iterator_peel,
|
||||
.release = files_ref_iterator_release,
|
||||
};
|
||||
|
||||
@@ -1367,30 +1354,29 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
|
||||
* Return true if the specified reference should be packed.
|
||||
*/
|
||||
static int should_pack_ref(struct files_ref_store *refs,
|
||||
const char *refname,
|
||||
const struct object_id *oid, unsigned int ref_flags,
|
||||
const struct reference *ref,
|
||||
struct pack_refs_opts *opts)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
|
||||
/* Do not pack per-worktree refs: */
|
||||
if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
|
||||
if (parse_worktree_ref(ref->name, NULL, NULL, NULL) !=
|
||||
REF_WORKTREE_SHARED)
|
||||
return 0;
|
||||
|
||||
/* Do not pack symbolic refs: */
|
||||
if (ref_flags & REF_ISSYMREF)
|
||||
if (ref->flags & REF_ISSYMREF)
|
||||
return 0;
|
||||
|
||||
/* Do not pack broken refs: */
|
||||
if (!ref_resolves_to_object(refname, refs->base.repo, oid, ref_flags))
|
||||
if (!ref_resolves_to_object(ref->name, refs->base.repo, ref->oid, ref->flags))
|
||||
return 0;
|
||||
|
||||
if (ref_excluded(opts->exclusions, refname))
|
||||
if (ref_excluded(opts->exclusions, ref->name))
|
||||
return 0;
|
||||
|
||||
for_each_string_list_item(item, opts->includes)
|
||||
if (!wildmatch(item->string, refname, 0))
|
||||
if (!wildmatch(item->string, ref->name, 0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -1443,8 +1429,7 @@ static int should_pack_refs(struct files_ref_store *refs,
|
||||
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
|
||||
refs->base.repo, 0);
|
||||
while ((ret = ref_iterator_advance(iter)) == ITER_OK) {
|
||||
if (should_pack_ref(refs, iter->refname, iter->oid,
|
||||
iter->flags, opts))
|
||||
if (should_pack_ref(refs, &iter->ref, opts))
|
||||
refcount++;
|
||||
if (refcount >= limit) {
|
||||
ref_iterator_free(iter);
|
||||
@@ -1489,24 +1474,24 @@ static int files_pack_refs(struct ref_store *ref_store,
|
||||
* in the packed ref cache. If the reference should be
|
||||
* pruned, also add it to refs_to_prune.
|
||||
*/
|
||||
if (!should_pack_ref(refs, iter->refname, iter->oid, iter->flags, opts))
|
||||
if (!should_pack_ref(refs, &iter->ref, opts))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add a reference creation for this reference to the
|
||||
* packed-refs transaction:
|
||||
*/
|
||||
if (ref_transaction_update(transaction, iter->refname,
|
||||
iter->oid, NULL, NULL, NULL,
|
||||
if (ref_transaction_update(transaction, iter->ref.name,
|
||||
iter->ref.oid, NULL, NULL, NULL,
|
||||
REF_NO_DEREF, NULL, &err))
|
||||
die("failure preparing to create packed reference %s: %s",
|
||||
iter->refname, err.buf);
|
||||
iter->ref.name, err.buf);
|
||||
|
||||
/* Schedule the loose reference for pruning if requested. */
|
||||
if ((opts->flags & PACK_REFS_PRUNE)) {
|
||||
struct ref_to_prune *n;
|
||||
FLEX_ALLOC_STR(n, name, iter->refname);
|
||||
oidcpy(&n->oid, iter->oid);
|
||||
FLEX_ALLOC_STR(n, name, iter->ref.name);
|
||||
oidcpy(&n->oid, iter->ref.oid);
|
||||
n->next = refs_to_prune;
|
||||
refs_to_prune = n;
|
||||
}
|
||||
@@ -2379,7 +2364,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
REFNAME_ALLOW_ONELEVEL))
|
||||
continue;
|
||||
|
||||
iter->base.refname = diter->relative_path;
|
||||
iter->base.ref.name = diter->relative_path;
|
||||
return ITER_OK;
|
||||
}
|
||||
|
||||
@@ -2393,12 +2378,6 @@ static int files_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
|
||||
BUG("ref_iterator_seek() called for reflog_iterator");
|
||||
}
|
||||
|
||||
static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
|
||||
struct object_id *peeled UNUSED)
|
||||
{
|
||||
BUG("ref_iterator_peel() called for reflog_iterator");
|
||||
}
|
||||
|
||||
static void files_reflog_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct files_reflog_iterator *iter =
|
||||
@@ -2409,7 +2388,6 @@ static void files_reflog_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable files_reflog_iterator_vtable = {
|
||||
.advance = files_reflog_iterator_advance,
|
||||
.seek = files_reflog_iterator_seek,
|
||||
.peel = files_reflog_iterator_peel,
|
||||
.release = files_reflog_iterator_release,
|
||||
};
|
||||
|
||||
@@ -3150,14 +3128,11 @@ static int parse_and_write_reflog(struct files_ref_store *refs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ref_present(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags UNUSED,
|
||||
void *cb_data)
|
||||
static int ref_present(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct string_list *affected_refnames = cb_data;
|
||||
|
||||
return string_list_has_string(affected_refnames, refname);
|
||||
return string_list_has_string(affected_refnames, ref->name);
|
||||
}
|
||||
|
||||
static int files_transaction_finish_initial(struct files_ref_store *refs,
|
||||
@@ -3327,7 +3302,13 @@ static int files_transaction_finish(struct ref_store *ref_store,
|
||||
* next update. If not, we try and create a regular symref.
|
||||
*/
|
||||
if (update->new_target && refs->prefer_symlink_refs)
|
||||
if (!create_ref_symlink(lock, update->new_target))
|
||||
/*
|
||||
* By using the `NOT_CONSTANT()` trick, we can avoid
|
||||
* errors by `clang`'s `-Wunreachable` logic that would
|
||||
* report that the `continue` statement is not reachable
|
||||
* when `NO_SYMLINK_HEAD` is `#define`d.
|
||||
*/
|
||||
if (NOT_CONSTANT(!create_ref_symlink(lock, update->new_target)))
|
||||
continue;
|
||||
|
||||
if (update->flags & REF_NEEDS_COMMIT) {
|
||||
|
||||
@@ -21,12 +21,6 @@ int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname,
|
||||
return ref_iterator->vtable->seek(ref_iterator, refname, flags);
|
||||
}
|
||||
|
||||
int ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
return ref_iterator->vtable->peel(ref_iterator, peeled);
|
||||
}
|
||||
|
||||
void ref_iterator_free(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
if (ref_iterator) {
|
||||
@@ -41,10 +35,7 @@ void base_ref_iterator_init(struct ref_iterator *iter,
|
||||
struct ref_iterator_vtable *vtable)
|
||||
{
|
||||
iter->vtable = vtable;
|
||||
iter->refname = NULL;
|
||||
iter->referent = NULL;
|
||||
iter->oid = NULL;
|
||||
iter->flags = 0;
|
||||
memset(&iter->ref, 0, sizeof(iter->ref));
|
||||
}
|
||||
|
||||
struct empty_ref_iterator {
|
||||
@@ -63,12 +54,6 @@ static int empty_ref_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
|
||||
struct object_id *peeled UNUSED)
|
||||
{
|
||||
BUG("peel called for empty iterator");
|
||||
}
|
||||
|
||||
static void empty_ref_iterator_release(struct ref_iterator *ref_iterator UNUSED)
|
||||
{
|
||||
}
|
||||
@@ -76,7 +61,6 @@ static void empty_ref_iterator_release(struct ref_iterator *ref_iterator UNUSED)
|
||||
static struct ref_iterator_vtable empty_ref_iterator_vtable = {
|
||||
.advance = empty_ref_iterator_advance,
|
||||
.seek = empty_ref_iterator_seek,
|
||||
.peel = empty_ref_iterator_peel,
|
||||
.release = empty_ref_iterator_release,
|
||||
};
|
||||
|
||||
@@ -127,8 +111,8 @@ enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
|
||||
* latter.
|
||||
*/
|
||||
if (iter_worktree) {
|
||||
int cmp = strcmp(iter_worktree->refname,
|
||||
iter_common->refname);
|
||||
int cmp = strcmp(iter_worktree->ref.name,
|
||||
iter_common->ref.name);
|
||||
if (cmp < 0)
|
||||
return ITER_SELECT_0;
|
||||
else if (!cmp)
|
||||
@@ -139,7 +123,7 @@ enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
|
||||
* We now know that the lexicographically-next ref is a common
|
||||
* ref. When the common ref is a shared one we return it.
|
||||
*/
|
||||
if (parse_worktree_ref(iter_common->refname, NULL, NULL,
|
||||
if (parse_worktree_ref(iter_common->ref.name, NULL, NULL,
|
||||
NULL) == REF_WORKTREE_SHARED)
|
||||
return ITER_SELECT_1;
|
||||
|
||||
@@ -212,10 +196,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
}
|
||||
|
||||
if (selection & ITER_YIELD_CURRENT) {
|
||||
iter->base.referent = (*iter->current)->referent;
|
||||
iter->base.refname = (*iter->current)->refname;
|
||||
iter->base.oid = (*iter->current)->oid;
|
||||
iter->base.flags = (*iter->current)->flags;
|
||||
iter->base.ref = (*iter->current)->ref;
|
||||
return ITER_OK;
|
||||
}
|
||||
}
|
||||
@@ -246,18 +227,6 @@ static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int merge_ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
struct merge_ref_iterator *iter =
|
||||
(struct merge_ref_iterator *)ref_iterator;
|
||||
|
||||
if (!iter->current) {
|
||||
BUG("peel called before advance for merge iterator");
|
||||
}
|
||||
return ref_iterator_peel(*iter->current, peeled);
|
||||
}
|
||||
|
||||
static void merge_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct merge_ref_iterator *iter =
|
||||
@@ -269,7 +238,6 @@ static void merge_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable merge_ref_iterator_vtable = {
|
||||
.advance = merge_ref_iterator_advance,
|
||||
.seek = merge_ref_iterator_seek,
|
||||
.peel = merge_ref_iterator_peel,
|
||||
.release = merge_ref_iterator_release,
|
||||
};
|
||||
|
||||
@@ -313,7 +281,7 @@ static enum iterator_selection overlay_iterator_select(
|
||||
else if (!front)
|
||||
return ITER_SELECT_1;
|
||||
|
||||
cmp = strcmp(front->refname, back->refname);
|
||||
cmp = strcmp(front->ref.name, back->ref.name);
|
||||
|
||||
if (cmp < 0)
|
||||
return ITER_SELECT_0;
|
||||
@@ -371,7 +339,7 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
int ok;
|
||||
|
||||
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
|
||||
int cmp = compare_prefix(iter->iter0->refname, iter->prefix);
|
||||
int cmp = compare_prefix(iter->iter0->ref.name, iter->prefix);
|
||||
if (cmp < 0)
|
||||
continue;
|
||||
/*
|
||||
@@ -382,6 +350,8 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
if (cmp > 0)
|
||||
return ITER_DONE;
|
||||
|
||||
iter->base.ref = iter->iter0->ref;
|
||||
|
||||
if (iter->trim) {
|
||||
/*
|
||||
* It is nonsense to trim off characters that
|
||||
@@ -392,15 +362,11 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
* one character left in the refname after
|
||||
* trimming, report it as a bug:
|
||||
*/
|
||||
if (strlen(iter->iter0->refname) <= iter->trim)
|
||||
if (strlen(iter->base.ref.name) <= iter->trim)
|
||||
BUG("attempt to trim too many characters");
|
||||
iter->base.refname = iter->iter0->refname + iter->trim;
|
||||
} else {
|
||||
iter->base.refname = iter->iter0->refname;
|
||||
iter->base.ref.name += iter->trim;
|
||||
}
|
||||
|
||||
iter->base.oid = iter->iter0->oid;
|
||||
iter->base.flags = iter->iter0->flags;
|
||||
return ITER_OK;
|
||||
}
|
||||
|
||||
@@ -420,15 +386,6 @@ static int prefix_ref_iterator_seek(struct ref_iterator *ref_iterator,
|
||||
return ref_iterator_seek(iter->iter0, refname, flags);
|
||||
}
|
||||
|
||||
static int prefix_ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
struct prefix_ref_iterator *iter =
|
||||
(struct prefix_ref_iterator *)ref_iterator;
|
||||
|
||||
return ref_iterator_peel(iter->iter0, peeled);
|
||||
}
|
||||
|
||||
static void prefix_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct prefix_ref_iterator *iter =
|
||||
@@ -440,7 +397,6 @@ static void prefix_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable prefix_ref_iterator_vtable = {
|
||||
.advance = prefix_ref_iterator_advance,
|
||||
.seek = prefix_ref_iterator_seek,
|
||||
.peel = prefix_ref_iterator_peel,
|
||||
.release = prefix_ref_iterator_release,
|
||||
};
|
||||
|
||||
@@ -466,23 +422,18 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
|
||||
return ref_iterator;
|
||||
}
|
||||
|
||||
struct ref_iterator *current_ref_iter = NULL;
|
||||
|
||||
int do_for_each_ref_iterator(struct ref_iterator *iter,
|
||||
each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
int retval = 0, ok;
|
||||
struct ref_iterator *old_ref_iter = current_ref_iter;
|
||||
|
||||
current_ref_iter = iter;
|
||||
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
|
||||
retval = fn(iter->refname, iter->referent, iter->oid, iter->flags, cb_data);
|
||||
retval = fn(&iter->ref, cb_data);
|
||||
if (retval)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
current_ref_iter = old_ref_iter;
|
||||
if (ok == ITER_ERROR)
|
||||
retval = -1;
|
||||
ref_iterator_free(iter);
|
||||
|
||||
@@ -882,6 +882,7 @@ static int next_record(struct packed_ref_iterator *iter)
|
||||
{
|
||||
const char *p, *eol;
|
||||
|
||||
memset(&iter->base.ref, 0, sizeof(iter->base.ref));
|
||||
strbuf_reset(&iter->refname_buf);
|
||||
|
||||
/*
|
||||
@@ -908,7 +909,7 @@ static int next_record(struct packed_ref_iterator *iter)
|
||||
if (iter->pos == iter->eof)
|
||||
return ITER_DONE;
|
||||
|
||||
iter->base.flags = REF_ISPACKED;
|
||||
iter->base.ref.flags = REF_ISPACKED;
|
||||
p = iter->pos;
|
||||
|
||||
if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||
|
||||
@@ -916,6 +917,7 @@ static int next_record(struct packed_ref_iterator *iter)
|
||||
!isspace(*p++))
|
||||
die_invalid_line(iter->snapshot->refs->path,
|
||||
iter->pos, iter->eof - iter->pos);
|
||||
iter->base.ref.oid = &iter->oid;
|
||||
|
||||
eol = memchr(p, '\n', iter->eof - p);
|
||||
if (!eol)
|
||||
@@ -923,22 +925,22 @@ static int next_record(struct packed_ref_iterator *iter)
|
||||
iter->pos, iter->eof - iter->pos);
|
||||
|
||||
strbuf_add(&iter->refname_buf, p, eol - p);
|
||||
iter->base.refname = iter->refname_buf.buf;
|
||||
iter->base.ref.name = iter->refname_buf.buf;
|
||||
|
||||
if (refname_contains_nul(&iter->refname_buf))
|
||||
die("packed refname contains embedded NULL: %s", iter->base.refname);
|
||||
die("packed refname contains embedded NULL: %s", iter->base.ref.name);
|
||||
|
||||
if (check_refname_format(iter->base.refname, REFNAME_ALLOW_ONELEVEL)) {
|
||||
if (!refname_is_safe(iter->base.refname))
|
||||
if (check_refname_format(iter->base.ref.name, REFNAME_ALLOW_ONELEVEL)) {
|
||||
if (!refname_is_safe(iter->base.ref.name))
|
||||
die("packed refname is dangerous: %s",
|
||||
iter->base.refname);
|
||||
iter->base.ref.name);
|
||||
oidclr(&iter->oid, iter->repo->hash_algo);
|
||||
iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN;
|
||||
iter->base.ref.flags |= REF_BAD_NAME | REF_ISBROKEN;
|
||||
}
|
||||
if (iter->snapshot->peeled == PEELED_FULLY ||
|
||||
(iter->snapshot->peeled == PEELED_TAGS &&
|
||||
starts_with(iter->base.refname, "refs/tags/")))
|
||||
iter->base.flags |= REF_KNOWS_PEELED;
|
||||
starts_with(iter->base.ref.name, "refs/tags/")))
|
||||
iter->base.ref.flags |= REF_KNOWS_PEELED;
|
||||
|
||||
iter->pos = eol + 1;
|
||||
|
||||
@@ -956,11 +958,12 @@ static int next_record(struct packed_ref_iterator *iter)
|
||||
* definitely know the value of *this* reference. But
|
||||
* we suppress it if the reference is broken:
|
||||
*/
|
||||
if ((iter->base.flags & REF_ISBROKEN)) {
|
||||
if ((iter->base.ref.flags & REF_ISBROKEN)) {
|
||||
oidclr(&iter->peeled, iter->repo->hash_algo);
|
||||
iter->base.flags &= ~REF_KNOWS_PEELED;
|
||||
iter->base.ref.flags &= ~REF_KNOWS_PEELED;
|
||||
} else {
|
||||
iter->base.flags |= REF_KNOWS_PEELED;
|
||||
iter->base.ref.flags |= REF_KNOWS_PEELED;
|
||||
iter->base.ref.peeled_oid = &iter->peeled;
|
||||
}
|
||||
} else {
|
||||
oidclr(&iter->peeled, iter->repo->hash_algo);
|
||||
@@ -976,15 +979,15 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
int ok;
|
||||
|
||||
while ((ok = next_record(iter)) == ITER_OK) {
|
||||
const char *refname = iter->base.refname;
|
||||
const char *refname = iter->base.ref.name;
|
||||
const char *prefix = iter->prefix;
|
||||
|
||||
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
|
||||
!is_per_worktree_ref(iter->base.refname))
|
||||
!is_per_worktree_ref(iter->base.ref.name))
|
||||
continue;
|
||||
|
||||
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
|
||||
!ref_resolves_to_object(iter->base.refname, iter->repo,
|
||||
!ref_resolves_to_object(iter->base.ref.name, iter->repo,
|
||||
&iter->oid, iter->flags))
|
||||
continue;
|
||||
|
||||
@@ -1027,22 +1030,6 @@ static int packed_ref_iterator_seek(struct ref_iterator *ref_iterator,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
struct packed_ref_iterator *iter =
|
||||
(struct packed_ref_iterator *)ref_iterator;
|
||||
|
||||
if ((iter->base.flags & REF_KNOWS_PEELED)) {
|
||||
oidcpy(peeled, &iter->peeled);
|
||||
return is_null_oid(&iter->peeled) ? -1 : 0;
|
||||
} else if ((iter->base.flags & (REF_ISBROKEN | REF_ISSYMREF))) {
|
||||
return -1;
|
||||
} else {
|
||||
return peel_object(iter->repo, &iter->oid, peeled) ? -1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void packed_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct packed_ref_iterator *iter =
|
||||
@@ -1056,7 +1043,6 @@ static void packed_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable packed_ref_iterator_vtable = {
|
||||
.advance = packed_ref_iterator_advance,
|
||||
.seek = packed_ref_iterator_seek,
|
||||
.peel = packed_ref_iterator_peel,
|
||||
.release = packed_ref_iterator_release,
|
||||
};
|
||||
|
||||
@@ -1194,7 +1180,6 @@ static struct ref_iterator *packed_ref_iterator_begin(
|
||||
iter->snapshot = snapshot;
|
||||
acquire_snapshot(snapshot);
|
||||
strbuf_init(&iter->refname_buf, 0);
|
||||
iter->base.oid = &iter->oid;
|
||||
iter->repo = ref_store->repo;
|
||||
iter->flags = flags;
|
||||
|
||||
@@ -1436,7 +1421,7 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
|
||||
if (!iter)
|
||||
cmp = +1;
|
||||
else
|
||||
cmp = strcmp(iter->refname, update->refname);
|
||||
cmp = strcmp(iter->ref.name, update->refname);
|
||||
}
|
||||
|
||||
if (!cmp) {
|
||||
@@ -1459,11 +1444,11 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
|
||||
}
|
||||
|
||||
goto error;
|
||||
} else if (!oideq(&update->old_oid, iter->oid)) {
|
||||
} else if (!oideq(&update->old_oid, iter->ref.oid)) {
|
||||
strbuf_addf(err, "cannot update ref '%s': "
|
||||
"is at %s but expected %s",
|
||||
update->refname,
|
||||
oid_to_hex(iter->oid),
|
||||
oid_to_hex(iter->ref.oid),
|
||||
oid_to_hex(&update->old_oid));
|
||||
ret = REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE;
|
||||
|
||||
@@ -1523,13 +1508,8 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
|
||||
|
||||
if (cmp < 0) {
|
||||
/* Pass the old reference through. */
|
||||
|
||||
struct object_id peeled;
|
||||
int peel_error = ref_iterator_peel(iter, &peeled);
|
||||
|
||||
if (write_packed_entry(out, iter->refname,
|
||||
iter->oid,
|
||||
peel_error ? NULL : &peeled))
|
||||
if (write_packed_entry(out, iter->ref.name,
|
||||
iter->ref.oid, iter->ref.peeled_oid))
|
||||
goto write_error;
|
||||
|
||||
if ((ok = ref_iterator_advance(iter)) != ITER_OK) {
|
||||
@@ -1547,9 +1527,8 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
|
||||
i++;
|
||||
} else {
|
||||
struct object_id peeled;
|
||||
int peel_error = peel_object(refs->base.repo,
|
||||
&update->new_oid,
|
||||
&peeled);
|
||||
int peel_error = peel_object(refs->base.repo, &update->new_oid,
|
||||
&peeled, PEEL_OBJECT_VERIFY_OBJECT_TYPE);
|
||||
|
||||
if (write_packed_entry(out, update->refname,
|
||||
&update->new_oid,
|
||||
|
||||
@@ -425,10 +425,11 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
level->prefix_state = entry_prefix_state;
|
||||
level->index = -1;
|
||||
} else {
|
||||
iter->base.refname = entry->name;
|
||||
iter->base.referent = entry->u.value.referent;
|
||||
iter->base.oid = &entry->u.value.oid;
|
||||
iter->base.flags = entry->flag;
|
||||
memset(&iter->base.ref, 0, sizeof(iter->base.ref));
|
||||
iter->base.ref.name = entry->name;
|
||||
iter->base.ref.target = entry->u.value.referent;
|
||||
iter->base.ref.oid = &entry->u.value.oid;
|
||||
iter->base.ref.flags = entry->flag;
|
||||
return ITER_OK;
|
||||
}
|
||||
}
|
||||
@@ -545,14 +546,6 @@ static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
struct cache_ref_iterator *iter =
|
||||
(struct cache_ref_iterator *)ref_iterator;
|
||||
return peel_object(iter->repo, ref_iterator->oid, peeled) ? -1 : 0;
|
||||
}
|
||||
|
||||
static void cache_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct cache_ref_iterator *iter =
|
||||
@@ -564,7 +557,6 @@ static void cache_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable cache_ref_iterator_vtable = {
|
||||
.advance = cache_ref_iterator_advance,
|
||||
.seek = cache_ref_iterator_seek,
|
||||
.peel = cache_ref_iterator_peel,
|
||||
.release = cache_ref_iterator_release,
|
||||
};
|
||||
|
||||
|
||||
@@ -249,10 +249,7 @@ const char *find_descendant_ref(const char *dirname,
|
||||
*/
|
||||
struct ref_iterator {
|
||||
struct ref_iterator_vtable *vtable;
|
||||
const char *refname;
|
||||
const char *referent;
|
||||
const struct object_id *oid;
|
||||
unsigned int flags;
|
||||
struct reference ref;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -360,12 +357,6 @@ typedef int ref_iterator_advance_fn(struct ref_iterator *ref_iterator);
|
||||
typedef int ref_iterator_seek_fn(struct ref_iterator *ref_iterator,
|
||||
const char *refname, unsigned int flags);
|
||||
|
||||
/*
|
||||
* Peels the current ref, returning 0 for success or -1 for failure.
|
||||
*/
|
||||
typedef int ref_iterator_peel_fn(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled);
|
||||
|
||||
/*
|
||||
* Implementations of this function should free any resources specific
|
||||
* to the derived class.
|
||||
@@ -375,23 +366,9 @@ typedef void ref_iterator_release_fn(struct ref_iterator *ref_iterator);
|
||||
struct ref_iterator_vtable {
|
||||
ref_iterator_advance_fn *advance;
|
||||
ref_iterator_seek_fn *seek;
|
||||
ref_iterator_peel_fn *peel;
|
||||
ref_iterator_release_fn *release;
|
||||
};
|
||||
|
||||
/*
|
||||
* current_ref_iter is a performance hack: when iterating over
|
||||
* references using the for_each_ref*() functions, current_ref_iter is
|
||||
* set to the reference iterator before calling the callback function.
|
||||
* If the callback function calls peel_ref(), then peel_ref() first
|
||||
* checks whether the reference to be peeled is the one referred to by
|
||||
* the iterator (it usually is) and if so, asks the iterator for the
|
||||
* peeled version of the reference if it is available. This avoids a
|
||||
* refname lookup in a common case. current_ref_iter is set to NULL
|
||||
* when the iteration is over.
|
||||
*/
|
||||
extern struct ref_iterator *current_ref_iter;
|
||||
|
||||
struct ref_store;
|
||||
|
||||
/* refs backends */
|
||||
|
||||
@@ -547,6 +547,7 @@ struct reftable_ref_iterator {
|
||||
struct reftable_iterator iter;
|
||||
struct reftable_ref_record ref;
|
||||
struct object_id oid;
|
||||
struct object_id peeled_oid;
|
||||
|
||||
char *prefix;
|
||||
size_t prefix_len;
|
||||
@@ -671,6 +672,8 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
case REFTABLE_REF_VAL2:
|
||||
oidread(&iter->oid, iter->ref.value.val2.value,
|
||||
refs->base.repo->hash_algo);
|
||||
oidread(&iter->peeled_oid, iter->ref.value.val2.target_value,
|
||||
refs->base.repo->hash_algo);
|
||||
break;
|
||||
case REFTABLE_REF_SYMREF:
|
||||
referent = refs_resolve_ref_unsafe(&iter->refs->base,
|
||||
@@ -704,10 +707,13 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
&iter->oid, flags))
|
||||
continue;
|
||||
|
||||
iter->base.refname = iter->ref.refname;
|
||||
iter->base.referent = referent;
|
||||
iter->base.oid = &iter->oid;
|
||||
iter->base.flags = flags;
|
||||
memset(&iter->base.ref, 0, sizeof(iter->base.ref));
|
||||
iter->base.ref.name = iter->ref.refname;
|
||||
iter->base.ref.target = referent;
|
||||
iter->base.ref.oid = &iter->oid;
|
||||
if (iter->ref.value_type == REFTABLE_REF_VAL2)
|
||||
iter->base.ref.peeled_oid = &iter->peeled_oid;
|
||||
iter->base.ref.flags = flags;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -738,21 +744,6 @@ static int reftable_ref_iterator_seek(struct ref_iterator *ref_iterator,
|
||||
return iter->err;
|
||||
}
|
||||
|
||||
static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
|
||||
struct object_id *peeled)
|
||||
{
|
||||
struct reftable_ref_iterator *iter =
|
||||
(struct reftable_ref_iterator *)ref_iterator;
|
||||
|
||||
if (iter->ref.value_type == REFTABLE_REF_VAL2) {
|
||||
oidread(peeled, iter->ref.value.val2.target_value,
|
||||
iter->refs->base.repo->hash_algo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void reftable_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct reftable_ref_iterator *iter =
|
||||
@@ -770,7 +761,6 @@ static void reftable_ref_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable reftable_ref_iterator_vtable = {
|
||||
.advance = reftable_ref_iterator_advance,
|
||||
.seek = reftable_ref_iterator_seek,
|
||||
.peel = reftable_ref_iterator_peel,
|
||||
.release = reftable_ref_iterator_release,
|
||||
};
|
||||
|
||||
@@ -828,7 +818,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
|
||||
|
||||
iter = xcalloc(1, sizeof(*iter));
|
||||
base_ref_iterator_init(&iter->base, &reftable_ref_iterator_vtable);
|
||||
iter->base.oid = &iter->oid;
|
||||
iter->base.ref.oid = &iter->oid;
|
||||
iter->flags = flags;
|
||||
iter->refs = refs;
|
||||
iter->exclude_patterns = filter_exclude_patterns(exclude_patterns);
|
||||
@@ -1642,7 +1632,8 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
|
||||
ref.refname = (char *)u->refname;
|
||||
ref.update_index = ts;
|
||||
|
||||
peel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled);
|
||||
peel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled,
|
||||
PEEL_OBJECT_VERIFY_OBJECT_TYPE);
|
||||
if (!peel_error) {
|
||||
ref.value_type = REFTABLE_REF_VAL2;
|
||||
memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
|
||||
@@ -2072,7 +2063,7 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
|
||||
strbuf_reset(&iter->last_name);
|
||||
strbuf_addstr(&iter->last_name, iter->log.refname);
|
||||
iter->base.refname = iter->log.refname;
|
||||
iter->base.ref.name = iter->log.refname;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -2092,13 +2083,6 @@ static int reftable_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSE
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int reftable_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
|
||||
struct object_id *peeled UNUSED)
|
||||
{
|
||||
BUG("reftable reflog iterator cannot be peeled");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void reftable_reflog_iterator_release(struct ref_iterator *ref_iterator)
|
||||
{
|
||||
struct reftable_reflog_iterator *iter =
|
||||
@@ -2111,7 +2095,6 @@ static void reftable_reflog_iterator_release(struct ref_iterator *ref_iterator)
|
||||
static struct ref_iterator_vtable reftable_reflog_iterator_vtable = {
|
||||
.advance = reftable_reflog_iterator_advance,
|
||||
.seek = reftable_reflog_iterator_seek,
|
||||
.peel = reftable_reflog_iterator_peel,
|
||||
.release = reftable_reflog_iterator_release,
|
||||
};
|
||||
|
||||
@@ -2515,7 +2498,7 @@ static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_da
|
||||
ref.refname = (char *)arg->refname;
|
||||
ref.update_index = ts;
|
||||
|
||||
if (!peel_object(arg->refs->base.repo, &arg->update_oid, &peeled)) {
|
||||
if (!peel_object(arg->refs->base.repo, &arg->update_oid, &peeled, 0)) {
|
||||
ref.value_type = REFTABLE_REF_VAL2;
|
||||
memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
|
||||
memcpy(ref.value.val2.value, arg->update_oid.hash, GIT_MAX_RAWSZ);
|
||||
|
||||
27
remote.c
27
remote.c
@@ -2315,21 +2315,19 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int one_local_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data)
|
||||
static int one_local_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct ref ***local_tail = cb_data;
|
||||
struct ref *ref;
|
||||
struct ref *local_ref;
|
||||
|
||||
/* we already know it starts with refs/ to get here */
|
||||
if (check_refname_format(refname + 5, 0))
|
||||
if (check_refname_format(ref->name + 5, 0))
|
||||
return 0;
|
||||
|
||||
ref = alloc_ref(refname);
|
||||
oidcpy(&ref->new_oid, oid);
|
||||
**local_tail = ref;
|
||||
*local_tail = &ref->next;
|
||||
local_ref = alloc_ref(ref->name);
|
||||
oidcpy(&local_ref->new_oid, ref->oid);
|
||||
**local_tail = local_ref;
|
||||
*local_tail = &local_ref->next;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2402,15 +2400,14 @@ struct stale_heads_info {
|
||||
struct refspec *rs;
|
||||
};
|
||||
|
||||
static int get_stale_heads_cb(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags, void *cb_data)
|
||||
static int get_stale_heads_cb(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct stale_heads_info *info = cb_data;
|
||||
struct string_list matches = STRING_LIST_INIT_DUP;
|
||||
struct refspec_item query;
|
||||
int i, stale = 1;
|
||||
memset(&query, 0, sizeof(struct refspec_item));
|
||||
query.dst = (char *)refname;
|
||||
query.dst = (char *)ref->name;
|
||||
|
||||
refspec_find_all_matches(info->rs, &query, &matches);
|
||||
if (matches.nr == 0)
|
||||
@@ -2423,7 +2420,7 @@ static int get_stale_heads_cb(const char *refname, const char *referent UNUSED,
|
||||
* overlapping refspecs, we need to go over all of the
|
||||
* matching refs.
|
||||
*/
|
||||
if (flags & REF_ISSYMREF)
|
||||
if (ref->flags & REF_ISSYMREF)
|
||||
goto clean_exit;
|
||||
|
||||
for (i = 0; stale && i < matches.nr; i++)
|
||||
@@ -2431,8 +2428,8 @@ static int get_stale_heads_cb(const char *refname, const char *referent UNUSED,
|
||||
stale = 0;
|
||||
|
||||
if (stale) {
|
||||
struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
|
||||
oidcpy(&ref->new_oid, oid);
|
||||
struct ref *linked_ref = make_linked_ref(ref->name, &info->stale_refs_tail);
|
||||
oidcpy(&linked_ref->new_oid, ref->oid);
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
|
||||
99
repack-cruft.c
Normal file
99
repack-cruft.c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "git-compat-util.h"
|
||||
#include "repack.h"
|
||||
#include "packfile.h"
|
||||
#include "repository.h"
|
||||
#include "run-command.h"
|
||||
|
||||
static void combine_small_cruft_packs(FILE *in, off_t combine_cruft_below_size,
|
||||
struct existing_packs *existing)
|
||||
{
|
||||
struct packfile_store *packs = existing->repo->objects->packfiles;
|
||||
struct packed_git *p;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
size_t i;
|
||||
|
||||
for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
|
||||
if (!(p->is_cruft && p->pack_local))
|
||||
continue;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, pack_basename(p));
|
||||
strbuf_strip_suffix(&buf, ".pack");
|
||||
|
||||
if (!string_list_has_string(&existing->cruft_packs, buf.buf))
|
||||
continue;
|
||||
|
||||
if (p->pack_size < combine_cruft_below_size) {
|
||||
fprintf(in, "-%s\n", pack_basename(p));
|
||||
} else {
|
||||
existing_packs_retain_cruft(existing, p);
|
||||
fprintf(in, "%s\n", pack_basename(p));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < existing->non_kept_packs.nr; i++)
|
||||
fprintf(in, "-%s.pack\n",
|
||||
existing->non_kept_packs.items[i].string);
|
||||
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
int write_cruft_pack(const struct write_pack_opts *opts,
|
||||
const char *cruft_expiration,
|
||||
unsigned long combine_cruft_below_size,
|
||||
struct string_list *names,
|
||||
struct existing_packs *existing)
|
||||
{
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
struct string_list_item *item;
|
||||
FILE *in;
|
||||
int ret;
|
||||
const char *pack_prefix = write_pack_opts_pack_prefix(opts);
|
||||
|
||||
prepare_pack_objects(&cmd, opts->po_args, opts->destination);
|
||||
|
||||
strvec_push(&cmd.args, "--cruft");
|
||||
if (cruft_expiration)
|
||||
strvec_pushf(&cmd.args, "--cruft-expiration=%s",
|
||||
cruft_expiration);
|
||||
|
||||
strvec_push(&cmd.args, "--non-empty");
|
||||
|
||||
cmd.in = -1;
|
||||
|
||||
ret = start_command(&cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* names has a confusing double use: it both provides the list
|
||||
* of just-written new packs, and accepts the name of the cruft
|
||||
* pack we are writing.
|
||||
*
|
||||
* By the time it is read here, it contains only the pack(s)
|
||||
* that were just written, which is exactly the set of packs we
|
||||
* want to consider kept.
|
||||
*
|
||||
* If `--expire-to` is given, the double-use served by `names`
|
||||
* ensures that the pack written to `--expire-to` excludes any
|
||||
* objects contained in the cruft pack.
|
||||
*/
|
||||
in = xfdopen(cmd.in, "w");
|
||||
for_each_string_list_item(item, names)
|
||||
fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
|
||||
if (combine_cruft_below_size && !cruft_expiration) {
|
||||
combine_small_cruft_packs(in, combine_cruft_below_size,
|
||||
existing);
|
||||
} else {
|
||||
for_each_string_list_item(item, &existing->non_kept_packs)
|
||||
fprintf(in, "-%s.pack\n", item->string);
|
||||
for_each_string_list_item(item, &existing->cruft_packs)
|
||||
fprintf(in, "-%s.pack\n", item->string);
|
||||
}
|
||||
for_each_string_list_item(item, &existing->kept_packs)
|
||||
fprintf(in, "%s.pack\n", item->string);
|
||||
fclose(in);
|
||||
|
||||
return finish_pack_objects_cmd(existing->repo->hash_algo, opts, &cmd,
|
||||
names);
|
||||
}
|
||||
51
repack-filtered.c
Normal file
51
repack-filtered.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "git-compat-util.h"
|
||||
#include "repack.h"
|
||||
#include "repository.h"
|
||||
#include "run-command.h"
|
||||
#include "string-list.h"
|
||||
|
||||
int write_filtered_pack(const struct write_pack_opts *opts,
|
||||
struct existing_packs *existing,
|
||||
struct string_list *names)
|
||||
{
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
struct string_list_item *item;
|
||||
FILE *in;
|
||||
int ret;
|
||||
const char *caret;
|
||||
const char *pack_prefix = write_pack_opts_pack_prefix(opts);
|
||||
|
||||
prepare_pack_objects(&cmd, opts->po_args, opts->destination);
|
||||
|
||||
strvec_push(&cmd.args, "--stdin-packs");
|
||||
|
||||
for_each_string_list_item(item, &existing->kept_packs)
|
||||
strvec_pushf(&cmd.args, "--keep-pack=%s", item->string);
|
||||
|
||||
cmd.in = -1;
|
||||
|
||||
ret = start_command(&cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Here 'names' contains only the pack(s) that were just
|
||||
* written, which is exactly the packs we want to keep. Also
|
||||
* 'existing_kept_packs' already contains the packs in
|
||||
* 'keep_pack_list'.
|
||||
*/
|
||||
in = xfdopen(cmd.in, "w");
|
||||
for_each_string_list_item(item, names)
|
||||
fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string);
|
||||
for_each_string_list_item(item, &existing->non_kept_packs)
|
||||
fprintf(in, "%s.pack\n", item->string);
|
||||
for_each_string_list_item(item, &existing->cruft_packs)
|
||||
fprintf(in, "%s.pack\n", item->string);
|
||||
caret = opts->po_args->pack_kept_objects ? "" : "^";
|
||||
for_each_string_list_item(item, &existing->kept_packs)
|
||||
fprintf(in, "%s%s.pack\n", caret, item->string);
|
||||
fclose(in);
|
||||
|
||||
return finish_pack_objects_cmd(existing->repo->hash_algo, opts, &cmd,
|
||||
names);
|
||||
}
|
||||
233
repack-geometry.c
Normal file
233
repack-geometry.c
Normal file
@@ -0,0 +1,233 @@
|
||||
#define DISABLE_SIGN_COMPARE_WARNINGS
|
||||
|
||||
#include "git-compat-util.h"
|
||||
#include "repack.h"
|
||||
#include "repository.h"
|
||||
#include "hex.h"
|
||||
#include "packfile.h"
|
||||
|
||||
static uint32_t pack_geometry_weight(struct packed_git *p)
|
||||
{
|
||||
if (open_pack_index(p))
|
||||
die(_("cannot open index for %s"), p->pack_name);
|
||||
return p->num_objects;
|
||||
}
|
||||
|
||||
static int pack_geometry_cmp(const void *va, const void *vb)
|
||||
{
|
||||
uint32_t aw = pack_geometry_weight(*(struct packed_git **)va),
|
||||
bw = pack_geometry_weight(*(struct packed_git **)vb);
|
||||
|
||||
if (aw < bw)
|
||||
return -1;
|
||||
if (aw > bw)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pack_geometry_init(struct pack_geometry *geometry,
|
||||
struct existing_packs *existing,
|
||||
const struct pack_objects_args *args)
|
||||
{
|
||||
struct packfile_store *packs = existing->repo->objects->packfiles;
|
||||
struct packed_git *p;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
|
||||
if (args->local && !p->pack_local)
|
||||
/*
|
||||
* When asked to only repack local packfiles we skip
|
||||
* over any packfiles that are borrowed from alternate
|
||||
* object directories.
|
||||
*/
|
||||
continue;
|
||||
|
||||
if (!args->pack_kept_objects) {
|
||||
/*
|
||||
* Any pack that has its pack_keep bit set will
|
||||
* appear in existing->kept_packs below, but
|
||||
* this saves us from doing a more expensive
|
||||
* check.
|
||||
*/
|
||||
if (p->pack_keep)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* The pack may be kept via the --keep-pack
|
||||
* option; check 'existing->kept_packs' to
|
||||
* determine whether to ignore it.
|
||||
*/
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, pack_basename(p));
|
||||
strbuf_strip_suffix(&buf, ".pack");
|
||||
|
||||
if (string_list_has_string(&existing->kept_packs, buf.buf))
|
||||
continue;
|
||||
}
|
||||
if (p->is_cruft)
|
||||
continue;
|
||||
|
||||
ALLOC_GROW(geometry->pack,
|
||||
geometry->pack_nr + 1,
|
||||
geometry->pack_alloc);
|
||||
|
||||
geometry->pack[geometry->pack_nr] = p;
|
||||
geometry->pack_nr++;
|
||||
}
|
||||
|
||||
QSORT(geometry->pack, geometry->pack_nr, pack_geometry_cmp);
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
void pack_geometry_split(struct pack_geometry *geometry)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t split;
|
||||
off_t total_size = 0;
|
||||
|
||||
if (!geometry->pack_nr) {
|
||||
geometry->split = geometry->pack_nr;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, count the number of packs (in descending order of size) which
|
||||
* already form a geometric progression.
|
||||
*/
|
||||
for (i = geometry->pack_nr - 1; i > 0; i--) {
|
||||
struct packed_git *ours = geometry->pack[i];
|
||||
struct packed_git *prev = geometry->pack[i - 1];
|
||||
|
||||
if (unsigned_mult_overflows(geometry->split_factor,
|
||||
pack_geometry_weight(prev)))
|
||||
die(_("pack %s too large to consider in geometric "
|
||||
"progression"),
|
||||
prev->pack_name);
|
||||
|
||||
if (pack_geometry_weight(ours) <
|
||||
geometry->split_factor * pack_geometry_weight(prev))
|
||||
break;
|
||||
}
|
||||
|
||||
split = i;
|
||||
|
||||
if (split) {
|
||||
/*
|
||||
* Move the split one to the right, since the top element in the
|
||||
* last-compared pair can't be in the progression. Only do this
|
||||
* when we split in the middle of the array (otherwise if we got
|
||||
* to the end, then the split is in the right place).
|
||||
*/
|
||||
split++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Then, anything to the left of 'split' must be in a new pack. But,
|
||||
* creating that new pack may cause packs in the heavy half to no longer
|
||||
* form a geometric progression.
|
||||
*
|
||||
* Compute an expected size of the new pack, and then determine how many
|
||||
* packs in the heavy half need to be joined into it (if any) to restore
|
||||
* the geometric progression.
|
||||
*/
|
||||
for (i = 0; i < split; i++) {
|
||||
struct packed_git *p = geometry->pack[i];
|
||||
|
||||
if (unsigned_add_overflows(total_size, pack_geometry_weight(p)))
|
||||
die(_("pack %s too large to roll up"), p->pack_name);
|
||||
total_size += pack_geometry_weight(p);
|
||||
}
|
||||
for (i = split; i < geometry->pack_nr; i++) {
|
||||
struct packed_git *ours = geometry->pack[i];
|
||||
|
||||
if (unsigned_mult_overflows(geometry->split_factor,
|
||||
total_size))
|
||||
die(_("pack %s too large to roll up"), ours->pack_name);
|
||||
|
||||
if (pack_geometry_weight(ours) <
|
||||
geometry->split_factor * total_size) {
|
||||
if (unsigned_add_overflows(total_size,
|
||||
pack_geometry_weight(ours)))
|
||||
die(_("pack %s too large to roll up"),
|
||||
ours->pack_name);
|
||||
|
||||
split++;
|
||||
total_size += pack_geometry_weight(ours);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
geometry->split = split;
|
||||
}
|
||||
|
||||
struct packed_git *pack_geometry_preferred_pack(struct pack_geometry *geometry)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (!geometry) {
|
||||
/*
|
||||
* No geometry means either an all-into-one repack (in which
|
||||
* case there is only one pack left and it is the largest) or an
|
||||
* incremental one.
|
||||
*
|
||||
* If repacking incrementally, then we could check the size of
|
||||
* all packs to determine which should be preferred, but leave
|
||||
* this for later.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
if (geometry->split == geometry->pack_nr)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* The preferred pack is the largest pack above the split line. In
|
||||
* other words, it is the largest pack that does not get rolled up in
|
||||
* the geometric repack.
|
||||
*/
|
||||
for (i = geometry->pack_nr; i > geometry->split; i--)
|
||||
/*
|
||||
* A pack that is not local would never be included in a
|
||||
* multi-pack index. We thus skip over any non-local packs.
|
||||
*/
|
||||
if (geometry->pack[i - 1]->pack_local)
|
||||
return geometry->pack[i - 1];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pack_geometry_remove_redundant(struct pack_geometry *geometry,
|
||||
struct string_list *names,
|
||||
struct existing_packs *existing,
|
||||
const char *packdir)
|
||||
{
|
||||
const struct git_hash_algo *algop = existing->repo->hash_algo;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < geometry->split; i++) {
|
||||
struct packed_git *p = geometry->pack[i];
|
||||
if (string_list_has_string(names, hash_to_hex_algop(p->hash,
|
||||
algop)))
|
||||
continue;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, pack_basename(p));
|
||||
strbuf_strip_suffix(&buf, ".pack");
|
||||
|
||||
if ((p->pack_keep) ||
|
||||
(string_list_has_string(&existing->kept_packs, buf.buf)))
|
||||
continue;
|
||||
|
||||
repack_remove_redundant_pack(existing->repo, packdir, buf.buf);
|
||||
}
|
||||
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
void pack_geometry_release(struct pack_geometry *geometry)
|
||||
{
|
||||
if (!geometry)
|
||||
return;
|
||||
|
||||
free(geometry->pack);
|
||||
}
|
||||
370
repack-midx.c
Normal file
370
repack-midx.c
Normal file
@@ -0,0 +1,370 @@
|
||||
#include "git-compat-util.h"
|
||||
#include "repack.h"
|
||||
#include "hash.h"
|
||||
#include "hex.h"
|
||||
#include "odb.h"
|
||||
#include "oidset.h"
|
||||
#include "pack-bitmap.h"
|
||||
#include "refs.h"
|
||||
#include "run-command.h"
|
||||
#include "tempfile.h"
|
||||
|
||||
struct midx_snapshot_ref_data {
|
||||
struct repository *repo;
|
||||
struct tempfile *f;
|
||||
struct oidset seen;
|
||||
int preferred;
|
||||
};
|
||||
|
||||
static int midx_snapshot_ref_one(const struct reference *ref, void *_data)
|
||||
{
|
||||
struct midx_snapshot_ref_data *data = _data;
|
||||
const struct object_id *maybe_peeled = ref->oid;
|
||||
struct object_id peeled;
|
||||
|
||||
if (!reference_get_peeled_oid(data->repo, ref, &peeled))
|
||||
maybe_peeled = &peeled;
|
||||
|
||||
if (oidset_insert(&data->seen, maybe_peeled))
|
||||
return 0; /* already seen */
|
||||
|
||||
if (odb_read_object_info(data->repo->objects, maybe_peeled, NULL) != OBJ_COMMIT)
|
||||
return 0;
|
||||
|
||||
fprintf(data->f->fp, "%s%s\n", data->preferred ? "+" : "",
|
||||
oid_to_hex(maybe_peeled));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void midx_snapshot_refs(struct repository *repo, struct tempfile *f)
|
||||
{
|
||||
struct midx_snapshot_ref_data data;
|
||||
const struct string_list *preferred = bitmap_preferred_tips(repo);
|
||||
|
||||
data.repo = repo;
|
||||
data.f = f;
|
||||
data.preferred = 0;
|
||||
oidset_init(&data.seen, 0);
|
||||
|
||||
if (!fdopen_tempfile(f, "w"))
|
||||
die(_("could not open tempfile %s for writing"),
|
||||
get_tempfile_path(f));
|
||||
|
||||
if (preferred) {
|
||||
struct string_list_item *item;
|
||||
|
||||
data.preferred = 1;
|
||||
for_each_string_list_item(item, preferred)
|
||||
refs_for_each_ref_in(get_main_ref_store(repo),
|
||||
item->string,
|
||||
midx_snapshot_ref_one, &data);
|
||||
data.preferred = 0;
|
||||
}
|
||||
|
||||
refs_for_each_ref(get_main_ref_store(repo),
|
||||
midx_snapshot_ref_one, &data);
|
||||
|
||||
if (close_tempfile_gently(f)) {
|
||||
int save_errno = errno;
|
||||
delete_tempfile(&f);
|
||||
errno = save_errno;
|
||||
die_errno(_("could not close refs snapshot tempfile"));
|
||||
}
|
||||
|
||||
oidset_clear(&data.seen);
|
||||
}
|
||||
|
||||
static int midx_has_unknown_packs(struct string_list *include,
|
||||
struct pack_geometry *geometry,
|
||||
struct existing_packs *existing)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
|
||||
string_list_sort(include);
|
||||
|
||||
for_each_string_list_item(item, &existing->midx_packs) {
|
||||
const char *pack_name = item->string;
|
||||
|
||||
/*
|
||||
* Determine whether or not each MIDX'd pack from the existing
|
||||
* MIDX (if any) is represented in the new MIDX. For each pack
|
||||
* in the MIDX, it must either be:
|
||||
*
|
||||
* - In the "include" list of packs to be included in the new
|
||||
* MIDX. Note this function is called before the include
|
||||
* list is populated with any cruft pack(s).
|
||||
*
|
||||
* - Below the geometric split line (if using pack geometry),
|
||||
* indicating that the pack won't be included in the new
|
||||
* MIDX, but its contents were rolled up as part of the
|
||||
* geometric repack.
|
||||
*
|
||||
* - In the existing non-kept packs list (if not using pack
|
||||
* geometry), and marked as non-deleted.
|
||||
*/
|
||||
if (string_list_has_string(include, pack_name)) {
|
||||
continue;
|
||||
} else if (geometry) {
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
uint32_t j;
|
||||
|
||||
for (j = 0; j < geometry->split; j++) {
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, pack_basename(geometry->pack[j]));
|
||||
strbuf_strip_suffix(&buf, ".pack");
|
||||
strbuf_addstr(&buf, ".idx");
|
||||
|
||||
if (!strcmp(pack_name, buf.buf)) {
|
||||
strbuf_release(&buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strbuf_release(&buf);
|
||||
|
||||
if (j < geometry->split)
|
||||
continue;
|
||||
} else {
|
||||
struct string_list_item *item;
|
||||
|
||||
item = string_list_lookup(&existing->non_kept_packs,
|
||||
pack_name);
|
||||
if (item && !existing_pack_is_marked_for_deletion(item))
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we got to this point, the MIDX includes some pack that we
|
||||
* don't know about.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void midx_included_packs(struct string_list *include,
|
||||
struct repack_write_midx_opts *opts)
|
||||
{
|
||||
struct existing_packs *existing = opts->existing;
|
||||
struct pack_geometry *geometry = opts->geometry;
|
||||
struct string_list *names = opts->names;
|
||||
struct string_list_item *item;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
for_each_string_list_item(item, &existing->kept_packs) {
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "%s.idx", item->string);
|
||||
string_list_insert(include, buf.buf);
|
||||
}
|
||||
|
||||
for_each_string_list_item(item, names) {
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "pack-%s.idx", item->string);
|
||||
string_list_insert(include, buf.buf);
|
||||
}
|
||||
|
||||
if (geometry->split_factor) {
|
||||
uint32_t i;
|
||||
|
||||
for (i = geometry->split; i < geometry->pack_nr; i++) {
|
||||
struct packed_git *p = geometry->pack[i];
|
||||
|
||||
/*
|
||||
* The multi-pack index never refers to packfiles part
|
||||
* of an alternate object database, so we skip these.
|
||||
* While git-multi-pack-index(1) would silently ignore
|
||||
* them anyway, this allows us to skip executing the
|
||||
* command completely when we have only non-local
|
||||
* packfiles.
|
||||
*/
|
||||
if (!p->pack_local)
|
||||
continue;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, pack_basename(p));
|
||||
strbuf_strip_suffix(&buf, ".pack");
|
||||
strbuf_addstr(&buf, ".idx");
|
||||
|
||||
string_list_insert(include, buf.buf);
|
||||
}
|
||||
} else {
|
||||
for_each_string_list_item(item, &existing->non_kept_packs) {
|
||||
if (existing_pack_is_marked_for_deletion(item))
|
||||
continue;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "%s.idx", item->string);
|
||||
string_list_insert(include, buf.buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->midx_must_contain_cruft ||
|
||||
midx_has_unknown_packs(include, geometry, existing)) {
|
||||
/*
|
||||
* If there are one or more unknown pack(s) present (see
|
||||
* midx_has_unknown_packs() for what makes a pack
|
||||
* "unknown") in the MIDX before the repack, keep them
|
||||
* as they may be required to form a reachability
|
||||
* closure if the MIDX is bitmapped.
|
||||
*
|
||||
* For example, a cruft pack can be required to form a
|
||||
* reachability closure if the MIDX is bitmapped and one
|
||||
* or more of the bitmap's selected commits reaches a
|
||||
* once-cruft object that was later made reachable.
|
||||
*/
|
||||
for_each_string_list_item(item, &existing->cruft_packs) {
|
||||
/*
|
||||
* When doing a --geometric repack, there is no
|
||||
* need to check for deleted packs, since we're
|
||||
* by definition not doing an ALL_INTO_ONE
|
||||
* repack (hence no packs will be deleted).
|
||||
* Otherwise we must check for and exclude any
|
||||
* packs which are enqueued for deletion.
|
||||
*
|
||||
* So we could omit the conditional below in the
|
||||
* --geometric case, but doing so is unnecessary
|
||||
* since no packs are marked as pending
|
||||
* deletion (since we only call
|
||||
* `existing_packs_mark_for_deletion()` when
|
||||
* doing an all-into-one repack).
|
||||
*/
|
||||
if (existing_pack_is_marked_for_deletion(item))
|
||||
continue;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "%s.idx", item->string);
|
||||
string_list_insert(include, buf.buf);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Modern versions of Git (with the appropriate
|
||||
* configuration setting) will write new copies of
|
||||
* once-cruft objects when doing a --geometric repack.
|
||||
*
|
||||
* If the MIDX has no cruft pack, new packs written
|
||||
* during a --geometric repack will not rely on the
|
||||
* cruft pack to form a reachability closure, so we can
|
||||
* avoid including them in the MIDX in that case.
|
||||
*/
|
||||
;
|
||||
}
|
||||
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
static void remove_redundant_bitmaps(struct string_list *include,
|
||||
const char *packdir)
|
||||
{
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
struct string_list_item *item;
|
||||
size_t packdir_len;
|
||||
|
||||
strbuf_addstr(&path, packdir);
|
||||
strbuf_addch(&path, '/');
|
||||
packdir_len = path.len;
|
||||
|
||||
/*
|
||||
* Remove any pack bitmaps corresponding to packs which are now
|
||||
* included in the MIDX.
|
||||
*/
|
||||
for_each_string_list_item(item, include) {
|
||||
strbuf_addstr(&path, item->string);
|
||||
strbuf_strip_suffix(&path, ".idx");
|
||||
strbuf_addstr(&path, ".bitmap");
|
||||
|
||||
if (unlink(path.buf) && errno != ENOENT)
|
||||
warning_errno(_("could not remove stale bitmap: %s"),
|
||||
path.buf);
|
||||
|
||||
strbuf_setlen(&path, packdir_len);
|
||||
}
|
||||
strbuf_release(&path);
|
||||
}
|
||||
|
||||
int write_midx_included_packs(struct repack_write_midx_opts *opts)
|
||||
{
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
struct string_list include = STRING_LIST_INIT_DUP;
|
||||
struct string_list_item *item;
|
||||
struct packed_git *preferred = pack_geometry_preferred_pack(opts->geometry);
|
||||
FILE *in;
|
||||
int ret = 0;
|
||||
|
||||
midx_included_packs(&include, opts);
|
||||
if (!include.nr)
|
||||
goto done;
|
||||
|
||||
cmd.in = -1;
|
||||
cmd.git_cmd = 1;
|
||||
|
||||
strvec_push(&cmd.args, "multi-pack-index");
|
||||
strvec_pushl(&cmd.args, "write", "--stdin-packs", NULL);
|
||||
|
||||
if (opts->show_progress)
|
||||
strvec_push(&cmd.args, "--progress");
|
||||
else
|
||||
strvec_push(&cmd.args, "--no-progress");
|
||||
|
||||
if (opts->write_bitmaps)
|
||||
strvec_push(&cmd.args, "--bitmap");
|
||||
|
||||
if (preferred)
|
||||
strvec_pushf(&cmd.args, "--preferred-pack=%s",
|
||||
pack_basename(preferred));
|
||||
else if (opts->names->nr) {
|
||||
/* The largest pack was repacked, meaning that either
|
||||
* one or two packs exist depending on whether the
|
||||
* repository has a cruft pack or not.
|
||||
*
|
||||
* Select the non-cruft one as preferred to encourage
|
||||
* pack-reuse among packs containing reachable objects
|
||||
* over unreachable ones.
|
||||
*
|
||||
* (Note we could write multiple packs here if
|
||||
* `--max-pack-size` was given, but any one of them
|
||||
* will suffice, so pick the first one.)
|
||||
*/
|
||||
for_each_string_list_item(item, opts->names) {
|
||||
struct generated_pack *pack = item->util;
|
||||
if (generated_pack_has_ext(pack, ".mtimes"))
|
||||
continue;
|
||||
|
||||
strvec_pushf(&cmd.args, "--preferred-pack=pack-%s.pack",
|
||||
item->string);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* No packs were kept, and no packs were written. The
|
||||
* only thing remaining are .keep packs (unless
|
||||
* --pack-kept-objects was given).
|
||||
*
|
||||
* Set the `--preferred-pack` arbitrarily here.
|
||||
*/
|
||||
;
|
||||
}
|
||||
|
||||
if (opts->refs_snapshot)
|
||||
strvec_pushf(&cmd.args, "--refs-snapshot=%s",
|
||||
opts->refs_snapshot);
|
||||
|
||||
ret = start_command(&cmd);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
in = xfdopen(cmd.in, "w");
|
||||
for_each_string_list_item(item, &include)
|
||||
fprintf(in, "%s\n", item->string);
|
||||
fclose(in);
|
||||
|
||||
ret = finish_command(&cmd);
|
||||
done:
|
||||
if (!ret && opts->write_bitmaps)
|
||||
remove_redundant_bitmaps(&include, opts->packdir);
|
||||
|
||||
string_list_clear(&include, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
102
repack-promisor.c
Normal file
102
repack-promisor.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "git-compat-util.h"
|
||||
#include "repack.h"
|
||||
#include "hex.h"
|
||||
#include "pack.h"
|
||||
#include "packfile.h"
|
||||
#include "path.h"
|
||||
#include "repository.h"
|
||||
#include "run-command.h"
|
||||
|
||||
struct write_oid_context {
|
||||
struct child_process *cmd;
|
||||
const struct git_hash_algo *algop;
|
||||
};
|
||||
|
||||
/*
|
||||
* Write oid to the given struct child_process's stdin, starting it first if
|
||||
* necessary.
|
||||
*/
|
||||
static int write_oid(const struct object_id *oid,
|
||||
struct packed_git *pack UNUSED,
|
||||
uint32_t pos UNUSED, void *data)
|
||||
{
|
||||
struct write_oid_context *ctx = data;
|
||||
struct child_process *cmd = ctx->cmd;
|
||||
|
||||
if (cmd->in == -1) {
|
||||
if (start_command(cmd))
|
||||
die(_("could not start pack-objects to repack promisor objects"));
|
||||
}
|
||||
|
||||
if (write_in_full(cmd->in, oid_to_hex(oid), ctx->algop->hexsz) < 0 ||
|
||||
write_in_full(cmd->in, "\n", 1) < 0)
|
||||
die(_("failed to feed promisor objects to pack-objects"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void repack_promisor_objects(struct repository *repo,
|
||||
const struct pack_objects_args *args,
|
||||
struct string_list *names, const char *packtmp)
|
||||
{
|
||||
struct write_oid_context ctx;
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
FILE *out;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
|
||||
prepare_pack_objects(&cmd, args, packtmp);
|
||||
cmd.in = -1;
|
||||
|
||||
/*
|
||||
* NEEDSWORK: Giving pack-objects only the OIDs without any ordering
|
||||
* hints may result in suboptimal deltas in the resulting pack. See if
|
||||
* the OIDs can be sent with fake paths such that pack-objects can use a
|
||||
* {type -> existing pack order} ordering when computing deltas instead
|
||||
* of a {type -> size} ordering, which may produce better deltas.
|
||||
*/
|
||||
ctx.cmd = &cmd;
|
||||
ctx.algop = repo->hash_algo;
|
||||
for_each_packed_object(repo, write_oid, &ctx,
|
||||
FOR_EACH_OBJECT_PROMISOR_ONLY);
|
||||
|
||||
if (cmd.in == -1) {
|
||||
/* No packed objects; cmd was never started */
|
||||
child_process_clear(&cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
close(cmd.in);
|
||||
|
||||
out = xfdopen(cmd.out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
char *promisor_name;
|
||||
|
||||
if (line.len != repo->hash_algo->hexsz)
|
||||
die(_("repack: Expecting full hex object ID lines only from pack-objects."));
|
||||
item = string_list_append(names, line.buf);
|
||||
|
||||
/*
|
||||
* pack-objects creates the .pack and .idx files, but not the
|
||||
* .promisor file. Create the .promisor file, which is empty.
|
||||
*
|
||||
* NEEDSWORK: fetch-pack sometimes generates non-empty
|
||||
* .promisor files containing the ref names and associated
|
||||
* hashes at the point of generation of the corresponding
|
||||
* packfile, but this would not preserve their contents. Maybe
|
||||
* concatenate the contents of all .promisor files instead of
|
||||
* just creating a new empty file.
|
||||
*/
|
||||
promisor_name = mkpathdup("%s-%s.promisor", packtmp,
|
||||
line.buf);
|
||||
write_promisor_file(promisor_name, NULL, 0);
|
||||
|
||||
item->util = generated_pack_populate(item->string, packtmp);
|
||||
|
||||
free(promisor_name);
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
if (finish_command(&cmd))
|
||||
die(_("could not finish pack-objects to repack promisor objects"));
|
||||
strbuf_release(&line);
|
||||
}
|
||||
360
repack.c
Normal file
360
repack.c
Normal file
@@ -0,0 +1,360 @@
|
||||
#include "git-compat-util.h"
|
||||
#include "dir.h"
|
||||
#include "midx.h"
|
||||
#include "odb.h"
|
||||
#include "packfile.h"
|
||||
#include "path.h"
|
||||
#include "repack.h"
|
||||
#include "repository.h"
|
||||
#include "run-command.h"
|
||||
#include "tempfile.h"
|
||||
|
||||
void prepare_pack_objects(struct child_process *cmd,
|
||||
const struct pack_objects_args *args,
|
||||
const char *out)
|
||||
{
|
||||
strvec_push(&cmd->args, "pack-objects");
|
||||
if (args->window)
|
||||
strvec_pushf(&cmd->args, "--window=%s", args->window);
|
||||
if (args->window_memory)
|
||||
strvec_pushf(&cmd->args, "--window-memory=%s", args->window_memory);
|
||||
if (args->depth)
|
||||
strvec_pushf(&cmd->args, "--depth=%s", args->depth);
|
||||
if (args->threads)
|
||||
strvec_pushf(&cmd->args, "--threads=%s", args->threads);
|
||||
if (args->max_pack_size)
|
||||
strvec_pushf(&cmd->args, "--max-pack-size=%lu", args->max_pack_size);
|
||||
if (args->no_reuse_delta)
|
||||
strvec_pushf(&cmd->args, "--no-reuse-delta");
|
||||
if (args->no_reuse_object)
|
||||
strvec_pushf(&cmd->args, "--no-reuse-object");
|
||||
if (args->name_hash_version)
|
||||
strvec_pushf(&cmd->args, "--name-hash-version=%d", args->name_hash_version);
|
||||
if (args->path_walk)
|
||||
strvec_pushf(&cmd->args, "--path-walk");
|
||||
if (args->local)
|
||||
strvec_push(&cmd->args, "--local");
|
||||
if (args->quiet)
|
||||
strvec_push(&cmd->args, "--quiet");
|
||||
if (args->delta_base_offset)
|
||||
strvec_push(&cmd->args, "--delta-base-offset");
|
||||
if (!args->pack_kept_objects)
|
||||
strvec_push(&cmd->args, "--honor-pack-keep");
|
||||
strvec_push(&cmd->args, out);
|
||||
cmd->git_cmd = 1;
|
||||
cmd->out = -1;
|
||||
}
|
||||
|
||||
void pack_objects_args_release(struct pack_objects_args *args)
|
||||
{
|
||||
free(args->window);
|
||||
free(args->window_memory);
|
||||
free(args->depth);
|
||||
free(args->threads);
|
||||
list_objects_filter_release(&args->filter_options);
|
||||
}
|
||||
|
||||
void repack_remove_redundant_pack(struct repository *repo, const char *dir_name,
|
||||
const char *base_name)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct odb_source *source = repo->objects->sources;
|
||||
struct multi_pack_index *m = get_multi_pack_index(source);
|
||||
strbuf_addf(&buf, "%s.pack", base_name);
|
||||
if (m && source->local && midx_contains_pack(m, buf.buf))
|
||||
clear_midx_file(repo);
|
||||
strbuf_insertf(&buf, 0, "%s/", dir_name);
|
||||
unlink_pack_path(buf.buf, 1);
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
const char *write_pack_opts_pack_prefix(const struct write_pack_opts *opts)
|
||||
{
|
||||
const char *pack_prefix;
|
||||
if (!skip_prefix(opts->packtmp, opts->packdir, &pack_prefix))
|
||||
die(_("pack prefix %s does not begin with objdir %s"),
|
||||
opts->packtmp, opts->packdir);
|
||||
if (*pack_prefix == '/')
|
||||
pack_prefix++;
|
||||
return pack_prefix;
|
||||
}
|
||||
|
||||
bool write_pack_opts_is_local(const struct write_pack_opts *opts)
|
||||
{
|
||||
return starts_with(opts->destination, opts->packdir);
|
||||
}
|
||||
|
||||
int finish_pack_objects_cmd(const struct git_hash_algo *algop,
|
||||
const struct write_pack_opts *opts,
|
||||
struct child_process *cmd,
|
||||
struct string_list *names)
|
||||
{
|
||||
FILE *out;
|
||||
bool local = write_pack_opts_is_local(opts);
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
|
||||
out = xfdopen(cmd->out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
|
||||
if (line.len != algop->hexsz)
|
||||
die(_("repack: Expecting full hex object ID lines only "
|
||||
"from pack-objects."));
|
||||
/*
|
||||
* Avoid putting packs written outside of the repository in the
|
||||
* list of names.
|
||||
*/
|
||||
if (local) {
|
||||
item = string_list_append(names, line.buf);
|
||||
item->util = generated_pack_populate(line.buf,
|
||||
opts->packtmp);
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
|
||||
strbuf_release(&line);
|
||||
|
||||
return finish_command(cmd);
|
||||
}
|
||||
|
||||
#define DELETE_PACK 1
|
||||
#define RETAIN_PACK 2
|
||||
|
||||
void existing_packs_collect(struct existing_packs *existing,
|
||||
const struct string_list *extra_keep)
|
||||
{
|
||||
struct packfile_store *packs = existing->repo->objects->packfiles;
|
||||
struct packed_git *p;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
|
||||
size_t i;
|
||||
const char *base;
|
||||
|
||||
if (p->multi_pack_index)
|
||||
string_list_append(&existing->midx_packs,
|
||||
pack_basename(p));
|
||||
if (!p->pack_local)
|
||||
continue;
|
||||
|
||||
base = pack_basename(p);
|
||||
|
||||
for (i = 0; i < extra_keep->nr; i++)
|
||||
if (!fspathcmp(base, extra_keep->items[i].string))
|
||||
break;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, base);
|
||||
strbuf_strip_suffix(&buf, ".pack");
|
||||
|
||||
if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep)
|
||||
string_list_append(&existing->kept_packs, buf.buf);
|
||||
else if (p->is_cruft)
|
||||
string_list_append(&existing->cruft_packs, buf.buf);
|
||||
else
|
||||
string_list_append(&existing->non_kept_packs, buf.buf);
|
||||
}
|
||||
|
||||
string_list_sort(&existing->kept_packs);
|
||||
string_list_sort(&existing->non_kept_packs);
|
||||
string_list_sort(&existing->cruft_packs);
|
||||
string_list_sort(&existing->midx_packs);
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
int existing_packs_has_non_kept(const struct existing_packs *existing)
|
||||
{
|
||||
return existing->non_kept_packs.nr || existing->cruft_packs.nr;
|
||||
}
|
||||
|
||||
static void existing_pack_mark_for_deletion(struct string_list_item *item)
|
||||
{
|
||||
item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
|
||||
}
|
||||
|
||||
static void existing_pack_unmark_for_deletion(struct string_list_item *item)
|
||||
{
|
||||
item->util = (void*)((uintptr_t)item->util & ~DELETE_PACK);
|
||||
}
|
||||
|
||||
int existing_pack_is_marked_for_deletion(struct string_list_item *item)
|
||||
{
|
||||
return (uintptr_t)item->util & DELETE_PACK;
|
||||
}
|
||||
|
||||
static void existing_packs_mark_retained(struct string_list_item *item)
|
||||
{
|
||||
item->util = (void*)((uintptr_t)item->util | RETAIN_PACK);
|
||||
}
|
||||
|
||||
static int existing_pack_is_retained(struct string_list_item *item)
|
||||
{
|
||||
return (uintptr_t)item->util & RETAIN_PACK;
|
||||
}
|
||||
|
||||
static void existing_packs_mark_for_deletion_1(const struct git_hash_algo *algop,
|
||||
struct string_list *names,
|
||||
struct string_list *list)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
const size_t hexsz = algop->hexsz;
|
||||
|
||||
for_each_string_list_item(item, list) {
|
||||
char *sha1;
|
||||
size_t len = strlen(item->string);
|
||||
if (len < hexsz)
|
||||
continue;
|
||||
sha1 = item->string + len - hexsz;
|
||||
|
||||
if (existing_pack_is_retained(item)) {
|
||||
existing_pack_unmark_for_deletion(item);
|
||||
} else if (!string_list_has_string(names, sha1)) {
|
||||
/*
|
||||
* Mark this pack for deletion, which ensures
|
||||
* that this pack won't be included in a MIDX
|
||||
* (if `--write-midx` was given) and that we
|
||||
* will actually delete this pack (if `-d` was
|
||||
* given).
|
||||
*/
|
||||
existing_pack_mark_for_deletion(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void existing_packs_retain_cruft(struct existing_packs *existing,
|
||||
struct packed_git *cruft)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct string_list_item *item;
|
||||
|
||||
strbuf_addstr(&buf, pack_basename(cruft));
|
||||
strbuf_strip_suffix(&buf, ".pack");
|
||||
|
||||
item = string_list_lookup(&existing->cruft_packs, buf.buf);
|
||||
if (!item)
|
||||
BUG("could not find cruft pack '%s'", pack_basename(cruft));
|
||||
|
||||
existing_packs_mark_retained(item);
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
void existing_packs_mark_for_deletion(struct existing_packs *existing,
|
||||
struct string_list *names)
|
||||
|
||||
{
|
||||
const struct git_hash_algo *algop = existing->repo->hash_algo;
|
||||
existing_packs_mark_for_deletion_1(algop, names,
|
||||
&existing->non_kept_packs);
|
||||
existing_packs_mark_for_deletion_1(algop, names,
|
||||
&existing->cruft_packs);
|
||||
}
|
||||
|
||||
static void remove_redundant_packs_1(struct repository *repo,
|
||||
struct string_list *packs,
|
||||
const char *packdir)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
for_each_string_list_item(item, packs) {
|
||||
if (!existing_pack_is_marked_for_deletion(item))
|
||||
continue;
|
||||
repack_remove_redundant_pack(repo, packdir, item->string);
|
||||
}
|
||||
}
|
||||
|
||||
void existing_packs_remove_redundant(struct existing_packs *existing,
|
||||
const char *packdir)
|
||||
{
|
||||
remove_redundant_packs_1(existing->repo, &existing->non_kept_packs,
|
||||
packdir);
|
||||
remove_redundant_packs_1(existing->repo, &existing->cruft_packs,
|
||||
packdir);
|
||||
}
|
||||
|
||||
void existing_packs_release(struct existing_packs *existing)
|
||||
{
|
||||
string_list_clear(&existing->kept_packs, 0);
|
||||
string_list_clear(&existing->non_kept_packs, 0);
|
||||
string_list_clear(&existing->cruft_packs, 0);
|
||||
string_list_clear(&existing->midx_packs, 0);
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
unsigned optional:1;
|
||||
} exts[] = {
|
||||
{".pack"},
|
||||
{".rev", 1},
|
||||
{".mtimes", 1},
|
||||
{".bitmap", 1},
|
||||
{".promisor", 1},
|
||||
{".idx"},
|
||||
};
|
||||
|
||||
struct generated_pack {
|
||||
struct tempfile *tempfiles[ARRAY_SIZE(exts)];
|
||||
};
|
||||
|
||||
struct generated_pack *generated_pack_populate(const char *name,
|
||||
const char *packtmp)
|
||||
{
|
||||
struct stat statbuf;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
struct generated_pack *pack = xcalloc(1, sizeof(*pack));
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(exts); i++) {
|
||||
strbuf_reset(&path);
|
||||
strbuf_addf(&path, "%s-%s%s", packtmp, name, exts[i].name);
|
||||
|
||||
if (stat(path.buf, &statbuf))
|
||||
continue;
|
||||
|
||||
pack->tempfiles[i] = register_tempfile(path.buf);
|
||||
}
|
||||
|
||||
strbuf_release(&path);
|
||||
return pack;
|
||||
}
|
||||
|
||||
int generated_pack_has_ext(const struct generated_pack *pack, const char *ext)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(exts); i++) {
|
||||
if (strcmp(exts[i].name, ext))
|
||||
continue;
|
||||
return !!pack->tempfiles[i];
|
||||
}
|
||||
BUG("unknown pack extension: '%s'", ext);
|
||||
}
|
||||
|
||||
void generated_pack_install(struct generated_pack *pack, const char *name,
|
||||
const char *packdir, const char *packtmp)
|
||||
{
|
||||
size_t ext;
|
||||
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
|
||||
char *fname;
|
||||
|
||||
fname = mkpathdup("%s/pack-%s%s", packdir, name,
|
||||
exts[ext].name);
|
||||
|
||||
if (pack->tempfiles[ext]) {
|
||||
const char *fname_old = get_tempfile_path(pack->tempfiles[ext]);
|
||||
struct stat statbuffer;
|
||||
|
||||
if (!stat(fname_old, &statbuffer)) {
|
||||
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||
chmod(fname_old, statbuffer.st_mode);
|
||||
}
|
||||
|
||||
if (rename_tempfile(&pack->tempfiles[ext], fname))
|
||||
die_errno(_("renaming pack to '%s' failed"),
|
||||
fname);
|
||||
} else if (!exts[ext].optional)
|
||||
die(_("pack-objects did not write a '%s' file for pack %s-%s"),
|
||||
exts[ext].name, packtmp, name);
|
||||
else if (unlink(fname) < 0 && errno != ENOENT)
|
||||
die_errno(_("could not unlink: %s"), fname);
|
||||
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
146
repack.h
Normal file
146
repack.h
Normal file
@@ -0,0 +1,146 @@
|
||||
#ifndef REPACK_H
|
||||
#define REPACK_H
|
||||
|
||||
#include "list-objects-filter-options.h"
|
||||
#include "string-list.h"
|
||||
|
||||
struct pack_objects_args {
|
||||
char *window;
|
||||
char *window_memory;
|
||||
char *depth;
|
||||
char *threads;
|
||||
unsigned long max_pack_size;
|
||||
int no_reuse_delta;
|
||||
int no_reuse_object;
|
||||
int quiet;
|
||||
int local;
|
||||
int name_hash_version;
|
||||
int path_walk;
|
||||
int delta_base_offset;
|
||||
int pack_kept_objects;
|
||||
struct list_objects_filter_options filter_options;
|
||||
};
|
||||
|
||||
#define PACK_OBJECTS_ARGS_INIT { \
|
||||
.delta_base_offset = 1, \
|
||||
.pack_kept_objects = -1, \
|
||||
}
|
||||
|
||||
struct child_process;
|
||||
|
||||
void prepare_pack_objects(struct child_process *cmd,
|
||||
const struct pack_objects_args *args,
|
||||
const char *out);
|
||||
void pack_objects_args_release(struct pack_objects_args *args);
|
||||
|
||||
void repack_remove_redundant_pack(struct repository *repo, const char *dir_name,
|
||||
const char *base_name);
|
||||
|
||||
struct write_pack_opts {
|
||||
struct pack_objects_args *po_args;
|
||||
const char *destination;
|
||||
const char *packdir;
|
||||
const char *packtmp;
|
||||
};
|
||||
|
||||
const char *write_pack_opts_pack_prefix(const struct write_pack_opts *opts);
|
||||
bool write_pack_opts_is_local(const struct write_pack_opts *opts);
|
||||
|
||||
int finish_pack_objects_cmd(const struct git_hash_algo *algop,
|
||||
const struct write_pack_opts *opts,
|
||||
struct child_process *cmd,
|
||||
struct string_list *names);
|
||||
|
||||
struct repository;
|
||||
struct packed_git;
|
||||
|
||||
struct existing_packs {
|
||||
struct repository *repo;
|
||||
struct string_list kept_packs;
|
||||
struct string_list non_kept_packs;
|
||||
struct string_list cruft_packs;
|
||||
struct string_list midx_packs;
|
||||
};
|
||||
|
||||
#define EXISTING_PACKS_INIT { \
|
||||
.kept_packs = STRING_LIST_INIT_DUP, \
|
||||
.non_kept_packs = STRING_LIST_INIT_DUP, \
|
||||
.cruft_packs = STRING_LIST_INIT_DUP, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds all packs hex strings (pack-$HASH) to either packs->non_kept
|
||||
* or packs->kept based on whether each pack has a corresponding
|
||||
* .keep file or not. Packs without a .keep file are not to be kept
|
||||
* if we are going to pack everything into one file.
|
||||
*/
|
||||
void existing_packs_collect(struct existing_packs *existing,
|
||||
const struct string_list *extra_keep);
|
||||
int existing_packs_has_non_kept(const struct existing_packs *existing);
|
||||
int existing_pack_is_marked_for_deletion(struct string_list_item *item);
|
||||
void existing_packs_retain_cruft(struct existing_packs *existing,
|
||||
struct packed_git *cruft);
|
||||
void existing_packs_mark_for_deletion(struct existing_packs *existing,
|
||||
struct string_list *names);
|
||||
void existing_packs_remove_redundant(struct existing_packs *existing,
|
||||
const char *packdir);
|
||||
void existing_packs_release(struct existing_packs *existing);
|
||||
|
||||
struct generated_pack;
|
||||
|
||||
struct generated_pack *generated_pack_populate(const char *name,
|
||||
const char *packtmp);
|
||||
int generated_pack_has_ext(const struct generated_pack *pack, const char *ext);
|
||||
void generated_pack_install(struct generated_pack *pack, const char *name,
|
||||
const char *packdir, const char *packtmp);
|
||||
|
||||
void repack_promisor_objects(struct repository *repo,
|
||||
const struct pack_objects_args *args,
|
||||
struct string_list *names, const char *packtmp);
|
||||
|
||||
struct pack_geometry {
|
||||
struct packed_git **pack;
|
||||
uint32_t pack_nr, pack_alloc;
|
||||
uint32_t split;
|
||||
|
||||
int split_factor;
|
||||
};
|
||||
|
||||
void pack_geometry_init(struct pack_geometry *geometry,
|
||||
struct existing_packs *existing,
|
||||
const struct pack_objects_args *args);
|
||||
void pack_geometry_split(struct pack_geometry *geometry);
|
||||
struct packed_git *pack_geometry_preferred_pack(struct pack_geometry *geometry);
|
||||
void pack_geometry_remove_redundant(struct pack_geometry *geometry,
|
||||
struct string_list *names,
|
||||
struct existing_packs *existing,
|
||||
const char *packdir);
|
||||
void pack_geometry_release(struct pack_geometry *geometry);
|
||||
|
||||
struct tempfile;
|
||||
|
||||
struct repack_write_midx_opts {
|
||||
struct existing_packs *existing;
|
||||
struct pack_geometry *geometry;
|
||||
struct string_list *names;
|
||||
const char *refs_snapshot;
|
||||
const char *packdir;
|
||||
int show_progress;
|
||||
int write_bitmaps;
|
||||
int midx_must_contain_cruft;
|
||||
};
|
||||
|
||||
void midx_snapshot_refs(struct repository *repo, struct tempfile *f);
|
||||
int write_midx_included_packs(struct repack_write_midx_opts *opts);
|
||||
|
||||
int write_filtered_pack(const struct write_pack_opts *opts,
|
||||
struct existing_packs *existing,
|
||||
struct string_list *names);
|
||||
|
||||
int write_cruft_pack(const struct write_pack_opts *opts,
|
||||
const char *cruft_expiration,
|
||||
unsigned long combine_cruft_below_size,
|
||||
struct string_list *names,
|
||||
struct existing_packs *existing);
|
||||
|
||||
#endif /* REPACK_H */
|
||||
@@ -8,31 +8,27 @@
|
||||
#include "repository.h"
|
||||
#include "commit.h"
|
||||
|
||||
static int register_replace_ref(const char *refname,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data)
|
||||
static int register_replace_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct repository *r = cb_data;
|
||||
|
||||
/* Get sha1 from refname */
|
||||
const char *slash = strrchr(refname, '/');
|
||||
const char *hash = slash ? slash + 1 : refname;
|
||||
const char *slash = strrchr(ref->name, '/');
|
||||
const char *hash = slash ? slash + 1 : ref->name;
|
||||
struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj));
|
||||
|
||||
if (get_oid_hex_algop(hash, &repl_obj->original.oid, r->hash_algo)) {
|
||||
free(repl_obj);
|
||||
warning(_("bad replace ref name: %s"), refname);
|
||||
warning(_("bad replace ref name: %s"), ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy sha1 from the read ref */
|
||||
oidcpy(&repl_obj->replacement, oid);
|
||||
oidcpy(&repl_obj->replacement, ref->oid);
|
||||
|
||||
/* Register new object */
|
||||
if (oidmap_put(&r->objects->replace_map, repl_obj))
|
||||
die(_("duplicate replace ref: %s"), refname);
|
||||
die(_("duplicate replace ref: %s"), ref->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
12
revision.c
12
revision.c
@@ -1644,19 +1644,17 @@ struct all_refs_cb {
|
||||
struct worktree *wt;
|
||||
};
|
||||
|
||||
static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data)
|
||||
static int handle_one_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct all_refs_cb *cb = cb_data;
|
||||
struct object *object;
|
||||
|
||||
if (ref_excluded(&cb->all_revs->ref_excludes, path))
|
||||
if (ref_excluded(&cb->all_revs->ref_excludes, ref->name))
|
||||
return 0;
|
||||
|
||||
object = get_reference(cb->all_revs, path, oid, cb->all_flags);
|
||||
add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
|
||||
add_pending_object(cb->all_revs, object, path);
|
||||
object = get_reference(cb->all_revs, ref->name, ref->oid, cb->all_flags);
|
||||
add_rev_cmdline(cb->all_revs, object, ref->name, REV_CMD_REF, cb->all_flags);
|
||||
add_pending_object(cb->all_revs, object, ref->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,23 +148,21 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int add_info_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data)
|
||||
static int add_info_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct update_info_ctx *uic = cb_data;
|
||||
struct object *o = parse_object(uic->repo, oid);
|
||||
struct object *o = parse_object(uic->repo, ref->oid);
|
||||
if (!o)
|
||||
return -1;
|
||||
|
||||
if (uic_printf(uic, "%s %s\n", oid_to_hex(oid), path) < 0)
|
||||
if (uic_printf(uic, "%s %s\n", oid_to_hex(ref->oid), ref->name) < 0)
|
||||
return -1;
|
||||
|
||||
if (o->type == OBJ_TAG) {
|
||||
o = deref_tag(uic->repo, o, path, 0);
|
||||
o = deref_tag(uic->repo, o, ref->name, 0);
|
||||
if (o)
|
||||
if (uic_printf(uic, "%s %s^{}\n",
|
||||
oid_to_hex(&o->oid), path) < 0)
|
||||
oid_to_hex(&o->oid), ref->name) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
16
shallow.c
16
shallow.c
@@ -626,14 +626,10 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static int mark_uninteresting(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED,
|
||||
void *cb_data UNUSED)
|
||||
static int mark_uninteresting(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct commit *commit = lookup_commit_reference_gently(the_repository,
|
||||
oid, 1);
|
||||
ref->oid, 1);
|
||||
if (!commit)
|
||||
return 0;
|
||||
commit->object.flags |= UNINTERESTING;
|
||||
@@ -742,16 +738,12 @@ struct commit_array {
|
||||
size_t nr, alloc;
|
||||
};
|
||||
|
||||
static int add_ref(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED,
|
||||
void *cb_data)
|
||||
static int add_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct commit_array *ca = cb_data;
|
||||
ALLOC_GROW(ca->commits, ca->nr + 1, ca->alloc);
|
||||
ca->commits[ca->nr] = lookup_commit_reference_gently(the_repository,
|
||||
oid, 1);
|
||||
ref->oid, 1);
|
||||
if (ca->commits[ca->nr])
|
||||
ca->nr++;
|
||||
return 0;
|
||||
|
||||
12
submodule.c
12
submodule.c
@@ -934,10 +934,7 @@ static void free_submodules_data(struct string_list *submodules)
|
||||
string_list_clear(submodules, 1);
|
||||
}
|
||||
|
||||
static int has_remote(const char *refname UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flags UNUSED, void *cb_data UNUSED)
|
||||
static int has_remote(const struct reference *ref UNUSED, void *cb_data UNUSED)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -1255,13 +1252,10 @@ int push_unpushed_submodules(struct repository *r,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int append_oid_to_array(const char *ref UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flags UNUSED, void *data)
|
||||
static int append_oid_to_array(const struct reference *ref, void *data)
|
||||
{
|
||||
struct oid_array *array = data;
|
||||
oid_array_append(array, oid);
|
||||
oid_array_append(array, ref->oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1809,7 +1809,9 @@ test_expect_success "${git_for_each_ref} reports broken tags" '
|
||||
bad=$(git hash-object -w -t tag bad) &&
|
||||
git update-ref refs/tags/broken-tag-bad $bad &&
|
||||
test_must_fail ${git_for_each_ref} --format="%(*objectname)" \
|
||||
refs/tags/broken-tag-*
|
||||
refs/tags/broken-tag-* &&
|
||||
test_must_fail ${git_for_each_ref} --format="%(*objectname)" \
|
||||
refs/tags/broken-tag-bad
|
||||
'
|
||||
|
||||
test_expect_success 'set up tag with signature and no blank lines' '
|
||||
|
||||
@@ -63,7 +63,7 @@ int cmd__reach(int ac, const char **av)
|
||||
die("failed to resolve %s", buf.buf + 2);
|
||||
|
||||
orig = parse_object(r, &oid);
|
||||
peeled = deref_tag_noverify(the_repository, orig);
|
||||
peeled = deref_tag(the_repository, orig, NULL, 0);
|
||||
|
||||
if (!peeled)
|
||||
die("failed to load commit for input %s resulting in oid %s",
|
||||
|
||||
@@ -154,10 +154,9 @@ static int cmd_rename_ref(struct ref_store *refs, const char **argv)
|
||||
return refs_rename_ref(refs, oldref, newref, logmsg);
|
||||
}
|
||||
|
||||
static int each_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flags, void *cb_data UNUSED)
|
||||
static int each_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
printf("%s %s 0x%x\n", oid_to_hex(oid), refname, flags);
|
||||
printf("%s %s 0x%x\n", oid_to_hex(ref->oid), ref->name, ref->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -238,6 +238,7 @@ integration_tests = [
|
||||
't1701-racy-split-index.sh',
|
||||
't1800-hook.sh',
|
||||
't1900-repo.sh',
|
||||
't1901-repo-structure.sh',
|
||||
't2000-conflict-when-checking-files-out.sh',
|
||||
't2002-checkout-cache-u.sh',
|
||||
't2003-checkout-cache-mkdir.sh',
|
||||
|
||||
@@ -428,4 +428,36 @@ do
|
||||
'
|
||||
done
|
||||
|
||||
test_expect_success 'pack-refs does not store invalid peeled tag value' '
|
||||
test_when_finished rm -rf repo &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
git commit --allow-empty --message initial &&
|
||||
|
||||
echo garbage >blob-content &&
|
||||
blob_id=$(git hash-object -w -t blob blob-content) &&
|
||||
|
||||
# Write an invalid tag into the object database. The tag itself
|
||||
# is well-formed, but the tagged object is a blob while we
|
||||
# claim that it is a commit.
|
||||
cat >tag-content <<-EOF &&
|
||||
object $blob_id
|
||||
type commit
|
||||
tag bad-tag
|
||||
tagger C O Mitter <committer@example.com> 1112354055 +0200
|
||||
|
||||
annotated
|
||||
EOF
|
||||
tag_id=$(git hash-object -w -t tag tag-content) &&
|
||||
git update-ref refs/tags/bad-tag "$tag_id" &&
|
||||
|
||||
# The packed-refs file should not contain the peeled object ID.
|
||||
# If it did this would cause commands that use the peeled value
|
||||
# to not notice this corrupted tag.
|
||||
git pack-refs --all &&
|
||||
test_grep ! "^\^" .git/packed-refs
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -1135,4 +1135,32 @@ test_expect_success 'fetch: accessing FETCH_HEAD special ref works' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'writes do not persist peeled value for invalid tags' '
|
||||
test_when_finished rm -rf repo &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
git commit --allow-empty --message initial &&
|
||||
|
||||
# We cannot easily verify that the peeled value is not stored
|
||||
# in the tables. Instead, we test this indirectly: we create
|
||||
# two tags that both point to the same object, but they claim
|
||||
# different object types. If we parse both tags we notice that
|
||||
# the parsed tagged object has a mismatch between the two tags
|
||||
# and bail out.
|
||||
#
|
||||
# If we instead use the persisted peeled value we would not
|
||||
# even parse the tags. As such, we would not notice the
|
||||
# discrepancy either and thus listing these tags would succeed.
|
||||
git tag tag-1 -m "tag 1" &&
|
||||
git cat-file tag tag-1 >raw-tag &&
|
||||
sed "s/^type commit$/type blob/" <raw-tag >broken-tag &&
|
||||
broken_tag_id=$(git hash-object -w -t tag broken-tag) &&
|
||||
git update-ref refs/tags/tag-2 $broken_tag_id &&
|
||||
|
||||
test_must_fail git for-each-ref --format="%(*objectname)" refs/tags/ 2>err &&
|
||||
test_grep "bad tag pointer" err
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
129
t/t1901-repo-structure.sh
Executable file
129
t/t1901-repo-structure.sh
Executable file
@@ -0,0 +1,129 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='test git repo structure'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'empty repository' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
cat >expect <<-\EOF &&
|
||||
| Repository structure | Value |
|
||||
| -------------------- | ----- |
|
||||
| * References | |
|
||||
| * Count | 0 |
|
||||
| * Branches | 0 |
|
||||
| * Tags | 0 |
|
||||
| * Remotes | 0 |
|
||||
| * Others | 0 |
|
||||
| | |
|
||||
| * Reachable objects | |
|
||||
| * Count | 0 |
|
||||
| * Commits | 0 |
|
||||
| * Trees | 0 |
|
||||
| * Blobs | 0 |
|
||||
| * Tags | 0 |
|
||||
EOF
|
||||
|
||||
git repo structure >out 2>err &&
|
||||
|
||||
test_cmp expect out &&
|
||||
test_line_count = 0 err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'repository with references and objects' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_commit_bulk 42 &&
|
||||
git tag -a foo -m bar &&
|
||||
|
||||
oid="$(git rev-parse HEAD)" &&
|
||||
git update-ref refs/remotes/origin/foo "$oid" &&
|
||||
|
||||
# Also creates a commit, tree, and blob.
|
||||
git notes add -m foo &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
| Repository structure | Value |
|
||||
| -------------------- | ----- |
|
||||
| * References | |
|
||||
| * Count | 4 |
|
||||
| * Branches | 1 |
|
||||
| * Tags | 1 |
|
||||
| * Remotes | 1 |
|
||||
| * Others | 1 |
|
||||
| | |
|
||||
| * Reachable objects | |
|
||||
| * Count | 130 |
|
||||
| * Commits | 43 |
|
||||
| * Trees | 43 |
|
||||
| * Blobs | 43 |
|
||||
| * Tags | 1 |
|
||||
EOF
|
||||
|
||||
git repo structure >out 2>err &&
|
||||
|
||||
test_cmp expect out &&
|
||||
test_line_count = 0 err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'keyvalue and nul format' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_commit_bulk 42 &&
|
||||
git tag -a foo -m bar &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
references.branches.count=1
|
||||
references.tags.count=1
|
||||
references.remotes.count=0
|
||||
references.others.count=0
|
||||
objects.commits.count=42
|
||||
objects.trees.count=42
|
||||
objects.blobs.count=42
|
||||
objects.tags.count=1
|
||||
EOF
|
||||
|
||||
git repo structure --format=keyvalue >out 2>err &&
|
||||
|
||||
test_cmp expect out &&
|
||||
test_line_count = 0 err &&
|
||||
|
||||
# Replace key and value delimiters for nul format.
|
||||
tr "\n=" "\0\n" <expect >expect_nul &&
|
||||
git repo structure --format=nul >out 2>err &&
|
||||
|
||||
test_cmp expect_nul out &&
|
||||
test_line_count = 0 err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'progress meter option' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_commit foo &&
|
||||
|
||||
GIT_PROGRESS_DELAY=0 git repo structure --progress >out 2>err &&
|
||||
|
||||
test_file_not_empty out &&
|
||||
test_grep "Counting references: 2, done." err &&
|
||||
test_grep "Counting objects: 3, done." err &&
|
||||
|
||||
GIT_PROGRESS_DELAY=0 git repo structure --no-progress >out 2>err &&
|
||||
|
||||
test_file_not_empty out &&
|
||||
test_line_count = 0 err
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -333,8 +333,8 @@ test_expect_success 'different prompts for mode change/deleted' '
|
||||
sed -n "s/^\(([0-9/]*) Stage .*?\).*/\1/p" actual >actual.filtered &&
|
||||
cat >expect <<-\EOF &&
|
||||
(1/1) Stage deletion [y,n,q,a,d,p,?]?
|
||||
(1/2) Stage mode change [y,n,q,a,d,j,J,g,/,p,?]?
|
||||
(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]?
|
||||
(1/2) Stage mode change [y,n,q,a,d,k,K,j,J,g,/,p,?]?
|
||||
(2/2) Stage this hunk [y,n,q,a,d,K,J,g,/,e,p,?]?
|
||||
EOF
|
||||
test_cmp expect actual.filtered
|
||||
'
|
||||
@@ -521,13 +521,13 @@ test_expect_success 'split hunk setup' '
|
||||
test_expect_success 'goto hunk 1 with "g 1"' '
|
||||
test_when_finished "git reset" &&
|
||||
tr _ " " >expect <<-EOF &&
|
||||
(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? + 1: -1,2 +1,3 +15
|
||||
(2/2) Stage this hunk [y,n,q,a,d,K,J,g,/,e,p,?]? + 1: -1,2 +1,3 +15
|
||||
_ 2: -2,4 +3,8 +21
|
||||
go to which hunk? @@ -1,2 +1,3 @@
|
||||
_10
|
||||
+15
|
||||
_20
|
||||
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
|
||||
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]?_
|
||||
EOF
|
||||
test_write_lines s y g 1 | git add -p >actual &&
|
||||
tail -n 7 <actual >actual.trimmed &&
|
||||
@@ -540,7 +540,7 @@ test_expect_success 'goto hunk 1 with "g1"' '
|
||||
_10
|
||||
+15
|
||||
_20
|
||||
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
|
||||
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]?_
|
||||
EOF
|
||||
test_write_lines s y g1 | git add -p >actual &&
|
||||
tail -n 4 <actual >actual.trimmed &&
|
||||
@@ -550,11 +550,11 @@ test_expect_success 'goto hunk 1 with "g1"' '
|
||||
test_expect_success 'navigate to hunk via regex /pattern' '
|
||||
test_when_finished "git reset" &&
|
||||
tr _ " " >expect <<-EOF &&
|
||||
(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? @@ -1,2 +1,3 @@
|
||||
(2/2) Stage this hunk [y,n,q,a,d,K,J,g,/,e,p,?]? @@ -1,2 +1,3 @@
|
||||
_10
|
||||
+15
|
||||
_20
|
||||
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
|
||||
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]?_
|
||||
EOF
|
||||
test_write_lines s y /1,2 | git add -p >actual &&
|
||||
tail -n 5 <actual >actual.trimmed &&
|
||||
@@ -567,7 +567,7 @@ test_expect_success 'navigate to hunk via regex / pattern' '
|
||||
_10
|
||||
+15
|
||||
_20
|
||||
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
|
||||
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]?_
|
||||
EOF
|
||||
test_write_lines s y / 1,2 | git add -p >actual &&
|
||||
tail -n 4 <actual >actual.trimmed &&
|
||||
@@ -579,11 +579,11 @@ test_expect_success 'print again the hunk' '
|
||||
tr _ " " >expect <<-EOF &&
|
||||
+15
|
||||
20
|
||||
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? @@ -1,2 +1,3 @@
|
||||
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]? @@ -1,2 +1,3 @@
|
||||
10
|
||||
+15
|
||||
20
|
||||
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
|
||||
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]?_
|
||||
EOF
|
||||
test_write_lines s y g 1 p | git add -p >actual &&
|
||||
tail -n 7 <actual >actual.trimmed &&
|
||||
@@ -595,11 +595,11 @@ test_expect_success TTY 'print again the hunk (PAGER)' '
|
||||
cat >expect <<-EOF &&
|
||||
<GREEN>+<RESET><GREEN>15<RESET>
|
||||
20<RESET>
|
||||
<BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>PAGER <CYAN>@@ -1,2 +1,3 @@<RESET>
|
||||
<BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]? <RESET>PAGER <CYAN>@@ -1,2 +1,3 @@<RESET>
|
||||
PAGER 10<RESET>
|
||||
PAGER <GREEN>+<RESET><GREEN>15<RESET>
|
||||
PAGER 20<RESET>
|
||||
<BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>
|
||||
<BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]? <RESET>
|
||||
EOF
|
||||
test_write_lines s y g 1 P |
|
||||
(
|
||||
@@ -802,15 +802,15 @@ test_expect_success 'colors can be overridden' '
|
||||
<BOLD>-old<RESET>
|
||||
<BLUE>+<RESET><BLUE>new<RESET>
|
||||
<CYAN> more-context<RESET>
|
||||
<YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET>
|
||||
<YELLOW>(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET>
|
||||
<CYAN> more-context<RESET>
|
||||
<BLUE>+<RESET><BLUE>another-one<RESET>
|
||||
<YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET>
|
||||
<YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,J,g,/,e,p,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET>
|
||||
<CYAN> context<RESET>
|
||||
<BOLD>-old<RESET>
|
||||
<BLUE>+new<RESET>
|
||||
<CYAN> more-context<RESET>
|
||||
<YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>
|
||||
<YELLOW>(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]? <RESET>
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
@@ -1385,4 +1385,50 @@ test_expect_success 'splitting edited hunk' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'options J, K roll over' '
|
||||
test_write_lines a b c d e f g h i >file &&
|
||||
git add file &&
|
||||
test_write_lines X b c d e f g h X >file &&
|
||||
test_write_lines J J K q | git add -p >out &&
|
||||
test_write_lines 1 2 1 2 >expect &&
|
||||
sed -n -e "s-/.*--" -e "s/^(//p" <out >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'options y, n, a, d, j, k, e roll over to next undecided (1)' '
|
||||
test_write_lines a b c d e f g h i j k l m n o p q >file &&
|
||||
git add file &&
|
||||
test_write_lines X b c d e f g h X j k l m n o p X >file &&
|
||||
test_set_editor : &&
|
||||
test_write_lines g3 y g3 n g3 a g3 d g3 j g3 e k q | git add -p >out &&
|
||||
test_write_lines 1 3 1 3 1 3 1 3 1 3 1 3 1 2 >expect &&
|
||||
sed -n -e "s-/.*--" -e "s/^(//p" <out >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'options y, n, a, d, j, k, e roll over to next undecided (2)' '
|
||||
test_write_lines a b c d e f g h i j k l m n o p q >file &&
|
||||
git add file &&
|
||||
test_write_lines X b c d e f g h X j k l m n o p X >file &&
|
||||
test_set_editor : &&
|
||||
test_write_lines y g3 y g3 n g3 a g3 d g3 j g3 e g1 k q | git add -p >out &&
|
||||
test_write_lines 1 2 3 2 3 2 3 2 3 2 3 2 3 2 1 2 >expect &&
|
||||
sed -n -e "s-/.*--" -e "s/^(//p" <out >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'invalid option s is rejected' '
|
||||
test_write_lines a b c d e f g h i j k >file &&
|
||||
git add file &&
|
||||
test_write_lines X b X d e f g h i j X >file &&
|
||||
test_write_lines j s q | git add -p >out &&
|
||||
sed -ne "s/ @@.*//" -e "s/ \$//" -e "/^(/p" <out >actual &&
|
||||
cat >expect <<-EOF &&
|
||||
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,s,e,p,?]?
|
||||
(2/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]? Sorry, cannot split this hunk
|
||||
(2/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,?]?
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -339,6 +339,22 @@ test_expect_success 'diff --no-index with pathspec' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'diff --no-index first path ending in slash with pathspec' '
|
||||
test_expect_code 1 git diff --name-status --no-index a/ b 1 >actual &&
|
||||
cat >expect <<-EOF &&
|
||||
D a/1
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'diff --no-index second path ending in slash with pathspec' '
|
||||
test_expect_code 1 git diff --name-status --no-index a b/ 1 >actual &&
|
||||
cat >expect <<-EOF &&
|
||||
D a/1
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'diff --no-index with pathspec no matches' '
|
||||
test_expect_code 0 git diff --name-status --no-index a b missing
|
||||
'
|
||||
|
||||
@@ -2293,24 +2293,26 @@ test_expect_success '--contains combined with --no-contains' '
|
||||
# don't recurse down to tags for trees or blobs pointed to by *those*
|
||||
# commits.
|
||||
test_expect_success 'Does --[no-]contains stop at commits? Yes!' '
|
||||
cd no-contains &&
|
||||
blob=$(git rev-parse v0.3:v0.3.t) &&
|
||||
tree=$(git rev-parse v0.3^{tree}) &&
|
||||
git tag tag-blob $blob &&
|
||||
git tag tag-tree $tree &&
|
||||
git tag --contains v0.3 >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
v0.3
|
||||
v0.4
|
||||
v0.5
|
||||
EOF
|
||||
test_cmp expected actual &&
|
||||
git tag --no-contains v0.3 >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
v0.1
|
||||
v0.2
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
(
|
||||
cd no-contains &&
|
||||
blob=$(git rev-parse v0.3:v0.3.t) &&
|
||||
tree=$(git rev-parse v0.3^{tree}) &&
|
||||
git tag tag-blob $blob &&
|
||||
git tag tag-tree $tree &&
|
||||
git tag --contains v0.3 >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
v0.3
|
||||
v0.4
|
||||
v0.5
|
||||
EOF
|
||||
test_cmp expected actual &&
|
||||
git tag --no-contains v0.3 >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
v0.1
|
||||
v0.2
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'If tag is created then tag message file is unlinked' '
|
||||
@@ -2332,4 +2334,24 @@ test_expect_success 'If tag cannot be created then tag message file is not unlin
|
||||
test_path_exists .git/TAG_EDITMSG
|
||||
'
|
||||
|
||||
test_expect_success 'annotated tag version sort' '
|
||||
git tag -a -m "sample 1.0" vsample-1.0 &&
|
||||
git tag -a -m "sample 2.0" vsample-2.0 &&
|
||||
git tag -a -m "sample 10.0" vsample-10.0 &&
|
||||
cat >expect <<-EOF &&
|
||||
vsample-1.0
|
||||
vsample-2.0
|
||||
vsample-10.0
|
||||
EOF
|
||||
|
||||
git tag --list --sort=version:tag vsample-\* >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
# Ensure that we also handle this case alright in the case we have the
|
||||
# peeled values cached e.g. via the packed-refs file.
|
||||
git pack-refs --all &&
|
||||
git tag --list --sort=version:tag vsample-\* &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
12
tag.c
12
tag.c
@@ -94,18 +94,6 @@ struct object *deref_tag(struct repository *r, struct object *o, const char *war
|
||||
return o;
|
||||
}
|
||||
|
||||
struct object *deref_tag_noverify(struct repository *r, struct object *o)
|
||||
{
|
||||
while (o && o->type == OBJ_TAG) {
|
||||
o = parse_object(r, &o->oid);
|
||||
if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
|
||||
o = ((struct tag *)o)->tagged;
|
||||
else
|
||||
o = NULL;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
struct tag *lookup_tag(struct repository *r, const struct object_id *oid)
|
||||
{
|
||||
struct object *obj = lookup_object(r, oid);
|
||||
|
||||
1
tag.h
1
tag.h
@@ -16,7 +16,6 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
|
||||
int parse_tag(struct tag *item);
|
||||
void release_tag_memory(struct tag *t);
|
||||
struct object *deref_tag(struct repository *r, struct object *, const char *, int);
|
||||
struct object *deref_tag_noverify(struct repository *r, struct object *);
|
||||
int gpg_verify_tag(const struct object_id *oid,
|
||||
const char *name_to_report, unsigned flags);
|
||||
struct object_id *get_tagged_oid(struct tag *tag);
|
||||
|
||||
@@ -870,8 +870,8 @@ static void send_unshallow(struct upload_pack_data *data)
|
||||
}
|
||||
}
|
||||
|
||||
static int check_ref(const char *refname_full, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag, void *cb_data);
|
||||
static int check_ref(const struct reference *ref, void *cb_data);
|
||||
|
||||
static void deepen(struct upload_pack_data *data, int depth)
|
||||
{
|
||||
if (depth == INFINITE_DEPTH && !is_repository_shallow(the_repository)) {
|
||||
@@ -1224,13 +1224,12 @@ static int mark_our_ref(const char *refname, const char *refname_full,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_ref(const char *refname_full, const char *referent UNUSED,const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data)
|
||||
static int check_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
const char *refname = strip_namespace(refname_full);
|
||||
const char *refname = strip_namespace(ref->name);
|
||||
struct upload_pack_data *data = cb_data;
|
||||
|
||||
mark_our_ref(refname, refname_full, oid, &data->hidden_refs);
|
||||
mark_our_ref(refname, ref->name, ref->oid, &data->hidden_refs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1250,15 +1249,15 @@ static void format_session_id(struct strbuf *buf, struct upload_pack_data *d) {
|
||||
}
|
||||
|
||||
static void write_v0_ref(struct upload_pack_data *data,
|
||||
const char *refname, const char *refname_nons,
|
||||
const struct object_id *oid)
|
||||
const struct reference *ref,
|
||||
const char *refname_nons)
|
||||
{
|
||||
static const char *capabilities = "multi_ack thin-pack side-band"
|
||||
" side-band-64k ofs-delta shallow deepen-since deepen-not"
|
||||
" deepen-relative no-progress include-tag multi_ack_detailed";
|
||||
struct object_id peeled;
|
||||
|
||||
if (mark_our_ref(refname_nons, refname, oid, &data->hidden_refs))
|
||||
if (mark_our_ref(refname_nons, ref->name, ref->oid, &data->hidden_refs))
|
||||
return;
|
||||
|
||||
if (capabilities) {
|
||||
@@ -1268,7 +1267,7 @@ static void write_v0_ref(struct upload_pack_data *data,
|
||||
format_symref_info(&symref_info, &data->symref);
|
||||
format_session_id(&session_id, data);
|
||||
packet_fwrite_fmt(stdout, "%s %s%c%s%s%s%s%s%s%s object-format=%s agent=%s\n",
|
||||
oid_to_hex(oid), refname_nons,
|
||||
oid_to_hex(ref->oid), refname_nons,
|
||||
0, capabilities,
|
||||
(data->allow_uor & ALLOW_TIP_SHA1) ?
|
||||
" allow-tip-sha1-in-want" : "",
|
||||
@@ -1284,35 +1283,33 @@ static void write_v0_ref(struct upload_pack_data *data,
|
||||
strbuf_release(&session_id);
|
||||
data->sent_capabilities = 1;
|
||||
} else {
|
||||
packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons);
|
||||
packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(ref->oid), refname_nons);
|
||||
}
|
||||
capabilities = NULL;
|
||||
if (!peel_iterated_oid(the_repository, oid, &peeled))
|
||||
if (!reference_get_peeled_oid(the_repository, ref, &peeled))
|
||||
packet_fwrite_fmt(stdout, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
|
||||
return;
|
||||
}
|
||||
|
||||
static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
|
||||
int flag UNUSED, void *cb_data)
|
||||
static int send_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
write_v0_ref(cb_data, refname, strip_namespace(refname), oid);
|
||||
write_v0_ref(cb_data, ref, strip_namespace(ref->name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_symref(const char *refname, const char *referent UNUSED,
|
||||
const struct object_id *oid UNUSED,
|
||||
int flag, void *cb_data)
|
||||
static int find_symref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
const char *symref_target;
|
||||
struct string_list_item *item;
|
||||
int flag;
|
||||
|
||||
if ((flag & REF_ISSYMREF) == 0)
|
||||
if ((ref->flags & REF_ISSYMREF) == 0)
|
||||
return 0;
|
||||
symref_target = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
|
||||
refname, 0, NULL, &flag);
|
||||
ref->name, 0, NULL, &flag);
|
||||
if (!symref_target || (flag & REF_ISSYMREF) == 0)
|
||||
die("'%s' is a symref but it is not?", refname);
|
||||
item = string_list_append(cb_data, strip_namespace(refname));
|
||||
die("'%s' is a symref but it is not?", ref->name);
|
||||
item = string_list_append(cb_data, strip_namespace(ref->name));
|
||||
item->util = xstrdup(strip_namespace(symref_target));
|
||||
return 0;
|
||||
}
|
||||
@@ -1445,8 +1442,12 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
|
||||
send_ref, &data);
|
||||
for_each_namespaced_ref_1(send_ref, &data);
|
||||
if (!data.sent_capabilities) {
|
||||
const char *refname = "capabilities^{}";
|
||||
write_v0_ref(&data, refname, refname, null_oid(the_hash_algo));
|
||||
struct reference ref = {
|
||||
.name = "capabilities^{}",
|
||||
.oid = null_oid(the_hash_algo),
|
||||
};
|
||||
|
||||
write_v0_ref(&data, &ref, ref.name);
|
||||
}
|
||||
/*
|
||||
* fflush stdout before calling advertise_shallow_grafts because send_ref
|
||||
|
||||
8
walker.c
8
walker.c
@@ -226,14 +226,10 @@ static int interpret_target(struct walker *walker, char *target, struct object_i
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mark_complete(const char *path UNUSED,
|
||||
const char *referent UNUSED,
|
||||
const struct object_id *oid,
|
||||
int flag UNUSED,
|
||||
void *cb_data UNUSED)
|
||||
static int mark_complete(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct commit *commit = lookup_commit_reference_gently(the_repository,
|
||||
oid, 1);
|
||||
ref->oid, 1);
|
||||
|
||||
if (commit) {
|
||||
commit->object.flags |= COMPLETE;
|
||||
|
||||
11
worktree.c
11
worktree.c
@@ -595,8 +595,15 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
|
||||
if (refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
|
||||
refname.buf,
|
||||
RESOLVE_REF_READING,
|
||||
&oid, &flag))
|
||||
ret = fn(refname.buf, NULL, &oid, flag, cb_data);
|
||||
&oid, &flag)) {
|
||||
struct reference ref = {
|
||||
.name = refname.buf,
|
||||
.oid = &oid,
|
||||
.flags = flag,
|
||||
};
|
||||
|
||||
ret = fn(&ref, cb_data);
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user