In order to pass the list of parents to fmt_merge_msg(), cmd_merge()
uses this strbuf to create something that look like FETCH_HEAD that
describes commits that are being merged. This is necessary only
when we are creating the merge commit message ourselves, but was
done unconditionally.
Move the variable and the logic to populate it to confine them in a
block that needs them.
merge: split reduce_parents() out of collect_parents()
The latter does two separate things:
- Parse the list of commits on the command line, and formulate the
list of commits to be merged (including the current HEAD);
- Compute the list of parents to be recorded in the resulting merge
commit.
Split the latter into a separate helper function, so that we can
later supply the list commits to be merged from a different source
(namely, FETCH_HEAD).
- The function initially collects all commits to be merged into a
commit_list "remoteheads"; the "remotes" pointer always points at
the tail of this list (either the remoteheads variable itself, or
the ->next slot of the element at the end of the list) to help
elongate the list by repeated calls to commit_list_insert().
Because the new element appended by commit_list_insert() will
always have its ->next slot NULLed out, there is no need for us
to assign NULL to *remotes to terminate the list at the end.
- The variable "head_subsumed" always confused me every time I read
this code. What is happening here is that we inspect what the
caller told us to merge (including the current HEAD) and come up
with the list of parents to be recorded for the resulting merge
commit, omitting commits that are ancestor of other commits.
This filtering may remove the current HEAD from the resulting
parent list---and we signal that fact with this variable, so that
we can later record it as the first parent when "--no-ff" is in
effect.
- The "parents" list is created for this function by reduce_heads()
and was not deallocated after its use, even though the loop
control was written in such a way to allow us to do so by taking
the "next" element in a separate variable so that it can be used
in the next-step part of the loop control.
When parsing a merged object name like "foo~20" to formulate a merge
summary "Merge branch foo (early part)", a temporary strbuf is used,
but we forgot to deallocate it when we failed to find the named
branch.
merge: do not check argc to determine number of remote heads
To reject merging multiple commits into an unborn branch, we check
argc, thinking that collect_parents() that reads the remaining
command line arguments from <argc, argv> will give us the same
number of commits as its input, i.e. argc.
Because what we really care about is the number of commits, let the
function run and then make sure it returns only one commit instead.
Instead of having it as one of the three if/elseif/.. case arms,
test the condition and handle this special case upfront. This makes
it easier to follow the flow of logic.
t5520: test pulling an octopus into an unborn branch
The code comment for "git merge" in builtin/merge.c, we say
If the merged head is a valid one there is no reason
to forbid "git merge" into a branch yet to be born.
We do the same for "git pull".
and t5520 does have an existing test for that behaviour. However,
there was no test to make sure that 'git pull' to pull multiple
branches into an unborn branch must fail.
Fix style funnies in early part of this test script that checks "git
pull" into an unborn branch. The primary change is that 'chdir' to
a newly created empty test repository is now protected by being done
in a subshell to make it more robust without having to chdir back to
the original place.
One of the first things cmd_merge() does is to see if the "--abort"
option is given and run "reset --merge" and exit. When the control
reaches this point, we know "--abort" was not given.
We seem to have tests for specific merge strategy backends
(e.g. recursive), but not much test coverage for the "git merge"
itself. As I am planning to update the semantics of merging
"FETCH_HEAD" in such a way that these two
filter-branch: avoid passing commit message through sed
On some systems (like OS X), if sed encounters input without
a trailing newline, it will silently add it. As a result,
"git filter-branch" on such systems may silently rewrite
commit messages that omit a trailing newline. Even though
this is not something we generate ourselves with "git
commit", it's better for filter-branch to preserve the
original data as closely as possible.
We're using sed here only to strip the header fields from
the commit object. We can accomplish the same thing with a
shell loop. Since shell "read" calls are slow (usually one
syscall per byte), we use "cat" once we've skipped past the
header. Depending on the size of your commit messages, this
is probably faster (you pay the cost to fork, but then read
the data in saner-sized chunks). This idea is shamelessly
stolen from Junio.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
When rebase--interactive processes a task, it removes the item from
the todo list and appends it to another list of executed tasks. If a
pick (this includes squash and fixup) fails before the index has
recorded the changes, take the corresponding item and put it on the todo
list again. Otherwise, the changes introduced by the scheduled commit
would be lost.
That kind of decision is possible since the cherry-pick command
signals why it failed to apply the changes of the given commit. Either
the changes are recorded in the index using a conflict (return value 1)
and rebase does not continue until they are resolved or the changes
are not recorded in the index (return value neither 0 nor 1) and
rebase has to try again with the same task.
Add a test cases for regression testing to the "rebase-interactive"
test suite.
Signed-off-by: Fabian Ruch <bafain@gmail.com> Signed-off-by: Phil Hord <hordp@cisco.com> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Now that the feature has had time to prove itself, and any
topics in flight have had a chance to clean up any broken
&&-chains, we can flip this feature on by default. This
makes one less thing submitters need to configure or check
before sending their patches.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
connect: improve check for plink to reduce false positives
The git_connect function has code to handle plink and tortoiseplink
specially, as they require different command line arguments from
OpenSSH (-P instead of -p for ports; tortoiseplink additionally requires
-batch). However, the match was done by checking for "plink" anywhere
in the string, which led to a GIT_SSH value containing "uplink" being
treated as an invocation of putty's plink.
Improve the check by looking for "plink" or "tortoiseplink" (or those
names suffixed with ".exe") only in the final component of the path.
This has the downside that a program such as "plink-0.63" would no
longer be recognized, but the increased robustness is likely worth it.
Add tests to cover these cases to avoid regressions.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t5601: fix quotation error leading to skipped tests
One of the tests in t5601 used single quotes to delimit an argument
containing spaces. However, this caused test_expect_success to be
passed three arguments instead of two, which in turn caused the test
name to be treated as a prerequisite instead of a test name. As there
was no prerequisite called "bracketed hostnames are still ssh", the test
was always skipped.
Because this test was always skipped, the fact that it passed the
arguments in the wrong order was obscured. Use double quotes inside the
test and reorder the arguments so that the test runs and properly
reflects the arguments that are passed to ssh.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The code path used in git_connect pushed the majority of the SSH
connection code into an else block, even though the if block returns.
Simplify the code by eliminating the else block, as it is unneeded.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Brian Carson noticed that a test piece in t5601 had a pair of single
quotes in the body, which made it into 4 parameter call to
test_expect_success, as if its test title were a prerequisite.
As the prerequisites have a specific syntax (i.e. comma separated
tokens spelled in capital letters, possibly prefixed with ! for
negation), validate them to catch such a mistake in the future.
Use test_lazy_prereq to setup prerequisites for the p4 move
test. This both makes the test simpler and clearer, and also
means it no longer fails the new --chain-lint tests.
Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Luke Diamand <luke@diamand.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
When the branch to be rebased is already up to date, we
"git checkout" the branch, print an "up to date" message,
and end the rebase early. However, our checkout may print
"Switched to branch 'foo'" or "Already on 'foo'", even if
the user has asked for "--quiet".
We should avoid printing these messages at all, "--quiet" or
no. Since the rebase is a noop, this checkout can be seen as
optimizing out these other two checkout operations (that
happen in a real rebase):
1. Moving to the detached HEAD to start the rebase; we
always feed "-q" to checkout there, and instead rely on
our own custom message (which respects --quiet).
2. Finishing a rebase, where we move to the final branch.
Here we actually use update-ref rather than
git-checkout, and produce no messages.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Merge branch 'tb/connect-ipv6-parse-fix' into maint
An earlier update to the parser that disects a URL broke an
address, followed by a colon, followed by an empty string (instead
of the port number), e.g. ssh://example.com:/path/to/repo.
* tb/connect-ipv6-parse-fix:
connect.c: ignore extra colon after hostname
The "git push --signed" protocol extension did not limit what the
"nonce" that is a server-chosen string can contain or how long it
can be, which was unnecessarily lax. Limit both the length and the
alphabet to a reasonably small space that can still have enough
entropy.
* jc/push-cert:
push --signed: tighten what the receiving end can ask to sign
Documentation: clarify how "git commit" cleans up the edited log message
The `-v` shows a unified diff in the editor to edit the commit
message to help the user to describe the change. The diff is
stripped and will not become a part of the commit message.
Add a note about this with the `-v` description and slightly modify
the description for the default `--cleanup` mode.
Signed-off-by: Fredrik Gustafsson <iveqy@iveqy.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
- Check if eols in a file are converted at commit, when the file has
CR (or CRLF) in the repo (technically speaking in the index).
- Add a test-file repoMIX with mixed line-endings.
- When converting LF->CRLF or CRLF->LF: check the warnings
checkout_files():
- Checking out CRLF_nul and checking for eol coversion does not
make much sense (CRLF will stay CRLF).
- Use the file LF_nul instead: It is handled a binary in "auto" modes,
and when declared as text the LF may be replaced with CRLF, depending
on the configuration.
Signed-off-by: Torsten Bögershausen <tboegi@web.de> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-p4: improve client path detection when branches are used
Perforce allows client side file/directory remapping through
the use of the client view definition that is part of the
user's client spec.
To support this functionality while branch detection is
enabled it is important to determine the branch location in
the workspace such that the correct files are patched before
Perforce submission. Perforce provides a command that
facilitates this process: p4 where.
This patch does two things to fix improve file location
detection when git-p4 has branch detection and use of client
spec enabled:
1. Enable usage of "p4 where" when Perforce branches exist
in the git repository, even when client specification is
used. This makes use of the already existing function
p4Where.
2. Allow identifying partial matches of the branch's depot
path while processing the output of "p4 where". For
robustness, paths will only match if ending in "/...".
Signed-off-by: Vitor Antunes <vitor.hda@gmail.com> Acked-by: Luke Diamand <luke@diamand.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
ignore: info/exclude should trump core.excludesfile
$GIT_DIR/info/exclude and core.excludesfile (which falls back to
$XDG_HOME/git/ignore) are both ways to override the ignore pattern
lists given by the project in .gitignore files. The former, which
is per-repository personal preference, should take precedence over
the latter, which is a personal preference default across different
repositories that are accessed from that machine. The existing
documentation also agrees.
However, the precedence order was screwed up between these two from
the very beginning when 896bdfa2 (add: Support specifying an
excludes file with a configuration variable, 2007-02-27) introduced
core.excludesfile variable.
Noticed-by: Yohei Endo <yoheie@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
When the "git" wrapper is invoked, we prepend the baked-in
exec-path to our PATH, so that any sub-processes we exec
will all find the git-foo commands that match the wrapper
version.
If you invoke git with an absolute path, like:
/usr/bin/git foo
we also prepend "/usr/bin" to the PATH. This was added long
ago by by 231af83 (Teach the "git" command to handle some
commands internally, 2006-02-26), with the intent that
things would just work if you did something like:
cd /opt
tar xzf premade-git-package.tar.gz
alias git=/opt/git/bin/git
as we would then find all of the related external commands
in /opt/git/bin. I.e., it made git runtime-relocatable,
since at the time of 231af83, we installed all of the git
commands into $(bindir). But these days, that is not enough.
Since f28ac70 (Move all dashed-form commands to libexecdir,
2007-11-28), we do not put commands into $(bindir), and you
actually need to convert "/usr/bin" into "/usr/libexec". And
not just for finding binaries; we want to find $(sharedir),
etc, the same way. The RUNTIME_PREFIX build knob does this
the right way, by assuming a sane hierarchy rooted at
"$prefix" when we run "$prefix/bin/git", and inferring
"$prefix/libexec/git-core", etc.
So this feature (prepending the argv[0] dirname to the PATH)
is broken for providing a runtime prefix, and has been for
many years. Does it do anything for other cases?
For the "git" wrapper itself, as well as any commands
shipped by "git", the answer is no. Those are already in
git's exec-path, which is consulted first. For third-party
commands which you've dropped into the same directory, it
does include them. So if you do
cd /opt
tar xzf git-built-specifically-for-opt-git.tar.gz
cp third-party/git-foo /opt/git/bin/git-foo
alias git=/opt/git/bin/git
it does mean that we will find the third-party "git-foo",
even if you do not put /opt/git/bin into your $PATH. But
the flipside of this is that we will bump the precedence of
_other_ third-party tools that happen to be in the same
directory as git. For example, consider this setup:
1. Git is installed by the system in /usr/bin. There are
other system utilities in /usr/bin. E.g., a system
"vi".
2. The user installs tools they prefer in /usr/local/bin.
E.g., vim with a "vi" symlink. They set their PATH to
/usr/local/bin:/usr/bin to prefer their custom tools.
3. Running /usr/bin/git puts "/usr/bin" at the front of
their PATH. When git invokes the editor on behalf of
the user, they get the system vi, not their normal vim.
There are other variants of this, including overriding
system ruby and python (which is quite common using tools
like "rvm" and "virtualenv", which use relocatable
hierarchies and $PATH settings to get a consistent
environment).
Given that the main motivation for git placing the argv[0]
dirname into the PATH has been broken for years, that the
remaining cases are obscure and unlikely (and easily fixed
by the user just setting up their $PATH sanely), and that
the behavior is hurting real, reasonably common use cases,
it's not worth continuing to do so.
Signed-off-by: Jeff King <peff@peff.net> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
If you have staged contents in your index and run "stash
apply", we may hit a conflict and put new entries into the
index. Recovering to your original state is difficult at
that point, because tools like "git reset --keep" will blow
away anything staged. We can make this safer by refusing to
apply when there are staged changes.
It's possible we could provide better tooling here, as "git
stash apply" should be writing only conflicts to the index
(so we know that any stage-0 entries are potentially
precious). But it is the odd duck; most "mergy" commands
will update the index for cleanly merged entries, and it is
not worth updating our tooling to support this use case
which is unlikely to be of interest (besides which, we would
still need to block a dirty index for "stash apply --index",
since that case _would_ be ambiguous).
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
One of the tests in t3903 wants to make sure that applying a
stash that touches only "file" can still happen even if there
are working tree changes to "other-file". To do so, it adds
"other-file" to the index (since otherwise it is an
untracked file, voiding the purpose of the test).
But as we are about to refactor the dirty-index handling,
and as this test does not actually care about having a dirty
index (only a dirty working tree), let's bump the tracking
of "other-file" into the setup phase, so we can have _just_
a dirty working tree here.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
When testing the diff output of "git stash list", we look
for the stash's subject of "WIP on master: $sha1", even
though it's not relevant to the diff output. This makes the
test brittle to refactoring, as any changes to earlier tests
may impact the commit sha1.
Since we don't care about the commit subject here, we can
simply ask stash not to print it.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t9801: check git-p4's branch detection with client spec enabled
Add failing scenario when branch detection (--detect-branches) is
enabled together with use client spec (--use-client-spec). In this
specific scenario git-p4 will break when the Perforce client view
removes part of the depot path, as in the following example:
//depot/branch1/base/... //client/branch1/...
The test case also includes an extra sub-file mapping to enforce
robustness check of git-p4's client view support:
"diff-highlight" (in contrib/) used to show byte-by-byte
differences, which meant that multi-byte characters can be chopped
in the middle. It learned to pay attention to character boundaries
(assuming the UTF-8 payload).
* jk/colors:
diff-highlight: do not split multibyte characters
* jk/test-annoyances:
t5551: make EXPENSIVE test cheaper
t5541: move run_with_cmdline_limit to test-lib.sh
t: pass GIT_TRACE through Apache
t: redirect stderr GIT_TRACE to descriptor 4
t: translate SIGINT to an exit
An earlier update to the parser that disects an address broke an
address, followed by a colon, followed by an empty string (instead
of the port number).
* tb/connect-ipv6-parse-fix:
connect.c: ignore extra colon after hostname
* va/fix-git-p4-tests:
t9814: guarantee only one source exists in git-p4 copy tests
git-p4: fix copy detection test
t9814: fix broken shell syntax in git-p4 rename test
The "git push --signed" protocol extension did not limit what the
"nonce" that is a server-chosen string can contain or how long it
can be, which was unnecessarily lax. Limit both the length and the
alphabet to a reasonably small space that can still have enough
entropy.
* jc/push-cert:
push --signed: tighten what the receiving end can ask to sign
A broken or badly formatted commit might not record author or
committer lines or we may not find a valid name on them. The
function record_person() returned after calling get_commit_buffer()
without calling unuse_commit_buffer() on the memory it obtained in
such cases, potentially leaking it.
Helped-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Since 33d4221 (write_sha1_file: freshen existing objects,
2014-10-15), we update the mtime of existing objects that we
would have written out (had they not existed). For the
common case in which many objects are packed, we may update
the mtime on a single packfile repeatedly. This can result
in a noticeable performance problem if calling utime() is
expensive (e.g., because your storage is on NFS).
We can fix this by keeping a per-pack flag that lets us
freshen only once per program invocation.
An alternative would be to keep the packed_git.mtime flag up
to date as we freshen, and freshen only once every N
seconds. In practice, it's not worth the complexity. We are
racing against prune expiration times here, which inherently
must be set to accomodate reasonable program running times
(because they really care about the time between an object
being written and it becoming referenced, and the latter is
typically the last step a program takes).
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
When writing out an object file, we first check whether it
already exists and if so optimize out the write. Prior to 33d4221, we did this by calling has_sha1_file(), which will
check for packed objects followed by loose. Since that
commit, we check loose objects first.
For the common case of a repository whose objects are mostly
packed, this means we will make a lot of extra access()
system calls checking for loose objects. We should follow
the same packed-then-loose order that all of our other
lookups use.
Reported-by: Stefan Saasen <ssaasen@atlassian.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
When pruning and repacking a repository that has an
alternate object store configured, we may traverse a large
number of objects in the alternate. This serves no purpose,
and may be expensive to do. A longer explanation is below.
Commits d3038d2 and abcb865 taught prune and pack-objects
(respectively) to treat "recent" objects as tips for
reachability, so that we keep whole chunks of history. They
built on the object traversal in 660c889 (sha1_file: add
for_each iterators for loose and packed objects,
2014-10-15), which covers both local and alternate objects.
In both cases, covering alternate objects is unnecessary, as
both commands can only drop objects from the local
repository. In the case of prune, we traverse only the local
object directory. And in the case of repacking, while we may
or may not include local objects in our pack, we will never
reach into the alternate with "repack -d". The "-l" option
is only a question of whether we are migrating objects from
the alternate into our repository, or leaving them
untouched.
It is possible that we may drop an object that is depended
upon by another object in the alternate. For example,
imagine two repositories, A and B, with A pointing to B as
an alternate. Now imagine a commit that is in B which
references a tree that is only in A. Traversing from recent
objects in B might prevent A from dropping that tree. But
this case isn't worth covering. Repo B should take
responsibility for its own objects. It would never have had
the commit in the first place if it did not also have the
tree, and assuming it is using the same "keep recent chunks
of history" scheme, then it would itself keep the tree, as
well.
So checking the alternate objects is not worth doing, and
come with a significant performance impact. In both cases,
we skip any recent objects that have already been marked
SEEN (i.e., that we know are already reachable for prune, or
included in the pack for a repack). So there is a slight
waste of time in opening the alternate packs at all, only to
notice that we have already considered each object. But much
worse, the alternate repository may have a large number of
objects that are not reachable from the local repository at
all, and we end up adding them to the traversal.
We can fix this by considering only local unseen objects.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Simply running "p4 changes" on a large branch can result in a "too
many rows scanned" error from the Perforce server. It is better to
use a sequence of smaller calls to "p4 changes", using the "-m"
option to limit the size of each call.
Signed-off-by: Lex Spoon <lex@lexspoon.org> Acked-by: Luke Diamand <luke@diamand.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The old wording was somehow implying that <start> and <end> were not
regular expressions. Also, the common case is to use a plain function
name here so <funcname> makes sense (the fact that it is a regular
expression is documented in line-range-format.txt).
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* tag 'gitgui-0.20.0' of http://repo.or.cz/r/git-gui:
git-gui: set version 0.20
git-gui: sv.po: Update Swedish translation (547t0f0u)
git-gui i18n: Updated Bulgarian translation (547t,0f,0u)
git-gui: Makes chooser set 'gitdir' to the resolved path
git-gui: Fixes chooser not accepting gitfiles
git-gui: reinstate support for Tcl 8.4
git-gui: fix problem with gui.maxfilesdisplayed
git-gui: fix verbose loading when git path contains spaces.
git-gui/gitk: Do not depend on Cygwin's "kill" command on Windows
git-gui: add configurable tab size to the diff view
git-gui: Make git-gui lib dir configurable at runime
git-gui i18n: Updated Bulgarian translation (520t,0f,0u)
L10n: vi.po (543t): Init translation for Vietnamese
git-gui: align the new recursive checkbox with the radiobuttons.
git-gui: Add a 'recursive' checkbox in the clone menu.
Once we know the number of objects in the input pack, we allocate an
array of nr_objects of struct delta_entry. On x86-64, this struct is
32 bytes long. The union delta_base, which is part of struct
delta_entry, provides enough space to store either ofs-delta (8 bytes)
or ref-delta (20 bytes).
Because ofs-delta encoding is more efficient space-wise and more
performant at runtime than ref-delta encoding, Git packers try to use
ofs-delta whenever possible, and it is expected that objects encoded
as ref-delta are minority.
In the best clone case where no ref-delta object is present, we waste
(20-8) * nr_objects bytes because of this union. That's about 38MB out
of 100MB for deltas[] with 3.4M objects, or 38%. deltas[] would be
around 62MB without the waste.
This patch attempts to eliminate that. deltas[] array is split into
two: one for ofs-delta and one for ref-delta. Many functions are also
duplicated because of this split. With this patch, ofs_deltas[] array
takes 51MB. ref_deltas[] should remain unallocated in clone case (0
bytes). This array grows as we see ref-delta. We save about half in
this case, or 25% of total bookkeeping.
The saving is more than the calculation above because some padding in
the old delta_entry struct is removed. ofs_delta_entry is 16 bytes,
including the 4 bytes padding. That's 13MB for padding, but packing
the struct could break platforms that do not support unaligned
access. If someone on 32-bit is really low on memory and only deals
with packs smaller than 2G, using 32-bit off_t would eliminate the
padding and save 27MB on top.
A note about ofs_deltas allocation. We could use ref_deltas memory
allocation strategy for ofs_deltas. But that probably just adds more
overhead on top. ofs-deltas are generally the majority (1/2 to 2/3) in
any pack. Incremental realloc may lead to too many memcpy. And if we
preallocate, say 1/2 or 2/3 of nr_objects initially, the growth rate
of ALLOC_GROW() could make this array larger than nr_objects, wasting
more memory.
Brought-up-by: Matthew Sporleder <msporleder@gmail.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t0027 expects the native end-of-lines to be a single line feed
character. On Windows, however, we set it to a carriage return
character followed by a line feed character. Thus, we have to
modify t0027 to expect different warnings depending on the
end-of-line markers.
Adjust the check of the warnings and use these macros:
WILC: Warn if LF becomes CRLF
WICL: Warn if CRLF becomes LF
WAMIX: Mixed line endings: either CRLF->LF or LF->CRLF
Improve the information given by check_warning().
Use test_cmp to show which warning is missing (or shouldn't be
there).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Torsten Bögershausen <tboegi@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
commit_check_warn():
Commit files and checks for conversion warnings.
Old name: create_file_in_repo()
checkout_files():
Checkout files from the repo and check if they have
the appropriate line endings in the work space.
Old name: check_files_in_ws()
Replace non-leading TABS with spaces
Signed-off-by: Torsten Bögershausen <tboegi@web.de> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
limit_list: avoid quadratic behavior from still_interesting
When we are limiting a rev-list traversal due to
UNINTERESTING refs, we have to walk down the tips (both
interesting and uninteresting) to find where they intersect.
We keep a queue of commits to examine, pop commits off
the queue one by one, and potentially add their parents. The
size of the queue will naturally fluctuate based on the
"width" of the history graph; i.e., the number of
simultaneous lines of development. But for the most part it
will stay in the same ballpark as the initial number of tips
we fed, shrinking over time (as we hit common ancestors of
the tips). So roughly speaking, if we start with `N` tips,
we'll spend much of the time with a queue around `N` items.
For each UNINTERESTING commit we pop, we call
still_interesting to check whether marking its parents as
UNINTERESTING has made the whole queue uninteresting (in
which case we can quit early). Because the queue is stored
as a linked list, this is `O(N)`, where `N` is the number of
items in the queue. So processing a queue with `N` commits
marked UNINTERESTING (and one or more interesting commits)
will take `O(N^2)`.
If you feed a lot of positive tips, this isn't a problem.
They aren't UNINTERESTING, so they don't incur the
still_interesting check. It also isn't a problem if you
traverse from an interesting tip to some UNINTERESTING
bases. We order the queue by recency, so the interesting
commits stay at the front of the queue as we walk down them.
The linear check can exit early as soon as it sees one
interesting commit left in the queue.
But if you want to know whether an older commit is reachable
from a set of newer tips, we end up processing in the
opposite direction: from the UNINTERESTING ones down to the
interesting one. This may happen when we call:
git rev-list $commits --not --all
in check_everything_connected after a fetch. If we fetched
something much older than most of our refs, and if we have a
large number of refs, the traversal cost is dominated by the
quadratic behavior.
These commands simulate the connectivity check of such a
fetch, when you have `$n` distinct refs in the receiver:
# positive ref is 100,000 commits deep
git rev-list --all | head -100000 | tail -1 >input
# huge number of more recent negative refs
git rev-list --all | head -$n | sed s/^/^/ >>input
time git rev-list --stdin <input
Here are timings for various `n` on the linux.git
repository. The `n=1` case provides a baseline for just
walking the commits, which lets us see the still_interesting
overhead. The times marked with `+` subtract that baseline
to show just the extra time growth due to the large number
of refs. The `x` numbers show the slowdown of the adjusted
time versus the prior trial.
Each trial doubles `n`, so you can see the quadratic (`4x`)
behavior before this patch. Afterwards, we have a roughly
linear relationship.
The implementation is fairly straightforward. Whenever we do
the linear search, we cache the interesting commit we find,
and next time check it before doing another linear search.
If that commit is removed from the list or becomes
UNINTERESTING itself, then we fall back to the linear
search. This is very similar to the trick used by fce87ae
(Fix quadratic performance in rewrite_one., 2008-07-12).
I considered and rejected several possible alternatives:
1. Keep a count of UNINTERESTING commits in the queue.
This requires managing the count not only when removing
an item from the queue, but also when marking an item
as UNINTERESTING. That requires touching the other
functions which mark commits, and would require knowing
quickly which commits are in the queue (lookup in the
queue is linear, so we would need an auxiliary
structure or to also maintain an IN_QUEUE flag in each
commit object).
2. Keep a separate list of interesting commits. Drop items
from it when they are dropped from the queue, or if
they become UNINTERESTING. This again suffers from
extra complexity to maintain the list, not to mention
CPU and memory.
3. Use a better data structure for the queue. This is
something that could help the fix in fce87ae, because
we order the queue by recency, and it is about
inserting quickly in recency order. So a normal
priority queue would help there. But here, we cannot
disturb the order of the queue, which makes things
harder. We really do need an auxiliary index to track
the flag we care about, which is basically option (2)
above.
The "cache" trick is simple, and the numbers above show that
it works well in practice. This is because the length of
time it takes to find an interesting commit is proportional
to the length of time it will remain cached (i.e., if we
have to walk a long way to find it, it also means we have to
pop a lot of elements in the queue until we get rid of it
and have to find another interesting commit).
The worst case is still quadratic, though. We could have `N`
uninteresting commits at the front of the queue, followed by
`N` interesting commits, where commit `i` has parent `i+N`.
When we pop commit `i`, we will notice that the parent of
the next commit, `i+1+N` is still interesting and cache it.
But then handling commit `i+1`, we will mark its parent
`i+1+N` uninteresting, and immediately invalidate our cache.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
When commit fe8e3b7 refactored type_from_string to allow
input that was not NUL-terminated, it switched to using
strncmp instead of strcmp. But this means we check only the
first "len" bytes of the strings, and ignore any remaining
bytes in the object_type_string. We should make sure that it
is also "len" bytes, or else we would accept "comm" as
"commit", and so forth.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
config: use utf8_bom[] from utf.[ch] in git_parse_source()
Because the function reads one character at the time, unfortunately
we cannot use the easier skip_utf8_bom() helper, but at least we do
not have to duplicate the constant string this way.
With the recent change to ignore the UTF8 BOM at the beginning of
.gitignore files, we now have two codepaths that do such a skipping
(the other one is for reading the configuration files).
Introduce utf8_bom[] constant string and skip_utf8_bom() helper
and teach .gitignore code how to use it.
add_excludes_from_file: clarify the bom skipping logic
Even though the previous step shifts where the "entry" begins, we
still iterate over the original buf[], which may begin with the
UTF-8 BOM we are supposed to be skipping. At the end of the first
line, the code grabs the contents of it starting at "entry", so
there is nothing wrong per-se, but the logic looks really confused.
Instead, move the buf pointer and shrink its size, to truly
pretend that UTF-8 BOM did not exist in the input.
dir: allow a BOM at the beginning of exclude files
Some text editors like Notepad or LibreOffice write an UTF-8 BOM in
order to indicate that the file is Unicode text rather than whatever the
current locale would indicate.
If someone uses such an editor to edit a gitignore file, we are left
with those three bytes at the beginning of the file. If we do not skip
them, we will attempt to match a filename with the BOM as prefix, which
won't match the files the user is expecting.
Signed-off-by: Carlos Martín Nieto <cmn@elego.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
In t1430, we check whether deleting the branch "../../foo"
will delete ".git/foo". However, this is not that
interesting a test; the precious file ".git/foo" does not
look like a ref, so even if we did not notice the "escape"
from the "refs/" hierarchy, we would fail for that reason
(i.e., if you turned refname_is_safe into a noop, the test
still passes).
Let's add an additional test for the same thing, but with a
file that actually looks like a ref. That will make sure we
are exercising the refname_is_safe code. While we're at it,
let's also make the code work a little harder by adding some
extra paths and some empty path components.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Prior to d0f810f (refs.c: allow listing and deleting badly
named refs, 2014-09-03), read_packed_refs would barf on any
malformed refnames by virtue of calling create_ref_entry
with the "check" parameter set to 1. That commit loosened
our reading so that we call check_refname_format ourselves
and just set a REF_BAD_NAME flag.
We then call create_ref_entry with the check parameter set
to 0. That function learned to do an extra safety check even
when the check parameter is 0, so that we don't load any
dangerous refnames (like "../../../etc/passwd"). This is
implemented by calling refname_is_safe() in
create_ref_entry().
However, we can observe that refname_is_safe() can only be
true if check_refname_format() also failed. So in the common
case of a sanely named ref, we perform _both_ checks, even
though we know that the latter will never trigger. This has
a noticeable performance impact when the packed-refs file is
large.
Let's drop the refname_is_safe check from create_ref_entry(),
and make it the responsibility of the caller. Of the three
callers that pass a check parameter of "0", two will have
just called check_refname_format(), and can check the
refname-safety only when it fails. The third case,
pack_if_possible_fn, is copying from an existing ref entry,
which must have previously passed our safety check.
With this patch, running "git rev-parse refs/heads/does-not-exist"
on a repo with a large (1.6GB) packed-refs file went from:
real 0m6.768s
user 0m6.340s
sys 0m0.432s
to:
real 0m5.703s
user 0m5.276s
sys 0m0.432s
for a wall-clock speedup of 15%.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
strbuf_getwholeline: use getdelim if it is available
We spend a lot of time in strbuf_getwholeline in a tight
loop reading characters from a stdio handle into a buffer.
The libc getdelim() function can do this for us with less
overhead. It's in POSIX.1-2008, and was a GNU extension
before that. Therefore we can't rely on it, but can fall
back to the existing getc loop when it is not available.
The HAVE_GETDELIM knob is turned on automatically for Linux,
where we have glibc. We don't need to set any new
feature-test macros, because we already define _GNU_SOURCE.
Other systems that implement getdelim may need to other
macros (probably _POSIX_C_SOURCE >= 200809L), but we can
address that along with setting the Makefile knob after
testing the feature on those systems.
Running "git rev-parse refs/heads/does-not-exist" on a repo
with an extremely large (1.6GB) packed-refs file went from
(best-of-5):
real 0m8.601s
user 0m8.084s
sys 0m0.524s
to:
real 0m6.768s
user 0m6.340s
sys 0m0.432s
for a wall-clock speedup of 21%.
Based on a patch from Rasmus Villemoes <rv@rasmusvillemoes.dk>.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
As with the recent speedup to strbuf_addch, we can avoid
calling strbuf_grow() in a tight loop of single-character
adds by instead checking strbuf_avail.
Note that we would instead call strbuf_addch directly here,
but it does more work than necessary: it will NUL-terminate
the result for each character read. Instead, in this loop we
read the characters one by one and then add the terminator
manually at the end.
Running "git rev-parse refs/heads/does-not-exist" on a repo
with an extremely large (1.6GB) packed-refs file went from
(best-of-5):
real 0m10.948s
user 0m10.548s
sys 0m0.412s
to:
real 0m8.601s
user 0m8.084s
sys 0m0.524s
for a wall-clock speedup of 21%.
Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
We mark strbuf_addch as inline, because we expect it may be
called from a tight loop. However, the first thing it does
is call the non-inline strbuf_grow(), which can handle
arbitrary-sized growth. Since we know that we only need a
single character, we can use the inline strbuf_avail() to
quickly check whether we need to grow at all.
Our check is redundant when we do call strbuf_grow(), but
that's OK. The common case is that we avoid calling it at
all, and we have made that case faster.