summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/CodingGuidelines4
-rw-r--r--Documentation/MyFirstContribution.txt53
-rw-r--r--Documentation/RelNotes/1.5.0.txt4
-rw-r--r--Documentation/RelNotes/1.6.5.4.txt2
-rw-r--r--Documentation/RelNotes/1.7.0.2.txt2
-rw-r--r--Documentation/RelNotes/1.7.10.4.txt2
-rw-r--r--Documentation/RelNotes/1.7.12.3.txt2
-rw-r--r--Documentation/RelNotes/1.7.5.3.txt2
-rw-r--r--Documentation/RelNotes/1.8.0.txt2
-rw-r--r--Documentation/RelNotes/1.8.4.1.txt2
-rw-r--r--Documentation/RelNotes/2.1.3.txt2
-rw-r--r--Documentation/RelNotes/2.10.0.txt2
-rw-r--r--Documentation/RelNotes/2.10.2.txt2
-rw-r--r--Documentation/RelNotes/2.11.1.txt2
-rw-r--r--Documentation/RelNotes/2.12.0.txt2
-rw-r--r--Documentation/RelNotes/2.13.0.txt2
-rw-r--r--Documentation/RelNotes/2.13.3.txt4
-rw-r--r--Documentation/RelNotes/2.14.0.txt4
-rw-r--r--Documentation/RelNotes/2.16.0.txt2
-rw-r--r--Documentation/RelNotes/2.16.3.txt2
-rw-r--r--Documentation/RelNotes/2.17.0.txt2
-rw-r--r--Documentation/RelNotes/2.18.0.txt2
-rw-r--r--Documentation/RelNotes/2.19.0.txt2
-rw-r--r--Documentation/RelNotes/2.20.0.txt2
-rw-r--r--Documentation/RelNotes/2.25.0.txt87
-rw-r--r--Documentation/RelNotes/2.3.3.txt2
-rw-r--r--Documentation/RelNotes/2.3.7.txt2
-rw-r--r--Documentation/RelNotes/2.4.3.txt2
-rw-r--r--Documentation/RelNotes/2.7.0.txt2
-rw-r--r--Documentation/RelNotes/2.8.0.txt2
-rw-r--r--Documentation/RelNotes/2.9.3.txt2
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/config/add.txt5
-rw-r--r--Documentation/config/tag.txt2
-rw-r--r--Documentation/fetch-options.txt4
-rw-r--r--Documentation/git-bisect-lk2009.txt2
-rw-r--r--Documentation/git-bisect.txt2
-rw-r--r--Documentation/git-bundle.txt35
-rw-r--r--Documentation/git-check-attr.txt2
-rw-r--r--Documentation/git-check-ignore.txt2
-rw-r--r--Documentation/git-commit-graph.txt12
-rw-r--r--Documentation/git-cvsserver.txt2
-rw-r--r--Documentation/git-diff.txt2
-rw-r--r--Documentation/git-fast-export.txt2
-rw-r--r--Documentation/git-filter-branch.txt4
-rw-r--r--Documentation/git-range-diff.txt2
-rw-r--r--Documentation/git-rebase.txt4
-rw-r--r--Documentation/git-shortlog.txt3
-rw-r--r--Documentation/git-tag.txt2
-rw-r--r--Documentation/git-update-index.txt2
-rw-r--r--Documentation/git.txt4
-rw-r--r--Documentation/gitattributes.txt8
-rw-r--r--Documentation/gitmodules.txt2
-rw-r--r--Documentation/gitsubmodules.txt2
-rw-r--r--Documentation/howto/separating-topic-branches.txt2
-rw-r--r--Documentation/merge-options.txt2
-rw-r--r--Documentation/merge-strategies.txt2
-rw-r--r--Documentation/rev-list-options.txt11
-rw-r--r--Documentation/technical/api-config.txt319
-rw-r--r--Documentation/technical/api-submodule-config.txt2
-rw-r--r--Documentation/technical/api-trace2.txt14
-rw-r--r--Documentation/technical/commit-graph.txt12
-rw-r--r--Documentation/technical/hash-function-transition.txt4
-rw-r--r--Documentation/technical/index-format.txt4
-rw-r--r--Documentation/technical/pack-protocol.txt2
-rw-r--r--Documentation/technical/partial-clone.txt2
-rw-r--r--Documentation/technical/protocol-v2.txt2
-rw-r--r--Documentation/technical/rerere.txt2
-rw-r--r--INSTALL6
-rw-r--r--Makefile2
-rw-r--r--add-interactive.c652
-rw-r--r--add-interactive.h8
-rw-r--r--apply.c4
-rw-r--r--builtin/add.c12
-rw-r--r--builtin/blame.c8
-rw-r--r--builtin/bundle.c217
-rw-r--r--builtin/clone.c11
-rw-r--r--builtin/commit-graph.c68
-rw-r--r--builtin/fetch.c19
-rw-r--r--builtin/fsck.c126
-rw-r--r--builtin/gc.c4
-rw-r--r--builtin/pack-objects.c2
-rw-r--r--builtin/stash.c7
-rw-r--r--builtin/worktree.c2
-rw-r--r--bundle.c9
-rw-r--r--bundle.h3
-rw-r--r--cache.h8
-rw-r--r--command-list.txt1
-rw-r--r--commit-graph.c5
-rw-r--r--commit.c33
-rw-r--r--commit.h2
-rw-r--r--compat/mingw.c2
-rw-r--r--compat/mingw.h2
-rw-r--r--compat/nedmalloc/malloc.c.h6
-rw-r--r--compat/obstack.h2
-rw-r--r--compat/regex/regcomp.c2
-rw-r--r--compat/regex/regex.h2
-rw-r--r--compat/regex/regex_internal.c2
-rw-r--r--compat/regex/regexec.c4
-rw-r--r--compat/vcbuild/find_vs_env.bat2
-rw-r--r--config.h335
-rw-r--r--configure.ac51
-rw-r--r--connected.c3
-rw-r--r--contrib/coccinelle/commit.cocci2
-rw-r--r--contrib/coccinelle/object_id.cocci32
-rw-r--r--contrib/completion/git-completion.bash9
-rwxr-xr-xcontrib/hooks/multimail/git_multimail.py8
-rwxr-xr-xcontrib/hooks/multimail/post-receive.example2
-rwxr-xr-xcontrib/hooks/post-receive-email2
-rwxr-xr-xcontrib/hooks/update-paranoid2
-rw-r--r--contrib/mw-to-git/.perlcriticrc2
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl2
-rw-r--r--contrib/mw-to-git/t/install-wiki/db_install.php2
-rwxr-xr-xcontrib/mw-to-git/t/t9360-mw-to-git-clone.sh2
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh2
-rwxr-xr-xcontrib/svn-fe/svnrdump_sim.py2
-rw-r--r--convert.c24
-rw-r--r--daemon.c4
-rw-r--r--diff.c43
-rw-r--r--diff.h20
-rw-r--r--dir.c2
-rw-r--r--fetch-pack.c49
-rw-r--r--fsck.c386
-rw-r--r--fsck.h39
-rw-r--r--fsmonitor.c6
-rwxr-xr-xgit-cvsimport.perl2
-rwxr-xr-xgit-send-email.perl2
-rwxr-xr-xgitweb/gitweb.perl49
-rw-r--r--graph.c646
-rw-r--r--hashmap.c2
-rw-r--r--hashmap.h8
-rw-r--r--help.c2
-rw-r--r--hex.c10
-rw-r--r--http.c18
-rw-r--r--kwset.h4
-rw-r--r--name-hash.c4
-rw-r--r--pack-objects.c5
-rw-r--r--pack-objects.h19
-rw-r--r--parse-options-cb.c3
-rw-r--r--parse-options.c2
-rw-r--r--path.c6
-rw-r--r--perl/Git.pm2
-rw-r--r--promisor-remote.c3
-rw-r--r--range-diff.h2
-rw-r--r--read-cache.c2
-rw-r--r--refs/refs-internal.h2
-rw-r--r--repository.c4
-rw-r--r--repository.h2
-rw-r--r--rerere.c2
-rw-r--r--send-pack.c8
-rw-r--r--sequencer.c27
-rw-r--r--server-info.c2
-rw-r--r--sha1dc/sha1.c2
-rw-r--r--sha1dc_git.c2
-rw-r--r--string-list.h2
-rw-r--r--t/README4
-rw-r--r--t/gitweb-lib.sh7
-rw-r--r--t/helper/test-read-graph.c53
-rw-r--r--t/helper/test-tool.c1
-rw-r--r--t/helper/test-tool.h1
-rwxr-xr-xt/perf/bisect_regression2
-rwxr-xr-xt/perf/p5303-many-packs.sh1
-rwxr-xr-xt/t0000-basic.sh2
-rwxr-xr-xt/t0027-auto-crlf.sh2
-rwxr-xr-xt/t0028-working-tree-encoding.sh4
-rwxr-xr-xt/t0060-path-utils.sh2
-rwxr-xr-xt/t0500-progress-display.sh4
-rwxr-xr-xt/t1050-large.sh6
-rwxr-xr-xt/t1400-update-ref.sh18
-rwxr-xr-xt/t1450-fsck.sh2
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh2
-rwxr-xr-xt/t2400-worktree-add.sh24
-rwxr-xr-xt/t3060-ls-files-with-tree.sh4
-rwxr-xr-xt/t3210-pack-refs.sh2
-rwxr-xr-xt/t3430-rebase-merges.sh2
-rwxr-xr-xt/t3434-rebase-i18n.sh84
-rw-r--r--t/t3434/ISO8859-1.txt3
-rw-r--r--t/t3434/eucJP.txt4
-rwxr-xr-xt/t3701-add-interactive.sh25
-rwxr-xr-xt/t3900-i18n-commit.sh37
-rwxr-xr-xt/t3903-stash.sh7
-rwxr-xr-xt/t3905-stash-include-untracked.sh4
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rw-r--r--t/t4018/elixir-do-not-pick-end5
-rw-r--r--t/t4018/elixir-ex-unit-test6
-rw-r--r--t/t4018/elixir-function5
-rw-r--r--t/t4018/elixir-macro5
-rw-r--r--t/t4018/elixir-module9
-rw-r--r--t/t4018/elixir-module-func8
-rw-r--r--t/t4018/elixir-nested-module9
-rw-r--r--t/t4018/elixir-private-function5
-rw-r--r--t/t4018/elixir-protocol6
-rw-r--r--t/t4018/elixir-protocol-implementation5
-rwxr-xr-xt/t4041-diff-submodule-option.sh20
-rwxr-xr-xt/t4057-diff-combined-paths.sh2
-rw-r--r--t/t4100/t-apply-1.patch4
-rw-r--r--t/t4100/t-apply-3.patch2
-rw-r--r--t/t4100/t-apply-5.patch4
-rw-r--r--t/t4100/t-apply-7.patch2
-rwxr-xr-xt/t4202-log.sh2
-rwxr-xr-xt/t4205-log-pretty-formats.sh2
-rwxr-xr-xt/t4213-log-tabexpand.sh2
-rwxr-xr-xt/t4214-log-graph-octopus.sh62
-rwxr-xr-xt/t4215-log-skewed-merges.sh243
-rwxr-xr-xt/t5318-commit-graph.sh4
-rwxr-xr-xt/t5324-split-commit-graph.sh2
-rwxr-xr-xt/t5528-push-default.sh2
-rwxr-xr-xt/t5535-fetch-push-symref.sh2
-rwxr-xr-xt/t5545-push-options.sh2
-rwxr-xr-xt/t5616-partial-clone.sh70
-rwxr-xr-xt/t5702-protocol-v2.sh10
-rwxr-xr-xt/t6016-rev-list-graph-simplify-history.sh30
-rwxr-xr-xt/t6024-recursive-merge.sh130
-rwxr-xr-xt/t6036-recursive-corner-cases.sh4
-rwxr-xr-xt/t6043-merge-rename-directories.sh6
-rwxr-xr-xt/t6102-rev-list-unexpected-objects.sh2
-rwxr-xr-xt/t7004-tag.sh8
-rwxr-xr-xt/t7030-verify-tag.sh14
-rwxr-xr-xt/t7508-status.sh2
-rwxr-xr-xt/t7513-interpret-trailers.sh2
-rwxr-xr-xt/t7519-status-fsmonitor.sh2
-rwxr-xr-xt/t7519/fsmonitor-watchman13
-rwxr-xr-xt/t9001-send-email.sh2
-rwxr-xr-xt/t9301-fast-import-notes.sh2
-rwxr-xr-xt/t9350-fast-export.sh2
-rwxr-xr-xt/t9502-gitweb-standalone-parse-output.sh7
-rwxr-xr-xt/t9809-git-p4-client-view.sh2
-rwxr-xr-xt/t9902-completion.sh6
-rw-r--r--t/test-lib.sh12
-rw-r--r--tag.c21
-rw-r--r--tar.h5
-rwxr-xr-xtemplates/hooks--fsmonitor-watchman.sample13
-rw-r--r--trace2/tr2_sid.c2
-rw-r--r--trace2/tr2_tgt_perf.c17
-rw-r--r--unpack-trees.c4
-rw-r--r--url.c2
-rw-r--r--usage.c20
-rw-r--r--userdiff.c12
-rw-r--r--utf8.c9
-rw-r--r--xdiff-interface.h2
240 files changed, 3342 insertions, 1620 deletions
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index f45db5b..ed4e443 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -75,7 +75,7 @@ For shell scripts specifically (not exhaustive):
- If you want to find out if a command is available on the user's
$PATH, you should use 'type <command>', instead of 'which <command>'.
- The output of 'which' is not machine parseable and its exit code
+ The output of 'which' is not machine parsable and its exit code
is not reliable across platforms.
- We use POSIX compliant parameter substitutions and avoid bashisms;
@@ -203,7 +203,7 @@ For C programs:
. since early 2012 with e1327023ea, we have been using an enum
definition whose last element is followed by a comma. This, like
an array initializer that ends with a trailing comma, can be used
- to reduce the patch noise when adding a new identifer at the end.
+ to reduce the patch noise when adding a new identifier at the end.
. since mid 2017 with cbc0f81d, we have been using designated
initializers for struct (e.g. "struct t v = { .val = 'a' };").
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index 5e9b808..b55837e 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -38,6 +38,26 @@ $ git clone https://github.com/git/git git
$ cd git
----
+[[dependencies]]
+=== Installing Dependencies
+
+To build Git from source, you need to have a handful of dependencies installed
+on your system. For a hint of what's needed, you can take a look at
+`INSTALL`, paying close attention to the section about Git's dependencies on
+external programs and libraries. That document mentions a way to "test-drive"
+our freshly built Git without installing; that's the method we'll be using in
+this tutorial.
+
+Make sure that your environment has everything you need by building your brand
+new clone of Git from the above step:
+
+----
+$ make
+----
+
+NOTE: The Git build is parallelizable. `-j#` is not included above but you can
+use it as you prefer, here and elsewhere.
+
[[identify-problem]]
=== Identify Problem to Solve
@@ -138,9 +158,6 @@ NOTE: When you are developing the Git project, it's preferred that you use the
`DEVELOPER` flag; if there's some reason it doesn't work for you, you can turn
it off, but it's a good idea to mention the problem to the mailing list.
-NOTE: The Git build is parallelizable. `-j#` is not included above but you can
-use it as you prefer, here and elsewhere.
-
Great, now your new command builds happily on its own. But nobody invokes it.
Let's change that.
@@ -534,6 +551,28 @@ you want to pass as a parameter something which would usually be interpreted as
a flag.) `parse_options()` will terminate parsing when it reaches `--` and give
you the rest of the options afterwards, untouched.
+Now that you have a usage hint, you can teach Git how to show it in the general
+command list shown by `git help git` or `git help -a`, which is generated from
+`command-list.txt`. Find the line for 'git-pull' so you can add your 'git-psuh'
+line above it in alphabetical order. Now, we can add some attributes about the
+command which impacts where it shows up in the aforementioned help commands. The
+top of `command-list.txt` shares some information about what each attribute
+means; in those help pages, the commands are sorted according to these
+attributes. `git psuh` is user-facing, or porcelain - so we will mark it as
+"mainporcelain". For "mainporcelain" commands, the comments at the top of
+`command-list.txt` indicate we can also optionally add an attribute from another
+list; since `git psuh` shows some information about the user's workspace but
+doesn't modify anything, let's mark it as "info". Make sure to keep your
+attributes in the same style as the rest of `command-list.txt` using spaces to
+align and delineate them:
+
+----
+git-prune-packed plumbingmanipulators
+git-psuh mainporcelain info
+git-pull mainporcelain remote
+git-push mainporcelain remote
+----
+
Build again. Now, when you run with `-h`, you should see your usage printed and
your command terminated before anything else interesting happens. Great!
@@ -746,6 +785,14 @@ will automatically run your PRs through the CI even without the permission given
but you will not be able to `/submit` your changes until someone allows you to
use the tool.
+NOTE: You can typically find someone who can `/allow` you on GitGitGadget by
+either examining recent pull requests where someone has been granted `/allow`
+(https://github.com/gitgitgadget/git/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+%22%2Fallow%22[Search:
+is:pr is:open "/allow"]), in which case both the author and the person who
+granted the `/allow` can now `/allow` you, or by inquiring on the
+https://webchat.freenode.net/#git-devel[#git-devel] IRC channel on Freenode
+linking your pull request and asking for someone to `/allow` you.
+
If the CI fails, you can update your changes with `git rebase -i` and push your
branch again:
diff --git a/Documentation/RelNotes/1.5.0.txt b/Documentation/RelNotes/1.5.0.txt
index daf4bdb..d6d42f3 100644
--- a/Documentation/RelNotes/1.5.0.txt
+++ b/Documentation/RelNotes/1.5.0.txt
@@ -251,7 +251,7 @@ Updates in v1.5.0 since v1.4.4 series
the repository when that happens.
-* Crufts removal
+* Cruft removal
- We used to say "old commits are retrievable using reflog and
'master@{yesterday}' syntax as long as you haven't run
@@ -379,7 +379,7 @@ Updates in v1.5.0 since v1.4.4 series
- The value of i18n.commitencoding in the originating
repository is recorded in the commit object on the "encoding"
header, if it is not UTF-8. git-log and friends notice this,
- and reencodes the message to the log output encoding when
+ and re-encodes the message to the log output encoding when
displaying, if they are different. The log output encoding
is determined by "git log --encoding=<encoding>",
i18n.logoutputencoding configuration, or i18n.commitencoding
diff --git a/Documentation/RelNotes/1.6.5.4.txt b/Documentation/RelNotes/1.6.5.4.txt
index d3a2a3e..344333d 100644
--- a/Documentation/RelNotes/1.6.5.4.txt
+++ b/Documentation/RelNotes/1.6.5.4.txt
@@ -10,7 +10,7 @@ Fixes since v1.6.5.3
* "git prune-packed" gave progress output even when its standard error is
not connected to a terminal; this caused cron jobs that run it to
- produce crufts.
+ produce cruft.
* "git pack-objects --all-progress" is an option to ask progress output
from write-object phase _if_ progress output were to be produced, and
diff --git a/Documentation/RelNotes/1.7.0.2.txt b/Documentation/RelNotes/1.7.0.2.txt
index fcb46ca..73ed2b5 100644
--- a/Documentation/RelNotes/1.7.0.2.txt
+++ b/Documentation/RelNotes/1.7.0.2.txt
@@ -34,7 +34,7 @@ Fixes since v1.7.0.1
* "git status" in 1.7.0 lacked the optimization we used to have in 1.6.X series
to speed up scanning of large working tree.
- * "gitweb" did not diagnose parsing errors properly while reading tis configuration
+ * "gitweb" did not diagnose parsing errors properly while reading its configuration
file.
And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.4.txt b/Documentation/RelNotes/1.7.10.4.txt
index 326670d..57597f2 100644
--- a/Documentation/RelNotes/1.7.10.4.txt
+++ b/Documentation/RelNotes/1.7.10.4.txt
@@ -7,7 +7,7 @@ Fixes since v1.7.10.3
* The message file for Swedish translation has been updated a bit.
* A name taken from mailmap was copied into an internal buffer
- incorrectly and could overun the buffer if it is too long.
+ incorrectly and could overrun the buffer if it is too long.
* A malformed commit object that has a header line chomped in the
middle could kill git with a NULL pointer dereference.
diff --git a/Documentation/RelNotes/1.7.12.3.txt b/Documentation/RelNotes/1.7.12.3.txt
index ecda427..4b82297 100644
--- a/Documentation/RelNotes/1.7.12.3.txt
+++ b/Documentation/RelNotes/1.7.12.3.txt
@@ -25,7 +25,7 @@ Fixes since v1.7.12.2
its Accept-Encoding header.
* "git receive-pack" (the counterpart to "git push") did not give
- progress output while processing objects it received to the puser
+ progress output while processing objects it received to the user
when run over the smart-http protocol.
* "git status" honored the ignore=dirty settings in .gitmodules but
diff --git a/Documentation/RelNotes/1.7.5.3.txt b/Documentation/RelNotes/1.7.5.3.txt
index 9c03353..1d24edc 100644
--- a/Documentation/RelNotes/1.7.5.3.txt
+++ b/Documentation/RelNotes/1.7.5.3.txt
@@ -22,7 +22,7 @@ Fixes since v1.7.5.2
* "git log --stdin path" with an input that has additional pathspec
used to corrupt memory.
- * "git send-pack" (hence "git push") over smalt-HTTP protocol could
+ * "git send-pack" (hence "git push") over smart-HTTP protocol could
deadlock when the client side pack-object died early.
* Compressed tarball gitweb generates used to be made with the timestamp
diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.txt
index 43883c1..63d6e4a 100644
--- a/Documentation/RelNotes/1.8.0.txt
+++ b/Documentation/RelNotes/1.8.0.txt
@@ -233,7 +233,7 @@ to them for details).
together, misdetected branches.
* "git receive-pack" (the counterpart to "git push") did not give
- progress output while processing objects it received to the puser
+ progress output while processing objects it received to the user
when run over the smart-http protocol.
* When you misspell the command name you give to the "exec" action in
diff --git a/Documentation/RelNotes/1.8.4.1.txt b/Documentation/RelNotes/1.8.4.1.txt
index 96090ef..c257beb 100644
--- a/Documentation/RelNotes/1.8.4.1.txt
+++ b/Documentation/RelNotes/1.8.4.1.txt
@@ -15,7 +15,7 @@ Fixes since v1.8.4
in 1.8.4-rc1).
* "git rebase -i" and other scripted commands were feeding a
- random, data dependant error message to 'echo' and expecting it
+ random, data dependent error message to 'echo' and expecting it
to come out literally.
* Setting the "submodule.<name>.path" variable to the empty
diff --git a/Documentation/RelNotes/2.1.3.txt b/Documentation/RelNotes/2.1.3.txt
index acc9ebb..0dfb17c 100644
--- a/Documentation/RelNotes/2.1.3.txt
+++ b/Documentation/RelNotes/2.1.3.txt
@@ -13,7 +13,7 @@ Git v2.1.3 Release Notes
they are new enough to support the `--output` option.
* "git pack-objects" forgot to disable the codepath to generate
- object recheability bitmap when it needs to split the resulting
+ object reachability bitmap when it needs to split the resulting
pack.
* "gitweb" used deprecated CGI::startfrom, which was removed from
diff --git a/Documentation/RelNotes/2.10.0.txt b/Documentation/RelNotes/2.10.0.txt
index f4da28a..3792b7d 100644
--- a/Documentation/RelNotes/2.10.0.txt
+++ b/Documentation/RelNotes/2.10.0.txt
@@ -478,7 +478,7 @@ notes for details).
* One part of "git am" had an oddball helper function that called
stuff from outside "his" as opposed to calling what we have "ours",
which was not gender-neutral and also inconsistent with the rest of
- the system where outside stuff is usuall called "theirs" in
+ the system where outside stuff is usually called "theirs" in
contrast to "ours".
* "git blame file" allowed the lineage of lines in the uncommitted,
diff --git a/Documentation/RelNotes/2.10.2.txt b/Documentation/RelNotes/2.10.2.txt
index c4d4397..abbd331 100644
--- a/Documentation/RelNotes/2.10.2.txt
+++ b/Documentation/RelNotes/2.10.2.txt
@@ -86,7 +86,7 @@ Fixes since v2.10.1
by refusing to check out a branch that is already checked out in
another worktree. However, this also prevented checking out a
branch, which is designated as the primary branch of a bare
- reopsitory, in a worktree that is connected to the bare
+ repository, in a worktree that is connected to the bare
repository. The check has been corrected to allow it.
* "git rebase" immediately after "git clone" failed to find the fork
diff --git a/Documentation/RelNotes/2.11.1.txt b/Documentation/RelNotes/2.11.1.txt
index 9cd14c8..7d35cf1 100644
--- a/Documentation/RelNotes/2.11.1.txt
+++ b/Documentation/RelNotes/2.11.1.txt
@@ -104,7 +104,7 @@ Fixes since v2.11
"git difftool --dir-diff" from a subdirectory never worked. This
has been fixed.
- * "git p4" that tracks multile p4 paths imported a single changelist
+ * "git p4" that tracks multiple p4 paths imported a single changelist
that touches files in these multiple paths as one commit, followed
by many empty commits. This has been fixed.
diff --git a/Documentation/RelNotes/2.12.0.txt b/Documentation/RelNotes/2.12.0.txt
index ef8b97d..d2f6a83 100644
--- a/Documentation/RelNotes/2.12.0.txt
+++ b/Documentation/RelNotes/2.12.0.txt
@@ -315,7 +315,7 @@ notes for details).
"git difftool --dir-diff" from a subdirectory never worked. This
has been fixed.
- * "git p4" that tracks multile p4 paths imported a single changelist
+ * "git p4" that tracks multiple p4 paths imported a single changelist
that touches files in these multiple paths as one commit, followed
by many empty commits. This has been fixed.
diff --git a/Documentation/RelNotes/2.13.0.txt b/Documentation/RelNotes/2.13.0.txt
index aa99d4b..2a47b4c 100644
--- a/Documentation/RelNotes/2.13.0.txt
+++ b/Documentation/RelNotes/2.13.0.txt
@@ -177,7 +177,7 @@ UI, Workflows & Features
been changed to enable "--decorate".
* The output from "git status --short" has been extended to show
- various kinds of dirtyness in submodules differently; instead of to
+ various kinds of dirtiness in submodules differently; instead of to
"M" for modified, 'm' and '?' can be shown to signal changes only
to the working tree of the submodule but not the commit that is
checked out.
diff --git a/Documentation/RelNotes/2.13.3.txt b/Documentation/RelNotes/2.13.3.txt
index 5d76ad5..384e4de 100644
--- a/Documentation/RelNotes/2.13.3.txt
+++ b/Documentation/RelNotes/2.13.3.txt
@@ -25,7 +25,7 @@ Fixes since v2.13.2
* The code to pick up and execute command alias definition from the
configuration used to switch to the top of the working tree and
then come back when the expanded alias was executed, which was
- unnecessarilyl complex. Attempt to simplify the logic by using the
+ unnecessarily complex. Attempt to simplify the logic by using the
early-config mechanism that does not chdir around.
* "git add -p" were updated in 2.12 timeframe to cope with custom
@@ -35,7 +35,7 @@ Fixes since v2.13.2
* Fix a recent regression to "git rebase -i" and add tests that would
have caught it and others.
- * An unaligned 32-bit access in pack-bitmap code ahs been corrected.
+ * An unaligned 32-bit access in pack-bitmap code has been corrected.
* Tighten error checks for invalid "git apply" input.
diff --git a/Documentation/RelNotes/2.14.0.txt b/Documentation/RelNotes/2.14.0.txt
index 4246c68..2711a25 100644
--- a/Documentation/RelNotes/2.14.0.txt
+++ b/Documentation/RelNotes/2.14.0.txt
@@ -141,7 +141,7 @@ Performance, Internal Implementation, Development Support etc.
* Some platforms have ulong that is smaller than time_t, and our
historical use of ulong for timestamp would mean they cannot
represent some timestamp that the platform allows. Invent a
- separate and dedicated timestamp_t (so that we can distingiuish
+ separate and dedicated timestamp_t (so that we can distinguish
timestamps and a vanilla ulongs, which along is already a good
move), and then declare uintmax_t is the type to be used as the
timestamp_t.
@@ -442,7 +442,7 @@ notes for details).
* The code to pick up and execute command alias definition from the
configuration used to switch to the top of the working tree and
then come back when the expanded alias was executed, which was
- unnecessarilyl complex. Attempt to simplify the logic by using the
+ unnecessarily complex. Attempt to simplify the logic by using the
early-config mechanism that does not chdir around.
* Fix configuration codepath to pay proper attention to commondir
diff --git a/Documentation/RelNotes/2.16.0.txt b/Documentation/RelNotes/2.16.0.txt
index 0c81c59..b474781 100644
--- a/Documentation/RelNotes/2.16.0.txt
+++ b/Documentation/RelNotes/2.16.0.txt
@@ -407,7 +407,7 @@ Fixes since v2.15
(merge eef3df5a93 bw/pathspec-match-submodule-boundary later to maint).
* Amending commits in git-gui broke the author name that is non-ascii
- due to incorrect enconding conversion.
+ due to incorrect encoding conversion.
* Recent update to the submodule configuration code broke "diff-tree"
by accidentally stopping to read from the index upfront.
diff --git a/Documentation/RelNotes/2.16.3.txt b/Documentation/RelNotes/2.16.3.txt
index 64a0bcb..f0121a8 100644
--- a/Documentation/RelNotes/2.16.3.txt
+++ b/Documentation/RelNotes/2.16.3.txt
@@ -24,7 +24,7 @@ Fixes since v2.16.2
* The http tracing code, often used to debug connection issues,
learned to redact potentially sensitive information from its output
- so that it can be more safely sharable.
+ so that it can be more safely shareable.
* Crash fix for a corner case where an error codepath tried to unlock
what it did not acquire lock on.
diff --git a/Documentation/RelNotes/2.17.0.txt b/Documentation/RelNotes/2.17.0.txt
index c2cf891..8b17c26 100644
--- a/Documentation/RelNotes/2.17.0.txt
+++ b/Documentation/RelNotes/2.17.0.txt
@@ -216,7 +216,7 @@ Fixes since v2.16
* The http tracing code, often used to debug connection issues,
learned to redact potentially sensitive information from its output
- so that it can be more safely sharable.
+ so that it can be more safely shareable.
(merge 8ba18e6fa4 jt/http-redact-cookies later to maint).
* Crash fix for a corner case where an error codepath tried to unlock
diff --git a/Documentation/RelNotes/2.18.0.txt b/Documentation/RelNotes/2.18.0.txt
index 3ea280c..6c8a0e9 100644
--- a/Documentation/RelNotes/2.18.0.txt
+++ b/Documentation/RelNotes/2.18.0.txt
@@ -179,7 +179,7 @@ Performance, Internal Implementation, Development Support etc.
(merge 00a3da2a13 nd/remove-ignore-env-field later to maint).
* Code to find the length to uniquely abbreviate object names based
- on packfile content, which is a relatively recent addtion, has been
+ on packfile content, which is a relatively recent addition, has been
optimized to use the same fan-out table.
* The mechanism to use parse-options API to automate the command line
diff --git a/Documentation/RelNotes/2.19.0.txt b/Documentation/RelNotes/2.19.0.txt
index a06ccf6..891c79b 100644
--- a/Documentation/RelNotes/2.19.0.txt
+++ b/Documentation/RelNotes/2.19.0.txt
@@ -106,7 +106,7 @@ Performance, Internal Implementation, Development Support etc.
* The conversion to pass "the_repository" and then "a_repository"
throughout the object access API continues.
- * Continuing with the idea to programatically enumerate various
+ * Continuing with the idea to programmatically enumerate various
pieces of data required for command line completion, teach the
codebase to report the list of configuration variables
subcommands care about to help complete them.
diff --git a/Documentation/RelNotes/2.20.0.txt b/Documentation/RelNotes/2.20.0.txt
index e71fe3d..3dd7e6e 100644
--- a/Documentation/RelNotes/2.20.0.txt
+++ b/Documentation/RelNotes/2.20.0.txt
@@ -119,7 +119,7 @@ UI, Workflows & Features
alias expansion.
* The documentation of "git gc" has been updated to mention that it
- is no longer limited to "pruning away crufts" but also updates
+ is no longer limited to "pruning away cruft" but also updates
ancillary files like commit-graph as a part of repository
optimization.
diff --git a/Documentation/RelNotes/2.25.0.txt b/Documentation/RelNotes/2.25.0.txt
index b61b69f..e4bb07a 100644
--- a/Documentation/RelNotes/2.25.0.txt
+++ b/Documentation/RelNotes/2.25.0.txt
@@ -29,6 +29,16 @@ UI, Workflows & Features
placeholder that is similar to e/E that fills in the e-mail
address, but only the local part on the left side of '@'.
+ * Documentation pages for "git shortlog" now list commit limiting
+ options explicitly.
+
+ * The patterns to detect function boundary for Elixir language has
+ been added.
+
+ * The completion script (in contrib/) learned that the "--onto"
+ option of "git rebase" can take its argument as the value of the
+ option.
+
Performance, Internal Implementation, Development Support etc.
@@ -39,6 +49,23 @@ Performance, Internal Implementation, Development Support etc.
* Test updates to prepare for SHA-2 transition continues.
+ * Crufty code and logic accumulated over time around the object
+ parsing and low-level object access used in "git fsck" have been
+ cleaned up.
+
+ * The implementation of "git log --graph" got refactored and then its
+ output got simplified.
+
+ * Follow recent push to move API docs from Documentation/ to header
+ files and update config.h
+
+ * "git bundle" has been taught to use the parse options API. "git
+ bundle verify" learned "--quiet" and "git bundle create" learned
+ options to control the progress output.
+
+ * Handling of commit objects that use non UTF-8 encoding during
+ "rebase -i" has been improved.
+
Fixes since v2.24
-----------------
@@ -63,6 +90,66 @@ Fixes since v2.24
mistakenly removed paths that are outside the area of interest.
(merge 4a58c3d7f7 js/update-index-ignore-removal-for-skip-worktree later to maint).
+ * "git rev-parse --git-path HEAD.lock" did not give the right path
+ when run in a secondary worktree.
+ (merge 76a53d640f js/git-path-head-dot-lock-fix later to maint).
+
+ * "git merge --no-commit" needs "--no-ff" if you do not want to move
+ HEAD, which has been corrected in the manual page for "git bisect".
+ (merge 8dd327b246 ma/bisect-doc-sample-update later to maint).
+
+ * "git worktree add" internally calls "reset --hard" that should not
+ descend into submodules, even when submodule.recurse configuration
+ is set, but it was affected. This has been corrected.
+ (merge 4782cf2ab6 pb/no-recursive-reset-hard-in-worktree-add later to maint).
+
+ * Messages from die() etc. can be mixed up from multiple processes
+ without even line buffering on Windows, which has been worked
+ around.
+ (merge 116d1fa6c6 js/vreportf-wo-buffering later to maint).
+
+ * HTTP transport had possible allocator/deallocator mismatch, which
+ has been corrected.
+
+ * The watchman integration for fsmonitor was racy, which has been
+ corrected to be more conservative.
+ (merge dd0b61f577 kw/fsmonitor-watchman-fix later to maint).
+
+ * Fetching from multiple remotes into the same repository in parallel
+ had a bad interaction with the recent change to (optionally) update
+ the commit-graph after a fetch job finishes, as these parallel
+ fetches compete with each other. Which has been corrected.
+
+ * Recent update to "git stash pop" made the command empty the index
+ when run with the "--quiet" option, which has been corrected.
+
+ * "git fetch" codepath had a big "do not lazily fetch missing objects
+ when I ask if something exists" switch. This has been corrected by
+ marking the "does this thing exist?" calls with "if not please do not
+ lazily fetch it" flag.
+
+ * Test update to avoid wasted cycles.
+ (merge e0316695ec sg/skip-skipped-prereq later to maint).
+
+ * Error handling after "git push" finishes sending the packdata and
+ waits for the response to the remote side has been improved.
+ (merge ad7a403268 jk/send-pack-remote-failure later to maint).
+
+ * Some codepaths in "gitweb" that forgot to escape URLs generated
+ based on end-user input have been corrected.
+ (merge a376e37b2c jk/gitweb-anti-xss later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 80736d7c5e jc/am-show-current-patch-docfix later to maint).
(merge 8b656572ca sg/commit-graph-usage-fix later to maint).
+ (merge 6c02042139 mr/clone-dir-exists-to-path-exists later to maint).
+ (merge 44ae131e38 sg/blame-indent-heuristics-is-now-the-default later to maint).
+ (merge 0115e5d929 dl/doc-diff-no-index-implies-exit-code later to maint).
+ (merge 270de6acbe en/t6024-style later to maint).
+ (merge 14c4776d75 ns/test-desc-typofix later to maint).
+ (merge 68d40f30c4 dj/typofix-merge-strat later to maint).
+ (merge f66e0401ab jk/optim-in-pack-idx-conversion later to maint).
+ (merge 169bed7421 rs/parse-options-dup-null-fix later to maint).
+ (merge 51bd6be32d rs/use-copy-array-in-mingw-shell-command-preparation later to maint).
+ (merge b018719927 ma/t7004 later to maint).
+ (merge 932757b0cc ar/install-doc-update-cmds-needing-the-shell later to maint).
diff --git a/Documentation/RelNotes/2.3.3.txt b/Documentation/RelNotes/2.3.3.txt
index 5ef1264..850dc68 100644
--- a/Documentation/RelNotes/2.3.3.txt
+++ b/Documentation/RelNotes/2.3.3.txt
@@ -12,7 +12,7 @@ Fixes since v2.3.2
* Description given by "grep -h" for its --exclude-standard option
was phrased poorly.
- * Documentaton for "git remote add" mentioned "--tags" and
+ * Documentation for "git remote add" mentioned "--tags" and
"--no-tags" and it was not clear that fetch from the remote in
the future will use the default behaviour when neither is given
to override it.
diff --git a/Documentation/RelNotes/2.3.7.txt b/Documentation/RelNotes/2.3.7.txt
index fc95812..5769184 100644
--- a/Documentation/RelNotes/2.3.7.txt
+++ b/Documentation/RelNotes/2.3.7.txt
@@ -4,7 +4,7 @@ Git v2.3.7 Release Notes
Fixes since v2.3.6
------------------
- * An earlier update to the parser that disects a URL broke an
+ * An earlier update to the parser that dissects 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.
diff --git a/Documentation/RelNotes/2.4.3.txt b/Documentation/RelNotes/2.4.3.txt
index 914d2c1..422e930 100644
--- a/Documentation/RelNotes/2.4.3.txt
+++ b/Documentation/RelNotes/2.4.3.txt
@@ -66,7 +66,7 @@ Fixes since v2.4.3
* Some time ago, "git blame" (incorrectly) lost the convert_to_git()
call when synthesizing a fake "tip" commit that represents the
state in the working tree, which broke folks who record the history
- with LF line ending to make their project portabile across
+ with LF line ending to make their project portable across
platforms while terminating lines in their working tree files with
CRLF for their platform.
diff --git a/Documentation/RelNotes/2.7.0.txt b/Documentation/RelNotes/2.7.0.txt
index 563dadc..e3cbf3a 100644
--- a/Documentation/RelNotes/2.7.0.txt
+++ b/Documentation/RelNotes/2.7.0.txt
@@ -40,7 +40,7 @@ UI, Workflows & Features
* "git interpret-trailers" can now run outside of a Git repository.
- * "git p4" learned to reencode the pathname it uses to communicate
+ * "git p4" learned to re-encode the pathname it uses to communicate
with the p4 depot with a new option.
* Give progress meter to "git filter-branch".
diff --git a/Documentation/RelNotes/2.8.0.txt b/Documentation/RelNotes/2.8.0.txt
index 5fbe1b8..27320b6 100644
--- a/Documentation/RelNotes/2.8.0.txt
+++ b/Documentation/RelNotes/2.8.0.txt
@@ -189,7 +189,7 @@ Performance, Internal Implementation, Development Support etc.
* Some calls to strcpy(3) triggers a false warning from static
analyzers that are less intelligent than humans, and reducing the
number of these false hits helps us notice real issues. A few
- calls to strcpy(3) in a couple of protrams that are already safe
+ calls to strcpy(3) in a couple of programs that are already safe
has been rewritten to avoid false warnings.
* The "name_path" API was an attempt to reduce the need to construct
diff --git a/Documentation/RelNotes/2.9.3.txt b/Documentation/RelNotes/2.9.3.txt
index 695b86f..305e080 100644
--- a/Documentation/RelNotes/2.9.3.txt
+++ b/Documentation/RelNotes/2.9.3.txt
@@ -36,7 +36,7 @@ Fixes since v2.9.2
* One part of "git am" had an oddball helper function that called
stuff from outside "his" as opposed to calling what we have "ours",
which was not gender-neutral and also inconsistent with the rest of
- the system where outside stuff is usuall called "theirs" in
+ the system where outside stuff is usually called "theirs" in
contrast to "ours".
* The test framework learned a new helper test_match_signal to
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f50f1b4..83e7bba 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -142,7 +142,7 @@ refer to linkgit:gitignore[5] for details. For convenience:
`gitdir/i`::
This is the same as `gitdir` except that matching is done
- case-insensitively (e.g. on case-insensitive file sytems)
+ case-insensitively (e.g. on case-insensitive file systems)
`onbranch`::
The data that follows the keyword `onbranch:` is taken to be a
diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt
index 4d753f0..c9f748f 100644
--- a/Documentation/config/add.txt
+++ b/Documentation/config/add.txt
@@ -5,3 +5,8 @@ add.ignore-errors (deprecated)::
option of linkgit:git-add[1]. `add.ignore-errors` is deprecated,
as it does not follow the usual naming convention for configuration
variables.
+
+add.interactive.useBuiltin::
+ [EXPERIMENTAL] Set to `true` to use the experimental built-in
+ implementation of the interactive version of linkgit:git-add[1]
+ instead of the Perl script version. Is `false` by default.
diff --git a/Documentation/config/tag.txt b/Documentation/config/tag.txt
index ef5adb3..6d9110d 100644
--- a/Documentation/config/tag.txt
+++ b/Documentation/config/tag.txt
@@ -13,7 +13,7 @@ tag.gpgSign::
Use of this option when running in an automated script can
result in a large number of tags being signed. It is therefore
convenient to use an agent to avoid typing your gpg passphrase
- several times. Note that this option doesn't affects tag signing
+ several times. Note that this option doesn't affect tag signing
behavior enabled by "-u <keyid>" or "--local-user=<keyid>" options.
tar.umask::
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 43b9ff3..a2f7862 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -92,6 +92,10 @@ ifndef::git-pull[]
Run `git gc --auto` at the end to perform garbage collection
if needed. This is enabled by default.
+--[no-]write-commit-graph::
+ Write a commit-graph after fetching. This overrides the config
+ setting `fetch.writeCommitGraph`.
+
-p::
--prune::
Before fetching, remove any remote-tracking references that no
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index e999251..2957bc5 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -158,7 +158,7 @@ Test suites are very nice. But when they are used alone, they are
supposed to be used so that all the tests are checked after each
commit. This means that they are not very efficient, because many
tests are run for no interesting result, and they suffer from
-combinational explosion.
+combinatorial explosion.
In fact the problem is that big software often has many different
configuration options and that each test case should pass for each
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 4b45d83..7586c5a 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -413,7 +413,7 @@ $ cat ~/test.sh
# tweak the working tree by merging the hot-fix branch
# and then attempt a build
-if git merge --no-commit hot-fix &&
+if git merge --no-commit --no-ff hot-fix &&
make
then
# run project specific test and report its status
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 7d6c9dc..ccada80 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -9,8 +9,8 @@ git-bundle - Move objects and refs by archive
SYNOPSIS
--------
[verse]
-'git bundle' create <file> <git-rev-list-args>
-'git bundle' verify <file>
+'git bundle' create [-q | --quiet | --progress | --all-progress] [--all-progress-implied] <file> <git-rev-list-args>
+'git bundle' verify [-q | --quiet] <file>
'git bundle' list-heads <file> [<refname>...]
'git bundle' unbundle <file> [<refname>...]
@@ -33,9 +33,11 @@ destination repository.
OPTIONS
-------
-create <file>::
+create [options] <file> <git-rev-list-args>::
Used to create a bundle named 'file'. This requires the
'git-rev-list-args' arguments to define the bundle contents.
+ 'options' contains the options specific to the 'git bundle create'
+ subcommand.
verify <file>::
Used to check that a bundle file is valid and will apply
@@ -75,6 +77,33 @@ unbundle <file>::
necessarily everything in the pack (in this case, 'git bundle' acts
like 'git fetch-pack').
+--progress::
+ Progress status is reported on the standard error stream
+ by default when it is attached to a terminal, unless -q
+ is specified. This flag forces progress status even if
+ the standard error stream is not directed to a terminal.
+
+--all-progress::
+ When --stdout is specified then progress report is
+ displayed during the object count and compression phases
+ but inhibited during the write-out phase. The reason is
+ that in some cases the output stream is directly linked
+ to another command which may wish to display progress
+ status of its own as it processes incoming pack data.
+ This flag is like --progress except that it forces progress
+ report for the write-out phase as well even if --stdout is
+ used.
+
+--all-progress-implied::
+ This is used to imply --all-progress whenever progress display
+ is activated. Unlike --all-progress this flag doesn't actually
+ force any progress display by itself.
+
+-q::
+--quiet::
+ This flag makes the command not to report its progress
+ on the standard error stream.
+
SPECIFYING REFERENCES
---------------------
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 3c05782..84f41a8 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -32,7 +32,7 @@ OPTIONS
instead of from the command-line.
-z::
- The output format is modified to be machine-parseable.
+ The output format is modified to be machine-parsable.
If `--stdin` is also given, input paths are separated
with a NUL character instead of a linefeed character.
diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt
index 8b42cb3..8b2d49c 100644
--- a/Documentation/git-check-ignore.txt
+++ b/Documentation/git-check-ignore.txt
@@ -39,7 +39,7 @@ OPTIONS
instead of from the command-line.
-z::
- The output format is modified to be machine-parseable (see
+ The output format is modified to be machine-parsable (see
below). If `--stdin` is also given, input paths are separated
with a NUL character instead of a linefeed character.
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 8c708a7..bcd85c1 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -9,7 +9,6 @@ git-commit-graph - Write and verify Git commit-graph files
SYNOPSIS
--------
[verse]
-'git commit-graph read' [--object-dir <dir>]
'git commit-graph verify' [--object-dir <dir>] [--shallow] [--[no-]progress]
'git commit-graph write' <options> [--object-dir <dir>] [--[no-]progress]
@@ -74,11 +73,6 @@ Finally, if `--expire-time=<datetime>` is not specified, let `datetime`
be the current time. After writing the split commit-graph, delete all
unused commit-graph whose modified times are older than `datetime`.
-'read'::
-
-Read the commit-graph file and output basic details about it.
-Used for debugging purposes.
-
'verify'::
Read the commit-graph file and verify its contents against the object
@@ -118,12 +112,6 @@ $ git show-ref -s | git commit-graph write --stdin-commits
$ git rev-parse HEAD | git commit-graph write --stdin-commits --append
------------------------------------------------
-* Read basic information from the commit-graph file.
-+
-------------------------------------------------
-$ git commit-graph read
-------------------------------------------------
-
GIT
---
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index 79e22b1..1b1c71a 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -294,7 +294,7 @@ In `dbDriver` and `dbUser` you can use the following variables:
Git directory name
%g::
Git directory name, where all characters except for
- alpha-numeric ones, `.`, and `-` are replaced with
+ alphanumeric ones, `.`, and `-` are replaced with
`_` (this should make it easier to use the directory
name in a filename if wanted)
%m::
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 72179d9..37781cf 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -36,7 +36,7 @@ two blob objects, or changes between two files on disk.
running the command in a working tree controlled by Git and
at least one of the paths points outside the working tree,
or when running the command outside a working tree
- controlled by Git.
+ controlled by Git. This form implies `--exit-code`.
'git diff' [<options>] --cached [<commit>] [--] [<path>...]::
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index 37634bf..e8950de 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -142,7 +142,7 @@ by keeping the marks the same across runs.
Specify how to handle `encoding` header in commit objects. When
asking to 'abort' (which is the default), this program will die
when encountering such a commit object. With 'yes', the commit
- message will be reencoded into UTF-8. With 'no', the original
+ message will be re-encoded into UTF-8. With 'no', the original
encoding will be preserved.
--refspec::
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 5876598..3686a67 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -534,7 +534,7 @@ repo-filter' also provides
https://github.com/newren/git-filter-repo/blob/master/contrib/filter-repo-demos/filter-lamely[filter-lamely],
a drop-in git-filter-branch replacement (with a few caveats). While
filter-lamely suffers from all the same safety issues as
-git-filter-branch, it at least ameloriates the performance issues a
+git-filter-branch, it at least ameliorates the performance issues a
little.
[[SAFETY]]
@@ -649,7 +649,7 @@ create hoards of confusing empty commits
commits from before the filtering operation are also pruned instead of
just pruning commits that became empty due to filtering rules.
-* If --prune empty is specified, sometimes empty commits are missed
+* If --prune-empty is specified, sometimes empty commits are missed
and left around anyway (a somewhat rare bug, but it happens...)
* A minor issue, but users who have a goal to update all names and
diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt
index 8a6ea2c..006feb7 100644
--- a/Documentation/git-range-diff.txt
+++ b/Documentation/git-range-diff.txt
@@ -242,7 +242,7 @@ corresponding.
The overall time needed to compute this algorithm is the time needed to
compute n+m commit diffs and then n*m diffs of patches, plus the time
-needed to compute the least-cost assigment between n and m diffs. Git
+needed to compute the least-cost assignment between n and m diffs. Git
uses an implementation of the Jonker-Volgenant algorithm to solve the
assignment problem, which has cubic runtime complexity. The matching
found in this case will look like this:
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 639a417..0c4f038 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -443,8 +443,8 @@ the `rebase-cousins` mode is turned on, such commits are instead rebased
onto `<upstream>` (or `<onto>`, if specified).
+
The `--rebase-merges` mode is similar in spirit to the deprecated
-`--preserve-merges`, but in contrast to that option works well in interactive
-rebases: commits can be reordered, inserted and dropped at will.
+`--preserve-merges` but works with interactive rebases,
+where commits can be reordered, inserted and dropped at will.
+
It is currently only possible to recreate the merge commits using the
`recursive` merge strategy; Different merge strategies can be used only via
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index bc80905..a72ea7f 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -76,6 +76,9 @@ them.
Paths may need to be prefixed with `--` to separate them from
options or the revision range, when confusion arises.
+:git-shortlog: 1
+include::rev-list-options.txt[]
+
MAPPING AUTHORS
---------------
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 2e5599a..f6d9791 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -65,7 +65,7 @@ OPTIONS
--sign::
Make a GPG-signed tag, using the default e-mail address's key.
The default behavior of tag GPG-signing is controlled by `tag.gpgSign`
- configuration variable if it exists, or disabled oder otherwise.
+ configuration variable if it exists, or disabled otherwise.
See linkgit:git-config[1].
--no-sign::
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 0839344..c7a6271 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -432,7 +432,7 @@ specified by the splitIndex.sharedIndexExpire config variable (see
linkgit:git-config[1]).
To avoid deleting a shared index file that is still used, its
-modification time is updated to the current time everytime a new split
+modification time is updated to the current time every time a new split
index based on the shared index file is either created or read from.
UNTRACKED CACHE
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 9b82564..1b678e2 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -271,8 +271,8 @@ In general, the interrogate commands do not touch the files in
the working tree.
-Synching repositories
-~~~~~~~~~~~~~~~~~~~~~
+Syncing repositories
+~~~~~~~~~~~~~~~~~~~~
include::cmds-synchingrepositories.txt[]
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index c5a528c..508fe71 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -293,10 +293,10 @@ web front ends do not visualize the contents of these files by default.
In these cases you can tell Git the encoding of a file in the working
directory with the `working-tree-encoding` attribute. If a file with this
-attribute is added to Git, then Git reencodes the content from the
+attribute is added to Git, then Git re-encodes the content from the
specified encoding to UTF-8. Finally, Git stores the UTF-8 encoded
content in its internal data structure (called "the index"). On checkout
-the content is reencoded back to the specified encoding.
+the content is re-encoded back to the specified encoding.
Please note that using the `working-tree-encoding` attribute may have a
number of pitfalls:
@@ -498,7 +498,7 @@ command. This is achieved by using the long-running process protocol
When Git encounters the first file that needs to be cleaned or smudged,
it starts the filter and performs the handshake. In the handshake, the
welcome message sent by Git is "git-filter-client", only version 2 is
-suppported, and the supported capabilities are "clean", "smudge", and
+supported, and the supported capabilities are "clean", "smudge", and
"delay".
Afterwards Git sends a list of "key=value" pairs terminated with
@@ -812,6 +812,8 @@ patterns are available:
- `dts` suitable for devicetree (DTS) files.
+- `elixir` suitable for source code in the Elixir language.
+
- `fortran` suitable for source code in the Fortran language.
- `fountain` suitable for Fountain documents.
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index f2a65ba..953c387 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -81,7 +81,7 @@ submodule.<name>.ignore::
Committed differences and modifications to tracked files will show
up.
- none;; No modifiations to submodules are ignored, all of committed
+ none;; No modifications to submodules are ignored, all of committed
differences, and modifications to tracked and untracked files are
shown. This is the default option.
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index 0a89020..c476f89 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -3,7 +3,7 @@ gitsubmodules(7)
NAME
----
-gitsubmodules - mounting one repository inside another
+gitsubmodules - Mounting one repository inside another
SYNOPSIS
--------
diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.txt
index bd10274..81be0d6 100644
--- a/Documentation/howto/separating-topic-branches.txt
+++ b/Documentation/howto/separating-topic-branches.txt
@@ -81,7 +81,7 @@ After I am done, I'd try a pretend-merge between "topicA" and
o---o---o---o---o---o
The last diff better not to show anything other than cleanups
-for crufts. Then I can finally clean things up:
+for cruft. Then I can finally clean things up:
$ git branch -D topic
$ git reset --hard HEAD^ ;# nuke pretend merge
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 59b8ff1..40dc4f5 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -34,7 +34,7 @@ set to `no` at the beginning of them.
--cleanup=<mode>::
This option determines how the merge message will be cleaned up before
- commiting. See linkgit:git-commit[1] for more details. In addition, if
+ committing. See linkgit:git-commit[1] for more details. In addition, if
the '<mode>' is given a value of `scissors`, scissors will be appended
to `MERGE_MSG` before being passed on to the commit machinery in the
case of a merge conflict.
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index aa66cbe..2912de7 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -32,7 +32,7 @@ The 'recursive' strategy can take the following options:
ours;;
This option forces conflicting hunks to be auto-resolved cleanly by
favoring 'our' version. Changes from the other tree that do not
- conflict with our side are reflected to the merge result.
+ conflict with our side are reflected in the merge result.
For a binary file, the entire contents are taken from our side.
+
This should not be confused with the 'ours' merge strategy, which does not
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 90ff9e2..e37df92 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -579,6 +579,7 @@ above) if (1) they are referenced by tags, or (2) they change the
contents of the paths given on the command line. All other
commits are marked as TREESAME (subject to be simplified away).
+ifndef::git-shortlog[]
ifdef::git-rev-list[]
Bisection Helpers
~~~~~~~~~~~~~~~~~
@@ -634,8 +635,9 @@ This option can be used along with `--bisect-vars`, in this case,
after all the sorted commit objects, there will be the same text as if
`--bisect-vars` had been used alone.
endif::git-rev-list[]
+endif::git-shortlog[]
-
+ifndef::git-shortlog[]
Commit Ordering
~~~~~~~~~~~~~~~
@@ -677,7 +679,9 @@ together.
Output the commits chosen to be shown (see Commit Limiting
section above) in reverse order. Cannot be combined with
`--walk-reflogs`.
+endif::git-shortlog[]
+ifndef::git-shortlog[]
Object Traversal
~~~~~~~~~~~~~~~~
@@ -817,7 +821,9 @@ endif::git-rev-list[]
--do-walk::
Overrides a previous `--no-walk`.
+endif::git-shortlog[]
+ifndef::git-shortlog[]
Commit Formatting
~~~~~~~~~~~~~~~~~
@@ -973,7 +979,9 @@ ifdef::git-rev-list[]
counts and print the count for equivalent commits separated
by a tab.
endif::git-rev-list[]
+endif::git-shortlog[]
+ifndef::git-shortlog[]
ifndef::git-rev-list[]
Diff Formatting
~~~~~~~~~~~~~~~
@@ -1016,3 +1024,4 @@ options may be given. See linkgit:git-diff-files[1] for more options.
-t::
Show the tree objects in the diff output. This implies `-r`.
endif::git-rev-list[]
+endif::git-shortlog[]
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
deleted file mode 100644
index 7d20716..0000000
--- a/Documentation/technical/api-config.txt
+++ /dev/null
@@ -1,319 +0,0 @@
-config API
-==========
-
-The config API gives callers a way to access Git configuration files
-(and files which have the same syntax). See linkgit:git-config[1] for a
-discussion of the config file syntax.
-
-General Usage
--------------
-
-Config files are parsed linearly, and each variable found is passed to a
-caller-provided callback function. The callback function is responsible
-for any actions to be taken on the config option, and is free to ignore
-some options. It is not uncommon for the configuration to be parsed
-several times during the run of a Git program, with different callbacks
-picking out different variables useful to themselves.
-
-A config callback function takes three parameters:
-
-- the name of the parsed variable. This is in canonical "flat" form: the
- section, subsection, and variable segments will be separated by dots,
- and the section and variable segments will be all lowercase. E.g.,
- `core.ignorecase`, `diff.SomeType.textconv`.
-
-- the value of the found variable, as a string. If the variable had no
- value specified, the value will be NULL (typically this means it
- should be interpreted as boolean true).
-
-- a void pointer passed in by the caller of the config API; this can
- contain callback-specific data
-
-A config callback should return 0 for success, or -1 if the variable
-could not be parsed properly.
-
-Basic Config Querying
----------------------
-
-Most programs will simply want to look up variables in all config files
-that Git knows about, using the normal precedence rules. To do this,
-call `git_config` with a callback function and void data pointer.
-
-`git_config` will read all config sources in order of increasing
-priority. Thus a callback should typically overwrite previously-seen
-entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
-repo-specific `.git/config` contain `color.ui`, the config machinery
-will first feed the user-wide one to the callback, and then the
-repo-specific one; by overwriting, the higher-priority repo-specific
-value is left at the end).
-
-The `config_with_options` function lets the caller examine config
-while adjusting some of the default behavior of `git_config`. It should
-almost never be used by "regular" Git code that is looking up
-configuration variables. It is intended for advanced callers like
-`git-config`, which are intentionally tweaking the normal config-lookup
-process. It takes two extra parameters:
-
-`config_source`::
-If this parameter is non-NULL, it specifies the source to parse for
-configuration, rather than looking in the usual files. See `struct
-git_config_source` in `config.h` for details. Regular `git_config` defaults
-to `NULL`.
-
-`opts`::
-Specify options to adjust the behavior of parsing config files. See `struct
-config_options` in `config.h` for details. As an example: regular `git_config`
-sets `opts.respect_includes` to `1` by default.
-
-Reading Specific Files
-----------------------
-
-To read a specific file in git-config format, use
-`git_config_from_file`. This takes the same callback and data parameters
-as `git_config`.
-
-Querying For Specific Variables
--------------------------------
-
-For programs wanting to query for specific variables in a non-callback
-manner, the config API provides two functions `git_config_get_value`
-and `git_config_get_value_multi`. They both read values from an internal
-cache generated previously from reading the config files.
-
-`int git_config_get_value(const char *key, const char **value)`::
-
- Finds the highest-priority value for the configuration variable `key`,
- stores the pointer to it in `value` and returns 0. When the
- configuration variable `key` is not found, returns 1 without touching
- `value`. The caller should not free or modify `value`, as it is owned
- by the cache.
-
-`const struct string_list *git_config_get_value_multi(const char *key)`::
-
- Finds and returns the value list, sorted in order of increasing priority
- for the configuration variable `key`. When the configuration variable
- `key` is not found, returns NULL. The caller should not free or modify
- the returned pointer, as it is owned by the cache.
-
-`void git_config_clear(void)`::
-
- Resets and invalidates the config cache.
-
-The config API also provides type specific API functions which do conversion
-as well as retrieval for the queried variable, including:
-
-`int git_config_get_int(const char *key, int *dest)`::
-
- Finds and parses the value to an integer for the configuration variable
- `key`. Dies on error; otherwise, stores the value of the parsed integer in
- `dest` and returns 0. When the configuration variable `key` is not found,
- returns 1 without touching `dest`.
-
-`int git_config_get_ulong(const char *key, unsigned long *dest)`::
-
- Similar to `git_config_get_int` but for unsigned longs.
-
-`int git_config_get_bool(const char *key, int *dest)`::
-
- Finds and parses the value into a boolean value, for the configuration
- variable `key` respecting keywords like "true" and "false". Integer
- values are converted into true/false values (when they are non-zero or
- zero, respectively). Other values cause a die(). If parsing is successful,
- stores the value of the parsed result in `dest` and returns 0. When the
- configuration variable `key` is not found, returns 1 without touching
- `dest`.
-
-`int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)`::
-
- Similar to `git_config_get_bool`, except that integers are copied as-is,
- and `is_bool` flag is unset.
-
-`int git_config_get_maybe_bool(const char *key, int *dest)`::
-
- Similar to `git_config_get_bool`, except that it returns -1 on error
- rather than dying.
-
-`int git_config_get_string_const(const char *key, const char **dest)`::
-
- Allocates and copies the retrieved string into the `dest` parameter for
- the configuration variable `key`; if NULL string is given, prints an
- error message and returns -1. When the configuration variable `key` is
- not found, returns 1 without touching `dest`.
-
-`int git_config_get_string(const char *key, char **dest)`::
-
- Similar to `git_config_get_string_const`, except that retrieved value
- copied into the `dest` parameter is a mutable string.
-
-`int git_config_get_pathname(const char *key, const char **dest)`::
-
- Similar to `git_config_get_string`, but expands `~` or `~user` into
- the user's home directory when found at the beginning of the path.
-
-`git_die_config(const char *key, const char *err, ...)`::
-
- First prints the error message specified by the caller in `err` and then
- dies printing the line number and the file name of the highest priority
- value for the configuration variable `key`.
-
-`void git_die_config_linenr(const char *key, const char *filename, int linenr)`::
-
- Helper function which formats the die error message according to the
- parameters entered. Used by `git_die_config()`. It can be used by callers
- handling `git_config_get_value_multi()` to print the correct error message
- for the desired value.
-
-See test-config.c for usage examples.
-
-Value Parsing Helpers
----------------------
-
-To aid in parsing string values, the config API provides callbacks with
-a number of helper functions, including:
-
-`git_config_int`::
-Parse the string to an integer, including unit factors. Dies on error;
-otherwise, returns the parsed result.
-
-`git_config_ulong`::
-Identical to `git_config_int`, but for unsigned longs.
-
-`git_config_bool`::
-Parse a string into a boolean value, respecting keywords like "true" and
-"false". Integer values are converted into true/false values (when they
-are non-zero or zero, respectively). Other values cause a die(). If
-parsing is successful, the return value is the result.
-
-`git_config_bool_or_int`::
-Same as `git_config_bool`, except that integers are returned as-is, and
-an `is_bool` flag is unset.
-
-`git_parse_maybe_bool`::
-Same as `git_config_bool`, except that it returns -1 on error rather
-than dying.
-
-`git_config_string`::
-Allocates and copies the value string into the `dest` parameter; if no
-string is given, prints an error message and returns -1.
-
-`git_config_pathname`::
-Similar to `git_config_string`, but expands `~` or `~user` into the
-user's home directory when found at the beginning of the path.
-
-Include Directives
-------------------
-
-By default, the config parser does not respect include directives.
-However, a caller can use the special `git_config_include` wrapper
-callback to support them. To do so, you simply wrap your "real" callback
-function and data pointer in a `struct config_include_data`, and pass
-the wrapper to the regular config-reading functions. For example:
-
--------------------------------------------
-int read_file_with_include(const char *file, config_fn_t fn, void *data)
-{
- struct config_include_data inc = CONFIG_INCLUDE_INIT;
- inc.fn = fn;
- inc.data = data;
- return git_config_from_file(git_config_include, file, &inc);
-}
--------------------------------------------
-
-`git_config` respects includes automatically. The lower-level
-`git_config_from_file` does not.
-
-Custom Configsets
------------------
-
-A `config_set` can be used to construct an in-memory cache for
-config-like files that the caller specifies (i.e., files like `.gitmodules`,
-`~/.gitconfig` etc.). For example,
-
-----------------------------------------
-struct config_set gm_config;
-git_configset_init(&gm_config);
-int b;
-/* we add config files to the config_set */
-git_configset_add_file(&gm_config, ".gitmodules");
-git_configset_add_file(&gm_config, ".gitmodules_alt");
-
-if (!git_configset_get_bool(gm_config, "submodule.frotz.ignore", &b)) {
- /* hack hack hack */
-}
-
-/* when we are done with the configset */
-git_configset_clear(&gm_config);
-----------------------------------------
-
-Configset API provides functions for the above mentioned work flow, including:
-
-`void git_configset_init(struct config_set *cs)`::
-
- Initializes the config_set `cs`.
-
-`int git_configset_add_file(struct config_set *cs, const char *filename)`::
-
- Parses the file and adds the variable-value pairs to the `config_set`,
- dies if there is an error in parsing the file. Returns 0 on success, or
- -1 if the file does not exist or is inaccessible. The user has to decide
- if he wants to free the incomplete configset or continue using it when
- the function returns -1.
-
-`int git_configset_get_value(struct config_set *cs, const char *key, const char **value)`::
-
- Finds the highest-priority value for the configuration variable `key`
- and config set `cs`, stores the pointer to it in `value` and returns 0.
- When the configuration variable `key` is not found, returns 1 without
- touching `value`. The caller should not free or modify `value`, as it
- is owned by the cache.
-
-`const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)`::
-
- Finds and returns the value list, sorted in order of increasing priority
- for the configuration variable `key` and config set `cs`. When the
- configuration variable `key` is not found, returns NULL. The caller
- should not free or modify the returned pointer, as it is owned by the cache.
-
-`void git_configset_clear(struct config_set *cs)`::
-
- Clears `config_set` structure, removes all saved variable-value pairs.
-
-In addition to above functions, the `config_set` API provides type specific
-functions in the vein of `git_config_get_int` and family but with an extra
-parameter, pointer to struct `config_set`.
-They all behave similarly to the `git_config_get*()` family described in
-"Querying For Specific Variables" above.
-
-Writing Config Files
---------------------
-
-Git gives multiple entry points in the Config API to write config values to
-files namely `git_config_set_in_file` and `git_config_set`, which write to
-a specific config file or to `.git/config` respectively. They both take a
-key/value pair as parameter.
-In the end they both call `git_config_set_multivar_in_file` which takes four
-parameters:
-
-- the name of the file, as a string, to which key/value pairs will be written.
-
-- the name of key, as a string. This is in canonical "flat" form: the section,
- subsection, and variable segments will be separated by dots, and the section
- and variable segments will be all lowercase.
- E.g., `core.ignorecase`, `diff.SomeType.textconv`.
-
-- the value of the variable, as a string. If value is equal to NULL, it will
- remove the matching key from the config file.
-
-- the value regex, as a string. It will disregard key/value pairs where value
- does not match.
-
-- a multi_replace value, as an int. If value is equal to zero, nothing or only
- one matching key/value is replaced, else all matching key/values (regardless
- how many) are removed, before the new pair is written.
-
-It returns 0 on success.
-
-Also, there are functions `git_config_rename_section` and
-`git_config_rename_section_in_file` with parameters `old_name` and `new_name`
-for renaming or removing sections in the config files. If NULL is passed
-through `new_name` parameter, the section will be removed from the config file.
diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt
index fb06089..c409559 100644
--- a/Documentation/technical/api-submodule-config.txt
+++ b/Documentation/technical/api-submodule-config.txt
@@ -58,7 +58,7 @@ Functions
Whenever a submodule configuration is parsed in `parse_submodule_config_option`
via e.g. `gitmodules_config()`, it will overwrite the null_sha1 entry.
-So in the normal case, when HEAD:.gitmodules is parsed first and then overlayed
+So in the normal case, when HEAD:.gitmodules is parsed first and then overlaid
with the repository configuration, the null_sha1 entry contains the local
configuration of a submodule (e.g. consolidated values from local git
configuration and the .gitmodules file in the worktree).
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index a045dbe..17490b5 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -178,7 +178,7 @@ describe the simplified forms.
== Public API
-All Trace2 API functions send a messsage to all of the active
+All Trace2 API functions send a message to all of the active
Trace2 Targets. This section describes the set of available
messages.
@@ -377,7 +377,7 @@ of `pthread_create()`.
and the thread elapsed time.
+
This function must be called by the thread-proc before it returns
-(so that the coorect TLS data is used and cleaned up. It should
+(so that the correct TLS data is used and cleaned up). It should
not be called by the caller of `pthread_join()`.
=== Region and Data Messages
@@ -406,7 +406,7 @@ The `label` field is an arbitrary label used to describe the activity
being started, such as "read_recursive" or "do_read_index".
+
The `repo` field, if set, will be used to get the "repo-id", so that
-recursive oerations can be attributed to the correct repository.
+recursive operations can be attributed to the correct repository.
`void trace2_region_leave(const char *category, const char *label, const struct repository *repo)`::
@@ -421,7 +421,7 @@ This function pops the region nesting stack on the current thread
and reports the elapsed time of the stack frame.
+
The `category`, `label`, and `repo` fields are the same as above.
-The `category` and `label` do not need to match the correpsonding
+The `category` and `label` do not need to match the corresponding
"region_enter" message, but it makes the data stream easier to
understand.
@@ -816,7 +816,7 @@ with "?".
Note that the session-id of the child process is not available to
the current/spawning process, so the child's PID is reported here as
a hint for post-processing. (But it is only a hint because the child
-proces may be a shell script which doesn't have a session-id.)
+process may be a shell script which doesn't have a session-id.)
+
Note that the `t_rel` field contains the observed run time in seconds
for the child process (starting before the fork/exec/spawn and
@@ -1176,7 +1176,7 @@ d0 | main | atexit | | 0.028809 | |
+
Regions may be nested. This causes messages to be indented in the
PERF target, for example.
-Elapsed times are relative to the start of the correpsonding nesting
+Elapsed times are relative to the start of the corresponding nesting
level as expected. For example, if we add region message to:
+
----------------
@@ -1371,7 +1371,7 @@ d0 | main | atexit | | 0.030027 | |
In this example, the preload region took 0.009122 seconds. The 7 threads
took between 0.006069 and 0.008947 seconds to work on their portion of
the index. Thread "th01" worked on 508 items at offset 0. Thread "th02"
-worked on 508 items at offset 2032. Thread "th04" worked on 508 itemts
+worked on 508 items at offset 2032. Thread "th04" worked on 508 items
at offset 508.
+
This example also shows that thread names are assigned in a racy manner
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt
index 729fbcb..1507117 100644
--- a/Documentation/technical/commit-graph.txt
+++ b/Documentation/technical/commit-graph.txt
@@ -22,11 +22,11 @@ as "commit-graph" either in the .git/objects/info directory or in the info
directory of an alternate.
The commit-graph file stores the commit graph structure along with some
-extra metadata to speed up graph walks. By listing commit OIDs in lexi-
-cographic order, we can identify an integer position for each commit and
-refer to the parents of a commit using those integer positions. We use
-binary search to find initial commits and then use the integer positions
-for fast lookups during the walk.
+extra metadata to speed up graph walks. By listing commit OIDs in
+lexicographic order, we can identify an integer position for each commit
+and refer to the parents of a commit using those integer positions. We
+use binary search to find initial commits and then use the integer
+positions for fast lookups during the walk.
A consumer may load the following info for a commit from the graph:
@@ -85,7 +85,7 @@ have generation number represented by the macro GENERATION_NUMBER_ZERO = 0.
Since the commit-graph file is closed under reachability, we can guarantee
the following weaker condition on all commits:
- If A and B are commits with generation numbers N amd M, respectively,
+ If A and B are commits with generation numbers N and M, respectively,
and N < M, then A cannot reach B.
Note how the strict inequality differs from the inequality when we have
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index 2ae8fa4..8a4596b 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -531,7 +531,7 @@ Until Git protocol gains SHA-256 support, using SHA-256 based storage
on public-facing Git servers is strongly discouraged. Once Git
protocol gains SHA-256 support, SHA-256 based servers are likely not
to support SHA-1 compatibility, to avoid what may be a very expensive
-hash reencode during clone and to encourage peers to modernize.
+hash re-encode during clone and to encourage peers to modernize.
The design described here allows fetches by SHA-1 clients of a
personal SHA-256 repository because it's not much more difficult than
@@ -602,7 +602,7 @@ git --output-format=sha1 log abac87a^{sha1}..f787cac^{sha256}
Choice of Hash
--------------
-In early 2005, around the time that Git was written, Xiaoyun Wang,
+In early 2005, around the time that Git was written, Xiaoyun Wang,
Yiqun Lisa Yin, and Hongbo Yu announced an attack finding SHA-1
collisions in 2^69 operations. In August they published details.
Luckily, no practical demonstrations of a collision in full SHA-1 were
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 7c4d67a..faa25c5 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -318,7 +318,7 @@ The remaining data of each directory block is grouped by type:
== End of Index Entry
The End of Index Entry (EOIE) is used to locate the end of the variable
- length index entries and the begining of the extensions. Code can take
+ length index entries and the beginning of the extensions. Code can take
advantage of this to quickly locate the index extensions without having
to parse through all of the index entries.
@@ -351,7 +351,7 @@ The remaining data of each directory block is grouped by type:
- A number of index offset entries each consisting of:
- - 32-bit offset from the begining of the file to the first cache entry
+ - 32-bit offset from the beginning of the file to the first cache entry
in this block of entries.
- 32-bit count of cache entries in this block
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index c73e72d..d5ce4ee 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -644,7 +644,7 @@ update was successful, or 'ng [refname] [error]' if the update was not.
command-ok = PKT-LINE("ok" SP refname)
command-fail = PKT-LINE("ng" SP refname SP error-msg)
- error-msg = 1*(OCTECT) ; where not "ok"
+ error-msg = 1*(OCTET) ; where not "ok"
----
Updates can be unsuccessful for a number of reasons. The reference can have
diff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.txt
index 210373e..a6034d5 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.txt
@@ -32,7 +32,7 @@ if/when needed.
A remote that can later provide the missing objects is called a
promisor remote, as it promises to send the objects when
-requested. Initialy Git supported only one promisor remote, the origin
+requested. Initially Git supported only one promisor remote, the origin
remote from which the user cloned and that was configured in the
"extensions.partialClone" config option. Later support for more than
one promisor remote has been implemented.
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index 40f91f6..7e3766c 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -252,7 +252,7 @@ A `fetch` request can take the following arguments:
ofs-delta
Indicate that the client understands PACKv2 with delta referring
to its base by position in pack rather than by an oid. That is,
- they can read OBJ_OFS_DELTA (ake type 6) in a packfile.
+ they can read OBJ_OFS_DELTA (aka type 6) in a packfile.
If the 'shallow' feature is advertised the following arguments can be
included in the clients request as well as the potential addition of the
diff --git a/Documentation/technical/rerere.txt b/Documentation/technical/rerere.txt
index aa22d7a..af5f9fc 100644
--- a/Documentation/technical/rerere.txt
+++ b/Documentation/technical/rerere.txt
@@ -117,7 +117,7 @@ early A became C or B, a late X became Y or Z". We can see there are
4 combinations of ("B or C", "C or B") x ("X or Y", "Y or X").
By sorting, the conflict is given its canonical name, namely, "an
-early part became B or C, a late part becames X or Y", and whenever
+early part became B or C, a late part became X or Y", and whenever
any of these four patterns appear, and we can get to the same conflict
and resolution that we saw earlier.
diff --git a/INSTALL b/INSTALL
index c39006e..22c364f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -109,15 +109,15 @@ Issues of note:
- Git is reasonably self-sufficient, but does depend on a few external
programs and libraries. Git can be used without most of them by adding
- the approriate "NO_<LIBRARY>=YesPlease" to the make command line or
+ the appropriate "NO_<LIBRARY>=YesPlease" to the make command line or
config.mak file.
- "zlib", the compression library. Git won't build without it.
- "ssh" is used to push and pull over the net.
- - A POSIX-compliant shell is required to run many scripts needed
- for everyday use (e.g. "bisect", "pull").
+ - A POSIX-compliant shell is required to run some scripts needed
+ for everyday use (e.g. "bisect", "request-pull").
- "Perl" version 5.8 or later is needed to use some of the
features (e.g. preparing a partial commit using "git add -i/-p",
diff --git a/Makefile b/Makefile
index 58b92af..b7d7374 100644
--- a/Makefile
+++ b/Makefile
@@ -727,6 +727,7 @@ TEST_BUILTINS_OBJS += test-prio-queue.o
TEST_BUILTINS_OBJS += test-progress.o
TEST_BUILTINS_OBJS += test-reach.o
TEST_BUILTINS_OBJS += test-read-cache.o
+TEST_BUILTINS_OBJS += test-read-graph.o
TEST_BUILTINS_OBJS += test-read-midx.o
TEST_BUILTINS_OBJS += test-ref-store.o
TEST_BUILTINS_OBJS += test-regex.o
@@ -823,6 +824,7 @@ LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentat
-name '*.h' -print)))
LIB_OBJS += abspath.o
+LIB_OBJS += add-interactive.o
LIB_OBJS += advice.o
LIB_OBJS += alias.o
LIB_OBJS += alloc.o
diff --git a/add-interactive.c b/add-interactive.c
new file mode 100644
index 0000000..d6cb98c
--- /dev/null
+++ b/add-interactive.c
@@ -0,0 +1,652 @@
+#include "cache.h"
+#include "add-interactive.h"
+#include "color.h"
+#include "config.h"
+#include "diffcore.h"
+#include "revision.h"
+#include "refs.h"
+#include "string-list.h"
+
+struct add_i_state {
+ struct repository *r;
+ int use_color;
+ char header_color[COLOR_MAXLEN];
+ char help_color[COLOR_MAXLEN];
+ char prompt_color[COLOR_MAXLEN];
+ char error_color[COLOR_MAXLEN];
+ char reset_color[COLOR_MAXLEN];
+};
+
+static void init_color(struct repository *r, struct add_i_state *s,
+ const char *slot_name, char *dst,
+ const char *default_color)
+{
+ char *key = xstrfmt("color.interactive.%s", slot_name);
+ const char *value;
+
+ if (!s->use_color)
+ dst[0] = '\0';
+ else if (repo_config_get_value(r, key, &value) ||
+ color_parse(value, dst))
+ strlcpy(dst, default_color, COLOR_MAXLEN);
+
+ free(key);
+}
+
+static void init_add_i_state(struct add_i_state *s, struct repository *r)
+{
+ const char *value;
+
+ s->r = r;
+
+ if (repo_config_get_value(r, "color.interactive", &value))
+ s->use_color = -1;
+ else
+ s->use_color =
+ git_config_colorbool("color.interactive", value);
+ s->use_color = want_color(s->use_color);
+
+ init_color(r, s, "header", s->header_color, GIT_COLOR_BOLD);
+ init_color(r, s, "help", s->help_color, GIT_COLOR_BOLD_RED);
+ init_color(r, s, "prompt", s->prompt_color, GIT_COLOR_BOLD_BLUE);
+ init_color(r, s, "error", s->error_color, GIT_COLOR_BOLD_RED);
+ init_color(r, s, "reset", s->reset_color, GIT_COLOR_RESET);
+}
+
+/*
+ * A "prefix item list" is a list of items that are identified by a string, and
+ * a unique prefix (if any) is determined for each item.
+ *
+ * It is implemented in the form of a pair of `string_list`s, the first one
+ * duplicating the strings, with the `util` field pointing at a structure whose
+ * first field must be `size_t prefix_length`.
+ *
+ * That `prefix_length` field will be computed by `find_unique_prefixes()`; It
+ * will be set to zero if no valid, unique prefix could be found.
+ *
+ * The second `string_list` is called `sorted` and does _not_ duplicate the
+ * strings but simply reuses the first one's, with the `util` field pointing at
+ * the `string_item_list` of the first `string_list`. It will be populated and
+ * sorted by `find_unique_prefixes()`.
+ */
+struct prefix_item_list {
+ struct string_list items;
+ struct string_list sorted;
+ size_t min_length, max_length;
+};
+#define PREFIX_ITEM_LIST_INIT \
+ { STRING_LIST_INIT_DUP, STRING_LIST_INIT_NODUP, 1, 4 }
+
+static void prefix_item_list_clear(struct prefix_item_list *list)
+{
+ string_list_clear(&list->items, 1);
+ string_list_clear(&list->sorted, 0);
+}
+
+static void extend_prefix_length(struct string_list_item *p,
+ const char *other_string, size_t max_length)
+{
+ size_t *len = p->util;
+
+ if (!*len || memcmp(p->string, other_string, *len))
+ return;
+
+ for (;;) {
+ char c = p->string[*len];
+
+ /*
+ * Is `p` a strict prefix of `other`? Or have we exhausted the
+ * maximal length of the prefix? Or is the current character a
+ * multi-byte UTF-8 one? If so, there is no valid, unique
+ * prefix.
+ */
+ if (!c || ++*len > max_length || !isascii(c)) {
+ *len = 0;
+ break;
+ }
+
+ if (c != other_string[*len - 1])
+ break;
+ }
+}
+
+static void find_unique_prefixes(struct prefix_item_list *list)
+{
+ size_t i;
+
+ if (list->sorted.nr == list->items.nr)
+ return;
+
+ string_list_clear(&list->sorted, 0);
+ /* Avoid reallocating incrementally */
+ list->sorted.items = xmalloc(st_mult(sizeof(*list->sorted.items),
+ list->items.nr));
+ list->sorted.nr = list->sorted.alloc = list->items.nr;
+
+ for (i = 0; i < list->items.nr; i++) {
+ list->sorted.items[i].string = list->items.items[i].string;
+ list->sorted.items[i].util = list->items.items + i;
+ }
+
+ string_list_sort(&list->sorted);
+
+ for (i = 0; i < list->sorted.nr; i++) {
+ struct string_list_item *sorted_item = list->sorted.items + i;
+ struct string_list_item *item = sorted_item->util;
+ size_t *len = item->util;
+
+ *len = 0;
+ while (*len < list->min_length) {
+ char c = item->string[(*len)++];
+
+ if (!c || !isascii(c)) {
+ *len = 0;
+ break;
+ }
+ }
+
+ if (i > 0)
+ extend_prefix_length(item, sorted_item[-1].string,
+ list->max_length);
+ if (i + 1 < list->sorted.nr)
+ extend_prefix_length(item, sorted_item[1].string,
+ list->max_length);
+ }
+}
+
+static ssize_t find_unique(const char *string, struct prefix_item_list *list)
+{
+ int index = string_list_find_insert_index(&list->sorted, string, 1);
+ struct string_list_item *item;
+
+ if (list->items.nr != list->sorted.nr)
+ BUG("prefix_item_list in inconsistent state (%"PRIuMAX
+ " vs %"PRIuMAX")",
+ (uintmax_t)list->items.nr, (uintmax_t)list->sorted.nr);
+
+ if (index < 0)
+ item = list->sorted.items[-1 - index].util;
+ else if (index > 0 &&
+ starts_with(list->sorted.items[index - 1].string, string))
+ return -1;
+ else if (index + 1 < list->sorted.nr &&
+ starts_with(list->sorted.items[index + 1].string, string))
+ return -1;
+ else if (index < list->sorted.nr)
+ item = list->sorted.items[index].util;
+ else
+ return -1;
+ return item - list->items.items;
+}
+
+struct list_options {
+ int columns;
+ const char *header;
+ void (*print_item)(int i, struct string_list_item *item, void *print_item_data);
+ void *print_item_data;
+};
+
+static void list(struct add_i_state *s, struct string_list *list,
+ struct list_options *opts)
+{
+ int i, last_lf = 0;
+
+ if (!list->nr)
+ return;
+
+ if (opts->header)
+ color_fprintf_ln(stdout, s->header_color,
+ "%s", opts->header);
+
+ for (i = 0; i < list->nr; i++) {
+ opts->print_item(i, list->items + i, opts->print_item_data);
+
+ if ((opts->columns) && ((i + 1) % (opts->columns))) {
+ putchar('\t');
+ last_lf = 0;
+ }
+ else {
+ putchar('\n');
+ last_lf = 1;
+ }
+ }
+
+ if (!last_lf)
+ putchar('\n');
+}
+struct list_and_choose_options {
+ struct list_options list_opts;
+
+ const char *prompt;
+ void (*print_help)(struct add_i_state *s);
+};
+
+#define LIST_AND_CHOOSE_ERROR (-1)
+#define LIST_AND_CHOOSE_QUIT (-2)
+
+/*
+ * Returns the selected index.
+ *
+ * If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF,
+ * `LIST_AND_CHOOSE_QUIT` is returned.
+ */
+static ssize_t list_and_choose(struct add_i_state *s,
+ struct prefix_item_list *items,
+ struct list_and_choose_options *opts)
+{
+ struct strbuf input = STRBUF_INIT;
+ ssize_t res = LIST_AND_CHOOSE_ERROR;
+
+ find_unique_prefixes(items);
+
+ for (;;) {
+ char *p;
+
+ strbuf_reset(&input);
+
+ list(s, &items->items, &opts->list_opts);
+
+ color_fprintf(stdout, s->prompt_color, "%s", opts->prompt);
+ fputs("> ", stdout);
+ fflush(stdout);
+
+ if (strbuf_getline(&input, stdin) == EOF) {
+ putchar('\n');
+ res = LIST_AND_CHOOSE_QUIT;
+ break;
+ }
+ strbuf_trim(&input);
+
+ if (!input.len)
+ break;
+
+ if (!strcmp(input.buf, "?")) {
+ opts->print_help(s);
+ continue;
+ }
+
+ p = input.buf;
+ for (;;) {
+ size_t sep = strcspn(p, " \t\r\n,");
+ ssize_t index = -1;
+
+ if (!sep) {
+ if (!*p)
+ break;
+ p++;
+ continue;
+ }
+
+ if (isdigit(*p)) {
+ char *endp;
+ index = strtoul(p, &endp, 10) - 1;
+ if (endp != p + sep)
+ index = -1;
+ }
+
+ if (p[sep])
+ p[sep++] = '\0';
+ if (index < 0)
+ index = find_unique(p, items);
+
+ if (index < 0 || index >= items->items.nr)
+ color_fprintf_ln(stdout, s->error_color,
+ _("Huh (%s)?"), p);
+ else {
+ res = index;
+ break;
+ }
+
+ p += sep;
+ }
+
+ if (res != LIST_AND_CHOOSE_ERROR)
+ break;
+ }
+
+ strbuf_release(&input);
+ return res;
+}
+
+struct adddel {
+ uintmax_t add, del;
+ unsigned seen:1, binary:1;
+};
+
+struct file_item {
+ struct adddel index, worktree;
+};
+
+static void add_file_item(struct string_list *files, const char *name)
+{
+ struct file_item *item = xcalloc(sizeof(*item), 1);
+
+ string_list_append(files, name)->util = item;
+}
+
+struct pathname_entry {
+ struct hashmap_entry ent;
+ const char *name;
+ struct file_item *item;
+};
+
+static int pathname_entry_cmp(const void *unused_cmp_data,
+ const struct hashmap_entry *he1,
+ const struct hashmap_entry *he2,
+ const void *name)
+{
+ const struct pathname_entry *e1 =
+ container_of(he1, const struct pathname_entry, ent);
+ const struct pathname_entry *e2 =
+ container_of(he2, const struct pathname_entry, ent);
+
+ return strcmp(e1->name, name ? (const char *)name : e2->name);
+}
+
+struct collection_status {
+ enum { FROM_WORKTREE = 0, FROM_INDEX = 1 } phase;
+
+ const char *reference;
+
+ struct string_list *files;
+ struct hashmap file_map;
+};
+
+static void collect_changes_cb(struct diff_queue_struct *q,
+ struct diff_options *options,
+ void *data)
+{
+ struct collection_status *s = data;
+ struct diffstat_t stat = { 0 };
+ int i;
+
+ if (!q->nr)
+ return;
+
+ compute_diffstat(options, &stat, q);
+
+ for (i = 0; i < stat.nr; i++) {
+ const char *name = stat.files[i]->name;
+ int hash = strhash(name);
+ struct pathname_entry *entry;
+ struct file_item *file_item;
+ struct adddel *adddel;
+
+ entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
+ struct pathname_entry, ent);
+ if (!entry) {
+ add_file_item(s->files, name);
+
+ entry = xcalloc(sizeof(*entry), 1);
+ hashmap_entry_init(&entry->ent, hash);
+ entry->name = s->files->items[s->files->nr - 1].string;
+ entry->item = s->files->items[s->files->nr - 1].util;
+ hashmap_add(&s->file_map, &entry->ent);
+ }
+
+ file_item = entry->item;
+ adddel = s->phase == FROM_INDEX ?
+ &file_item->index : &file_item->worktree;
+ adddel->seen = 1;
+ adddel->add = stat.files[i]->added;
+ adddel->del = stat.files[i]->deleted;
+ if (stat.files[i]->is_binary)
+ adddel->binary = 1;
+ }
+ free_diffstat_info(&stat);
+}
+
+static int get_modified_files(struct repository *r, struct string_list *files,
+ const struct pathspec *ps)
+{
+ struct object_id head_oid;
+ int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
+ &head_oid, NULL);
+ struct collection_status s = { FROM_WORKTREE };
+
+ if (discard_index(r->index) < 0 ||
+ repo_read_index_preload(r, ps, 0) < 0)
+ return error(_("could not read index"));
+
+ string_list_clear(files, 1);
+ s.files = files;
+ hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0);
+
+ for (s.phase = FROM_WORKTREE; s.phase <= FROM_INDEX; s.phase++) {
+ struct rev_info rev;
+ struct setup_revision_opt opt = { 0 };
+
+ opt.def = is_initial ?
+ empty_tree_oid_hex() : oid_to_hex(&head_oid);
+
+ init_revisions(&rev, NULL);
+ setup_revisions(0, NULL, &rev, &opt);
+
+ rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ rev.diffopt.format_callback = collect_changes_cb;
+ rev.diffopt.format_callback_data = &s;
+
+ if (ps)
+ copy_pathspec(&rev.prune_data, ps);
+
+ if (s.phase == FROM_INDEX)
+ run_diff_index(&rev, 1);
+ else {
+ rev.diffopt.flags.ignore_dirty_submodules = 1;
+ run_diff_files(&rev, 0);
+ }
+ }
+ hashmap_free_entries(&s.file_map, struct pathname_entry, ent);
+
+ /* While the diffs are ordered already, we ran *two* diffs... */
+ string_list_sort(files);
+
+ return 0;
+}
+
+static void render_adddel(struct strbuf *buf,
+ struct adddel *ad, const char *no_changes)
+{
+ if (ad->binary)
+ strbuf_addstr(buf, _("binary"));
+ else if (ad->seen)
+ strbuf_addf(buf, "+%"PRIuMAX"/-%"PRIuMAX,
+ (uintmax_t)ad->add, (uintmax_t)ad->del);
+ else
+ strbuf_addstr(buf, no_changes);
+}
+
+/* filters out prefixes which have special meaning to list_and_choose() */
+static int is_valid_prefix(const char *prefix, size_t prefix_len)
+{
+ return prefix_len && prefix &&
+ /*
+ * We expect `prefix` to be NUL terminated, therefore this
+ * `strcspn()` call is okay, even if it might do much more
+ * work than strictly necessary.
+ */
+ strcspn(prefix, " \t\r\n,") >= prefix_len && /* separators */
+ *prefix != '-' && /* deselection */
+ !isdigit(*prefix) && /* selection */
+ (prefix_len != 1 ||
+ (*prefix != '*' && /* "all" wildcard */
+ *prefix != '?')); /* prompt help */
+}
+
+struct print_file_item_data {
+ const char *modified_fmt;
+ struct strbuf buf, index, worktree;
+};
+
+static void print_file_item(int i, struct string_list_item *item,
+ void *print_file_item_data)
+{
+ struct file_item *c = item->util;
+ struct print_file_item_data *d = print_file_item_data;
+
+ strbuf_reset(&d->index);
+ strbuf_reset(&d->worktree);
+ strbuf_reset(&d->buf);
+
+ render_adddel(&d->worktree, &c->worktree, _("nothing"));
+ render_adddel(&d->index, &c->index, _("unchanged"));
+ strbuf_addf(&d->buf, d->modified_fmt,
+ d->index.buf, d->worktree.buf, item->string);
+
+ printf(" %2d: %s", i + 1, d->buf.buf);
+}
+
+static int run_status(struct add_i_state *s, const struct pathspec *ps,
+ struct string_list *files, struct list_options *opts)
+{
+ if (get_modified_files(s->r, files, ps) < 0)
+ return -1;
+
+ list(s, files, opts);
+ putchar('\n');
+
+ return 0;
+}
+
+static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
+ struct string_list *unused_files,
+ struct list_options *unused_opts)
+{
+ color_fprintf_ln(stdout, s->help_color, "status - %s",
+ _("show paths with changes"));
+ color_fprintf_ln(stdout, s->help_color, "update - %s",
+ _("add working tree state to the staged set of changes"));
+ color_fprintf_ln(stdout, s->help_color, "revert - %s",
+ _("revert staged set of changes back to the HEAD version"));
+ color_fprintf_ln(stdout, s->help_color, "patch - %s",
+ _("pick hunks and update selectively"));
+ color_fprintf_ln(stdout, s->help_color, "diff - %s",
+ _("view diff between HEAD and index"));
+ color_fprintf_ln(stdout, s->help_color, "add untracked - %s",
+ _("add contents of untracked files to the staged set of changes"));
+
+ return 0;
+}
+
+typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps,
+ struct string_list *files,
+ struct list_options *opts);
+
+struct command_item {
+ size_t prefix_length;
+ command_t command;
+};
+
+struct print_command_item_data {
+ const char *color, *reset;
+};
+
+static void print_command_item(int i, struct string_list_item *item,
+ void *print_command_item_data)
+{
+ struct print_command_item_data *d = print_command_item_data;
+ struct command_item *util = item->util;
+
+ if (!util->prefix_length ||
+ !is_valid_prefix(item->string, util->prefix_length))
+ printf(" %2d: %s", i + 1, item->string);
+ else
+ printf(" %2d: %s%.*s%s%s", i + 1,
+ d->color, (int)util->prefix_length, item->string,
+ d->reset, item->string + util->prefix_length);
+}
+
+static void command_prompt_help(struct add_i_state *s)
+{
+ const char *help_color = s->help_color;
+ color_fprintf_ln(stdout, help_color, "%s", _("Prompt help:"));
+ color_fprintf_ln(stdout, help_color, "1 - %s",
+ _("select a numbered item"));
+ color_fprintf_ln(stdout, help_color, "foo - %s",
+ _("select item based on unique prefix"));
+ color_fprintf_ln(stdout, help_color, " - %s",
+ _("(empty) select nothing"));
+}
+
+int run_add_i(struct repository *r, const struct pathspec *ps)
+{
+ struct add_i_state s = { NULL };
+ struct print_command_item_data data = { "[", "]" };
+ struct list_and_choose_options main_loop_opts = {
+ { 4, N_("*** Commands ***"), print_command_item, &data },
+ N_("What now"), command_prompt_help
+ };
+ struct {
+ const char *string;
+ command_t command;
+ } command_list[] = {
+ { "status", run_status },
+ { "help", run_help },
+ };
+ struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;
+
+ struct print_file_item_data print_file_item_data = {
+ "%12s %12s %s", STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+ };
+ struct list_options opts = {
+ 0, NULL, print_file_item, &print_file_item_data
+ };
+ struct strbuf header = STRBUF_INIT;
+ struct string_list files = STRING_LIST_INIT_DUP;
+ ssize_t i;
+ int res = 0;
+
+ for (i = 0; i < ARRAY_SIZE(command_list); i++) {
+ struct command_item *util = xcalloc(sizeof(*util), 1);
+ util->command = command_list[i].command;
+ string_list_append(&commands.items, command_list[i].string)
+ ->util = util;
+ }
+
+ init_add_i_state(&s, r);
+
+ /*
+ * When color was asked for, use the prompt color for
+ * highlighting, otherwise use square brackets.
+ */
+ if (s.use_color) {
+ data.color = s.prompt_color;
+ data.reset = s.reset_color;
+ }
+
+ strbuf_addstr(&header, " ");
+ strbuf_addf(&header, print_file_item_data.modified_fmt,
+ _("staged"), _("unstaged"), _("path"));
+ opts.header = header.buf;
+
+ if (discard_index(r->index) < 0 ||
+ repo_read_index(r) < 0 ||
+ repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
+ NULL, NULL, NULL) < 0)
+ warning(_("could not refresh index"));
+
+ res = run_status(&s, ps, &files, &opts);
+
+ for (;;) {
+ i = list_and_choose(&s, &commands, &main_loop_opts);
+ if (i == LIST_AND_CHOOSE_QUIT) {
+ printf(_("Bye.\n"));
+ res = 0;
+ break;
+ }
+ if (i != LIST_AND_CHOOSE_ERROR) {
+ struct command_item *util =
+ commands.items.items[i].util;
+ res = util->command(&s, ps, &files, &opts);
+ }
+ }
+
+ string_list_clear(&files, 1);
+ strbuf_release(&print_file_item_data.buf);
+ strbuf_release(&print_file_item_data.index);
+ strbuf_release(&print_file_item_data.worktree);
+ strbuf_release(&header);
+ prefix_item_list_clear(&commands);
+
+ return res;
+}
diff --git a/add-interactive.h b/add-interactive.h
new file mode 100644
index 0000000..7043b87
--- /dev/null
+++ b/add-interactive.h
@@ -0,0 +1,8 @@
+#ifndef ADD_INTERACTIVE_H
+#define ADD_INTERACTIVE_H
+
+struct repository;
+struct pathspec;
+int run_add_i(struct repository *r, const struct pathspec *ps);
+
+#endif
diff --git a/apply.c b/apply.c
index b9291f5..d57ac0d 100644
--- a/apply.c
+++ b/apply.c
@@ -4183,8 +4183,8 @@ static void show_rename_copy(struct patch *p)
old_name = slash_old + 1;
new_name = slash_new + 1;
}
- /* p->old_name thru old_name is the common prefix, and old_name and new_name
- * through the end of names are renames
+ /* p->old_name through old_name is the common prefix, and old_name and
+ * new_name through the end of names are renames
*/
if (old_name != p->old_name)
printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
diff --git a/builtin/add.c b/builtin/add.c
index dd18e5c..d4686d5 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -20,6 +20,7 @@
#include "bulk-checkin.h"
#include "argv-array.h"
#include "submodule.h"
+#include "add-interactive.h"
static const char * const builtin_add_usage[] = {
N_("git add [<options>] [--] <pathspec>..."),
@@ -185,6 +186,16 @@ int run_add_interactive(const char *revision, const char *patch_mode,
{
int status, i;
struct argv_array argv = ARGV_ARRAY_INIT;
+ int use_builtin_add_i =
+ git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
+
+ if (!patch_mode) {
+ if (use_builtin_add_i < 0)
+ git_config_get_bool("add.interactive.usebuiltin",
+ &use_builtin_add_i);
+ if (use_builtin_add_i == 1)
+ return !!run_add_i(the_repository, pathspec);
+ }
argv_array_push(&argv, "add--interactive");
if (patch_mode)
@@ -319,6 +330,7 @@ static int add_config(const char *var, const char *value, void *cb)
ignore_add_errors = git_config_bool(var, value);
return 0;
}
+
return git_default_config(var, value, cb);
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 10185cc..bf1cecd 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -861,14 +861,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("Ignore revisions from <file>")),
OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
-
- /*
- * The following two options are parsed by parse_revision_opt()
- * and are only included here to get included in the "-h"
- * output:
- */
- { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, NULL, 0, parse_opt_unknown_cb },
-
OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 1ea4bfd..f049d27 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,4 +1,6 @@
#include "builtin.h"
+#include "argv-array.h"
+#include "parse-options.h"
#include "cache.h"
#include "bundle.h"
@@ -9,59 +11,184 @@
* bundle supporting "fetch", "pull", and "ls-remote".
*/
-static const char builtin_bundle_usage[] =
- "git bundle create <file> <git-rev-list args>\n"
- " or: git bundle verify <file>\n"
- " or: git bundle list-heads <file> [<refname>...]\n"
- " or: git bundle unbundle <file> [<refname>...]";
+static const char * const builtin_bundle_usage[] = {
+ N_("git bundle create [<options>] <file> <git-rev-list args>"),
+ N_("git bundle verify [<options>] <file>"),
+ N_("git bundle list-heads <file> [<refname>...]"),
+ N_("git bundle unbundle <file> [<refname>...]"),
+ NULL
+};
-int cmd_bundle(int argc, const char **argv, const char *prefix)
-{
+static const char * const builtin_bundle_create_usage[] = {
+ N_("git bundle create [<options>] <file> <git-rev-list args>"),
+ NULL
+};
+
+static const char * const builtin_bundle_verify_usage[] = {
+ N_("git bundle verify [<options>] <file>"),
+ NULL
+};
+
+static const char * const builtin_bundle_list_heads_usage[] = {
+ N_("git bundle list-heads <file> [<refname>...]"),
+ NULL
+};
+
+static const char * const builtin_bundle_unbundle_usage[] = {
+ N_("git bundle unbundle <file> [<refname>...]"),
+ NULL
+};
+
+static int verbose;
+
+static int parse_options_cmd_bundle(int argc,
+ const char **argv,
+ const char* prefix,
+ const char * const usagestr[],
+ const struct option options[],
+ const char **bundle_file) {
+ int newargc;
+ newargc = parse_options(argc, argv, NULL, options, usagestr,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ if (argc < 1)
+ usage_with_options(usagestr, options);
+ *bundle_file = prefix_filename(prefix, argv[0]);
+ return newargc;
+}
+
+static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
+ int all_progress_implied = 0;
+ int progress = isatty(STDERR_FILENO);
+ struct argv_array pack_opts;
+
+ struct option options[] = {
+ OPT_SET_INT('q', "quiet", &progress,
+ N_("do not show progress meter"), 0),
+ OPT_SET_INT(0, "progress", &progress,
+ N_("show progress meter"), 1),
+ OPT_SET_INT(0, "all-progress", &progress,
+ N_("show progress meter during object writing phase"), 2),
+ OPT_BOOL(0, "all-progress-implied",
+ &all_progress_implied,
+ N_("similar to --all-progress when progress meter is shown")),
+ OPT_END()
+ };
+ const char* bundle_file;
+
+ argc = parse_options_cmd_bundle(argc, argv, prefix,
+ builtin_bundle_create_usage, options, &bundle_file);
+ /* bundle internals use argv[1] as further parameters */
+
+ argv_array_init(&pack_opts);
+ if (progress == 0)
+ argv_array_push(&pack_opts, "--quiet");
+ else if (progress == 1)
+ argv_array_push(&pack_opts, "--progress");
+ else if (progress == 2)
+ argv_array_push(&pack_opts, "--all-progress");
+ if (progress && all_progress_implied)
+ argv_array_push(&pack_opts, "--all-progress-implied");
+
+ if (!startup_info->have_repository)
+ die(_("Need a repository to create a bundle."));
+ return !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts);
+}
+
+static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
- const char *cmd, *bundle_file;
int bundle_fd = -1;
+ int quiet = 0;
- if (argc < 3)
- usage(builtin_bundle_usage);
+ struct option options[] = {
+ OPT_BOOL('q', "quiet", &quiet,
+ N_("do not show bundle details")),
+ OPT_END()
+ };
+ const char* bundle_file;
- cmd = argv[1];
- bundle_file = prefix_filename(prefix, argv[2]);
- argc -= 2;
- argv += 2;
+ argc = parse_options_cmd_bundle(argc, argv, prefix,
+ builtin_bundle_verify_usage, options, &bundle_file);
+ /* bundle internals use argv[1] as further parameters */
memset(&header, 0, sizeof(header));
- if (strcmp(cmd, "create") && (bundle_fd =
- read_bundle_header(bundle_file, &header)) < 0)
+ if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
+ return 1;
+ close(bundle_fd);
+ if (verify_bundle(the_repository, &header, !quiet))
return 1;
+ fprintf(stderr, _("%s is okay\n"), bundle_file);
+ return 0;
+}
- if (!strcmp(cmd, "verify")) {
- close(bundle_fd);
- if (argc != 1) {
- usage(builtin_bundle_usage);
- return 1;
- }
- if (verify_bundle(the_repository, &header, 1))
- return 1;
- fprintf(stderr, _("%s is okay\n"), bundle_file);
- return 0;
- }
- if (!strcmp(cmd, "list-heads")) {
- close(bundle_fd);
- return !!list_bundle_refs(&header, argc, argv);
+static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
+ struct bundle_header header;
+ int bundle_fd = -1;
+
+ struct option options[] = {
+ OPT_END()
+ };
+ const char* bundle_file;
+
+ argc = parse_options_cmd_bundle(argc, argv, prefix,
+ builtin_bundle_list_heads_usage, options, &bundle_file);
+ /* bundle internals use argv[1] as further parameters */
+
+ memset(&header, 0, sizeof(header));
+ if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
+ return 1;
+ close(bundle_fd);
+ return !!list_bundle_refs(&header, argc, argv);
+}
+
+static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
+ struct bundle_header header;
+ int bundle_fd = -1;
+
+ struct option options[] = {
+ OPT_END()
+ };
+ const char* bundle_file;
+
+ argc = parse_options_cmd_bundle(argc, argv, prefix,
+ builtin_bundle_unbundle_usage, options, &bundle_file);
+ /* bundle internals use argv[1] as further parameters */
+
+ memset(&header, 0, sizeof(header));
+ if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
+ return 1;
+ if (!startup_info->have_repository)
+ die(_("Need a repository to unbundle."));
+ return !!unbundle(the_repository, &header, bundle_fd, 0) ||
+ list_bundle_refs(&header, argc, argv);
+}
+
+int cmd_bundle(int argc, const char **argv, const char *prefix)
+{
+ struct option options[] = {
+ OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
+ OPT_END()
+ };
+ int result;
+
+ argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ packet_trace_identity("bundle");
+
+ if (argc < 2)
+ usage_with_options(builtin_bundle_usage, options);
+
+ else if (!strcmp(argv[0], "create"))
+ result = cmd_bundle_create(argc, argv, prefix);
+ else if (!strcmp(argv[0], "verify"))
+ result = cmd_bundle_verify(argc, argv, prefix);
+ else if (!strcmp(argv[0], "list-heads"))
+ result = cmd_bundle_list_heads(argc, argv, prefix);
+ else if (!strcmp(argv[0], "unbundle"))
+ result = cmd_bundle_unbundle(argc, argv, prefix);
+ else {
+ error(_("Unknown subcommand: %s"), argv[0]);
+ usage_with_options(builtin_bundle_usage, options);
}
- if (!strcmp(cmd, "create")) {
- if (argc < 2) {
- usage(builtin_bundle_usage);
- return 1;
- }
- if (!startup_info->have_repository)
- die(_("Need a repository to create a bundle."));
- return !!create_bundle(the_repository, bundle_file, argc, argv);
- } else if (!strcmp(cmd, "unbundle")) {
- if (!startup_info->have_repository)
- die(_("Need a repository to unbundle."));
- return !!unbundle(the_repository, &header, bundle_fd, 0) ||
- list_bundle_refs(&header, argc, argv);
- } else
- usage(builtin_bundle_usage);
+ return result ? 1 : 0;
}
diff --git a/builtin/clone.c b/builtin/clone.c
index c46ee29..40c0bf2 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -899,7 +899,7 @@ static void dissociate_from_references(void)
free(alternates);
}
-static int dir_exists(const char *path)
+static int path_exists(const char *path)
{
struct stat sb;
return !stat(path, &sb);
@@ -927,8 +927,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
- fetch_if_missing = 0;
-
packet_trace_identity("clone");
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
@@ -981,7 +979,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
dir = guess_dir_name(repo_name, is_bundle, option_bare);
strip_trailing_slashes(dir);
- dest_exists = dir_exists(dir);
+ dest_exists = path_exists(dir);
if (dest_exists && !is_empty_dir(dir))
die(_("destination path '%s' already exists and is not "
"an empty directory."), dir);
@@ -992,7 +990,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
work_tree = NULL;
else {
work_tree = getenv("GIT_WORK_TREE");
- if (work_tree && dir_exists(work_tree))
+ if (work_tree && path_exists(work_tree))
die(_("working tree '%s' already exists."), work_tree);
}
@@ -1020,7 +1018,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (real_git_dir) {
- if (dir_exists(real_git_dir))
+ if (path_exists(real_git_dir))
junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
junk_git_dir = real_git_dir;
} else {
@@ -1265,7 +1263,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
junk_mode = JUNK_LEAVE_REPO;
- fetch_if_missing = 1;
err = checkout(submodule_progress);
strbuf_release(&reflog_msg);
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index ec0fc93..e0c6fc4 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -8,7 +8,6 @@
#include "object-store.h"
static char const * const builtin_commit_graph_usage[] = {
- N_("git commit-graph read [--object-dir <objdir>]"),
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
NULL
@@ -19,11 +18,6 @@ static const char * const builtin_commit_graph_verify_usage[] = {
NULL
};
-static const char * const builtin_commit_graph_read_usage[] = {
- N_("git commit-graph read [--object-dir <objdir>]"),
- NULL
-};
-
static const char * const builtin_commit_graph_write_usage[] = {
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
NULL
@@ -93,66 +87,6 @@ static int graph_verify(int argc, const char **argv)
return verify_commit_graph(the_repository, graph, flags);
}
-static int graph_read(int argc, const char **argv)
-{
- struct commit_graph *graph = NULL;
- char *graph_name;
- int open_ok;
- int fd;
- struct stat st;
-
- static struct option builtin_commit_graph_read_options[] = {
- OPT_STRING(0, "object-dir", &opts.obj_dir,
- N_("dir"),
- N_("The object directory to store the graph")),
- OPT_END(),
- };
-
- trace2_cmd_mode("read");
-
- argc = parse_options(argc, argv, NULL,
- builtin_commit_graph_read_options,
- builtin_commit_graph_read_usage, 0);
-
- if (!opts.obj_dir)
- opts.obj_dir = get_object_directory();
-
- graph_name = get_commit_graph_filename(opts.obj_dir);
-
- open_ok = open_commit_graph(graph_name, &fd, &st);
- if (!open_ok)
- die_errno(_("Could not open commit-graph '%s'"), graph_name);
-
- graph = load_commit_graph_one_fd_st(fd, &st);
- if (!graph)
- return 1;
-
- FREE_AND_NULL(graph_name);
-
- printf("header: %08x %d %d %d %d\n",
- ntohl(*(uint32_t*)graph->data),
- *(unsigned char*)(graph->data + 4),
- *(unsigned char*)(graph->data + 5),
- *(unsigned char*)(graph->data + 6),
- *(unsigned char*)(graph->data + 7));
- printf("num_commits: %u\n", graph->num_commits);
- printf("chunks:");
-
- if (graph->chunk_oid_fanout)
- printf(" oid_fanout");
- if (graph->chunk_oid_lookup)
- printf(" oid_lookup");
- if (graph->chunk_commit_data)
- printf(" commit_metadata");
- if (graph->chunk_extra_edges)
- printf(" extra_edges");
- printf("\n");
-
- UNLEAK(graph);
-
- return 0;
-}
-
extern int read_replace_refs;
static struct split_commit_graph_opts split_opts;
@@ -268,8 +202,6 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
save_commit_buffer = 0;
if (argc > 0) {
- if (!strcmp(argv[0], "read"))
- return graph_read(argc, argv);
if (!strcmp(argv[0], "verify"))
return graph_verify(argc, argv);
if (!strcmp(argv[0], "write"))
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 863c858..46ce7c2 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -77,6 +77,7 @@ static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
+static int fetch_write_commit_graph = -1;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@@ -198,6 +199,8 @@ static struct option builtin_fetch_options[] = {
N_("run 'gc --auto' after fetching")),
OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
N_("check for forced-updates on all updated branches")),
+ OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
+ N_("write the commit-graph after fetching")),
OPT_END()
};
@@ -1074,7 +1077,8 @@ static int check_exist_and_connected(struct ref *ref_map)
* we need all direct targets to exist.
*/
for (r = rm; r; r = r->next) {
- if (!has_object_file(&r->old_oid))
+ if (!has_object_file_with_flags(&r->old_oid,
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
return -1;
}
@@ -1400,7 +1404,7 @@ static int do_fetch(struct transport *transport,
/*
* We're setting the upstream configuration for the
- * current branch. The relevent upstream is the
+ * current branch. The relevant upstream is the
* fetched branch that is meant to be merged with the
* current one, i.e. the one fetched to FETCH_HEAD.
*
@@ -1411,7 +1415,7 @@ static int do_fetch(struct transport *transport,
for (rm = ref_map; rm; rm = rm->next) {
if (!rm->peer_ref) {
if (source_ref) {
- warning(_("multiple branch detected, incompatible with --set-upstream"));
+ warning(_("multiple branches detected, incompatible with --set-upstream"));
goto skip;
} else {
source_ref = rm;
@@ -1599,7 +1603,8 @@ static int fetch_multiple(struct string_list *list, int max_children)
return errcode;
}
- argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc", NULL);
+ argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc",
+ "--no-write-commit-graph", NULL);
add_options_to_argv(&argv);
if (max_children != 1 && list->nr != 1) {
@@ -1822,8 +1827,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
}
- fetch_if_missing = 0;
-
if (remote) {
if (filter_options.choice || has_promisor_remote())
fetch_one_setup_partial(remote);
@@ -1865,7 +1868,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
string_list_clear(&list, 0);
prepare_repo_settings(the_repository);
- if (the_repository->settings.fetch_write_commit_graph) {
+ if (fetch_write_commit_graph > 0 ||
+ (fetch_write_commit_graph < 0 &&
+ the_repository->settings.fetch_write_commit_graph)) {
int commit_graph_flags = COMMIT_GRAPH_WRITE_SPLIT;
struct split_commit_graph_opts split_opts;
memset(&split_opts, 0, sizeof(struct split_commit_graph_opts));
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 18403a9..8d13794 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -50,40 +50,20 @@ static int name_objects;
#define ERROR_REFS 010
#define ERROR_COMMIT_GRAPH 020
-static const char *describe_object(struct object *obj)
+static const char *describe_object(const struct object_id *oid)
{
- static struct strbuf bufs[] = {
- STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
- };
- static int b = 0;
- struct strbuf *buf;
- char *name = NULL;
-
- if (name_objects)
- name = lookup_decoration(fsck_walk_options.object_names, obj);
-
- buf = bufs + b;
- b = (b + 1) % ARRAY_SIZE(bufs);
- strbuf_reset(buf);
- strbuf_addstr(buf, oid_to_hex(&obj->oid));
- if (name)
- strbuf_addf(buf, " (%s)", name);
-
- return buf->buf;
+ return fsck_describe_object(&fsck_walk_options, oid);
}
-static const char *printable_type(struct object *obj)
+static const char *printable_type(const struct object_id *oid,
+ enum object_type type)
{
const char *ret;
- if (obj->type == OBJ_NONE) {
- enum object_type type = oid_object_info(the_repository,
- &obj->oid, NULL);
- if (type > 0)
- object_as_type(the_repository, obj, type, 0);
- }
+ if (type == OBJ_NONE)
+ type = oid_object_info(the_repository, oid, NULL);
- ret = type_name(obj->type);
+ ret = type_name(type);
if (!ret)
ret = _("unknown");
@@ -118,26 +98,32 @@ static int objerror(struct object *obj, const char *err)
errors_found |= ERROR_OBJECT;
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
- printable_type(obj), describe_object(obj), err);
+ printable_type(&obj->oid, obj->type),
+ describe_object(&obj->oid), err);
return -1;
}
static int fsck_error_func(struct fsck_options *o,
- struct object *obj, int type, const char *message)
+ const struct object_id *oid,
+ enum object_type object_type,
+ int msg_type, const char *message)
{
- switch (type) {
+ switch (msg_type) {
case FSCK_WARN:
/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("warning in %s %s: %s"),
- printable_type(obj), describe_object(obj), message);
+ printable_type(oid, object_type),
+ describe_object(oid), message);
return 0;
case FSCK_ERROR:
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
- printable_type(obj), describe_object(obj), message);
+ printable_type(oid, object_type),
+ describe_object(oid), message);
return 1;
default:
- BUG("%d (FSCK_IGNORE?) should never trigger this callback", type);
+ BUG("%d (FSCK_IGNORE?) should never trigger this callback",
+ msg_type);
}
}
@@ -155,7 +141,8 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
if (!obj) {
/* ... these references to parent->fld are safe here */
printf_ln(_("broken link from %7s %s"),
- printable_type(parent), describe_object(parent));
+ printable_type(&parent->oid, parent->type),
+ describe_object(&parent->oid));
printf_ln(_("broken link from %7s %s"),
(type == OBJ_ANY ? _("unknown") : type_name(type)),
_("unknown"));
@@ -183,10 +170,10 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
if (parent && !has_object_file(&obj->oid)) {
printf_ln(_("broken link from %7s %s\n"
" to %7s %s"),
- printable_type(parent),
- describe_object(parent),
- printable_type(obj),
- describe_object(obj));
+ printable_type(&parent->oid, parent->type),
+ describe_object(&parent->oid),
+ printable_type(&obj->oid, obj->type),
+ describe_object(&obj->oid));
errors_found |= ERROR_REACHABLE;
}
return 1;
@@ -292,8 +279,9 @@ static void check_reachable_object(struct object *obj)
return;
if (has_object_pack(&obj->oid))
return; /* it is in pack - forget about it */
- printf_ln(_("missing %s %s"), printable_type(obj),
- describe_object(obj));
+ printf_ln(_("missing %s %s"),
+ printable_type(&obj->oid, obj->type),
+ describe_object(&obj->oid));
errors_found |= ERROR_REACHABLE;
return;
}
@@ -318,8 +306,9 @@ static void check_unreachable_object(struct object *obj)
* since this is something that is prunable.
*/
if (show_unreachable) {
- printf_ln(_("unreachable %s %s"), printable_type(obj),
- describe_object(obj));
+ printf_ln(_("unreachable %s %s"),
+ printable_type(&obj->oid, obj->type),
+ describe_object(&obj->oid));
return;
}
@@ -337,12 +326,13 @@ static void check_unreachable_object(struct object *obj)
*/
if (!(obj->flags & USED)) {
if (show_dangling)
- printf_ln(_("dangling %s %s"), printable_type(obj),
- describe_object(obj));
+ printf_ln(_("dangling %s %s"),
+ printable_type(&obj->oid, obj->type),
+ describe_object(&obj->oid));
if (write_lost_and_found) {
char *filename = git_pathdup("lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
- describe_object(obj));
+ describe_object(&obj->oid));
FILE *f;
if (safe_create_leading_directories_const(filename)) {
@@ -355,7 +345,7 @@ static void check_unreachable_object(struct object *obj)
if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
die_errno(_("could not write '%s'"), filename);
} else
- fprintf(f, "%s\n", describe_object(obj));
+ fprintf(f, "%s\n", describe_object(&obj->oid));
if (fclose(f))
die_errno(_("could not finish '%s'"),
filename);
@@ -374,7 +364,7 @@ static void check_unreachable_object(struct object *obj)
static void check_object(struct object *obj)
{
if (verbose)
- fprintf_ln(stderr, _("Checking %s"), describe_object(obj));
+ fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid));
if (obj->flags & REACHABLE)
check_reachable_object(obj);
@@ -432,7 +422,8 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (verbose)
fprintf_ln(stderr, _("Checking %s %s"),
- printable_type(obj), describe_object(obj));
+ printable_type(&obj->oid, obj->type),
+ describe_object(&obj->oid));
if (fsck_walk(obj, NULL, &fsck_obj_options))
objerror(obj, _("broken links"));
@@ -445,7 +436,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (!commit->parents && show_root)
printf_ln(_("root %s"),
- describe_object(&commit->object));
+ describe_object(&commit->object.oid));
}
if (obj->type == OBJ_TAG) {
@@ -453,10 +444,10 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (show_tags && tag->tagged) {
printf_ln(_("tagged %s %s (%s) in %s"),
- printable_type(tag->tagged),
- describe_object(tag->tagged),
+ printable_type(&tag->tagged->oid, tag->tagged->type),
+ describe_object(&tag->tagged->oid),
tag->tag,
- describe_object(&tag->object));
+ describe_object(&tag->object.oid));
}
}
@@ -499,10 +490,10 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
if (!is_null_oid(oid)) {
obj = lookup_object(the_repository, oid);
if (obj && (obj->flags & HAS_OBJ)) {
- if (timestamp && name_objects)
- add_decoration(fsck_walk_options.object_names,
- obj,
- xstrfmt("%s@{%"PRItime"}", refname, timestamp));
+ if (timestamp)
+ fsck_put_object_name(&fsck_walk_options, oid,
+ "%s@{%"PRItime"}",
+ refname, timestamp);
obj->flags |= USED;
mark_object_reachable(obj);
} else if (!is_promisor_object(oid)) {
@@ -566,9 +557,8 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
}
default_refs++;
obj->flags |= USED;
- if (name_objects)
- add_decoration(fsck_walk_options.object_names,
- obj, xstrdup(refname));
+ fsck_put_object_name(&fsck_walk_options,
+ oid, "%s", refname);
mark_object_reachable(obj);
return 0;
@@ -742,9 +732,7 @@ static int fsck_cache_tree(struct cache_tree *it)
return 1;
}
obj->flags |= USED;
- if (name_objects)
- add_decoration(fsck_walk_options.object_names,
- obj, xstrdup(":"));
+ fsck_put_object_name(&fsck_walk_options, &it->oid, ":");
mark_object_reachable(obj);
if (obj->type != OBJ_TREE)
err |= objerror(obj, _("non-tree in cache-tree"));
@@ -830,8 +818,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
if (name_objects)
- fsck_walk_options.object_names =
- xcalloc(1, sizeof(struct decoration));
+ fsck_enable_object_names(&fsck_walk_options);
git_config(fsck_config, NULL);
@@ -890,9 +877,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
obj->flags |= USED;
- if (name_objects)
- add_decoration(fsck_walk_options.object_names,
- obj, xstrdup(arg));
+ fsck_put_object_name(&fsck_walk_options, &oid,
+ "%s", arg);
mark_object_reachable(obj);
continue;
}
@@ -928,10 +914,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
continue;
obj = &blob->object;
obj->flags |= USED;
- if (name_objects)
- add_decoration(fsck_walk_options.object_names,
- obj,
- xstrfmt(":%s", active_cache[i]->name));
+ fsck_put_object_name(&fsck_walk_options, &obj->oid,
+ ":%s", active_cache[i]->name);
mark_object_reachable(obj);
}
if (active_cache_tree)
diff --git a/builtin/gc.c b/builtin/gc.c
index fadb454..3f76bf4 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -458,7 +458,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
/*
* Returns 0 if there was no previous error and gc can proceed, 1 if
* gc should not proceed due to an error in the last run. Prints a
- * message and returns -1 if an error occured while reading gc.log
+ * message and returns -1 if an error occurred while reading gc.log
*/
static int report_last_gc_error(void)
{
@@ -601,7 +601,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (detach_auto) {
int ret = report_last_gc_error();
if (ret < 0)
- /* an I/O error occured, already reported */
+ /* an I/O error occurred, already reported */
exit(128);
if (ret == 1)
/* Last gc --auto failed. Skip this one. */
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 5876583..393c20a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -163,7 +163,7 @@ static void *get_delta(struct object_entry *entry)
delta_buf = diff_delta(base_buf, base_size,
buf, size, &delta_size, 0);
/*
- * We succesfully computed this delta once but dropped it for
+ * We successfully computed this delta once but dropped it for
* memory reasons. Something is very wrong if this time we
* recompute and create a different delta.
*/
diff --git a/builtin/stash.c b/builtin/stash.c
index d913487..4ad3adf 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -483,13 +483,12 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
if (ret)
return -1;
+ /* read back the result of update_index() back from the disk */
discard_cache();
+ read_cache();
}
- if (quiet) {
- if (refresh_and_write_cache(REFRESH_QUIET, 0, 0))
- warning("could not refresh index");
- } else {
+ if (!quiet) {
struct child_process cp = CHILD_PROCESS_INIT;
/*
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4de44f5..d6bc526 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -376,7 +376,7 @@ static int add_worktree(const char *path, const char *refname,
if (opts->checkout) {
cp.argv = NULL;
argv_array_clear(&cp.args);
- argv_array_pushl(&cp.args, "reset", "--hard", NULL);
+ argv_array_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
if (opts->quiet)
argv_array_push(&cp.args, "--quiet");
cp.env = child_env.argv;
diff --git a/bundle.c b/bundle.c
index a85ed3f..99439e0 100644
--- a/bundle.c
+++ b/bundle.c
@@ -249,15 +249,16 @@ out:
/* Write the pack data to bundle_fd */
-static int write_pack_data(int bundle_fd, struct rev_info *revs)
+static int write_pack_data(int bundle_fd, struct rev_info *revs, struct argv_array *pack_options)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
int i;
argv_array_pushl(&pack_objects.args,
- "pack-objects", "--all-progress-implied",
+ "pack-objects",
"--stdout", "--thin", "--delta-base-offset",
NULL);
+ argv_array_pushv(&pack_objects.args, pack_options->argv);
pack_objects.in = -1;
pack_objects.out = bundle_fd;
pack_objects.git_cmd = 1;
@@ -428,7 +429,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
}
int create_bundle(struct repository *r, const char *path,
- int argc, const char **argv)
+ int argc, const char **argv, struct argv_array *pack_options)
{
struct lock_file lock = LOCK_INIT;
int bundle_fd = -1;
@@ -470,7 +471,7 @@ int create_bundle(struct repository *r, const char *path,
goto err;
/* write pack */
- if (write_pack_data(bundle_fd, &revs))
+ if (write_pack_data(bundle_fd, &revs, pack_options))
goto err;
if (!bundle_to_stdout) {
diff --git a/bundle.h b/bundle.h
index 37c37d7..ceab0c7 100644
--- a/bundle.h
+++ b/bundle.h
@@ -1,6 +1,7 @@
#ifndef BUNDLE_H
#define BUNDLE_H
+#include "argv-array.h"
#include "cache.h"
struct ref_list {
@@ -19,7 +20,7 @@ struct bundle_header {
int is_bundle(const char *path, int quiet);
int read_bundle_header(const char *path, struct bundle_header *header);
int create_bundle(struct repository *r, const char *path,
- int argc, const char **argv);
+ int argc, const char **argv, struct argv_array *pack_options);
int verify_bundle(struct repository *r, struct bundle_header *header, int verbose);
#define BUNDLE_VERBOSE 1
int unbundle(struct repository *r, struct bundle_header *header,
diff --git a/cache.h b/cache.h
index 04cabaa..64669a4 100644
--- a/cache.h
+++ b/cache.h
@@ -1451,7 +1451,8 @@ int get_oid_hex(const char *hex, struct object_id *sha1);
int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
/*
- * Convert a binary hash to its hex equivalent. The `_r` variant is reentrant,
+ * Convert a binary hash in "unsigned char []" or an object name in
+ * "struct object_id *" to its hex equivalent. The `_r` variant is reentrant,
* and writes the NUL-terminated output to the buffer `out`, which must be at
* least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for
* convenience.
@@ -1459,13 +1460,12 @@ int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
* The non-`_r` variant returns a static buffer, but uses a ring of 4
* buffers, making it safe to make multiple calls for a single statement, like:
*
- * printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
+ * printf("%s -> %s", hash_to_hex(one), hash_to_hex(two));
+ * printf("%s -> %s", oid_to_hex(one), oid_to_hex(two));
*/
char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *);
-char *sha1_to_hex_r(char *out, const unsigned char *sha1);
char *oid_to_hex_r(char *out, const struct object_id *oid);
char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *); /* static buffer result! */
-char *sha1_to_hex(const unsigned char *sha1); /* same static buffer */
char *hash_to_hex(const unsigned char *hash); /* same static buffer */
char *oid_to_hex(const struct object_id *oid); /* same static buffer */
diff --git a/command-list.txt b/command-list.txt
index a9ac72b..72e435c 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -203,6 +203,7 @@ gitmodules guide
gitnamespaces guide
gitrepository-layout guide
gitrevisions guide
+gitsubmodules guide
gittutorial-2 guide
gittutorial guide
gitworkflows guide
diff --git a/commit-graph.c b/commit-graph.c
index 0aea7b2..79bc564 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -464,7 +464,7 @@ static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
/*
* Return 1 if commit_graph is non-NULL, and 0 otherwise.
*
- * On the first invocation, this function attemps to load the commit
+ * On the first invocation, this function attempts to load the commit
* graph if the_repository is configured to have one.
*/
static int prepare_commit_graph(struct repository *r)
@@ -858,9 +858,6 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
die(_("unable to parse commit %s"),
oid_to_hex(&(*list)->object.oid));
tree = get_commit_tree_oid(*list);
- if (!tree)
- die(_("unable to get tree for %s"),
- oid_to_hex(&(*list)->object.oid));
hashwrite(f, tree->hash, hash_len);
parent = (*list)->parents;
diff --git a/commit.c b/commit.c
index 52036bc..434ec03 100644
--- a/commit.c
+++ b/commit.c
@@ -402,10 +402,22 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
struct commit_graft *graft;
const int tree_entry_len = the_hash_algo->hexsz + 5;
const int parent_entry_len = the_hash_algo->hexsz + 7;
+ struct tree *tree;
if (item->object.parsed)
return 0;
- item->object.parsed = 1;
+
+ if (item->parents) {
+ /*
+ * Presumably this is leftover from an earlier failed parse;
+ * clear it out in preparation for us re-parsing (we'll hit the
+ * same error, but that's good, since it lets our caller know
+ * the result cannot be trusted.
+ */
+ free_commit_list(item->parents);
+ item->parents = NULL;
+ }
+
tail += size;
if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
bufptr[tree_entry_len] != '\n')
@@ -413,7 +425,12 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
if (get_oid_hex(bufptr + 5, &parent) < 0)
return error("bad tree pointer in commit %s",
oid_to_hex(&item->object.oid));
- set_commit_tree(item, lookup_tree(r, &parent));
+ tree = lookup_tree(r, &parent);
+ if (!tree)
+ return error("bad tree pointer %s in commit %s",
+ oid_to_hex(&parent),
+ oid_to_hex(&item->object.oid));
+ set_commit_tree(item, tree);
bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
pptr = &item->parents;
@@ -433,8 +450,11 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
continue;
new_parent = lookup_commit(r, &parent);
- if (new_parent)
- pptr = &commit_list_insert(new_parent, pptr)->next;
+ if (!new_parent)
+ return error("bad parent %s in commit %s",
+ oid_to_hex(&parent),
+ oid_to_hex(&item->object.oid));
+ pptr = &commit_list_insert(new_parent, pptr)->next;
}
if (graft) {
int i;
@@ -443,7 +463,9 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
new_parent = lookup_commit(r,
&graft->parent[i]);
if (!new_parent)
- continue;
+ return error("bad graft parent %s in commit %s",
+ oid_to_hex(&graft->parent[i]),
+ oid_to_hex(&item->object.oid));
pptr = &commit_list_insert(new_parent, pptr)->next;
}
}
@@ -452,6 +474,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
if (check_graph)
load_commit_graph_info(r, item);
+ item->object.parsed = 1;
return 0;
}
diff --git a/commit.h b/commit.h
index f5295ca..221cdaa 100644
--- a/commit.h
+++ b/commit.h
@@ -132,7 +132,7 @@ const void *repo_get_commit_buffer(struct repository *r,
#endif
/*
- * Tell the commit subsytem that we are done with a particular commit buffer.
+ * Tell the commit subsystem that we are done with a particular commit buffer.
* The commit and buffer should be the input and return value, respectively,
* from an earlier call to get_commit_buffer. The buffer may or may not be
* freed by this call; callers should not access the memory afterwards.
diff --git a/compat/mingw.c b/compat/mingw.c
index fe60923..2f4654c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1566,7 +1566,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
while (argv[argc]) argc++;
ALLOC_ARRAY(argv2, argc + 1);
argv2[0] = (char *)cmd; /* full path to the script file */
- memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
+ COPY_ARRAY(&argv2[1], &argv[1], argc);
exec_id = trace2_exec(prog, argv2);
pid = mingw_spawnv(prog, argv2, 1);
if (pid >= 0) {
diff --git a/compat/mingw.h b/compat/mingw.h
index 9ad204c..1a46334 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -558,7 +558,7 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
/*
* A critical section used in the implementation of the spawn
- * functions (mingw_spawnv[p]e()) and waitpid(). Intialised in
+ * functions (mingw_spawnv[p]e()) and waitpid(). Initialised in
* the replacement main() macro below.
*/
extern CRITICAL_SECTION pinfo_cs;
diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h
index 9134349..814845d 100644
--- a/compat/nedmalloc/malloc.c.h
+++ b/compat/nedmalloc/malloc.c.h
@@ -1564,7 +1564,7 @@ static FORCEINLINE void* win32direct_mmap(size_t size) {
return (ptr != 0)? ptr: MFAIL;
}
-/* This function supports releasing coalesed segments */
+/* This function supports releasing coalesced segments */
static FORCEINLINE int win32munmap(void* ptr, size_t size) {
MEMORY_BASIC_INFORMATION minfo;
char* cptr = (char*)ptr;
@@ -1655,7 +1655,7 @@ static FORCEINLINE int win32munmap(void* ptr, size_t size) {
#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
#endif /* HAVE_MMAP && HAVE_MREMAP */
-/* mstate bit set if continguous morecore disabled or failed */
+/* mstate bit set if contiguous morecore disabled or failed */
#define USE_NONCONTIGUOUS_BIT (4U)
/* segment bit set in create_mspace_with_base */
@@ -2485,7 +2485,7 @@ typedef struct malloc_segment* msegmentptr;
Trim support
Fields holding the amount of unused topmost memory that should trigger
- timming, and a counter to force periodic scanning to release unused
+ timing, and a counter to force periodic scanning to release unused
non-topmost segments.
Locking
diff --git a/compat/obstack.h b/compat/obstack.h
index ae36ed6..01e7c81 100644
--- a/compat/obstack.h
+++ b/compat/obstack.h
@@ -79,7 +79,7 @@ change its address during its lifetime.
When the chars burst over a chunk boundary, we allocate a larger
chunk, and then copy the partly formed object from the end of the old
chunk to the beginning of the new larger chunk. We then carry on
-accreting characters to the end of the object as we normally would.
+accrediting characters to the end of the object as we normally would.
A special macro is provided to add a single char at a time to a
growing object. This allows the use of register variables, which
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
index c0d8388..d1bc09e 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -3462,7 +3462,7 @@ build_equiv_class (bitset_t sbcset, const unsigned char *name)
/* This isn't a valid character. */
return REG_ECOLLATE;
- /* Build single byte matcing table for this equivalence class. */
+ /* Build single byte matching table for this equivalence class. */
char_buf[1] = (unsigned char) '\0';
len = weights[idx1 & 0xffffff];
for (ch = 0; ch < SBC_MAX; ++ch)
diff --git a/compat/regex/regex.h b/compat/regex/regex.h
index 4d81358..08a2609 100644
--- a/compat/regex/regex.h
+++ b/compat/regex/regex.h
@@ -322,7 +322,7 @@ typedef enum
/* POSIX regcomp return error codes. (In the order listed in the
standard.) */
REG_BADPAT, /* Invalid pattern. */
- REG_ECOLLATE, /* Inalid collating element. */
+ REG_ECOLLATE, /* Invalid collating element. */
REG_ECTYPE, /* Invalid character class name. */
REG_EESCAPE, /* Trailing backslash. */
REG_ESUBREG, /* Invalid back reference. */
diff --git a/compat/regex/regex_internal.c b/compat/regex/regex_internal.c
index 59bf151..ec51cf3 100644
--- a/compat/regex/regex_internal.c
+++ b/compat/regex/regex_internal.c
@@ -1616,7 +1616,7 @@ free_state (re_dfastate_t *state)
re_free (state);
}
-/* Create the new state which is independ of contexts.
+/* Create the new state which is independent of contexts.
Return the new state if succeeded, otherwise return NULL. */
static re_dfastate_t *
diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c
index 1b5d89f..49358ae 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -2420,7 +2420,7 @@ find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
/* From the node set CUR_NODES, pick up the nodes whose types are
OP_OPEN_SUBEXP and which have corresponding back references in the regular
expression. And register them to use them later for evaluating the
- correspoding back references. */
+ corresponding back references. */
static reg_errcode_t
internal_function
@@ -3347,7 +3347,7 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
dests_node = dests_alloc->dests_node;
dests_ch = dests_alloc->dests_ch;
- /* Initialize transiton table. */
+ /* Initialize transition table. */
state->word_trtable = state->trtable = NULL;
/* At first, group all nodes belonging to `state' into several
diff --git a/compat/vcbuild/find_vs_env.bat b/compat/vcbuild/find_vs_env.bat
index 40194dd..b35d264 100644
--- a/compat/vcbuild/find_vs_env.bat
+++ b/compat/vcbuild/find_vs_env.bat
@@ -18,7 +18,7 @@ REM and MAKE, we must blend these two different worlds. This script
REM attempts to do that.
REM ================================================================
REM This BAT file starts in a plain (non-developer) command prompt,
-REM searches for the "best" commmand prompt setup script, installs
+REM searches for the "best" command prompt setup script, installs
REM it into the current CMD process, and exports the various MSVC
REM environment variables for use by MAKE.
REM
diff --git a/config.h b/config.h
index f0ed464..91fd4c5 100644
--- a/config.h
+++ b/config.h
@@ -4,6 +4,22 @@
#include "hashmap.h"
#include "string-list.h"
+
+/**
+ * The config API gives callers a way to access Git configuration files
+ * (and files which have the same syntax).
+ *
+ * General Usage
+ * -------------
+ *
+ * Config files are parsed linearly, and each variable found is passed to a
+ * caller-provided callback function. The callback function is responsible
+ * for any actions to be taken on the config option, and is free to ignore
+ * some options. It is not uncommon for the configuration to be parsed
+ * several times during the run of a Git program, with different callbacks
+ * picking out different variables useful to themselves.
+ */
+
struct object_id;
/* git_config_parse_key() returns these negated: */
@@ -71,9 +87,34 @@ struct config_options {
} error_action;
};
+/**
+ * A config callback function takes three parameters:
+ *
+ * - the name of the parsed variable. This is in canonical "flat" form: the
+ * section, subsection, and variable segments will be separated by dots,
+ * and the section and variable segments will be all lowercase. E.g.,
+ * `core.ignorecase`, `diff.SomeType.textconv`.
+ *
+ * - the value of the found variable, as a string. If the variable had no
+ * value specified, the value will be NULL (typically this means it
+ * should be interpreted as boolean true).
+ *
+ * - a void pointer passed in by the caller of the config API; this can
+ * contain callback-specific data
+ *
+ * A config callback should return 0 for success, or -1 if the variable
+ * could not be parsed properly.
+ */
typedef int (*config_fn_t)(const char *, const char *, void *);
+
int git_default_config(const char *, const char *, void *);
+
+/**
+ * Read a specific file in git-config format.
+ * This function takes the same callback and data parameters as `git_config`.
+ */
int git_config_from_file(config_fn_t fn, const char *, void *);
+
int git_config_from_file_with_options(config_fn_t fn, const char *,
void *,
const struct config_options *);
@@ -88,34 +129,157 @@ void git_config_push_parameter(const char *text);
int git_config_from_parameters(config_fn_t fn, void *data);
void read_early_config(config_fn_t cb, void *data);
void read_very_early_config(config_fn_t cb, void *data);
+
+/**
+ * Most programs will simply want to look up variables in all config files
+ * that Git knows about, using the normal precedence rules. To do this,
+ * call `git_config` with a callback function and void data pointer.
+ *
+ * `git_config` will read all config sources in order of increasing
+ * priority. Thus a callback should typically overwrite previously-seen
+ * entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
+ * repo-specific `.git/config` contain `color.ui`, the config machinery
+ * will first feed the user-wide one to the callback, and then the
+ * repo-specific one; by overwriting, the higher-priority repo-specific
+ * value is left at the end).
+ */
void git_config(config_fn_t fn, void *);
+
+/**
+ * Lets the caller examine config while adjusting some of the default
+ * behavior of `git_config`. It should almost never be used by "regular"
+ * Git code that is looking up configuration variables.
+ * It is intended for advanced callers like `git-config`, which are
+ * intentionally tweaking the normal config-lookup process.
+ * It takes two extra parameters:
+ *
+ * - `config_source`
+ * If this parameter is non-NULL, it specifies the source to parse for
+ * configuration, rather than looking in the usual files. See `struct
+ * git_config_source` in `config.h` for details. Regular `git_config` defaults
+ * to `NULL`.
+ *
+ * - `opts`
+ * Specify options to adjust the behavior of parsing config files. See `struct
+ * config_options` in `config.h` for details. As an example: regular `git_config`
+ * sets `opts.respect_includes` to `1` by default.
+ */
int config_with_options(config_fn_t fn, void *,
struct git_config_source *config_source,
const struct config_options *opts);
+
+/**
+ * Value Parsing Helpers
+ * ---------------------
+ *
+ * The following helper functions aid in parsing string values
+ */
+
int git_parse_ssize_t(const char *, ssize_t *);
int git_parse_ulong(const char *, unsigned long *);
+
+/**
+ * Same as `git_config_bool`, except that it returns -1 on error rather
+ * than dying.
+ */
int git_parse_maybe_bool(const char *);
+
+/**
+ * Parse the string to an integer, including unit factors. Dies on error;
+ * otherwise, returns the parsed result.
+ */
int git_config_int(const char *, const char *);
+
int64_t git_config_int64(const char *, const char *);
+
+/**
+ * Identical to `git_config_int`, but for unsigned longs.
+ */
unsigned long git_config_ulong(const char *, const char *);
+
ssize_t git_config_ssize_t(const char *, const char *);
+
+/**
+ * Same as `git_config_bool`, except that integers are returned as-is, and
+ * an `is_bool` flag is unset.
+ */
int git_config_bool_or_int(const char *, const char *, int *);
+
+/**
+ * Parse a string into a boolean value, respecting keywords like "true" and
+ * "false". Integer values are converted into true/false values (when they
+ * are non-zero or zero, respectively). Other values cause a die(). If
+ * parsing is successful, the return value is the result.
+ */
int git_config_bool(const char *, const char *);
+
+/**
+ * Allocates and copies the value string into the `dest` parameter; if no
+ * string is given, prints an error message and returns -1.
+ */
int git_config_string(const char **, const char *, const char *);
+
+/**
+ * Similar to `git_config_string`, but expands `~` or `~user` into the
+ * user's home directory when found at the beginning of the path.
+ */
int git_config_pathname(const char **, const char *, const char *);
+
int git_config_expiry_date(timestamp_t *, const char *, const char *);
int git_config_color(char *, const char *, const char *);
int git_config_set_in_file_gently(const char *, const char *, const char *);
+
+/**
+ * write config values to a specific config file, takes a key/value pair as
+ * parameter.
+ */
void git_config_set_in_file(const char *, const char *, const char *);
+
int git_config_set_gently(const char *, const char *);
+
+/**
+ * write config values to `.git/config`, takes a key/value pair as parameter.
+ */
void git_config_set(const char *, const char *);
+
int git_config_parse_key(const char *, char **, int *);
int git_config_key_is_valid(const char *key);
int git_config_set_multivar_gently(const char *, const char *, const char *, int);
void git_config_set_multivar(const char *, const char *, const char *, int);
int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
+
+/**
+ * takes four parameters:
+ *
+ * - the name of the file, as a string, to which key/value pairs will be written.
+ *
+ * - the name of key, as a string. This is in canonical "flat" form: the section,
+ * subsection, and variable segments will be separated by dots, and the section
+ * and variable segments will be all lowercase.
+ * E.g., `core.ignorecase`, `diff.SomeType.textconv`.
+ *
+ * - the value of the variable, as a string. If value is equal to NULL, it will
+ * remove the matching key from the config file.
+ *
+ * - the value regex, as a string. It will disregard key/value pairs where value
+ * does not match.
+ *
+ * - a multi_replace value, as an int. If value is equal to zero, nothing or only
+ * one matching key/value is replaced, else all matching key/values (regardless
+ * how many) are removed, before the new pair is written.
+ *
+ * It returns 0 on success.
+ */
void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
+
+/**
+ * rename or remove sections in the config file
+ * parameters `old_name` and `new_name`
+ * If NULL is passed through `new_name` parameter,
+ * the section will be removed from the config file.
+ */
int git_config_rename_section(const char *, const char *);
+
int git_config_rename_section_in_file(const char *, const char *, const char *);
int git_config_copy_section(const char *, const char *);
int git_config_copy_section_in_file(const char *, const char *, const char *);
@@ -142,6 +306,30 @@ enum config_scope current_config_scope(void);
const char *current_config_origin_type(void);
const char *current_config_name(void);
+/**
+ * Include Directives
+ * ------------------
+ *
+ * By default, the config parser does not respect include directives.
+ * However, a caller can use the special `git_config_include` wrapper
+ * callback to support them. To do so, you simply wrap your "real" callback
+ * function and data pointer in a `struct config_include_data`, and pass
+ * the wrapper to the regular config-reading functions. For example:
+ *
+ * -------------------------------------------
+ * int read_file_with_include(const char *file, config_fn_t fn, void *data)
+ * {
+ * struct config_include_data inc = CONFIG_INCLUDE_INIT;
+ * inc.fn = fn;
+ * inc.data = data;
+ * return git_config_from_file(git_config_include, file, &inc);
+ * }
+ * -------------------------------------------
+ *
+ * `git_config` respects includes automatically. The lower-level
+ * `git_config_from_file` does not.
+ *
+ */
struct config_include_data {
int depth;
config_fn_t fn;
@@ -169,6 +357,33 @@ int parse_config_key(const char *var,
const char **subsection, int *subsection_len,
const char **key);
+/**
+ * Custom Configsets
+ * -----------------
+ *
+ * A `config_set` can be used to construct an in-memory cache for
+ * config-like files that the caller specifies (i.e., files like `.gitmodules`,
+ * `~/.gitconfig` etc.). For example,
+ *
+ * ----------------------------------------
+ * struct config_set gm_config;
+ * git_configset_init(&gm_config);
+ * int b;
+ * //we add config files to the config_set
+ * git_configset_add_file(&gm_config, ".gitmodules");
+ * git_configset_add_file(&gm_config, ".gitmodules_alt");
+ *
+ * if (!git_configset_get_bool(gm_config, "submodule.frotz.ignore", &b)) {
+ * //hack hack hack
+ * }
+ *
+ * when we are done with the configset:
+ * git_configset_clear(&gm_config);
+ * ----------------------------------------
+ *
+ * Configset API provides functions for the above mentioned work flow
+ */
+
struct config_set_element {
struct hashmap_entry ent;
char *key;
@@ -197,16 +412,47 @@ struct config_set {
struct configset_list list;
};
+/**
+ * Initializes the config_set `cs`.
+ */
void git_configset_init(struct config_set *cs);
+
+/**
+ * Parses the file and adds the variable-value pairs to the `config_set`,
+ * dies if there is an error in parsing the file. Returns 0 on success, or
+ * -1 if the file does not exist or is inaccessible. The user has to decide
+ * if he wants to free the incomplete configset or continue using it when
+ * the function returns -1.
+ */
int git_configset_add_file(struct config_set *cs, const char *filename);
+
+/**
+ * Finds and returns the value list, sorted in order of increasing priority
+ * for the configuration variable `key` and config set `cs`. When the
+ * configuration variable `key` is not found, returns NULL. The caller
+ * should not free or modify the returned pointer, as it is owned by the cache.
+ */
const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
+
+/**
+ * Clears `config_set` structure, removes all saved variable-value pairs.
+ */
void git_configset_clear(struct config_set *cs);
/*
* These functions return 1 if not found, and 0 if found, leaving the found
* value in the 'dest' pointer.
*/
+
+/*
+ * Finds the highest-priority value for the configuration variable `key`
+ * and config set `cs`, stores the pointer to it in `value` and returns 0.
+ * When the configuration variable `key` is not found, returns 1 without
+ * touching `value`. The caller should not free or modify `value`, as it
+ * is owned by the cache.
+ */
int git_configset_get_value(struct config_set *cs, const char *key, const char **dest);
+
int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
@@ -240,17 +486,94 @@ int repo_config_get_maybe_bool(struct repository *repo,
int repo_config_get_pathname(struct repository *repo,
const char *key, const char **dest);
+/**
+ * Querying For Specific Variables
+ * -------------------------------
+ *
+ * For programs wanting to query for specific variables in a non-callback
+ * manner, the config API provides two functions `git_config_get_value`
+ * and `git_config_get_value_multi`. They both read values from an internal
+ * cache generated previously from reading the config files.
+ */
+
+/**
+ * Finds the highest-priority value for the configuration variable `key`,
+ * stores the pointer to it in `value` and returns 0. When the
+ * configuration variable `key` is not found, returns 1 without touching
+ * `value`. The caller should not free or modify `value`, as it is owned
+ * by the cache.
+ */
int git_config_get_value(const char *key, const char **value);
+
+/**
+ * Finds and returns the value list, sorted in order of increasing priority
+ * for the configuration variable `key`. When the configuration variable
+ * `key` is not found, returns NULL. The caller should not free or modify
+ * the returned pointer, as it is owned by the cache.
+ */
const struct string_list *git_config_get_value_multi(const char *key);
+
+/**
+ * Resets and invalidates the config cache.
+ */
void git_config_clear(void);
+
+/**
+ * Allocates and copies the retrieved string into the `dest` parameter for
+ * the configuration variable `key`; if NULL string is given, prints an
+ * error message and returns -1. When the configuration variable `key` is
+ * not found, returns 1 without touching `dest`.
+ */
int git_config_get_string_const(const char *key, const char **dest);
+
+/**
+ * Similar to `git_config_get_string_const`, except that retrieved value
+ * copied into the `dest` parameter is a mutable string.
+ */
int git_config_get_string(const char *key, char **dest);
+
+/**
+ * Finds and parses the value to an integer for the configuration variable
+ * `key`. Dies on error; otherwise, stores the value of the parsed integer in
+ * `dest` and returns 0. When the configuration variable `key` is not found,
+ * returns 1 without touching `dest`.
+ */
int git_config_get_int(const char *key, int *dest);
+
+/**
+ * Similar to `git_config_get_int` but for unsigned longs.
+ */
int git_config_get_ulong(const char *key, unsigned long *dest);
+
+/**
+ * Finds and parses the value into a boolean value, for the configuration
+ * variable `key` respecting keywords like "true" and "false". Integer
+ * values are converted into true/false values (when they are non-zero or
+ * zero, respectively). Other values cause a die(). If parsing is successful,
+ * stores the value of the parsed result in `dest` and returns 0. When the
+ * configuration variable `key` is not found, returns 1 without touching
+ * `dest`.
+ */
int git_config_get_bool(const char *key, int *dest);
+
+/**
+ * Similar to `git_config_get_bool`, except that integers are copied as-is,
+ * and `is_bool` flag is unset.
+ */
int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
+
+/**
+ * Similar to `git_config_get_bool`, except that it returns -1 on error
+ * rather than dying.
+ */
int git_config_get_maybe_bool(const char *key, int *dest);
+
+/**
+ * Similar to `git_config_get_string`, but expands `~` or `~user` into
+ * the user's home directory when found at the beginning of the path.
+ */
int git_config_get_pathname(const char *key, const char **dest);
+
int git_config_get_index_threads(int *dest);
int git_config_get_untracked_cache(void);
int git_config_get_split_index(void);
@@ -270,7 +593,19 @@ struct key_value_info {
enum config_scope scope;
};
+/**
+ * First prints the error message specified by the caller in `err` and then
+ * dies printing the line number and the file name of the highest priority
+ * value for the configuration variable `key`.
+ */
NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+
+/**
+ * Helper function which formats the die error message according to the
+ * parameters entered. Used by `git_die_config()`. It can be used by callers
+ * handling `git_config_get_value_multi()` to print the correct error message
+ * for the desired value.
+ */
NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
#define LOOKUP_CONFIG(mapping, var) \
diff --git a/configure.ac b/configure.ac
index a43b476..66aedb9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,7 +85,7 @@ AC_DEFUN([GIT_PARSE_WITH],
# GIT_PARSE_WITH_SET_MAKE_VAR(WITHNAME, VAR, HELP_TEXT)
# -----------------------------------------------------
-# Set VAR to the value specied by --with-WITHNAME.
+# Set VAR to the value specified by --with-WITHNAME.
# No verification of arguments is performed, but warnings are issued
# if either 'yes' or 'no' is specified.
# HELP_TEXT is presented when --help is called.
@@ -844,12 +844,61 @@ AC_MSG_CHECKING([for old iconv()])
AC_COMPILE_IFELSE([OLDICONVTEST_SRC],
[AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_OLD_ICONV, 1)
OLD_ICONV=UnfortunatelyYes])
GIT_UNSTASH_FLAGS($ICONVDIR)
GIT_CONF_SUBST([OLD_ICONV])
+#
+# Define ICONV_OMITS_BOM if you are on a system which
+# iconv omits bom for utf-{16,32}
+if test -z "$NO_ICONV"; then
+AC_CACHE_CHECK([whether iconv omits bom for utf-16 and utf-32],
+ [ac_cv_iconv_omits_bom],
+[
+old_LIBS="$LIBS"
+if test -n "$NEEDS_LIBICONV"; then
+ LIBS="$LIBS -liconv"
+fi
+
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
+ #include <iconv.h>
+ #ifdef HAVE_OLD_ICONV
+ typedef const char *iconv_ibp;
+ #else
+ typedef char *iconv_ibp;
+ #endif
+ ],
+ [[
+ int v;
+ iconv_t conv;
+ char in[] = "a"; iconv_ibp pin = in;
+ char out[20] = ""; char *pout = out;
+ size_t isz = sizeof in;
+ size_t osz = sizeof out;
+
+ conv = iconv_open("UTF-16", "UTF-8");
+ iconv(conv, &pin, &isz, &pout, &osz);
+ iconv_close(conv);
+ v = (unsigned char)(out[0]) + (unsigned char)(out[1]);
+ return v != 0xfe + 0xff;
+ ]])],
+ [ac_cv_iconv_omits_bom=no],
+ [ac_cv_iconv_omits_bom=yes])
+
+LIBS="$old_LIBS"
+])
+if test "x$ac_cv_iconv_omits_bom" = xyes; then
+ ICONV_OMITS_BOM=Yes
+else
+ ICONV_OMITS_BOM=
+fi
+GIT_CONF_SUBST([ICONV_OMITS_BOM])
+fi
+
## Checks for typedefs, structures, and compiler characteristics.
AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
#
diff --git a/connected.c b/connected.c
index 36c4e5d..c337f5f 100644
--- a/connected.c
+++ b/connected.c
@@ -62,7 +62,8 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
* received the objects pointed to by each wanted ref.
*/
do {
- if (!repo_has_object_file(the_repository, &oid))
+ if (!repo_has_object_file_with_flags(the_repository, &oid,
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
return 1;
} while (!fn(cb_data, &oid));
return 0;
diff --git a/contrib/coccinelle/commit.cocci b/contrib/coccinelle/commit.cocci
index d034533..778e470 100644
--- a/contrib/coccinelle/commit.cocci
+++ b/contrib/coccinelle/commit.cocci
@@ -20,7 +20,7 @@ expression s;
+ set_commit_tree(c, s)
...>}
-// These excluded functions must access c->maybe_tree direcly.
+// These excluded functions must access c->maybe_tree directly.
// Note that if c->maybe_tree is written somewhere outside of these
// functions, then the recommended transformation will be bogus with
// repo_get_commit_tree() on the LHS.
diff --git a/contrib/coccinelle/object_id.cocci b/contrib/coccinelle/object_id.cocci
index 3e536a9..ddf4f22 100644
--- a/contrib/coccinelle/object_id.cocci
+++ b/contrib/coccinelle/object_id.cocci
@@ -13,38 +13,6 @@ struct object_id *OIDPTR;
@@
struct object_id OID;
@@
-- sha1_to_hex(OID.hash)
-+ oid_to_hex(&OID)
-
-@@
-identifier f != oid_to_hex;
-struct object_id *OIDPTR;
-@@
- f(...) {<...
-- sha1_to_hex(OIDPTR->hash)
-+ oid_to_hex(OIDPTR)
- ...>}
-
-@@
-expression E;
-struct object_id OID;
-@@
-- sha1_to_hex_r(E, OID.hash)
-+ oid_to_hex_r(E, &OID)
-
-@@
-identifier f != oid_to_hex_r;
-expression E;
-struct object_id *OIDPTR;
-@@
- f(...) {<...
-- sha1_to_hex_r(E, OIDPTR->hash)
-+ oid_to_hex_r(E, OIDPTR)
- ...>}
-
-@@
-struct object_id OID;
-@@
- hashclr(OID.hash)
+ oidclr(&OID)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 00fbe6c..67705da 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -550,7 +550,7 @@ __git_index_files ()
esc_idx, 1)
} else if (esc == "n") {
# Uh-oh, a newline character.
- # We cant reliably put a pathname
+ # We cannot reliably put a pathname
# containing a newline into COMPREPLY,
# and the newline would create a mess.
# Skip this path.
@@ -565,7 +565,7 @@ __git_index_files ()
}
}
# Drop closing double quote, if there is one.
- # (There isnt any if this is a directory, as it was
+ # (There is not any if this is a directory, as it was
# already stripped with the trailing path components.)
if (substr(p, length(p), 1) == "\"")
out = out substr(p, 1, length(p) - 1)
@@ -2043,6 +2043,10 @@ _git_rebase ()
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
return
;;
+ --onto=*)
+ __git_complete_refs --cur="${cur##--onto=}"
+ return
+ ;;
--*)
__gitcomp_builtin rebase "" \
"$__git_rebase_interactive_inprogress_options"
@@ -2843,6 +2847,7 @@ _git_svn ()
--log-window-size= --no-checkout --quiet
--repack-flags --use-log-author --localtime
--add-author-from
+ --recursive
--ignore-paths= --include-paths= $remote_opts
"
local init_opts="
diff --git a/contrib/hooks/multimail/git_multimail.py b/contrib/hooks/multimail/git_multimail.py
index 8823399..f563be8 100755
--- a/contrib/hooks/multimail/git_multimail.py
+++ b/contrib/hooks/multimail/git_multimail.py
@@ -95,7 +95,7 @@ if PYTHON3:
unicode = str
def write_str(f, msg):
- # Try outputing with the default encoding. If it fails,
+ # Try outputting with the default encoding. If it fails,
# try UTF-8.
try:
f.buffer.write(msg.encode(sys.getdefaultencoding()))
@@ -2129,7 +2129,7 @@ class SMTPMailer(Mailer):
# equivalent to
# self.smtp.ehlo()
# self.smtp.starttls()
- # with acces to the ssl layer
+ # with access to the ssl layer
self.smtp.ehlo()
if not self.smtp.has_extn("starttls"):
raise smtplib.SMTPException("STARTTLS extension not supported by server")
@@ -2148,7 +2148,7 @@ class SMTPMailer(Mailer):
cert_reqs=ssl.CERT_NONE
)
self.environment.get_logger().error(
- '*** Warning, the server certificat is not verified (smtp) ***\n'
+ '*** Warning, the server certificate is not verified (smtp) ***\n'
'*** set the option smtpCACerts ***\n'
)
if not hasattr(self.smtp.sock, "read"):
@@ -3189,7 +3189,7 @@ class ProjectdescEnvironmentMixin(Environment):
self.COMPUTED_KEYS += ['projectdesc']
def get_projectdesc(self):
- """Return a one-line descripition of the project."""
+ """Return a one-line description of the project."""
git_dir = get_git_dir()
try:
diff --git a/contrib/hooks/multimail/post-receive.example b/contrib/hooks/multimail/post-receive.example
index b9bb118..0f98c5a 100755
--- a/contrib/hooks/multimail/post-receive.example
+++ b/contrib/hooks/multimail/post-receive.example
@@ -56,7 +56,7 @@ config = git_multimail.Config('multimailhook')
# Set some Git configuration variables. Equivalent to passing var=val
# to "git -c var=val" each time git is called, or to adding the
-# configuration in .git/config (must come before instanciating the
+# configuration in .git/config (must come before instantiating the
# environment) :
#git_multimail.Config.add_config_parameters('multimailhook.commitEmailFormat=html')
#git_multimail.Config.add_config_parameters(('user.name=foo', 'user.email=foo@example.com'))
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 8747b84..ff565eb 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -329,7 +329,7 @@ generate_update_branch_email()
#
# git rev-parse --not --all | grep -v $(git rev-parse $refname)
#
- # Get's us to something pretty safe (apart from the small time
+ # Gets us to something pretty safe (apart from the small time
# between refname being read, and git rev-parse running - for that,
# I give up)
#
diff --git a/contrib/hooks/update-paranoid b/contrib/hooks/update-paranoid
index d18b317..0092d67 100755
--- a/contrib/hooks/update-paranoid
+++ b/contrib/hooks/update-paranoid
@@ -49,7 +49,7 @@ opcode.
Repository sections are matched on the basename of the repository
(after removing the .git suffix).
-The opcode abbrevations are:
+The opcode abbreviations are:
C: create new ref
D: delete existing ref
diff --git a/contrib/mw-to-git/.perlcriticrc b/contrib/mw-to-git/.perlcriticrc
index 158958d..b733326 100644
--- a/contrib/mw-to-git/.perlcriticrc
+++ b/contrib/mw-to-git/.perlcriticrc
@@ -14,7 +14,7 @@
# This rule states that each system call should have its return value checked
# The problem is that it includes the print call. Checking every print call's
-# return value would be harmful to the code readabilty.
+# return value would be harmful to the code readability.
# This configuration keeps all default function but print.
[InputOutput::RequireCheckedSyscalls]
functions = open say close
diff --git a/contrib/mw-to-git/git-remote-mediawiki.perl b/contrib/mw-to-git/git-remote-mediawiki.perl
index af9cbc9..d8ff2e6 100755
--- a/contrib/mw-to-git/git-remote-mediawiki.perl
+++ b/contrib/mw-to-git/git-remote-mediawiki.perl
@@ -79,7 +79,7 @@ chomp($export_media);
$export_media = !($export_media eq 'false');
my $wiki_login = run_git("config --get remote.${remotename}.mwLogin");
-# Note: mwPassword is discourraged. Use the credential system instead.
+# Note: mwPassword is discouraged. Use the credential system instead.
my $wiki_passwd = run_git("config --get remote.${remotename}.mwPassword");
my $wiki_domain = run_git("config --get remote.${remotename}.mwDomain");
chomp($wiki_login);
diff --git a/contrib/mw-to-git/t/install-wiki/db_install.php b/contrib/mw-to-git/t/install-wiki/db_install.php
index 0f3f4e0..b033849 100644
--- a/contrib/mw-to-git/t/install-wiki/db_install.php
+++ b/contrib/mw-to-git/t/install-wiki/db_install.php
@@ -24,7 +24,7 @@ $url = 'http://localhost:'.$port.'/wiki/mw-config/index.php';
$db_dir = urlencode($tmp);
$tmp_cookie = tempnam($tmp, "COOKIE_");
/*
- * Fetchs a page with cURL.
+ * Fetches a page with cURL.
*/
function get($page_name = "") {
$curl = curl_init();
diff --git a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
index cfbfe7d..9106833 100755
--- a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
+++ b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
@@ -143,7 +143,7 @@ test_expect_success 'Git clone works with one specific page cloned ' '
test_expect_success 'Git clone works with multiple specific page cloned ' '
wiki_reset &&
wiki_editpage foo "I will be there" false &&
- wiki_editpage bar "I will not disapear" false &&
+ wiki_editpage bar "I will not disappear" false &&
wiki_editpage namnam "I be erased" false &&
wiki_editpage nyancat "nyan nyan nyan you will not erase me" false &&
wiki_delete_page namnam &&
diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh
index 6546294..3948a00 100755
--- a/contrib/mw-to-git/t/test-gitmw-lib.sh
+++ b/contrib/mw-to-git/t/test-gitmw-lib.sh
@@ -279,7 +279,7 @@ start_lighttpd () {
"$LIGHTTPD_DIR"/lighttpd -f "$WEB"/lighttpd.conf
if test $? -ne 0 ; then
- echo "Could not execute http deamon lighttpd"
+ echo "Could not execute http daemon lighttpd"
exit 1
fi
}
diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
index 50c6a4f..8a3cee6 100755
--- a/contrib/svn-fe/svnrdump_sim.py
+++ b/contrib/svn-fe/svnrdump_sim.py
@@ -54,7 +54,7 @@ if __name__ == "__main__":
print("usage: %s dump URL -rLOWER:UPPER")
sys.exit(1)
if not sys.argv[1] == 'dump':
- raise NotImplementedError('only "dump" is suppported.')
+ raise NotImplementedError('only "dump" is supported.')
url = sys.argv[2]
r = ('0', 'HEAD')
if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
diff --git a/convert.c b/convert.c
index 25ac525..797e0bd 100644
--- a/convert.c
+++ b/convert.c
@@ -270,8 +270,12 @@ static int will_convert_lf_to_crlf(struct text_stat *stats,
static int validate_encoding(const char *path, const char *enc,
const char *data, size_t len, int die_on_error)
{
+ const char *stripped;
+
/* We only check for UTF here as UTF?? can be an alias for UTF-?? */
- if (istarts_with(enc, "UTF")) {
+ if (skip_iprefix(enc, "UTF", &stripped)) {
+ skip_prefix(stripped, "-", &stripped);
+
/*
* Check for detectable errors in UTF encodings
*/
@@ -285,15 +289,10 @@ static int validate_encoding(const char *path, const char *enc,
*/
const char *advise_msg = _(
"The file '%s' contains a byte order "
- "mark (BOM). Please use UTF-%s as "
+ "mark (BOM). Please use UTF-%.*s as "
"working-tree-encoding.");
- const char *stripped = NULL;
- char *upper = xstrdup_toupper(enc);
- upper[strlen(upper)-2] = '\0';
- if (skip_prefix(upper, "UTF", &stripped))
- skip_prefix(stripped, "-", &stripped);
- advise(advise_msg, path, stripped);
- free(upper);
+ int stripped_len = strlen(stripped) - strlen("BE");
+ advise(advise_msg, path, stripped_len, stripped);
if (die_on_error)
die(error_msg, path, enc);
else {
@@ -308,12 +307,7 @@ static int validate_encoding(const char *path, const char *enc,
"mark (BOM). Please use UTF-%sBE or UTF-%sLE "
"(depending on the byte order) as "
"working-tree-encoding.");
- const char *stripped = NULL;
- char *upper = xstrdup_toupper(enc);
- if (skip_prefix(upper, "UTF", &stripped))
- skip_prefix(stripped, "-", &stripped);
advise(advise_msg, path, stripped, stripped);
- free(upper);
if (die_on_error)
die(error_msg, path, enc);
else {
@@ -418,7 +412,7 @@ static int encode_to_git(const char *path, const char *src, size_t src_len,
if (!dst) {
/*
* We could add the blob "as-is" to Git. However, on checkout
- * we would try to reencode to the original encoding. This
+ * we would try to re-encode to the original encoding. This
* would fail and we would leave the user with a messed-up
* working tree. Let's try to avoid this by screaming loud.
*/
diff --git a/daemon.c b/daemon.c
index 9d2e0d2..fd669ed 100644
--- a/daemon.c
+++ b/daemon.c
@@ -598,7 +598,7 @@ static void canonicalize_client(struct strbuf *out, const char *in)
* Read the host as supplied by the client connection.
*
* Returns a pointer to the character after the NUL byte terminating the host
- * arguemnt, or 'extra_args' if there is no host arguemnt.
+ * argument, or 'extra_args' if there is no host argument.
*/
static char *parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
{
@@ -652,7 +652,7 @@ static void parse_extra_args(struct hostinfo *hi, struct argv_array *env,
* service that will be run.
*
* If there ends up being a particular arg in the future that
- * git-daemon needs to parse specificly (like the 'host' arg)
+ * git-daemon needs to parse specifically (like the 'host' arg)
* then it can be parsed here and not added to 'git_protocol'.
*/
if (*arg) {
diff --git a/diff.c b/diff.c
index afe4400..8e2914c 100644
--- a/diff.c
+++ b/diff.c
@@ -2495,22 +2495,6 @@ static void pprint_rename(struct strbuf *name, const char *a, const char *b)
}
}
-struct diffstat_t {
- int nr;
- int alloc;
- struct diffstat_file {
- char *from_name;
- char *name;
- char *print_name;
- const char *comments;
- unsigned is_unmerged:1;
- unsigned is_binary:1;
- unsigned is_renamed:1;
- unsigned is_interesting:1;
- uintmax_t added, deleted;
- } **files;
-};
-
static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
const char *name_a,
const char *name_b)
@@ -2551,7 +2535,7 @@ static int scale_linear(int it, int width, int max_change)
/*
* make sure that at least one '-' or '+' is printed if
* there is any change to this path. The easiest way is to
- * scale linearly as if the alloted width is one column shorter
+ * scale linearly as if the allotted width is one column shorter
* than it is, and then add 1 to the result.
*/
return 1 + (it * (width - 1) / max_change);
@@ -3157,7 +3141,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o
gather_dirstat(options, &dir, changed, "", 0);
}
-static void free_diffstat_info(struct diffstat_t *diffstat)
+void free_diffstat_info(struct diffstat_t *diffstat)
{
int i;
for (i = 0; i < diffstat->nr; i++) {
@@ -3196,7 +3180,7 @@ static int is_conflict_marker(const char *line, int marker_size, unsigned long l
for (cnt = 1; cnt < marker_size; cnt++)
if (line[cnt] != firstchar)
return 0;
- /* line[1] thru line[marker_size-1] are same as firstchar */
+ /* line[1] through line[marker_size-1] are same as firstchar */
if (len < marker_size + 1 || !isspace(line[marker_size]))
return 0;
return 1;
@@ -6283,12 +6267,7 @@ void diff_flush(struct diff_options *options)
dirstat_by_line) {
struct diffstat_t diffstat;
- memset(&diffstat, 0, sizeof(struct diffstat_t));
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- if (check_pair_status(p))
- diff_flush_stat(p, options, &diffstat);
- }
+ compute_diffstat(options, &diffstat, q);
if (output_format & DIFF_FORMAT_NUMSTAT)
show_numstat(&diffstat, options);
if (output_format & DIFF_FORMAT_DIFFSTAT)
@@ -6621,6 +6600,20 @@ static int is_submodule_ignored(const char *path, struct diff_options *options)
return ignored;
}
+void compute_diffstat(struct diff_options *options,
+ struct diffstat_t *diffstat,
+ struct diff_queue_struct *q)
+{
+ int i;
+
+ memset(diffstat, 0, sizeof(struct diffstat_t));
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ if (check_pair_status(p))
+ diff_flush_stat(p, options, diffstat);
+ }
+}
+
void diff_addremove(struct diff_options *options,
int addremove, unsigned mode,
const struct object_id *oid,
diff --git a/diff.h b/diff.h
index 7f8f024..d986ddc 100644
--- a/diff.h
+++ b/diff.h
@@ -245,6 +245,22 @@ void diff_emit_submodule_error(struct diff_options *o, const char *err);
void diff_emit_submodule_pipethrough(struct diff_options *o,
const char *line, int len);
+struct diffstat_t {
+ int nr;
+ int alloc;
+ struct diffstat_file {
+ char *from_name;
+ char *name;
+ char *print_name;
+ const char *comments;
+ unsigned is_unmerged:1;
+ unsigned is_binary:1;
+ unsigned is_renamed:1;
+ unsigned is_interesting:1;
+ uintmax_t added, deleted;
+ } **files;
+};
+
enum color_diff {
DIFF_RESET = 0,
DIFF_CONTEXT = 1,
@@ -334,6 +350,10 @@ void diff_change(struct diff_options *,
struct diff_filepair *diff_unmerge(struct diff_options *, const char *path);
+void compute_diffstat(struct diff_options *options, struct diffstat_t *diffstat,
+ struct diff_queue_struct *q);
+void free_diffstat_info(struct diffstat_t *diffstat);
+
#define DIFF_SETUP_REVERSE 1
#define DIFF_SETUP_USE_SIZE_CACHE 4
diff --git a/dir.c b/dir.c
index 61f559f9..9047373 100644
--- a/dir.c
+++ b/dir.c
@@ -2489,7 +2489,7 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
* wanted anyway
*/
continue;
- /* fall thru */
+ /* fall through */
} else if (S_ISDIR(st.st_mode)) {
if (!remove_dir_recurse(path, flag, &kept_down))
continue; /* happy */
diff --git a/fetch-pack.c b/fetch-pack.c
index f80e2d1..ba92587 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -673,7 +673,8 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
struct object *o;
if (!has_object_file_with_flags(&ref->old_oid,
- OBJECT_INFO_QUICK))
+ OBJECT_INFO_QUICK |
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
o = parse_object(the_repository, &ref->old_oid);
if (!o)
@@ -934,8 +935,15 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
struct object_id oid;
const char *agent_feature;
int agent_len;
- struct fetch_negotiator negotiator;
- fetch_negotiator_init(r, &negotiator);
+ struct fetch_negotiator negotiator_alloc;
+ struct fetch_negotiator *negotiator;
+
+ if (args->no_dependents) {
+ negotiator = NULL;
+ } else {
+ negotiator = &negotiator_alloc;
+ fetch_negotiator_init(r, negotiator);
+ }
sort_ref_list(&ref, ref_compare_name);
QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -1022,7 +1030,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die(_("Server does not support --deepen"));
if (!args->no_dependents) {
- mark_complete_and_common_ref(&negotiator, args, &ref);
+ mark_complete_and_common_ref(negotiator, args, &ref);
filter_refs(args, &ref, sought, nr_sought);
if (everything_local(args, &ref)) {
packet_flush(fd[1]);
@@ -1031,7 +1039,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
} else {
filter_refs(args, &ref, sought, nr_sought);
}
- if (find_common(&negotiator, args, fd, &oid, ref) < 0)
+ if (find_common(negotiator, args, fd, &oid, ref) < 0)
if (!args->keep_pack)
/* When cloning, it is not unusual to have
* no common commit.
@@ -1051,7 +1059,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die(_("git fetch-pack: fetch failed."));
all_done:
- negotiator.release(&negotiator);
+ if (negotiator)
+ negotiator->release(negotiator);
return ref;
}
@@ -1269,7 +1278,8 @@ static int process_acks(struct fetch_negotiator *negotiator,
struct commit *commit;
oidset_insert(common, &oid);
commit = lookup_commit(the_repository, &oid);
- negotiator->ack(negotiator, commit);
+ if (negotiator)
+ negotiator->ack(negotiator, commit);
}
continue;
}
@@ -1421,8 +1431,16 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct packet_reader reader;
int in_vain = 0, negotiation_started = 0;
int haves_to_send = INITIAL_FLUSH;
- struct fetch_negotiator negotiator;
- fetch_negotiator_init(r, &negotiator);
+ struct fetch_negotiator negotiator_alloc;
+ struct fetch_negotiator *negotiator;
+
+ if (args->no_dependents) {
+ negotiator = NULL;
+ } else {
+ negotiator = &negotiator_alloc;
+ fetch_negotiator_init(r, negotiator);
+ }
+
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE |
PACKET_READ_DIE_ON_ERR_PACKET);
@@ -1446,15 +1464,15 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
/* Filter 'ref' by 'sought' and those that aren't local */
if (!args->no_dependents) {
- mark_complete_and_common_ref(&negotiator, args, &ref);
+ mark_complete_and_common_ref(negotiator, args, &ref);
filter_refs(args, &ref, sought, nr_sought);
if (everything_local(args, &ref))
state = FETCH_DONE;
else
state = FETCH_SEND_REQUEST;
- mark_tips(&negotiator, args->negotiation_tips);
- for_each_cached_alternate(&negotiator,
+ mark_tips(negotiator, args->negotiation_tips);
+ for_each_cached_alternate(negotiator,
insert_one_alternate_object);
} else {
filter_refs(args, &ref, sought, nr_sought);
@@ -1468,7 +1486,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
"negotiation_v2",
the_repository);
}
- if (send_fetch_request(&negotiator, fd[1], args, ref,
+ if (send_fetch_request(negotiator, fd[1], args, ref,
&common,
&haves_to_send, &in_vain,
reader.use_sideband))
@@ -1478,7 +1496,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
break;
case FETCH_PROCESS_ACKS:
/* Process ACKs/NAKs */
- switch (process_acks(&negotiator, &reader, &common)) {
+ switch (process_acks(negotiator, &reader, &common)) {
case 2:
state = FETCH_GET_PACK;
break;
@@ -1513,7 +1531,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
}
}
- negotiator.release(&negotiator);
+ if (negotiator)
+ negotiator->release(negotiator);
oidset_clear(&common);
return ref;
}
diff --git a/fsck.c b/fsck.c
index cdb7d8d..ac4ba4c 100644
--- a/fsck.c
+++ b/fsck.c
@@ -43,21 +43,17 @@ static struct oidset gitmodules_done = OIDSET_INIT;
FUNC(MISSING_AUTHOR, ERROR) \
FUNC(MISSING_COMMITTER, ERROR) \
FUNC(MISSING_EMAIL, ERROR) \
- FUNC(MISSING_GRAFT, ERROR) \
FUNC(MISSING_NAME_BEFORE_EMAIL, ERROR) \
FUNC(MISSING_OBJECT, ERROR) \
- FUNC(MISSING_PARENT, ERROR) \
FUNC(MISSING_SPACE_BEFORE_DATE, ERROR) \
FUNC(MISSING_SPACE_BEFORE_EMAIL, ERROR) \
FUNC(MISSING_TAG, ERROR) \
FUNC(MISSING_TAG_ENTRY, ERROR) \
- FUNC(MISSING_TAG_OBJECT, ERROR) \
FUNC(MISSING_TREE, ERROR) \
FUNC(MISSING_TREE_OBJECT, ERROR) \
FUNC(MISSING_TYPE, ERROR) \
FUNC(MISSING_TYPE_ENTRY, ERROR) \
FUNC(MULTIPLE_AUTHORS, ERROR) \
- FUNC(TAG_OBJECT_NOT_TAG, ERROR) \
FUNC(TREE_NOT_SORTED, ERROR) \
FUNC(UNKNOWN_TYPE, ERROR) \
FUNC(ZERO_PADDED_DATE, ERROR) \
@@ -281,14 +277,16 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id)
strbuf_addstr(sb, ": ");
}
-static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
+static int object_on_skiplist(struct fsck_options *opts,
+ const struct object_id *oid)
{
- return opts && obj && oidset_contains(&opts->skiplist, &obj->oid);
+ return opts && oid && oidset_contains(&opts->skiplist, oid);
}
-__attribute__((format (printf, 4, 5)))
-static int report(struct fsck_options *options, struct object *object,
- enum fsck_msg_id id, const char *fmt, ...)
+__attribute__((format (printf, 5, 6)))
+static int report(struct fsck_options *options,
+ const struct object_id *oid, enum object_type object_type,
+ enum fsck_msg_id id, const char *fmt, ...)
{
va_list ap;
struct strbuf sb = STRBUF_INIT;
@@ -297,7 +295,7 @@ static int report(struct fsck_options *options, struct object *object,
if (msg_type == FSCK_IGNORE)
return 0;
- if (object_on_skiplist(options, object))
+ if (object_on_skiplist(options, oid))
return 0;
if (msg_type == FSCK_FATAL)
@@ -309,49 +307,71 @@ static int report(struct fsck_options *options, struct object *object,
va_start(ap, fmt);
strbuf_vaddf(&sb, fmt, ap);
- result = options->error_func(options, object, msg_type, sb.buf);
+ result = options->error_func(options, oid, object_type,
+ msg_type, sb.buf);
strbuf_release(&sb);
va_end(ap);
return result;
}
-static char *get_object_name(struct fsck_options *options, struct object *obj)
+void fsck_enable_object_names(struct fsck_options *options)
{
if (!options->object_names)
+ options->object_names = kh_init_oid_map();
+}
+
+const char *fsck_get_object_name(struct fsck_options *options,
+ const struct object_id *oid)
+{
+ khiter_t pos;
+ if (!options->object_names)
+ return NULL;
+ pos = kh_get_oid_map(options->object_names, *oid);
+ if (pos >= kh_end(options->object_names))
return NULL;
- return lookup_decoration(options->object_names, obj);
+ return kh_value(options->object_names, pos);
}
-static void put_object_name(struct fsck_options *options, struct object *obj,
- const char *fmt, ...)
+void fsck_put_object_name(struct fsck_options *options,
+ const struct object_id *oid,
+ const char *fmt, ...)
{
va_list ap;
struct strbuf buf = STRBUF_INIT;
- char *existing;
+ khiter_t pos;
+ int hashret;
if (!options->object_names)
return;
- existing = lookup_decoration(options->object_names, obj);
- if (existing)
+
+ pos = kh_put_oid_map(options->object_names, *oid, &hashret);
+ if (!hashret)
return;
va_start(ap, fmt);
strbuf_vaddf(&buf, fmt, ap);
- add_decoration(options->object_names, obj, strbuf_detach(&buf, NULL));
+ kh_value(options->object_names, pos) = strbuf_detach(&buf, NULL);
va_end(ap);
}
-static const char *describe_object(struct fsck_options *o, struct object *obj)
+const char *fsck_describe_object(struct fsck_options *options,
+ const struct object_id *oid)
{
- static struct strbuf buf = STRBUF_INIT;
- char *name;
-
- strbuf_reset(&buf);
- strbuf_addstr(&buf, oid_to_hex(&obj->oid));
- if (o->object_names && (name = lookup_decoration(o->object_names, obj)))
- strbuf_addf(&buf, " (%s)", name);
+ static struct strbuf bufs[] = {
+ STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+ };
+ static int b = 0;
+ struct strbuf *buf;
+ const char *name = fsck_get_object_name(options, oid);
+
+ buf = bufs + b;
+ b = (b + 1) % ARRAY_SIZE(bufs);
+ strbuf_reset(buf);
+ strbuf_addstr(buf, oid_to_hex(oid));
+ if (name)
+ strbuf_addf(buf, " (%s)", name);
- return buf.buf;
+ return buf->buf;
}
static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
@@ -364,7 +384,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
if (parse_tree(tree))
return -1;
- name = get_object_name(options, &tree->object);
+ name = fsck_get_object_name(options, &tree->object.oid);
if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
return -1;
while (tree_entry_gently(&desc, &entry)) {
@@ -377,20 +397,21 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
if (S_ISDIR(entry.mode)) {
obj = (struct object *)lookup_tree(the_repository, &entry.oid);
if (name && obj)
- put_object_name(options, obj, "%s%s/", name,
- entry.path);
+ fsck_put_object_name(options, &entry.oid, "%s%s/",
+ name, entry.path);
result = options->walk(obj, OBJ_TREE, data, options);
}
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
obj = (struct object *)lookup_blob(the_repository, &entry.oid);
if (name && obj)
- put_object_name(options, obj, "%s%s", name,
- entry.path);
+ fsck_put_object_name(options, &entry.oid, "%s%s",
+ name, entry.path);
result = options->walk(obj, OBJ_BLOB, data, options);
}
else {
result = error("in tree %s: entry %s has bad mode %.6o",
- describe_object(options, &tree->object), entry.path, entry.mode);
+ fsck_describe_object(options, &tree->object.oid),
+ entry.path, entry.mode);
}
if (result < 0)
return result;
@@ -411,10 +432,10 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
if (parse_commit(commit))
return -1;
- name = get_object_name(options, &commit->object);
+ name = fsck_get_object_name(options, &commit->object.oid);
if (name)
- put_object_name(options, &get_commit_tree(commit)->object,
- "%s:", name);
+ fsck_put_object_name(options, get_commit_tree_oid(commit),
+ "%s:", name);
result = options->walk((struct object *)get_commit_tree(commit),
OBJ_TREE, data, options);
@@ -442,16 +463,17 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
while (parents) {
if (name) {
- struct object *obj = &parents->item->object;
+ struct object_id *oid = &parents->item->object.oid;
if (counter++)
- put_object_name(options, obj, "%s^%d",
- name, counter);
+ fsck_put_object_name(options, oid, "%s^%d",
+ name, counter);
else if (generation > 0)
- put_object_name(options, obj, "%.*s~%d",
- name_prefix_len, name, generation + 1);
+ fsck_put_object_name(options, oid, "%.*s~%d",
+ name_prefix_len, name,
+ generation + 1);
else
- put_object_name(options, obj, "%s^", name);
+ fsck_put_object_name(options, oid, "%s^", name);
}
result = options->walk((struct object *)parents->item, OBJ_COMMIT, data, options);
if (result < 0)
@@ -465,12 +487,12 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)
{
- char *name = get_object_name(options, &tag->object);
+ const char *name = fsck_get_object_name(options, &tag->object.oid);
if (parse_tag(tag))
return -1;
if (name)
- put_object_name(options, tag->tagged, "%s", name);
+ fsck_put_object_name(options, &tag->tagged->oid, "%s", name);
return options->walk(tag->tagged, OBJ_ANY, data, options);
}
@@ -492,7 +514,8 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
case OBJ_TAG:
return fsck_walk_tag((struct tag *)obj, data, options);
default:
- error("Unknown object type for %s", describe_object(options, obj));
+ error("Unknown object type for %s",
+ fsck_describe_object(options, &obj->oid));
return -1;
}
}
@@ -543,7 +566,9 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con
return c1 < c2 ? 0 : TREE_UNORDERED;
}
-static int fsck_tree(struct tree *item, struct fsck_options *options)
+static int fsck_tree(const struct object_id *oid,
+ const char *buffer, unsigned long size,
+ struct fsck_options *options)
{
int retval = 0;
int has_null_sha1 = 0;
@@ -560,8 +585,8 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
unsigned o_mode;
const char *o_name;
- if (init_tree_desc_gently(&desc, item->buffer, item->size)) {
- retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
+ if (init_tree_desc_gently(&desc, buffer, size)) {
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
return retval;
}
@@ -587,13 +612,14 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
if (!S_ISLNK(mode))
oidset_insert(&gitmodules_found, oid);
else
- retval += report(options, &item->object,
+ retval += report(options,
+ oid, OBJ_TREE,
FSCK_MSG_GITMODULES_SYMLINK,
".gitmodules is a symbolic link");
}
if (update_tree_entry_gently(&desc)) {
- retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
break;
}
@@ -638,30 +664,31 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
}
if (has_null_sha1)
- retval += report(options, &item->object, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
if (has_full_path)
- retval += report(options, &item->object, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
if (has_empty_name)
- retval += report(options, &item->object, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
if (has_dot)
- retval += report(options, &item->object, FSCK_MSG_HAS_DOT, "contains '.'");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOT, "contains '.'");
if (has_dotdot)
- retval += report(options, &item->object, FSCK_MSG_HAS_DOTDOT, "contains '..'");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOTDOT, "contains '..'");
if (has_dotgit)
- retval += report(options, &item->object, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
if (has_zero_pad)
- retval += report(options, &item->object, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
if (has_bad_modes)
- retval += report(options, &item->object, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
if (has_dup_entries)
- retval += report(options, &item->object, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
if (not_properly_sorted)
- retval += report(options, &item->object, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
+ retval += report(options, oid, OBJ_TREE, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
return retval;
}
static int verify_headers(const void *data, unsigned long size,
- struct object *obj, struct fsck_options *options)
+ const struct object_id *oid, enum object_type type,
+ struct fsck_options *options)
{
const char *buffer = (const char *)data;
unsigned long i;
@@ -669,7 +696,7 @@ static int verify_headers(const void *data, unsigned long size,
for (i = 0; i < size; i++) {
switch (buffer[i]) {
case '\0':
- return report(options, obj,
+ return report(options, oid, type,
FSCK_MSG_NUL_IN_HEADER,
"unterminated header: NUL at offset %ld", i);
case '\n':
@@ -687,11 +714,13 @@ static int verify_headers(const void *data, unsigned long size,
if (size && buffer[size - 1] == '\n')
return 0;
- return report(options, obj,
+ return report(options, oid, type,
FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
}
-static int fsck_ident(const char **ident, struct object *obj, struct fsck_options *options)
+static int fsck_ident(const char **ident,
+ const struct object_id *oid, enum object_type type,
+ struct fsck_options *options)
{
const char *p = *ident;
char *end;
@@ -701,28 +730,28 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option
(*ident)++;
if (*p == '<')
- return report(options, obj, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
+ return report(options, oid, type, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
p += strcspn(p, "<>\n");
if (*p == '>')
- return report(options, obj, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
+ return report(options, oid, type, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
if (*p != '<')
- return report(options, obj, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
+ return report(options, oid, type, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
if (p[-1] != ' ')
- return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
+ return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
p++;
p += strcspn(p, "<>\n");
if (*p != '>')
- return report(options, obj, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
+ return report(options, oid, type, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
p++;
if (*p != ' ')
- return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
+ return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
p++;
if (*p == '0' && p[1] != ' ')
- return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
+ return report(options, oid, type, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
if (date_overflows(parse_timestamp(p, &end, 10)))
- return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
+ return report(options, oid, type, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
if ((end == p || *end != ' '))
- return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
+ return report(options, oid, type, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
p = end + 1;
if ((*p != '+' && *p != '-') ||
!isdigit(p[1]) ||
@@ -730,83 +759,60 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option
!isdigit(p[3]) ||
!isdigit(p[4]) ||
(p[5] != '\n'))
- return report(options, obj, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
+ return report(options, oid, type, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
p += 6;
return 0;
}
-static int fsck_commit_buffer(struct commit *commit, const char *buffer,
- unsigned long size, struct fsck_options *options)
+static int fsck_commit(const struct object_id *oid,
+ const char *buffer, unsigned long size,
+ struct fsck_options *options)
{
- struct object_id tree_oid, oid;
- struct commit_graft *graft;
- unsigned parent_count, parent_line_count = 0, author_count;
+ struct object_id tree_oid, parent_oid;
+ unsigned author_count;
int err;
const char *buffer_begin = buffer;
const char *p;
- if (verify_headers(buffer, size, &commit->object, options))
+ if (verify_headers(buffer, size, oid, OBJ_COMMIT, options))
return -1;
if (!skip_prefix(buffer, "tree ", &buffer))
- return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
+ return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
- err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
+ err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
if (err)
return err;
}
buffer = p + 1;
while (skip_prefix(buffer, "parent ", &buffer)) {
- if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
- err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
+ if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
+ err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
if (err)
return err;
}
buffer = p + 1;
- parent_line_count++;
- }
- graft = lookup_commit_graft(the_repository, &commit->object.oid);
- parent_count = commit_list_count(commit->parents);
- if (graft) {
- if (graft->nr_parent == -1 && !parent_count)
- ; /* shallow commit */
- else if (graft->nr_parent != parent_count) {
- err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing");
- if (err)
- return err;
- }
- } else {
- if (parent_count != parent_line_count) {
- err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing");
- if (err)
- return err;
- }
}
author_count = 0;
while (skip_prefix(buffer, "author ", &buffer)) {
author_count++;
- err = fsck_ident(&buffer, &commit->object, options);
+ err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
if (err)
return err;
}
if (author_count < 1)
- err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
+ err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
else if (author_count > 1)
- err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
+ err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
if (err)
return err;
if (!skip_prefix(buffer, "committer ", &buffer))
- return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
- err = fsck_ident(&buffer, &commit->object, options);
+ return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
+ err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
if (err)
return err;
- if (!get_commit_tree(commit)) {
- err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", oid_to_hex(&tree_oid));
- if (err)
- return err;
- }
if (memchr(buffer_begin, '\0', size)) {
- err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT,
+ err = report(options, oid, OBJ_COMMIT, FSCK_MSG_NUL_IN_COMMIT,
"NUL byte in the commit object body");
if (err)
return err;
@@ -814,91 +820,60 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
return 0;
}
-static int fsck_commit(struct commit *commit, const char *data,
- unsigned long size, struct fsck_options *options)
-{
- const char *buffer = data ? data : get_commit_buffer(commit, &size);
- int ret = fsck_commit_buffer(commit, buffer, size, options);
- if (!data)
- unuse_commit_buffer(commit, buffer);
- return ret;
-}
-
-static int fsck_tag_buffer(struct tag *tag, const char *data,
- unsigned long size, struct fsck_options *options)
+static int fsck_tag(const struct object_id *oid, const char *buffer,
+ unsigned long size, struct fsck_options *options)
{
- struct object_id oid;
+ struct object_id tagged_oid;
int ret = 0;
- const char *buffer;
- char *to_free = NULL, *eol;
+ char *eol;
struct strbuf sb = STRBUF_INIT;
const char *p;
- if (data)
- buffer = data;
- else {
- enum object_type type;
-
- buffer = to_free =
- read_object_file(&tag->object.oid, &type, &size);
- if (!buffer)
- return report(options, &tag->object,
- FSCK_MSG_MISSING_TAG_OBJECT,
- "cannot read tag object");
-
- if (type != OBJ_TAG) {
- ret = report(options, &tag->object,
- FSCK_MSG_TAG_OBJECT_NOT_TAG,
- "expected tag got %s",
- type_name(type));
- goto done;
- }
- }
-
- ret = verify_headers(buffer, size, &tag->object, options);
+ ret = verify_headers(buffer, size, oid, OBJ_TAG, options);
if (ret)
goto done;
if (!skip_prefix(buffer, "object ", &buffer)) {
- ret = report(options, &tag->object, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
goto done;
}
- if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
- ret = report(options, &tag->object, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
+ if (parse_oid_hex(buffer, &tagged_oid, &p) || *p != '\n') {
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
if (ret)
goto done;
}
buffer = p + 1;
if (!skip_prefix(buffer, "type ", &buffer)) {
- ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
goto done;
}
eol = strchr(buffer, '\n');
if (!eol) {
- ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
goto done;
}
if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
- ret = report(options, &tag->object, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
if (ret)
goto done;
buffer = eol + 1;
if (!skip_prefix(buffer, "tag ", &buffer)) {
- ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
goto done;
}
eol = strchr(buffer, '\n');
if (!eol) {
- ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
goto done;
}
strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
if (check_refname_format(sb.buf, 0)) {
- ret = report(options, &tag->object, FSCK_MSG_BAD_TAG_NAME,
- "invalid 'tag' name: %.*s",
- (int)(eol - buffer), buffer);
+ ret = report(options, oid, OBJ_TAG,
+ FSCK_MSG_BAD_TAG_NAME,
+ "invalid 'tag' name: %.*s",
+ (int)(eol - buffer), buffer);
if (ret)
goto done;
}
@@ -906,32 +881,20 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
if (!skip_prefix(buffer, "tagger ", &buffer)) {
/* early tags do not contain 'tagger' lines; warn only */
- ret = report(options, &tag->object, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
if (ret)
goto done;
}
else
- ret = fsck_ident(&buffer, &tag->object, options);
+ ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
done:
strbuf_release(&sb);
- free(to_free);
return ret;
}
-static int fsck_tag(struct tag *tag, const char *data,
- unsigned long size, struct fsck_options *options)
-{
- struct object *tagged = tag->tagged;
-
- if (!tagged)
- return report(options, &tag->object, FSCK_MSG_BAD_TAG_OBJECT, "could not load tagged object");
-
- return fsck_tag_buffer(tag, data, size, options);
-}
-
struct fsck_gitmodules_data {
- struct object *obj;
+ const struct object_id *oid;
struct fsck_options *options;
int ret;
};
@@ -949,19 +912,22 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
name = xmemdupz(subsection, subsection_len);
if (check_submodule_name(name) < 0)
- data->ret |= report(data->options, data->obj,
+ data->ret |= report(data->options,
+ data->oid, OBJ_BLOB,
FSCK_MSG_GITMODULES_NAME,
"disallowed submodule name: %s",
name);
if (!strcmp(key, "url") && value &&
looks_like_command_line_option(value))
- data->ret |= report(data->options, data->obj,
+ data->ret |= report(data->options,
+ data->oid, OBJ_BLOB,
FSCK_MSG_GITMODULES_URL,
"disallowed submodule url: %s",
value);
if (!strcmp(key, "path") && value &&
looks_like_command_line_option(value))
- data->ret |= report(data->options, data->obj,
+ data->ret |= report(data->options,
+ data->oid, OBJ_BLOB,
FSCK_MSG_GITMODULES_PATH,
"disallowed submodule path: %s",
value);
@@ -970,17 +936,17 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
return 0;
}
-static int fsck_blob(struct blob *blob, const char *buf,
+static int fsck_blob(const struct object_id *oid, const char *buf,
unsigned long size, struct fsck_options *options)
{
struct fsck_gitmodules_data data;
struct config_options config_opts = { 0 };
- if (!oidset_contains(&gitmodules_found, &blob->object.oid))
+ if (!oidset_contains(&gitmodules_found, oid))
return 0;
- oidset_insert(&gitmodules_done, &blob->object.oid);
+ oidset_insert(&gitmodules_done, oid);
- if (object_on_skiplist(options, &blob->object))
+ if (object_on_skiplist(options, oid))
return 0;
if (!buf) {
@@ -989,18 +955,18 @@ static int fsck_blob(struct blob *blob, const char *buf,
* blob too gigantic to load into memory. Let's just consider
* that an error.
*/
- return report(options, &blob->object,
+ return report(options, oid, OBJ_BLOB,
FSCK_MSG_GITMODULES_LARGE,
".gitmodules too large to parse");
}
- data.obj = &blob->object;
+ data.oid = oid;
data.options = options;
data.ret = 0;
config_opts.error_action = CONFIG_ERROR_SILENT;
if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
".gitmodules", buf, size, &data, &config_opts))
- data.ret |= report(options, &blob->object,
+ data.ret |= report(options, oid, OBJ_BLOB,
FSCK_MSG_GITMODULES_PARSE,
"could not parse gitmodules blob");
@@ -1011,31 +977,33 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
struct fsck_options *options)
{
if (!obj)
- return report(options, obj, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
+ return report(options, NULL, OBJ_NONE, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
if (obj->type == OBJ_BLOB)
- return fsck_blob((struct blob *)obj, data, size, options);
+ return fsck_blob(&obj->oid, data, size, options);
if (obj->type == OBJ_TREE)
- return fsck_tree((struct tree *) obj, options);
+ return fsck_tree(&obj->oid, data, size, options);
if (obj->type == OBJ_COMMIT)
- return fsck_commit((struct commit *) obj, (const char *) data,
- size, options);
+ return fsck_commit(&obj->oid, data, size, options);
if (obj->type == OBJ_TAG)
- return fsck_tag((struct tag *) obj, (const char *) data,
- size, options);
+ return fsck_tag(&obj->oid, data, size, options);
- return report(options, obj, FSCK_MSG_UNKNOWN_TYPE, "unknown type '%d' (internal fsck error)",
- obj->type);
+ return report(options, &obj->oid, obj->type,
+ FSCK_MSG_UNKNOWN_TYPE,
+ "unknown type '%d' (internal fsck error)",
+ obj->type);
}
int fsck_error_function(struct fsck_options *o,
- struct object *obj, int msg_type, const char *message)
+ const struct object_id *oid,
+ enum object_type object_type,
+ int msg_type, const char *message)
{
if (msg_type == FSCK_WARN) {
- warning("object %s: %s", describe_object(o, obj), message);
+ warning("object %s: %s", fsck_describe_object(o, oid), message);
return 0;
}
- error("object %s: %s", describe_object(o, obj), message);
+ error("object %s: %s", fsck_describe_object(o, oid), message);
return 1;
}
@@ -1047,7 +1015,6 @@ int fsck_finish(struct fsck_options *options)
oidset_iter_init(&gitmodules_found, &iter);
while ((oid = oidset_iter_next(&iter))) {
- struct blob *blob;
enum object_type type;
unsigned long size;
char *buf;
@@ -1055,29 +1022,22 @@ int fsck_finish(struct fsck_options *options)
if (oidset_contains(&gitmodules_done, oid))
continue;
- blob = lookup_blob(the_repository, oid);
- if (!blob) {
- struct object *obj = lookup_unknown_object(oid);
- ret |= report(options, obj,
- FSCK_MSG_GITMODULES_BLOB,
- "non-blob found at .gitmodules");
- continue;
- }
-
buf = read_object_file(oid, &type, &size);
if (!buf) {
- if (is_promisor_object(&blob->object.oid))
+ if (is_promisor_object(oid))
continue;
- ret |= report(options, &blob->object,
+ ret |= report(options,
+ oid, OBJ_BLOB,
FSCK_MSG_GITMODULES_MISSING,
"unable to read .gitmodules blob");
continue;
}
if (type == OBJ_BLOB)
- ret |= fsck_blob(blob, buf, size, options);
+ ret |= fsck_blob(oid, buf, size, options);
else
- ret |= report(options, &blob->object,
+ ret |= report(options,
+ oid, type,
FSCK_MSG_GITMODULES_BLOB,
"non-blob found at .gitmodules");
free(buf);
diff --git a/fsck.h b/fsck.h
index b95595a..69cf715 100644
--- a/fsck.h
+++ b/fsck.h
@@ -27,10 +27,12 @@ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data, struct f
/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
typedef int (*fsck_error)(struct fsck_options *o,
- struct object *obj, int type, const char *message);
+ const struct object_id *oid, enum object_type object_type,
+ int msg_type, const char *message);
int fsck_error_function(struct fsck_options *o,
- struct object *obj, int type, const char *message);
+ const struct object_id *oid, enum object_type object_type,
+ int msg_type, const char *message);
struct fsck_options {
fsck_walk_func walk;
@@ -38,7 +40,7 @@ struct fsck_options {
unsigned strict:1;
int *msg_type;
struct oidset skiplist;
- struct decoration *object_names;
+ kh_oid_map_t *object_names;
};
#define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL, OIDSET_INIT }
@@ -52,7 +54,11 @@ struct fsck_options {
* 0 everything OK
*/
int fsck_walk(struct object *obj, void *data, struct fsck_options *options);
-/* If NULL is passed for data, we assume the object is local and read it. */
+
+/*
+ * Blob objects my pass a NULL data pointer, which indicates they are too large
+ * to fit in memory. All other types must pass a real buffer.
+ */
int fsck_object(struct object *obj, void *data, unsigned long size,
struct fsck_options *options);
@@ -63,4 +69,29 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
*/
int fsck_finish(struct fsck_options *options);
+/*
+ * Subsystem for storing human-readable names for each object.
+ *
+ * If fsck_enable_object_names() has not been called, all other functions are
+ * noops.
+ *
+ * Use fsck_put_object_name() to seed initial names (e.g. from refnames); the
+ * fsck code will extend that while walking trees, etc.
+ *
+ * Use fsck_get_object_name() to get a single name (or NULL if none). Or the
+ * more convenient describe_object(), which always produces an output string
+ * with the oid combined with the name (if any). Note that the return value
+ * points to a rotating array of static buffers, and may be invalidated by a
+ * subsequent call.
+ */
+void fsck_enable_object_names(struct fsck_options *options);
+const char *fsck_get_object_name(struct fsck_options *options,
+ const struct object_id *oid);
+__attribute__((format (printf,3,4)))
+void fsck_put_object_name(struct fsck_options *options,
+ const struct object_id *oid,
+ const char *fmt, ...);
+const char *fsck_describe_object(struct fsck_options *options,
+ const struct object_id *oid);
+
#endif
diff --git a/fsmonitor.c b/fsmonitor.c
index 1f4aa1b..0477500 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -55,7 +55,8 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,
}
istate->fsmonitor_dirty = fsmonitor_dirty;
- if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
+ if (!istate->split_index &&
+ istate->fsmonitor_dirty->bit_size > istate->cache_nr)
BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
(uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
@@ -83,7 +84,8 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
uint32_t ewah_size = 0;
int fixup = 0;
- if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
+ if (!istate->split_index &&
+ istate->fsmonitor_dirty->bit_size > istate->cache_nr)
BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
(uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index b31613c..1057f38 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -600,7 +600,7 @@ my $cvs = CVSconn->new($opt_d, $cvs_tree);
sub pdate($) {
my ($d) = @_;
m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
- or die "Unparseable date: $d\n";
+ or die "Unparsable date: $d\n";
my $y=$1;
$y+=100 if $y<70;
$y+=1900 if $y<1000;
diff --git a/git-send-email.perl b/git-send-email.perl
index 5f92c89..dc95656 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1228,7 +1228,7 @@ sub process_address_list {
# domain name that corresponds the IP address in the HELO/EHLO
# handshake. This is used to verify the connection and prevent
# spammers from trying to hide their identity. If the DNS and IP don't
-# match, the receiveing MTA may deny the connection.
+# match, the receiving MTA may deny the connection.
#
# Here is a deny example of Net::SMTP with the default "localhost.localdomain"
#
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 7fef19f..0f857d7 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1657,15 +1657,15 @@ sub quot_cec {
my $cntrl = shift;
my %opts = @_;
my %es = ( # character escape codes, aka escape sequences
- "\t" => '\t', # tab (HT)
- "\n" => '\n', # line feed (LF)
- "\r" => '\r', # carrige return (CR)
- "\f" => '\f', # form feed (FF)
- "\b" => '\b', # backspace (BS)
- "\a" => '\a', # alarm (bell) (BEL)
- "\e" => '\e', # escape (ESC)
- "\013" => '\v', # vertical tab (VT)
- "\000" => '\0', # nul character (NUL)
+ "\t" => '\t', # tab (HT)
+ "\n" => '\n', # line feed (LF)
+ "\r" => '\r', # carriage return (CR)
+ "\f" => '\f', # form feed (FF)
+ "\b" => '\b', # backspace (BS)
+ "\a" => '\a', # alarm (bell) (BEL)
+ "\e" => '\e', # escape (ESC)
+ "\013" => '\v', # vertical tab (VT)
+ "\000" => '\0', # nul character (NUL)
);
my $chr = ( (exists $es{$cntrl})
? $es{$cntrl}
@@ -4048,7 +4048,7 @@ sub print_feed_meta {
$href_params{'extra_options'} = undef;
$href_params{'action'} = $type;
- $link_attr{'-href'} = href(%href_params);
+ $link_attr{'-href'} = esc_attr(href(%href_params));
print "<link ".
"rel=\"$link_attr{'-rel'}\" ".
"title=\"$link_attr{'-title'}\" ".
@@ -4057,7 +4057,7 @@ sub print_feed_meta {
"/>\n";
$href_params{'extra_options'} = '--no-merges';
- $link_attr{'-href'} = href(%href_params);
+ $link_attr{'-href'} = esc_attr(href(%href_params));
$link_attr{'-title'} .= ' (no merges)';
print "<link ".
"rel=\"$link_attr{'-rel'}\" ".
@@ -4070,10 +4070,12 @@ sub print_feed_meta {
} else {
printf('<link rel="alternate" title="%s projects list" '.
'href="%s" type="text/plain; charset=utf-8" />'."\n",
- esc_attr($site_name), href(project=>undef, action=>"project_index"));
+ esc_attr($site_name),
+ esc_attr(href(project=>undef, action=>"project_index")));
printf('<link rel="alternate" title="%s projects feeds" '.
'href="%s" type="text/x-opml" />'."\n",
- esc_attr($site_name), href(project=>undef, action=>"opml"));
+ esc_attr($site_name),
+ esc_attr(href(project=>undef, action=>"opml")));
}
}
@@ -4287,8 +4289,8 @@ sub git_footer_html {
if (defined $action &&
$action eq 'blame_incremental') {
print qq!<script type="text/javascript">\n!.
- qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!.
- qq! "!. href() .qq!");\n!.
+ qq!startBlame("!. esc_attr(href(action=>"blame_data", -replay=>1)) .qq!",\n!.
+ qq! "!. esc_attr(href()) .qq!");\n!.
qq!</script>\n!;
} else {
my ($jstimezone, $tz_cookie, $datetime_class) =
@@ -7155,8 +7157,8 @@ sub git_blob {
print qq! alt="!.esc_attr($file_name).qq!" title="!.esc_attr($file_name).qq!"!;
}
print qq! src="! .
- href(action=>"blob_plain", hash=>$hash,
- hash_base=>$hash_base, file_name=>$file_name) .
+ esc_attr(href(action=>"blob_plain", hash=>$hash,
+ hash_base=>$hash_base, file_name=>$file_name)) .
qq!" />\n!;
} else {
my $nr;
@@ -8239,6 +8241,7 @@ sub git_feed {
} else {
$alt_url = href(-full=>1, action=>"summary");
}
+ $alt_url = esc_attr($alt_url);
print qq!<?xml version="1.0" encoding="utf-8"?>\n!;
if ($format eq 'rss') {
print <<XML;
@@ -8276,7 +8279,7 @@ XML
$alt_url . '" />' . "\n" .
'<link rel="self" type="' . $content_type . '" href="' .
$cgi->self_url() . '" />' . "\n" .
- "<id>" . href(-full=>1) . "</id>\n" .
+ "<id>" . esc_url(href(-full=>1)) . "</id>\n" .
# use project owner for feed author
"<author><name>$owner</name></author>\n";
if (defined $favicon) {
@@ -8322,7 +8325,7 @@ XML
"<author>" . esc_html($co{'author'}) . "</author>\n" .
"<pubDate>$cd{'rfc2822'}</pubDate>\n" .
"<guid isPermaLink=\"true\">$co_url</guid>\n" .
- "<link>$co_url</link>\n" .
+ "<link>" . esc_html($co_url) . "</link>\n" .
"<description>" . esc_html($co{'title'}) . "</description>\n" .
"<content:encoded>" .
"<![CDATA[\n";
@@ -8344,8 +8347,8 @@ XML
}
print "</contributor>\n" .
"<published>$cd{'iso-8601'}</published>\n" .
- "<link rel=\"alternate\" type=\"text/html\" href=\"$co_url\" />\n" .
- "<id>$co_url</id>\n" .
+ "<link rel=\"alternate\" type=\"text/html\" href=\"" . esc_attr($co_url) . "\" />\n" .
+ "<id>" . esc_html($co_url) . "</id>\n" .
"<content type=\"xhtml\" xml:base=\"" . esc_url($my_url) . "\">\n" .
"<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
}
@@ -8452,8 +8455,8 @@ XML
}
my $path = esc_html(chop_str($proj{'path'}, 25, 5));
- my $rss = href('project' => $proj{'path'}, 'action' => 'rss', -full => 1);
- my $html = href('project' => $proj{'path'}, 'action' => 'summary', -full => 1);
+ my $rss = esc_attr(href('project' => $proj{'path'}, 'action' => 'rss', -full => 1));
+ my $html = esc_attr(href('project' => $proj{'path'}, 'action' => 'summary', -full => 1));
print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
}
print <<XML;
diff --git a/graph.c b/graph.c
index f531354..e3fd0ea 100644
--- a/graph.c
+++ b/graph.c
@@ -112,14 +112,42 @@ static const char *column_get_color_code(unsigned short color)
return column_colors[color];
}
-static void strbuf_write_column(struct strbuf *sb, const struct column *c,
- char col_char)
+struct graph_line {
+ struct strbuf *buf;
+ size_t width;
+};
+
+static inline void graph_line_addch(struct graph_line *line, int c)
+{
+ strbuf_addch(line->buf, c);
+ line->width++;
+}
+
+static inline void graph_line_addchars(struct graph_line *line, int c, size_t n)
+{
+ strbuf_addchars(line->buf, c, n);
+ line->width += n;
+}
+
+static inline void graph_line_addstr(struct graph_line *line, const char *s)
+{
+ strbuf_addstr(line->buf, s);
+ line->width += strlen(s);
+}
+
+static inline void graph_line_addcolor(struct graph_line *line, unsigned short color)
+{
+ strbuf_addstr(line->buf, column_get_color_code(color));
+}
+
+static void graph_line_write_column(struct graph_line *line, const struct column *c,
+ char col_char)
{
if (c->color < column_colors_max)
- strbuf_addstr(sb, column_get_color_code(c->color));
- strbuf_addch(sb, col_char);
+ graph_line_addcolor(line, c->color);
+ graph_line_addch(line, col_char);
if (c->color < column_colors_max)
- strbuf_addstr(sb, column_get_color_code(column_colors_max));
+ graph_line_addcolor(line, column_colors_max);
}
struct git_graph {
@@ -175,9 +203,63 @@ struct git_graph {
*/
int prev_commit_index;
/*
+ * Which layout variant to use to display merge commits. If the
+ * commit's first parent is known to be in a column to the left of the
+ * merge, then this value is 0 and we use the layout on the left.
+ * Otherwise, the value is 1 and the layout on the right is used. This
+ * field tells us how many columns the first parent occupies.
+ *
+ * 0) 1)
+ *
+ * | | | *-. | | *---.
+ * | |_|/|\ \ | | |\ \ \
+ * |/| | | | | | | | | | *
+ */
+ int merge_layout;
+ /*
+ * The number of columns added to the graph by the current commit. For
+ * 2-way and octopus merges, this is is usually one less than the
+ * number of parents:
+ *
+ * | | | | | \
+ * | * | | *---. \
+ * | |\ \ | |\ \ \ \
+ * | | | | | | | | | |
+ *
+ * num_parents: 2 num_parents: 4
+ * edges_added: 1 edges_added: 3
+ *
+ * For left-skewed merges, the first parent fuses with its neighbor and
+ * so one less column is added:
+ *
+ * | | | | | \
+ * | * | | *-. \
+ * |/| | |/|\ \ \
+ * | | | | | | | |
+ *
+ * num_parents: 2 num_parents: 4
+ * edges_added: 0 edges_added: 2
+ *
+ * This number determines how edges to the right of the merge are
+ * displayed in commit and post-merge lines; if no columns have been
+ * added then a vertical line should be used where a right-tracking
+ * line would otherwise be used.
+ *
+ * | * \ | * |
+ * | |\ \ |/| |
+ * | | * \ | * |
+ */
+ int edges_added;
+ /*
+ * The number of columns added by the previous commit, which is used to
+ * smooth edges appearing to the right of a commit in a commit line
+ * following a post-merge line.
+ */
+ int prev_edges_added;
+ /*
* The maximum number of columns that can be stored in the columns
* and new_columns arrays. This is also half the number of entries
- * that can be stored in the mapping and new_mapping arrays.
+ * that can be stored in the mapping and old_mapping arrays.
*/
int column_capacity;
/*
@@ -215,12 +297,12 @@ struct git_graph {
*/
int *mapping;
/*
- * A temporary array for computing the next mapping state
- * while we are outputting a mapping line. This is stored as part
- * of the git_graph simply so we don't have to allocate a new
- * temporary array each time we have to output a collapsing line.
+ * A copy of the contents of the mapping array from the last commit,
+ * which we use to improve the display of columns that are tracking
+ * from right to left through a commit line. We also use this to
+ * avoid allocating a fresh array when we compute the next mapping.
*/
- int *new_mapping;
+ int *old_mapping;
/*
* The current default column color being used. This is
* stored as an index into the array column_colors.
@@ -285,6 +367,9 @@ struct git_graph *graph_init(struct rev_info *opt)
graph->prev_state = GRAPH_PADDING;
graph->commit_index = 0;
graph->prev_commit_index = 0;
+ graph->merge_layout = 0;
+ graph->edges_added = 0;
+ graph->prev_edges_added = 0;
graph->num_columns = 0;
graph->num_new_columns = 0;
graph->mapping_size = 0;
@@ -303,7 +388,7 @@ struct git_graph *graph_init(struct rev_info *opt)
ALLOC_ARRAY(graph->columns, graph->column_capacity);
ALLOC_ARRAY(graph->new_columns, graph->column_capacity);
ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);
- ALLOC_ARRAY(graph->new_mapping, 2 * graph->column_capacity);
+ ALLOC_ARRAY(graph->old_mapping, 2 * graph->column_capacity);
/*
* The diff output prefix callback, with this we can make
@@ -333,7 +418,7 @@ static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
REALLOC_ARRAY(graph->columns, graph->column_capacity);
REALLOC_ARRAY(graph->new_columns, graph->column_capacity);
REALLOC_ARRAY(graph->mapping, graph->column_capacity * 2);
- REALLOC_ARRAY(graph->new_mapping, graph->column_capacity * 2);
+ REALLOC_ARRAY(graph->old_mapping, graph->column_capacity * 2);
}
/*
@@ -432,74 +517,76 @@ static unsigned short graph_find_commit_color(const struct git_graph *graph,
return graph_get_current_column_color(graph);
}
-static void graph_insert_into_new_columns(struct git_graph *graph,
- struct commit *commit,
- int *mapping_index)
+static int graph_find_new_column_by_commit(struct git_graph *graph,
+ struct commit *commit)
{
int i;
-
- /*
- * If the commit is already in the new_columns list, we don't need to
- * add it. Just update the mapping correctly.
- */
for (i = 0; i < graph->num_new_columns; i++) {
- if (graph->new_columns[i].commit == commit) {
- graph->mapping[*mapping_index] = i;
- *mapping_index += 2;
- return;
- }
+ if (graph->new_columns[i].commit == commit)
+ return i;
}
-
- /*
- * This commit isn't already in new_columns. Add it.
- */
- graph->new_columns[graph->num_new_columns].commit = commit;
- graph->new_columns[graph->num_new_columns].color = graph_find_commit_color(graph, commit);
- graph->mapping[*mapping_index] = graph->num_new_columns;
- *mapping_index += 2;
- graph->num_new_columns++;
+ return -1;
}
-static void graph_update_width(struct git_graph *graph,
- int is_commit_in_existing_columns)
+static void graph_insert_into_new_columns(struct git_graph *graph,
+ struct commit *commit,
+ int idx)
{
- /*
- * Compute the width needed to display the graph for this commit.
- * This is the maximum width needed for any row. All other rows
- * will be padded to this width.
- *
- * Compute the number of columns in the widest row:
- * Count each existing column (graph->num_columns), and each new
- * column added by this commit.
- */
- int max_cols = graph->num_columns + graph->num_parents;
+ int i = graph_find_new_column_by_commit(graph, commit);
+ int mapping_idx;
/*
- * Even if the current commit has no parents to be printed, it
- * still takes up a column for itself.
+ * If the commit is not already in the new_columns array, then add it
+ * and record it as being in the final column.
*/
- if (graph->num_parents < 1)
- max_cols++;
+ if (i < 0) {
+ i = graph->num_new_columns++;
+ graph->new_columns[i].commit = commit;
+ graph->new_columns[i].color = graph_find_commit_color(graph, commit);
+ }
- /*
- * We added a column for the current commit as part of
- * graph->num_parents. If the current commit was already in
- * graph->columns, then we have double counted it.
- */
- if (is_commit_in_existing_columns)
- max_cols--;
+ if (graph->num_parents > 1 && idx > -1 && graph->merge_layout == -1) {
+ /*
+ * If this is the first parent of a merge, choose a layout for
+ * the merge line based on whether the parent appears in a
+ * column to the left of the merge
+ */
+ int dist, shift;
- /*
- * Each column takes up 2 spaces
- */
- graph->width = max_cols * 2;
+ dist = idx - i;
+ shift = (dist > 1) ? 2 * dist - 3 : 1;
+
+ graph->merge_layout = (dist > 0) ? 0 : 1;
+ graph->edges_added = graph->num_parents + graph->merge_layout - 2;
+
+ mapping_idx = graph->width + (graph->merge_layout - 1) * shift;
+ graph->width += 2 * graph->merge_layout;
+
+ } else if (graph->edges_added > 0 && i == graph->mapping[graph->width - 2]) {
+ /*
+ * If some columns have been added by a merge, but this commit
+ * was found in the last existing column, then adjust the
+ * numbers so that the two edges immediately join, i.e.:
+ *
+ * * | * |
+ * |\ \ => |\|
+ * | |/ | *
+ * | *
+ */
+ mapping_idx = graph->width - 2;
+ graph->edges_added = -1;
+ } else {
+ mapping_idx = graph->width;
+ graph->width += 2;
+ }
+
+ graph->mapping[mapping_idx] = i;
}
static void graph_update_columns(struct git_graph *graph)
{
struct commit_list *parent;
int max_new_columns;
- int mapping_idx;
int i, seen_this, is_commit_in_columns;
/*
@@ -532,6 +619,10 @@ static void graph_update_columns(struct git_graph *graph)
for (i = 0; i < graph->mapping_size; i++)
graph->mapping[i] = -1;
+ graph->width = 0;
+ graph->prev_edges_added = graph->edges_added;
+ graph->edges_added = 0;
+
/*
* Populate graph->new_columns and graph->mapping
*
@@ -542,7 +633,6 @@ static void graph_update_columns(struct git_graph *graph)
* supposed to end up after the collapsing is performed.
*/
seen_this = 0;
- mapping_idx = 0;
is_commit_in_columns = 1;
for (i = 0; i <= graph->num_columns; i++) {
struct commit *col_commit;
@@ -556,9 +646,9 @@ static void graph_update_columns(struct git_graph *graph)
}
if (col_commit == graph->commit) {
- int old_mapping_idx = mapping_idx;
seen_this = 1;
graph->commit_index = i;
+ graph->merge_layout = -1;
for (parent = first_interesting_parent(graph);
parent;
parent = next_interesting_parent(graph, parent)) {
@@ -571,21 +661,18 @@ static void graph_update_columns(struct git_graph *graph)
!is_commit_in_columns) {
graph_increment_column_color(graph);
}
- graph_insert_into_new_columns(graph,
- parent->item,
- &mapping_idx);
+ graph_insert_into_new_columns(graph, parent->item, i);
}
/*
- * We always need to increment mapping_idx by at
+ * We always need to increment graph->width by at
* least 2, even if it has no interesting parents.
* The current commit always takes up at least 2
* spaces.
*/
- if (mapping_idx == old_mapping_idx)
- mapping_idx += 2;
+ if (graph->num_parents == 0)
+ graph->width += 2;
} else {
- graph_insert_into_new_columns(graph, col_commit,
- &mapping_idx);
+ graph_insert_into_new_columns(graph, col_commit, -1);
}
}
@@ -595,11 +682,43 @@ static void graph_update_columns(struct git_graph *graph)
while (graph->mapping_size > 1 &&
graph->mapping[graph->mapping_size - 1] < 0)
graph->mapping_size--;
+}
+
+static int graph_num_dashed_parents(struct git_graph *graph)
+{
+ return graph->num_parents + graph->merge_layout - 3;
+}
+static int graph_num_expansion_rows(struct git_graph *graph)
+{
/*
- * Compute graph->width for this commit
+ * Normally, we need two expansion rows for each dashed parent line from
+ * an octopus merge:
+ *
+ * | *
+ * | |\
+ * | | \
+ * | | \
+ * | *-. \
+ * | |\ \ \
+ *
+ * If the merge is skewed to the left, then its parents occupy one less
+ * column, and we don't need as many expansion rows to route around it;
+ * in some cases that means we don't need any expansion rows at all:
+ *
+ * | *
+ * | |\
+ * | * \
+ * |/|\ \
*/
- graph_update_width(graph, is_commit_in_columns);
+ return graph_num_dashed_parents(graph) * 2;
+}
+
+static int graph_needs_pre_commit_line(struct git_graph *graph)
+{
+ return graph->num_parents >= 3 &&
+ graph->commit_index < (graph->num_columns - 1) &&
+ graph->expansion_row < graph_num_expansion_rows(graph);
}
void graph_update(struct git_graph *graph, struct commit *commit)
@@ -657,8 +776,7 @@ void graph_update(struct git_graph *graph, struct commit *commit)
*/
if (graph->state != GRAPH_PADDING)
graph->state = GRAPH_SKIP;
- else if (graph->num_parents >= 3 &&
- graph->commit_index < (graph->num_columns - 1))
+ else if (graph_needs_pre_commit_line(graph))
graph->state = GRAPH_PRE_COMMIT;
else
graph->state = GRAPH_COMMIT;
@@ -686,8 +804,7 @@ static int graph_is_mapping_correct(struct git_graph *graph)
return 1;
}
-static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb,
- int chars_written)
+static void graph_pad_horizontally(struct git_graph *graph, struct graph_line *line)
{
/*
* Add additional spaces to the end of the strbuf, so that all
@@ -696,34 +813,22 @@ static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb,
* This way, fields printed to the right of the graph will remain
* aligned for the entire commit.
*/
- if (chars_written < graph->width)
- strbuf_addchars(sb, ' ', graph->width - chars_written);
+ if (line->width < graph->width)
+ graph_line_addchars(line, ' ', graph->width - line->width);
}
static void graph_output_padding_line(struct git_graph *graph,
- struct strbuf *sb)
+ struct graph_line *line)
{
int i;
/*
- * We could conceivable be called with a NULL commit
- * if our caller has a bug, and invokes graph_next_line()
- * immediately after graph_init(), without first calling
- * graph_update(). Return without outputting anything in this
- * case.
- */
- if (!graph->commit)
- return;
-
- /*
* Output a padding row, that leaves all branch lines unchanged
*/
for (i = 0; i < graph->num_new_columns; i++) {
- strbuf_write_column(sb, &graph->new_columns[i], '|');
- strbuf_addch(sb, ' ');
+ graph_line_write_column(line, &graph->new_columns[i], '|');
+ graph_line_addch(line, ' ');
}
-
- graph_pad_horizontally(graph, sb, graph->num_new_columns * 2);
}
@@ -733,28 +838,24 @@ int graph_width(struct git_graph *graph)
}
-static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_skip_line(struct git_graph *graph, struct graph_line *line)
{
/*
* Output an ellipsis to indicate that a portion
* of the graph is missing.
*/
- strbuf_addstr(sb, "...");
- graph_pad_horizontally(graph, sb, 3);
+ graph_line_addstr(line, "...");
- if (graph->num_parents >= 3 &&
- graph->commit_index < (graph->num_columns - 1))
+ if (graph_needs_pre_commit_line(graph))
graph_update_state(graph, GRAPH_PRE_COMMIT);
else
graph_update_state(graph, GRAPH_COMMIT);
}
static void graph_output_pre_commit_line(struct git_graph *graph,
- struct strbuf *sb)
+ struct graph_line *line)
{
- int num_expansion_rows;
int i, seen_this;
- int chars_written;
/*
* This function formats a row that increases the space around a commit
@@ -764,27 +865,24 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
* We need 2 extra rows for every parent over 2.
*/
assert(graph->num_parents >= 3);
- num_expansion_rows = (graph->num_parents - 2) * 2;
/*
* graph->expansion_row tracks the current expansion row we are on.
* It should be in the range [0, num_expansion_rows - 1]
*/
assert(0 <= graph->expansion_row &&
- graph->expansion_row < num_expansion_rows);
+ graph->expansion_row < graph_num_expansion_rows(graph));
/*
* Output the row
*/
seen_this = 0;
- chars_written = 0;
for (i = 0; i < graph->num_columns; i++) {
struct column *col = &graph->columns[i];
if (col->commit == graph->commit) {
seen_this = 1;
- strbuf_write_column(sb, col, '|');
- strbuf_addchars(sb, ' ', graph->expansion_row);
- chars_written += 1 + graph->expansion_row;
+ graph_line_write_column(line, col, '|');
+ graph_line_addchars(line, ' ', graph->expansion_row);
} else if (seen_this && (graph->expansion_row == 0)) {
/*
* This is the first line of the pre-commit output.
@@ -797,33 +895,27 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
*/
if (graph->prev_state == GRAPH_POST_MERGE &&
graph->prev_commit_index < i)
- strbuf_write_column(sb, col, '\\');
+ graph_line_write_column(line, col, '\\');
else
- strbuf_write_column(sb, col, '|');
- chars_written++;
+ graph_line_write_column(line, col, '|');
} else if (seen_this && (graph->expansion_row > 0)) {
- strbuf_write_column(sb, col, '\\');
- chars_written++;
+ graph_line_write_column(line, col, '\\');
} else {
- strbuf_write_column(sb, col, '|');
- chars_written++;
+ graph_line_write_column(line, col, '|');
}
- strbuf_addch(sb, ' ');
- chars_written++;
+ graph_line_addch(line, ' ');
}
- graph_pad_horizontally(graph, sb, chars_written);
-
/*
* Increment graph->expansion_row,
* and move to state GRAPH_COMMIT if necessary
*/
graph->expansion_row++;
- if (graph->expansion_row >= num_expansion_rows)
+ if (!graph_needs_pre_commit_line(graph))
graph_update_state(graph, GRAPH_COMMIT);
}
-static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_commit_char(struct git_graph *graph, struct graph_line *line)
{
/*
* For boundary commits, print 'o'
@@ -831,72 +923,67 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
*/
if (graph->commit->object.flags & BOUNDARY) {
assert(graph->revs->boundary);
- strbuf_addch(sb, 'o');
+ graph_line_addch(line, 'o');
return;
}
/*
* get_revision_mark() handles all other cases without assert()
*/
- strbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit));
+ graph_line_addstr(line, get_revision_mark(graph->revs, graph->commit));
}
/*
- * Draw the horizontal dashes of an octopus merge and return the number of
- * characters written.
+ * Draw the horizontal dashes of an octopus merge.
*/
-static int graph_draw_octopus_merge(struct git_graph *graph,
- struct strbuf *sb)
+static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line *line)
{
/*
- * Here dashless_parents represents the number of parents which don't
- * need to have dashes (the edges labeled "0" and "1"). And
- * dashful_parents are the remaining ones.
+ * The parents of a merge commit can be arbitrarily reordered as they
+ * are mapped onto display columns, for example this is a valid merge:
*
- * | *---.
- * | |\ \ \
- * | | | | |
- * x 0 1 2 3
+ * | | *---.
+ * | | |\ \ \
+ * | | |/ / /
+ * | |/| | /
+ * | |_|_|/
+ * |/| | |
+ * 3 1 0 2
*
- */
- const int dashless_parents = 2;
- int dashful_parents = graph->num_parents - dashless_parents;
-
- /*
- * Usually, we add one new column for each parent (like the diagram
- * above) but sometimes the first parent goes into an existing column,
- * like this:
+ * The numbers denote which parent of the merge each visual column
+ * corresponds to; we can't assume that the parents will initially
+ * display in the order given by new_columns.
*
- * | *---.
- * | |\ \ \
- * |/ / / /
- * x 0 1 2
+ * To find the right color for each dash, we need to consult the
+ * mapping array, starting from the column 2 places to the right of the
+ * merge commit, and use that to find out which logical column each
+ * edge will collapse to.
*
- * In which case the number of parents will be one greater than the
- * number of added columns.
+ * Commits are rendered once all edges have collapsed to their correct
+ * logcial column, so commit_index gives us the right visual offset for
+ * the merge commit.
*/
- int added_cols = (graph->num_new_columns - graph->num_columns);
- int parent_in_old_cols = graph->num_parents - added_cols;
- /*
- * In both cases, commit_index corresponds to the edge labeled "0".
- */
- int first_col = graph->commit_index + dashless_parents
- - parent_in_old_cols;
+ int i, j;
+ struct column *col;
- int i;
- for (i = 0; i < dashful_parents; i++) {
- strbuf_write_column(sb, &graph->new_columns[i+first_col], '-');
- strbuf_write_column(sb, &graph->new_columns[i+first_col],
- i == dashful_parents-1 ? '.' : '-');
+ int dashed_parents = graph_num_dashed_parents(graph);
+
+ for (i = 0; i < dashed_parents; i++) {
+ j = graph->mapping[(graph->commit_index + i + 2) * 2];
+ col = &graph->new_columns[j];
+
+ graph_line_write_column(line, col, '-');
+ graph_line_write_column(line, col, (i == dashed_parents - 1) ? '.' : '-');
}
- return 2 * dashful_parents;
+
+ return;
}
-static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_commit_line(struct git_graph *graph, struct graph_line *line)
{
int seen_this = 0;
- int i, chars_written;
+ int i;
/*
* Output the row containing this commit
@@ -906,7 +993,6 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
* children that we have already processed.)
*/
seen_this = 0;
- chars_written = 0;
for (i = 0; i <= graph->num_columns; i++) {
struct column *col = &graph->columns[i];
struct commit *col_commit;
@@ -920,19 +1006,17 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
if (col_commit == graph->commit) {
seen_this = 1;
- graph_output_commit_char(graph, sb);
- chars_written++;
+ graph_output_commit_char(graph, line);
if (graph->num_parents > 2)
- chars_written += graph_draw_octopus_merge(graph,
- sb);
- } else if (seen_this && (graph->num_parents > 2)) {
- strbuf_write_column(sb, col, '\\');
- chars_written++;
- } else if (seen_this && (graph->num_parents == 2)) {
+ graph_draw_octopus_merge(graph, line);
+ } else if (seen_this && (graph->edges_added > 1)) {
+ graph_line_write_column(line, col, '\\');
+ } else if (seen_this && (graph->edges_added == 1)) {
/*
- * This is a 2-way merge commit.
- * There is no GRAPH_PRE_COMMIT stage for 2-way
+ * This is either a right-skewed 2-way merge
+ * commit, or a left-skewed 3-way merge.
+ * There is no GRAPH_PRE_COMMIT stage for such
* merges, so this is the first line of output
* for this commit. Check to see what the previous
* line of output was.
@@ -944,21 +1028,21 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
* makes the output look nicer.
*/
if (graph->prev_state == GRAPH_POST_MERGE &&
+ graph->prev_edges_added > 0 &&
graph->prev_commit_index < i)
- strbuf_write_column(sb, col, '\\');
+ graph_line_write_column(line, col, '\\');
else
- strbuf_write_column(sb, col, '|');
- chars_written++;
+ graph_line_write_column(line, col, '|');
+ } else if (graph->prev_state == GRAPH_COLLAPSING &&
+ graph->old_mapping[2 * i + 1] == i &&
+ graph->mapping[2 * i] < i) {
+ graph_line_write_column(line, col, '/');
} else {
- strbuf_write_column(sb, col, '|');
- chars_written++;
+ graph_line_write_column(line, col, '|');
}
- strbuf_addch(sb, ' ');
- chars_written++;
+ graph_line_addch(line, ' ');
}
- graph_pad_horizontally(graph, sb, chars_written);
-
/*
* Update graph->state
*/
@@ -970,26 +1054,19 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
graph_update_state(graph, GRAPH_COLLAPSING);
}
-static struct column *find_new_column_by_commit(struct git_graph *graph,
- struct commit *commit)
-{
- int i;
- for (i = 0; i < graph->num_new_columns; i++) {
- if (graph->new_columns[i].commit == commit)
- return &graph->new_columns[i];
- }
- return NULL;
-}
+const char merge_chars[] = {'/', '|', '\\'};
-static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_post_merge_line(struct git_graph *graph, struct graph_line *line)
{
int seen_this = 0;
- int i, j, chars_written;
+ int i, j;
+
+ struct commit_list *first_parent = first_interesting_parent(graph);
+ int seen_parent = 0;
/*
* Output the post-merge row
*/
- chars_written = 0;
for (i = 0; i <= graph->num_columns; i++) {
struct column *col = &graph->columns[i];
struct commit *col_commit;
@@ -1008,37 +1085,44 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf
* new_columns and use those to format the
* edges.
*/
- struct commit_list *parents = NULL;
- struct column *par_column;
+ struct commit_list *parents = first_parent;
+ int par_column;
+ int idx = graph->merge_layout;
+ char c;
seen_this = 1;
- parents = first_interesting_parent(graph);
- assert(parents);
- par_column = find_new_column_by_commit(graph, parents->item);
- assert(par_column);
-
- strbuf_write_column(sb, par_column, '|');
- chars_written++;
- for (j = 0; j < graph->num_parents - 1; j++) {
+
+ for (j = 0; j < graph->num_parents; j++) {
+ par_column = graph_find_new_column_by_commit(graph, parents->item);
+ assert(par_column >= 0);
+
+ c = merge_chars[idx];
+ graph_line_write_column(line, &graph->new_columns[par_column], c);
+ if (idx == 2) {
+ if (graph->edges_added > 0 || j < graph->num_parents - 1)
+ graph_line_addch(line, ' ');
+ } else {
+ idx++;
+ }
parents = next_interesting_parent(graph, parents);
- assert(parents);
- par_column = find_new_column_by_commit(graph, parents->item);
- assert(par_column);
- strbuf_write_column(sb, par_column, '\\');
- strbuf_addch(sb, ' ');
}
- chars_written += j * 2;
+ if (graph->edges_added == 0)
+ graph_line_addch(line, ' ');
+
} else if (seen_this) {
- strbuf_write_column(sb, col, '\\');
- strbuf_addch(sb, ' ');
- chars_written += 2;
+ if (graph->edges_added > 0)
+ graph_line_write_column(line, col, '\\');
+ else
+ graph_line_write_column(line, col, '|');
+ graph_line_addch(line, ' ');
} else {
- strbuf_write_column(sb, col, '|');
- strbuf_addch(sb, ' ');
- chars_written += 2;
+ graph_line_write_column(line, col, '|');
+ if (graph->merge_layout != 0 || i != graph->commit_index - 1)
+ graph_line_addch(line, seen_parent ? '_' : ' ');
}
- }
- graph_pad_horizontally(graph, sb, chars_written);
+ if (col_commit == first_parent->item)
+ seen_parent = 1;
+ }
/*
* Update graph->state
@@ -1049,7 +1133,7 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf
graph_update_state(graph, GRAPH_COLLAPSING);
}
-static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_collapsing_line(struct git_graph *graph, struct graph_line *line)
{
int i;
short used_horizontal = 0;
@@ -1057,13 +1141,18 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
int horizontal_edge_target = -1;
/*
- * Clear out the new_mapping array
+ * Swap the mapping and old_mapping arrays
+ */
+ SWAP(graph->mapping, graph->old_mapping);
+
+ /*
+ * Clear out the mapping array
*/
for (i = 0; i < graph->mapping_size; i++)
- graph->new_mapping[i] = -1;
+ graph->mapping[i] = -1;
for (i = 0; i < graph->mapping_size; i++) {
- int target = graph->mapping[i];
+ int target = graph->old_mapping[i];
if (target < 0)
continue;
@@ -1084,14 +1173,14 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
* This column is already in the
* correct place
*/
- assert(graph->new_mapping[i] == -1);
- graph->new_mapping[i] = target;
- } else if (graph->new_mapping[i - 1] < 0) {
+ assert(graph->mapping[i] == -1);
+ graph->mapping[i] = target;
+ } else if (graph->mapping[i - 1] < 0) {
/*
* Nothing is to the left.
* Move to the left by one
*/
- graph->new_mapping[i - 1] = target;
+ graph->mapping[i - 1] = target;
/*
* If there isn't already an edge moving horizontally
* select this one.
@@ -1107,9 +1196,9 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
* line.
*/
for (j = (target * 2)+3; j < (i - 2); j += 2)
- graph->new_mapping[j] = target;
+ graph->mapping[j] = target;
}
- } else if (graph->new_mapping[i - 1] == target) {
+ } else if (graph->mapping[i - 1] == target) {
/*
* There is a branch line to our left
* already, and it is our target. We
@@ -1117,7 +1206,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
* the same parent commit.
*
* We don't have to add anything to the
- * output or new_mapping, since the
+ * output or mapping, since the
* existing branch line has already taken
* care of it.
*/
@@ -1133,10 +1222,10 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
* The branch to the left of that space
* should be our eventual target.
*/
- assert(graph->new_mapping[i - 1] > target);
- assert(graph->new_mapping[i - 2] < 0);
- assert(graph->new_mapping[i - 3] == target);
- graph->new_mapping[i - 2] = target;
+ assert(graph->mapping[i - 1] > target);
+ assert(graph->mapping[i - 2] < 0);
+ assert(graph->mapping[i - 3] == target);
+ graph->mapping[i - 2] = target;
/*
* Mark this branch as the horizontal edge to
* prevent any other edges from moving
@@ -1148,20 +1237,25 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
}
/*
+ * Copy the current mapping array into old_mapping
+ */
+ COPY_ARRAY(graph->old_mapping, graph->mapping, graph->mapping_size);
+
+ /*
* The new mapping may be 1 smaller than the old mapping
*/
- if (graph->new_mapping[graph->mapping_size - 1] < 0)
+ if (graph->mapping[graph->mapping_size - 1] < 0)
graph->mapping_size--;
/*
* Output out a line based on the new mapping info
*/
for (i = 0; i < graph->mapping_size; i++) {
- int target = graph->new_mapping[i];
+ int target = graph->mapping[i];
if (target < 0)
- strbuf_addch(sb, ' ');
+ graph_line_addch(line, ' ');
else if (target * 2 == i)
- strbuf_write_column(sb, &graph->new_columns[target], '|');
+ graph_line_write_column(line, &graph->new_columns[target], '|');
else if (target == horizontal_edge_target &&
i != horizontal_edge - 1) {
/*
@@ -1170,24 +1264,17 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
* won't continue into the next line.
*/
if (i != (target * 2)+3)
- graph->new_mapping[i] = -1;
+ graph->mapping[i] = -1;
used_horizontal = 1;
- strbuf_write_column(sb, &graph->new_columns[target], '_');
+ graph_line_write_column(line, &graph->new_columns[target], '_');
} else {
if (used_horizontal && i < horizontal_edge)
- graph->new_mapping[i] = -1;
- strbuf_write_column(sb, &graph->new_columns[target], '/');
+ graph->mapping[i] = -1;
+ graph_line_write_column(line, &graph->new_columns[target], '/');
}
}
- graph_pad_horizontally(graph, sb, graph->mapping_size);
-
- /*
- * Swap mapping and new_mapping
- */
- SWAP(graph->mapping, graph->new_mapping);
-
/*
* If graph->mapping indicates that all of the branch lines
* are already in the correct positions, we are done.
@@ -1199,35 +1286,49 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
int graph_next_line(struct git_graph *graph, struct strbuf *sb)
{
+ int shown_commit_line = 0;
+ struct graph_line line = { .buf = sb, .width = 0 };
+
+ /*
+ * We could conceivable be called with a NULL commit
+ * if our caller has a bug, and invokes graph_next_line()
+ * immediately after graph_init(), without first calling
+ * graph_update(). Return without outputting anything in this
+ * case.
+ */
+ if (!graph->commit)
+ return -1;
+
switch (graph->state) {
case GRAPH_PADDING:
- graph_output_padding_line(graph, sb);
- return 0;
+ graph_output_padding_line(graph, &line);
+ break;
case GRAPH_SKIP:
- graph_output_skip_line(graph, sb);
- return 0;
+ graph_output_skip_line(graph, &line);
+ break;
case GRAPH_PRE_COMMIT:
- graph_output_pre_commit_line(graph, sb);
- return 0;
+ graph_output_pre_commit_line(graph, &line);
+ break;
case GRAPH_COMMIT:
- graph_output_commit_line(graph, sb);
- return 1;
+ graph_output_commit_line(graph, &line);
+ shown_commit_line = 1;
+ break;
case GRAPH_POST_MERGE:
- graph_output_post_merge_line(graph, sb);
- return 0;
+ graph_output_post_merge_line(graph, &line);
+ break;
case GRAPH_COLLAPSING:
- graph_output_collapsing_line(graph, sb);
- return 0;
+ graph_output_collapsing_line(graph, &line);
+ break;
}
- assert(0);
- return 0;
+ graph_pad_horizontally(graph, &line);
+ return shown_commit_line;
}
static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
{
int i;
- int chars_written = 0;
+ struct graph_line line = { .buf = sb, .width = 0 };
if (graph->state != GRAPH_COMMIT) {
graph_next_line(graph, sb);
@@ -1244,20 +1345,17 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
for (i = 0; i < graph->num_columns; i++) {
struct column *col = &graph->columns[i];
- strbuf_write_column(sb, col, '|');
- chars_written++;
+ graph_line_write_column(&line, col, '|');
if (col->commit == graph->commit && graph->num_parents > 2) {
int len = (graph->num_parents - 2) * 2;
- strbuf_addchars(sb, ' ', len);
- chars_written += len;
+ graph_line_addchars(&line, ' ', len);
} else {
- strbuf_addch(sb, ' ');
- chars_written++;
+ graph_line_addch(&line, ' ');
}
}
- graph_pad_horizontally(graph, sb, chars_written);
+ graph_pad_horizontally(graph, &line);
/*
* Update graph->prev_state since we have output a padding line
diff --git a/hashmap.c b/hashmap.c
index 39c1311..09813e1 100644
--- a/hashmap.c
+++ b/hashmap.c
@@ -51,7 +51,7 @@ unsigned int memihash(const void *buf, size_t len)
}
/*
- * Incoporate another chunk of data into a memihash
+ * Incorporate another chunk of data into a memihash
* computation.
*/
unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len)
diff --git a/hashmap.h b/hashmap.h
index bd27015..79ae9f8 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -59,7 +59,7 @@
*
* if (!strcmp("print_all_by_key", action)) {
* struct long2string k, *e;
- * hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));
+ * hashmap_entry_init(&k.ent, memhash(&key, sizeof(long)));
* k.key = key;
*
* flags &= ~COMPARE_VALUE;
@@ -87,12 +87,12 @@
*
* if (!strcmp("has_exact_match_no_heap_alloc", action)) {
* struct long2string k;
- * hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));
+ * hashmap_entry_init(&k.ent, memhash(&key, sizeof(long)));
* k.key = key;
*
* flags |= COMPARE_VALUE;
* printf("%sfound\n",
- * hashmap_get(&map, &k->ent, value) ? "" : "not ");
+ * hashmap_get(&map, &k.ent, value) ? "" : "not ");
* }
*
* if (!strcmp("end", action)) {
@@ -502,7 +502,7 @@ static inline void hashmap_disable_item_counting(struct hashmap *map)
}
/*
- * Re-enable item couting when adding/removing items.
+ * Re-enable item counting when adding/removing items.
* If counting is currently disabled, it will force count them.
* It WILL NOT automatically rehash them.
*/
diff --git a/help.c b/help.c
index 9ff2be6..cf67624 100644
--- a/help.c
+++ b/help.c
@@ -34,7 +34,7 @@ static struct category_description main_categories[] = {
{ CAT_foreignscminterface, N_("Interacting with Others") },
{ CAT_plumbingmanipulators, N_("Low-level Commands / Manipulators") },
{ CAT_plumbinginterrogators, N_("Low-level Commands / Interrogators") },
- { CAT_synchingrepositories, N_("Low-level Commands / Synching Repositories") },
+ { CAT_synchingrepositories, N_("Low-level Commands / Syncing Repositories") },
{ CAT_purehelpers, N_("Low-level Commands / Internal Helpers") },
{ 0, NULL }
};
diff --git a/hex.c b/hex.c
index 7850a88..fd7f00c 100644
--- a/hex.c
+++ b/hex.c
@@ -90,11 +90,6 @@ char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash,
return buffer;
}
-char *sha1_to_hex_r(char *buffer, const unsigned char *sha1)
-{
- return hash_to_hex_algop_r(buffer, sha1, &hash_algos[GIT_HASH_SHA1]);
-}
-
char *oid_to_hex_r(char *buffer, const struct object_id *oid)
{
return hash_to_hex_algop_r(buffer, oid->hash, the_hash_algo);
@@ -108,11 +103,6 @@ char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *a
return hash_to_hex_algop_r(hexbuffer[bufno], hash, algop);
}
-char *sha1_to_hex(const unsigned char *sha1)
-{
- return hash_to_hex_algop(sha1, &hash_algos[GIT_HASH_SHA1]);
-}
-
char *hash_to_hex(const unsigned char *hash)
{
return hash_to_hex_algop(hash, the_hash_algo);
diff --git a/http.c b/http.c
index 027a86d..5f34816 100644
--- a/http.c
+++ b/http.c
@@ -150,7 +150,7 @@ static unsigned long empty_auth_useless =
static struct curl_slist *pragma_header;
static struct curl_slist *no_pragma_header;
-static struct curl_slist *extra_http_headers;
+static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
static struct active_request_slot *active_queue_head;
@@ -414,11 +414,9 @@ static int http_options(const char *var, const char *value, void *cb)
if (!value) {
return config_error_nonbool(var);
} else if (!*value) {
- curl_slist_free_all(extra_http_headers);
- extra_http_headers = NULL;
+ string_list_clear(&extra_http_headers, 0);
} else {
- extra_http_headers =
- curl_slist_append(extra_http_headers, value);
+ string_list_append(&extra_http_headers, value);
}
return 0;
}
@@ -1202,8 +1200,7 @@ void http_cleanup(void)
#endif
curl_global_cleanup();
- curl_slist_free_all(extra_http_headers);
- extra_http_headers = NULL;
+ string_list_clear(&extra_http_headers, 0);
curl_slist_free_all(pragma_header);
pragma_header = NULL;
@@ -1627,10 +1624,11 @@ int run_one_slot(struct active_request_slot *slot,
struct curl_slist *http_copy_default_headers(void)
{
- struct curl_slist *headers = NULL, *h;
+ struct curl_slist *headers = NULL;
+ const struct string_list_item *item;
- for (h = extra_http_headers; h; h = h->next)
- headers = curl_slist_append(headers, h->data);
+ for_each_string_list_item(item, &extra_http_headers)
+ headers = curl_slist_append(headers, item->string);
return headers;
}
diff --git a/kwset.h b/kwset.h
index df99a92..f50ecae 100644
--- a/kwset.h
+++ b/kwset.h
@@ -1,3 +1,6 @@
+#ifndef KWSET_H
+#define KWSET_H
+
/* This file has been copied from commit e7ac713d^ in the GNU grep git
* repository. A few small changes have been made to adapt the code to
* Git.
@@ -59,3 +62,4 @@ size_t kwsexec(kwset_t, char const *, size_t, struct kwsmatch *);
/* Deallocate the given keyword set and all its associated storage. */
void kwsfree(kwset_t);
+#endif /* KWSET_H */
diff --git a/name-hash.c b/name-hash.c
index ceb1d7b..fb526a3 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -138,7 +138,7 @@ static int lazy_nr_dir_threads;
/*
* Set a minimum number of cache_entries that we will handle per
- * thread and use that to decide how many threads to run (upto
+ * thread and use that to decide how many threads to run (up to
* the number on the system).
*
* For guidance setting the lower per-thread bound, see:
@@ -218,7 +218,7 @@ static int lookup_lazy_params(struct index_state *istate)
* However, the hashmap is going to put items into bucket
* chains based on their hash values. Use that to create n
* mutexes and lock on mutex[bucket(hash) % n]. This will
- * decrease the collision rate by (hopefully) by a factor of n.
+ * decrease the collision rate by (hopefully) a factor of n.
*/
static void init_dir_mutex(void)
{
diff --git a/pack-objects.c b/pack-objects.c
index c6250d7..5e5a3c6 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -119,7 +119,10 @@ void oe_map_new_pack(struct packing_data *pack)
{
uint32_t i;
- REALLOC_ARRAY(pack->in_pack, pack->nr_alloc);
+ if (pack->in_pack)
+ BUG("packing_data has already been converted to pack array");
+
+ ALLOC_ARRAY(pack->in_pack, pack->nr_alloc);
for (i = 0; i < pack->nr_objects; i++)
pack->in_pack[i] = oe_in_pack(pack, pack->objects + i);
diff --git a/pack-objects.h b/pack-objects.h
index 6fe6ae5..d3975e0 100644
--- a/pack-objects.h
+++ b/pack-objects.h
@@ -251,12 +251,21 @@ static inline void oe_set_in_pack(struct packing_data *pack,
struct object_entry *e,
struct packed_git *p)
{
- if (!p->index)
+ if (pack->in_pack_by_idx) {
+ if (p->index) {
+ e->in_pack_idx = p->index;
+ return;
+ }
+ /*
+ * We're accessing packs by index, but this pack doesn't have
+ * an index (e.g., because it was added since we created the
+ * in_pack_by_idx array). Bail to oe_map_new_pack(), which
+ * will convert us to using the full in_pack array, and then
+ * fall through to our in_pack handling.
+ */
oe_map_new_pack(pack);
- if (pack->in_pack_by_idx)
- e->in_pack_idx = p->index;
- else
- pack->in_pack[e - pack->objects] = p;
+ }
+ pack->in_pack[e - pack->objects] = p;
}
static inline struct object_entry *oe_delta(
diff --git a/parse-options-cb.c b/parse-options-cb.c
index 1240a85..c2062ae 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -161,6 +161,7 @@ int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)
struct option *parse_options_dup(const struct option *o)
{
+ const struct option *orig = o;
struct option *opts;
int nr = 0;
@@ -170,7 +171,7 @@ struct option *parse_options_dup(const struct option *o)
}
ALLOC_ARRAY(opts, nr + 1);
- memcpy(opts, o - nr, sizeof(*o) * nr);
+ COPY_ARRAY(opts, orig, nr);
memset(opts + nr, 0, sizeof(*opts));
opts[nr].type = OPTION_END;
return opts;
diff --git a/parse-options.c b/parse-options.c
index b42f54d..60fae3a 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -623,7 +623,7 @@ static int show_gitcomp(const struct option *opts)
* Scan and may produce a new option[] array, which should be used
* instead of the original 'options'.
*
- * Right now this is only used to preprocess and substitue
+ * Right now this is only used to preprocess and substitute
* OPTION_ALIAS.
*/
static struct option *preprocess_options(struct parse_opt_ctx_t *ctx,
diff --git a/path.c b/path.c
index e21b00c..0607156 100644
--- a/path.c
+++ b/path.c
@@ -11,6 +11,7 @@
#include "path.h"
#include "packfile.h"
#include "object-store.h"
+#include "lockfile.h"
static int get_st_mode_bits(const char *path, int *mode)
{
@@ -362,9 +363,14 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,
const char *common_dir)
{
char *base = buf->buf + git_dir_len;
+ int has_lock_suffix = strbuf_strip_suffix(buf, LOCK_SUFFIX);
+
init_common_trie();
if (trie_find(&common_trie, base, check_common, NULL) > 0)
replace_dir(buf, git_dir_len, common_dir);
+
+ if (has_lock_suffix)
+ strbuf_addstr(buf, LOCK_SUFFIX);
}
void report_linked_checkout_garbage(void)
diff --git a/perl/Git.pm b/perl/Git.pm
index 62c472e..54c9ed0 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -563,7 +563,7 @@ sub get_record {
Query user C<PROMPT> and return answer from user.
Honours GIT_ASKPASS and SSH_ASKPASS environment variables for querying
-the user. If no *_ASKPASS variable is set or an error occoured,
+the user. If no *_ASKPASS variable is set or an error occurred,
the terminal is tried as a fallback.
If C<ISPASSWORD> is set and true, the terminal disables echo.
diff --git a/promisor-remote.c b/promisor-remote.c
index 9bd5b79..9f338c9 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -16,10 +16,8 @@ static int fetch_refs(const char *remote_name, struct ref *ref)
{
struct remote *remote;
struct transport *transport;
- int original_fetch_if_missing = fetch_if_missing;
int res;
- fetch_if_missing = 0;
remote = remote_get(remote_name);
if (!remote->url[0])
die(_("Remote with no URL"));
@@ -28,7 +26,6 @@ static int fetch_refs(const char *remote_name, struct ref *ref)
transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
res = transport_fetch_refs(transport, ref);
- fetch_if_missing = original_fetch_if_missing;
return res;
}
diff --git a/range-diff.h b/range-diff.h
index 08a50b6..77347a9 100644
--- a/range-diff.h
+++ b/range-diff.h
@@ -6,7 +6,7 @@
#define RANGE_DIFF_CREATION_FACTOR_DEFAULT 60
/*
- * Compare series of commmits in RANGE1 and RANGE2, and emit to the
+ * Compare series of commits in RANGE1 and RANGE2, and emit to the
* standard output. NULL can be passed to DIFFOPT to use the built-in
* default.
*/
diff --git a/read-cache.c b/read-cache.c
index 133f790..0674428 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1790,7 +1790,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
const unsigned char *cp = (const unsigned char *)name;
size_t strip_len, previous_len;
- /* If we're at the begining of a block, ignore the previous name */
+ /* If we're at the beginning of a block, ignore the previous name */
strip_len = decode_varint(&cp);
if (previous_ce) {
previous_len = previous_ce->ce_namelen;
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index f2d8c01..ff2436c 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -262,7 +262,7 @@ int refs_rename_ref_available(struct ref_store *refs,
* after calling ref_iterator_advance() again or calling
* ref_iterator_abort(), you must make a copy. When the iteration has
* been exhausted, ref_iterator_advance() releases any resources
- * assocated with the iteration, frees the ref_iterator object, and
+ * associated with the iteration, frees the ref_iterator object, and
* returns ITER_DONE. If you want to abort the iteration early, call
* ref_iterator_abort(), which also frees the ref_iterator object and
* any associated resources. If there was an internal error advancing
diff --git a/repository.c b/repository.c
index 682c239..a4174dd 100644
--- a/repository.c
+++ b/repository.c
@@ -200,9 +200,9 @@ int repo_submodule_init(struct repository *subrepo,
if (repo_init(subrepo, gitdir.buf, worktree.buf)) {
/*
- * If initilization fails then it may be due to the submodule
+ * If initialization fails then it may be due to the submodule
* not being populated in the superproject's worktree. Instead
- * we can try to initilize the submodule by finding it's gitdir
+ * we can try to initialize the submodule by finding it's gitdir
* in the superproject's 'modules' directory. In this case the
* submodule would not have a worktree.
*/
diff --git a/repository.h b/repository.h
index fe42197..040057d 100644
--- a/repository.h
+++ b/repository.h
@@ -172,7 +172,7 @@ void repo_clear(struct repository *repo);
* be allocated if needed.
*
* Return the number of index entries in the populated index or a value less
- * than zero if an error occured. If the repository's index has already been
+ * than zero if an error occurred. If the repository's index has already been
* populated then the number of entries will simply be returned.
*/
int repo_read_index(struct repository *repo);
diff --git a/rerere.c b/rerere.c
index 3e51fdf..9281131 100644
--- a/rerere.c
+++ b/rerere.c
@@ -431,7 +431,7 @@ static int handle_conflict(struct strbuf *out, struct rerere_io *io,
* and NUL concatenated together.
*
* Return 1 if conflict hunks are found, 0 if there are no conflict
- * hunks and -1 if an error occured.
+ * hunks and -1 if an error occurred.
*/
static int handle_path(unsigned char *hash, struct rerere_io *io, int marker_size)
{
diff --git a/send-pack.c b/send-pack.c
index 34c77cb..a7322d3 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -565,8 +565,6 @@ int send_pack(struct send_pack_args *args,
if (need_pack_data && cmds_sent) {
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
- for (ref = remote_refs; ref; ref = ref->next)
- ref->status = REF_STATUS_NONE;
if (args->stateless_rpc)
close(out);
if (git_connection_is_socket(conn))
@@ -574,10 +572,12 @@ int send_pack(struct send_pack_args *args,
/*
* Do not even bother with the return value; we know we
- * are failing, and just want the error() side effects.
+ * are failing, and just want the error() side effects,
+ * as well as marking refs with their remote status (if
+ * we get one).
*/
if (status_report)
- receive_unpack_status(&reader);
+ receive_status(&reader, remote_refs);
if (use_sideband) {
close(demux.out);
diff --git a/sequencer.c b/sequencer.c
index 9147d02..e65076f 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -131,7 +131,7 @@ static GIT_PATH_FUNC(rebase_path_rewritten_pending,
"rebase-merge/rewritten-pending")
/*
- * The path of the file containig the OID of the "squash onto" commit, i.e.
+ * The path of the file containing the OID of the "squash onto" commit, i.e.
* the dummy commit used for `reset [new root]`.
*/
static GIT_PATH_FUNC(rebase_path_squash_onto, "rebase-merge/squash-onto")
@@ -1574,6 +1574,7 @@ static int update_squash_messages(struct repository *r,
struct strbuf buf = STRBUF_INIT;
int res;
const char *message, *body;
+ const char *encoding = get_commit_output_encoding();
if (opts->current_fixup_count > 0) {
struct strbuf header = STRBUF_INIT;
@@ -1600,7 +1601,7 @@ static int update_squash_messages(struct repository *r,
return error(_("need a HEAD to fixup"));
if (!(head_commit = lookup_commit_reference(r, &head)))
return error(_("could not read HEAD"));
- if (!(head_message = get_commit_buffer(head_commit, NULL)))
+ if (!(head_message = logmsg_reencode(head_commit, NULL, encoding)))
return error(_("could not read HEAD's commit message"));
find_commit_subject(head_message, &body);
@@ -1621,7 +1622,7 @@ static int update_squash_messages(struct repository *r,
unuse_commit_buffer(head_commit, head_message);
}
- if (!(message = get_commit_buffer(commit, NULL)))
+ if (!(message = logmsg_reencode(commit, NULL, encoding)))
return error(_("could not read commit message of %s"),
oid_to_hex(&commit->object.oid));
find_commit_subject(message, &body);
@@ -2562,14 +2563,17 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
enum todo_command command = opts->action == REPLAY_PICK ?
TODO_PICK : TODO_REVERT;
const char *command_string = todo_command_info[command].str;
+ const char *encoding;
struct commit *commit;
if (prepare_revs(opts))
return -1;
+ encoding = get_log_output_encoding();
+
while ((commit = get_revision(opts->revs))) {
struct todo_item *item = append_new_todo(todo_list);
- const char *commit_buffer = get_commit_buffer(commit, NULL);
+ const char *commit_buffer = logmsg_reencode(commit, NULL, encoding);
const char *subject;
int subject_len;
@@ -2966,7 +2970,8 @@ static int make_patch(struct repository *r,
strbuf_addf(&buf, "%s/message", get_dir(opts));
if (!file_exists(buf.buf)) {
- const char *commit_buffer = get_commit_buffer(commit, NULL);
+ const char *encoding = get_commit_output_encoding();
+ const char *commit_buffer = logmsg_reencode(commit, NULL, encoding);
find_commit_subject(commit_buffer, &subject);
res |= write_message(subject, strlen(subject), buf.buf, 1);
unuse_commit_buffer(commit, commit_buffer);
@@ -3368,7 +3373,8 @@ static int do_merge(struct repository *r,
}
if (commit) {
- const char *message = get_commit_buffer(commit, NULL);
+ const char *encoding = get_commit_output_encoding();
+ const char *message = logmsg_reencode(commit, NULL, encoding);
const char *body;
int len;
@@ -4149,9 +4155,10 @@ static int commit_staged_changes(struct repository *r,
*/
struct commit *commit;
const char *path = rebase_path_squash_msg();
+ const char *encoding = get_commit_output_encoding();
if (parse_head(r, &commit) ||
- !(p = get_commit_buffer(commit, NULL)) ||
+ !(p = logmsg_reencode(commit, NULL, encoding)) ||
write_message(p, strlen(p), path, 0)) {
unuse_commit_buffer(commit, p);
return error(_("could not write file: "
@@ -4665,7 +4672,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
label_oid(oid, "branch-point", &state);
}
- /* Add HEAD as implict "tip of branch" */
+ /* Add HEAD as implicit "tip of branch" */
if (!iter->next)
tips_tail = &commit_list_insert(iter->item,
tips_tail)->next;
@@ -4847,7 +4854,7 @@ void todo_list_add_exec_commands(struct todo_list *todo_list,
* are considered part of the pick, so we insert the commands *after*
* those chains if there are any.
*
- * As we insert the exec commands immediatly after rearranging
+ * As we insert the exec commands immediately after rearranging
* any fixups and before the user edits the list, a fixup chain
* can never contain comments (any comments are empty picks that
* have been commented out because the user did not specify
@@ -5190,7 +5197,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
*commit_todo_item_at(&commit_todo, item->commit) = item;
parse_commit(item->commit);
- commit_buffer = get_commit_buffer(item->commit, NULL);
+ commit_buffer = logmsg_reencode(item->commit, NULL, "UTF-8");
find_commit_subject(commit_buffer, &subject);
format_subject(&buf, subject, " ");
subject = subjects[i] = strbuf_detach(&buf, &subject_len);
diff --git a/server-info.c b/server-info.c
index 4d8199b..bae2cdf 100644
--- a/server-info.c
+++ b/server-info.c
@@ -93,7 +93,7 @@ static int update_info_file(char *path,
uic.old_fp = fopen_or_warn(path, "r");
/*
- * uic_printf will compare incremental comparison aginst old_fp
+ * uic_printf will compare incremental comparison against old_fp
* and mark uic as stale if needed
*/
ret = generate(&uic);
diff --git a/sha1dc/sha1.c b/sha1dc/sha1.c
index 9d3cf81..63cd5c9 100644
--- a/sha1dc/sha1.c
+++ b/sha1dc/sha1.c
@@ -72,7 +72,7 @@
/* Not under GCC-alike or glibc */
#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
/*
- * *BSD and newlib (embeded linux, cygwin, etc).
+ * *BSD and newlib (embedded linux, cygwin, etc).
* the defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) part prevents
* this condition from matching with Solaris/sparc.
* (Solaris defines only one endian macro)
diff --git a/sha1dc_git.c b/sha1dc_git.c
index e0cc9d9..5c300e8 100644
--- a/sha1dc_git.c
+++ b/sha1dc_git.c
@@ -19,7 +19,7 @@ void git_SHA1DCFinal(unsigned char hash[20], SHA1_CTX *ctx)
if (!SHA1DCFinal(hash, ctx))
return;
die("SHA-1 appears to be part of a collision attack: %s",
- sha1_to_hex(hash));
+ hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1]));
}
/*
diff --git a/string-list.h b/string-list.h
index f964399..7bb0ad0 100644
--- a/string-list.h
+++ b/string-list.h
@@ -179,7 +179,7 @@ void string_list_remove(struct string_list *list, const char *string,
/**
* Check if the given string is part of a sorted list. If it is part of the list,
- * return the coresponding string_list_item, NULL otherwise.
+ * return the corresponding string_list_item, NULL otherwise.
*/
struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
diff --git a/t/README b/t/README
index 60d5b77..5132ec8 100644
--- a/t/README
+++ b/t/README
@@ -397,6 +397,10 @@ GIT_TEST_STASH_USE_BUILTIN=<boolean>, when false, disables the
built-in version of git-stash. See 'stash.useBuiltin' in
git-config(1).
+GIT_TEST_ADD_I_USE_BUILTIN=<boolean>, when true, enables the
+built-in version of git add -i. See 'add.interactive.useBuiltin' in
+git-config(1).
+
GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
of the index for the whole test suite by bypassing the default number of
cache entries and thread minimums. Setting this to 1 will make the
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
index 006d2a8..1f32ca6 100644
--- a/t/gitweb-lib.sh
+++ b/t/gitweb-lib.sh
@@ -58,10 +58,11 @@ gitweb_run () {
GATEWAY_INTERFACE='CGI/1.1'
HTTP_ACCEPT='*/*'
REQUEST_METHOD='GET'
- QUERY_STRING=""$1""
- PATH_INFO=""$2""
+ QUERY_STRING=$1
+ PATH_INFO=$2
+ REQUEST_URI=/gitweb.cgi$PATH_INFO
export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
- QUERY_STRING PATH_INFO
+ QUERY_STRING PATH_INFO REQUEST_URI
GITWEB_CONFIG=$(pwd)/gitweb_config.perl
export GITWEB_CONFIG
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
new file mode 100644
index 0000000..d2884ef
--- /dev/null
+++ b/t/helper/test-read-graph.c
@@ -0,0 +1,53 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "commit-graph.h"
+#include "repository.h"
+#include "object-store.h"
+
+int cmd__read_graph(int argc, const char **argv)
+{
+ struct commit_graph *graph = NULL;
+ char *graph_name;
+ int open_ok;
+ int fd;
+ struct stat st;
+ const char *object_dir;
+
+ setup_git_directory();
+ object_dir = get_object_directory();
+
+ graph_name = get_commit_graph_filename(object_dir);
+
+ open_ok = open_commit_graph(graph_name, &fd, &st);
+ if (!open_ok)
+ die_errno(_("Could not open commit-graph '%s'"), graph_name);
+
+ graph = load_commit_graph_one_fd_st(fd, &st);
+ if (!graph)
+ return 1;
+
+ FREE_AND_NULL(graph_name);
+
+ printf("header: %08x %d %d %d %d\n",
+ ntohl(*(uint32_t*)graph->data),
+ *(unsigned char*)(graph->data + 4),
+ *(unsigned char*)(graph->data + 5),
+ *(unsigned char*)(graph->data + 6),
+ *(unsigned char*)(graph->data + 7));
+ printf("num_commits: %u\n", graph->num_commits);
+ printf("chunks:");
+
+ if (graph->chunk_oid_fanout)
+ printf(" oid_fanout");
+ if (graph->chunk_oid_lookup)
+ printf(" oid_lookup");
+ if (graph->chunk_commit_data)
+ printf(" commit_metadata");
+ if (graph->chunk_extra_edges)
+ printf(" extra_edges");
+ printf("\n");
+
+ UNLEAK(graph);
+
+ return 0;
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 19ee26d..f20989d 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -45,6 +45,7 @@ static struct test_cmd cmds[] = {
{ "progress", cmd__progress },
{ "reach", cmd__reach },
{ "read-cache", cmd__read_cache },
+ { "read-graph", cmd__read_graph },
{ "read-midx", cmd__read_midx },
{ "ref-store", cmd__ref_store },
{ "regex", cmd__regex },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index c2aa56e..8ed2af7 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -35,6 +35,7 @@ int cmd__prio_queue(int argc, const char **argv);
int cmd__progress(int argc, const char **argv);
int cmd__reach(int argc, const char **argv);
int cmd__read_cache(int argc, const char **argv);
+int cmd__read_graph(int argc, const char **argv);
int cmd__read_midx(int argc, const char **argv);
int cmd__ref_store(int argc, const char **argv);
int cmd__regex(int argc, const char **argv);
diff --git a/t/perf/bisect_regression b/t/perf/bisect_regression
index a94d995..ce47e16 100755
--- a/t/perf/bisect_regression
+++ b/t/perf/bisect_regression
@@ -51,7 +51,7 @@ oldtime=$(echo "$oldtime" | sed -e 's/^\([0-9]\+\.[0-9]\+\).*$/\1/')
newtime=$(echo "$newtime" | sed -e 's/^\([0-9]\+\.[0-9]\+\).*$/\1/')
test $(echo "$newtime" "$oldtime" | awk '{ print ($1 > $2) }') = 1 ||
- die "New time '$newtime' shoud be greater than old time '$oldtime'"
+ die "New time '$newtime' should be greater than old time '$oldtime'"
tmpdir=$(mktemp -d -t bisect_regression_XXXXXX) || die "Failed to create temp directory"
echo "$oldtime" >"$tmpdir/oldtime" || die "Failed to write to '$tmpdir/oldtime'"
diff --git a/t/perf/p5303-many-packs.sh b/t/perf/p5303-many-packs.sh
index 3779851..a369152 100755
--- a/t/perf/p5303-many-packs.sh
+++ b/t/perf/p5303-many-packs.sh
@@ -77,6 +77,7 @@ do
# actual pack generation, without smudging the on-disk setup
# between trials.
test_perf "repack ($nr_packs)" '
+ GIT_TEST_FULL_IN_PACK_ARRAY=1 \
git pack-objects --keep-true-parents \
--honor-pack-keep --non-empty --all \
--reflog --indexed-objects --delta-base-offset \
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 4d3f7ba..7aabde1 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -126,7 +126,7 @@ check_sub_test_lib_test () {
check_sub_test_lib_test_err () {
name="$1" # stdin is the expected output from the test
- # expected error output is in descriptior 3
+ # expected error output is in descriptor 3
(
cd "$name" &&
sed -e 's/^> //' -e 's/Z$//' >expect.out &&
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 959b6da..9fcd56f 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -215,7 +215,7 @@ stats_ascii () {
}
-# contruct the attr/ returned by git ls-files --eol
+# construct the attr/ returned by git ls-files --eol
# Take none (=empty), one or two args
# convert.c: eol=XX overrides text=auto
attr_ascii () {
diff --git a/t/t0028-working-tree-encoding.sh b/t/t0028-working-tree-encoding.sh
index 7aa0945..bfc4fb9 100755
--- a/t/t0028-working-tree-encoding.sh
+++ b/t/t0028-working-tree-encoding.sh
@@ -17,7 +17,7 @@ test_lazy_prereq NO_UTF32_BOM '
write_utf16 () {
if test_have_prereq NO_UTF16_BOM
then
- printf '\xfe\xff'
+ printf '\376\377'
fi &&
iconv -f UTF-8 -t UTF-16
}
@@ -25,7 +25,7 @@ write_utf16 () {
write_utf32 () {
if test_have_prereq NO_UTF32_BOM
then
- printf '\x00\x00\xfe\xff'
+ printf '\0\0\376\377'
fi &&
iconv -f UTF-8 -t UTF-32
}
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 501e1a2..553e94b 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -285,8 +285,10 @@ test_git_path GIT_OBJECT_DIRECTORY=foo objects/foo foo/foo
test_git_path GIT_OBJECT_DIRECTORY=foo objects2 .git/objects2
test_expect_success 'setup common repository' 'git --git-dir=bar init'
test_git_path GIT_COMMON_DIR=bar index .git/index
+test_git_path GIT_COMMON_DIR=bar index.lock .git/index.lock
test_git_path GIT_COMMON_DIR=bar HEAD .git/HEAD
test_git_path GIT_COMMON_DIR=bar logs/HEAD .git/logs/HEAD
+test_git_path GIT_COMMON_DIR=bar logs/HEAD.lock .git/logs/HEAD.lock
test_git_path GIT_COMMON_DIR=bar logs/refs/bisect/foo .git/logs/refs/bisect/foo
test_git_path GIT_COMMON_DIR=bar logs/refs bar/logs/refs
test_git_path GIT_COMMON_DIR=bar logs/refs/ bar/logs/refs/
diff --git a/t/t0500-progress-display.sh b/t/t0500-progress-display.sh
index 24ccbd8..d2d088d 100755
--- a/t/t0500-progress-display.sh
+++ b/t/t0500-progress-display.sh
@@ -76,7 +76,7 @@ EOF
'
test_expect_success 'progress display breaks long lines #2' '
- # Note: we dont need that many spaces after the title to cover up
+ # Note: we do not need that many spaces after the title to cover up
# the last line before breaking the progress line.
sed -e "s/Z$//" >expect <<\EOF &&
Working hard.......2.........3.........4.........5.........6: 0% (1/100000)<CR>
@@ -104,7 +104,7 @@ EOF
'
test_expect_success 'progress display breaks long lines #3 - even the first is too long' '
- # Note: we dont actually need any spaces at the end of the title
+ # Note: we do not actually need any spaces at the end of the title
# line, because there is no previous progress line to cover up.
sed -e "s/Z$//" >expect <<\EOF &&
Working hard.......2.........3.........4.........5.........6: Z
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index dcb4dbb..d3b2adb 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -194,15 +194,15 @@ test_expect_success 'pack-objects with large loose object' '
test_cmp huge actual
'
-test_expect_success 'tar achiving' '
+test_expect_success 'tar archiving' '
git archive --format=tar HEAD >/dev/null
'
-test_expect_success 'zip achiving, store only' '
+test_expect_success 'zip archiving, store only' '
git archive --format=zip -0 HEAD >/dev/null
'
-test_expect_success 'zip achiving, deflate' '
+test_expect_success 'zip archiving, deflate' '
git archive --format=zip HEAD >/dev/null
'
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 1fbd940..69a7f27 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -344,14 +344,16 @@ test_expect_success "verifying $m's log (logged by config)" '
test_cmp expect .git/logs/$m
'
-git update-ref $m $D
-cat >.git/logs/$m <<EOF
-$Z $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
-$C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150350 -0500
-$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500
-$F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500
-$Z $E $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 -0500
-EOF
+test_expect_success 'set up for querying the reflog' '
+ git update-ref $m $D &&
+ cat >.git/logs/$m <<-EOF
+ $Z $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
+ $C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150350 -0500
+ $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500
+ $F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500
+ $Z $E $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 -0500
+ EOF
+'
ed="Thu, 26 May 2005 18:32:00 -0500"
gd="Thu, 26 May 2005 18:33:00 -0500"
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 50d28e6..7c7ff7e 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -616,7 +616,7 @@ test_expect_success 'fsck --name-objects' '
remove_object $(git rev-parse julius:caesar.t) &&
test_must_fail git fsck --name-objects >out &&
tree=$(git rev-parse --verify julius:) &&
- test_i18ngrep -E "$tree \((refs/heads/master|HEAD)@\{[0-9]*\}:" out
+ test_i18ngrep "$tree (refs/tags/julius:" out
)
'
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index c19fb50..25744e2 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -339,7 +339,7 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '
test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '
test_must_fail git rev-parse 000000000^{commit} 2>stderr &&
grep ^hint: stderr >hints &&
- # 5 commits, 1 tag (which is a commitish), plus intro line
+ # 5 commits, 1 tag (which is a committish), plus intro line
test_line_count = 7 hints
'
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index e819ba7..8a98314 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -587,4 +587,28 @@ test_expect_success '"add" should not fail because of another bad worktree' '
)
'
+test_expect_success '"add" with uninitialized submodule, with submodule.recurse unset' '
+ test_create_repo submodule &&
+ test_commit -C submodule first &&
+ test_create_repo project &&
+ git -C project submodule add ../submodule &&
+ git -C project add submodule &&
+ test_tick &&
+ git -C project commit -m add_sub &&
+ git clone project project-clone &&
+ git -C project-clone worktree add ../project-2
+'
+test_expect_success '"add" with uninitialized submodule, with submodule.recurse set' '
+ git -C project-clone -c submodule.recurse worktree add ../project-3
+'
+
+test_expect_success '"add" with initialized submodule, with submodule.recurse unset' '
+ git -C project-clone submodule update --init &&
+ git -C project-clone worktree add ../project-4
+'
+
+test_expect_success '"add" with initialized submodule, with submodule.recurse set' '
+ git -C project-clone -c submodule.recurse worktree add ../project-5
+'
+
test_done
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 44f378c..52ed665 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -47,7 +47,7 @@ test_expect_success setup '
git add .
'
-test_expect_success 'git -ls-files --with-tree should succeed from subdir' '
+test_expect_success 'git ls-files --with-tree should succeed from subdir' '
# We have to run from a sub-directory to trigger prune_path
# Then we finally get to run our --with-tree test
(
@@ -57,7 +57,7 @@ test_expect_success 'git -ls-files --with-tree should succeed from subdir' '
'
test_expect_success \
- 'git -ls-files --with-tree should add entries from named tree.' \
+ 'git ls-files --with-tree should add entries from named tree.' \
'test_cmp expected output'
test_done
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 9ea5fa4..f41b2af 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -240,7 +240,7 @@ test_expect_success 'retry acquiring packed-refs.lock' '
test_expect_success SYMLINKS 'pack symlinked packed-refs' '
# First make sure that symlinking works when reading:
- git update-ref refs/heads/loosy refs/heads/master &&
+ git update-ref refs/heads/lossy refs/heads/master &&
git for-each-ref >all-refs-before &&
mv .git/packed-refs .git/my-deviant-packed-refs &&
ln -s my-deviant-packed-refs .git/packed-refs &&
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 4e2c0ed..7ab0152 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -408,7 +408,7 @@ test_expect_success 'octopus merges' '
| | * three
| * | two
| |/
- * | one
+ * / one
|/
o before-octopus
EOF
diff --git a/t/t3434-rebase-i18n.sh b/t/t3434-rebase-i18n.sh
new file mode 100755
index 0000000..4b5b128
--- /dev/null
+++ b/t/t3434-rebase-i18n.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Doan Tran Cong Danh
+#
+
+test_description='rebase with changing encoding
+
+Initial setup:
+
+1 - 2 master
+ \
+ 3 - 4 first
+ \
+ 5 - 6 second
+'
+
+. ./test-lib.sh
+
+compare_msg () {
+ iconv -f "$2" -t "$3" "$TEST_DIRECTORY/t3434/$1" >expect &&
+ git cat-file commit HEAD >raw &&
+ sed "1,/^$/d" raw >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success setup '
+ test_commit one &&
+ git branch first &&
+ test_commit two &&
+ git switch first &&
+ test_commit three &&
+ git branch second &&
+ test_commit four &&
+ git switch second &&
+ test_commit five &&
+ test_commit six
+'
+
+test_expect_success 'rebase --rebase-merges update encoding eucJP to UTF-8' '
+ git switch -c merge-eucJP-UTF-8 first &&
+ git config i18n.commitencoding eucJP &&
+ git merge -F "$TEST_DIRECTORY/t3434/eucJP.txt" second &&
+ git config i18n.commitencoding UTF-8 &&
+ git rebase --rebase-merges master &&
+ compare_msg eucJP.txt eucJP UTF-8
+'
+
+test_expect_failure 'rebase --rebase-merges update encoding eucJP to ISO-2022-JP' '
+ git switch -c merge-eucJP-ISO-2022-JP first &&
+ git config i18n.commitencoding eucJP &&
+ git merge -F "$TEST_DIRECTORY/t3434/eucJP.txt" second &&
+ git config i18n.commitencoding ISO-2022-JP &&
+ git rebase --rebase-merges master &&
+ compare_msg eucJP.txt eucJP ISO-2022-JP
+'
+
+test_rebase_continue_update_encode () {
+ old=$1
+ new=$2
+ msgfile=$3
+ test_expect_success "rebase --continue update from $old to $new" '
+ (git rebase --abort || : abort current git-rebase failure) &&
+ git switch -c conflict-$old-$new one &&
+ echo for-conflict >two.t &&
+ git add two.t &&
+ git config i18n.commitencoding $old &&
+ git commit -F "$TEST_DIRECTORY/t3434/$msgfile" &&
+ git config i18n.commitencoding $new &&
+ test_must_fail git rebase -m master &&
+ test -f .git/rebase-merge/message &&
+ git stripspace <.git/rebase-merge/message >two.t &&
+ git add two.t &&
+ git rebase --continue &&
+ compare_msg $msgfile $old $new &&
+ : git-commit assume invalid utf-8 is latin1 &&
+ test_cmp expect two.t
+ '
+}
+
+test_rebase_continue_update_encode ISO-8859-1 UTF-8 ISO8859-1.txt
+test_rebase_continue_update_encode eucJP UTF-8 eucJP.txt
+test_rebase_continue_update_encode eucJP ISO-2022-JP eucJP.txt
+
+test_done
diff --git a/t/t3434/ISO8859-1.txt b/t/t3434/ISO8859-1.txt
new file mode 100644
index 0000000..7cbef0e
--- /dev/null
+++ b/t/t3434/ISO8859-1.txt
@@ -0,0 +1,3 @@
+ÄËÑÏÖ
+
+Ábçdèfg
diff --git a/t/t3434/eucJP.txt b/t/t3434/eucJP.txt
new file mode 100644
index 0000000..546f2aa
--- /dev/null
+++ b/t/t3434/eucJP.txt
@@ -0,0 +1,4 @@
+¤Ï¤ì¤Ò¤Û¤Õ
+
+¤·¤Æ¤¤¤ë¤Î¤¬¡¢¤¤¤ë¤Î¤Ç¡£
+ßÀÉͤۤì¤×¤ê¤Ý¤ì¤Þ¤Ó¤°¤ê¤í¤Ø¡£
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index d50e165..d4f9386 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -647,4 +647,29 @@ test_expect_success 'checkout -p works with pathological context lines' '
test_write_lines a b a b a a b a b a >expect &&
test_cmp expect a
'
+
+test_expect_success 'show help from add--helper' '
+ git reset --hard &&
+ cat >expect <<-EOF &&
+
+ <BOLD>*** Commands ***<RESET>
+ 1: <BOLD;BLUE>s<RESET>tatus 2: <BOLD;BLUE>u<RESET>pdate 3: <BOLD;BLUE>r<RESET>evert 4: <BOLD;BLUE>a<RESET>dd untracked
+ 5: <BOLD;BLUE>p<RESET>atch 6: <BOLD;BLUE>d<RESET>iff 7: <BOLD;BLUE>q<RESET>uit 8: <BOLD;BLUE>h<RESET>elp
+ <BOLD;BLUE>What now<RESET>> <BOLD;RED>status - show paths with changes<RESET>
+ <BOLD;RED>update - add working tree state to the staged set of changes<RESET>
+ <BOLD;RED>revert - revert staged set of changes back to the HEAD version<RESET>
+ <BOLD;RED>patch - pick hunks and update selectively<RESET>
+ <BOLD;RED>diff - view diff between HEAD and index<RESET>
+ <BOLD;RED>add untracked - add contents of untracked files to the staged set of changes<RESET>
+ <BOLD>*** Commands ***<RESET>
+ 1: <BOLD;BLUE>s<RESET>tatus 2: <BOLD;BLUE>u<RESET>pdate 3: <BOLD;BLUE>r<RESET>evert 4: <BOLD;BLUE>a<RESET>dd untracked
+ 5: <BOLD;BLUE>p<RESET>atch 6: <BOLD;BLUE>d<RESET>iff 7: <BOLD;BLUE>q<RESET>uit 8: <BOLD;BLUE>h<RESET>elp
+ <BOLD;BLUE>What now<RESET>>$SP
+ Bye.
+ EOF
+ test_write_lines h | GIT_PAGER_IN_USE=true TERM=vt100 git add -i >actual.colored &&
+ test_decode_color <actual.colored >actual &&
+ test_i18ncmp expect actual
+'
+
test_done
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index b92ff95..d277a9f 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -204,4 +204,41 @@ test_commit_autosquash_flags eucJP fixup
test_commit_autosquash_flags ISO-2022-JP squash
+test_commit_autosquash_multi_encoding () {
+ flag=$1
+ old=$2
+ new=$3
+ msg=$4
+ test_expect_success "commit --$flag into $old from $new" '
+ git checkout -b $flag-$old-$new C0 &&
+ git config i18n.commitencoding $old &&
+ echo $old >>F &&
+ git commit -a -F "$TEST_DIRECTORY"/t3900/$msg &&
+ test_tick &&
+ echo intermediate stuff >>G &&
+ git add G &&
+ git commit -a -m "intermediate commit" &&
+ test_tick &&
+ git config i18n.commitencoding $new &&
+ echo $new-$flag >>F &&
+ git commit -a --$flag HEAD^ &&
+ git rebase --autosquash -i HEAD^^^ &&
+ git rev-list HEAD >actual &&
+ test_line_count = 3 actual &&
+ iconv -f $old -t UTF-8 "$TEST_DIRECTORY"/t3900/$msg >expect &&
+ if test $flag = squash; then
+ subject="$(head -1 expect)" &&
+ printf "\nsquash! %s\n" "$subject" >>expect
+ fi &&
+ git cat-file commit HEAD^ >raw &&
+ (sed "1,/^$/d" raw | iconv -f $new -t utf-8) >actual &&
+ test_cmp expect actual
+ '
+}
+
+test_commit_autosquash_multi_encoding fixup UTF-8 ISO-8859-1 1-UTF-8.txt
+test_commit_autosquash_multi_encoding squash ISO-8859-1 UTF-8 ISO8859-1.txt
+test_commit_autosquash_multi_encoding squash eucJP ISO-2022-JP eucJP.txt
+test_commit_autosquash_multi_encoding fixup ISO-2022-JP UTF-8 ISO-2022-JP.txt
+
test_done
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index a4da72f..ea56e85 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -244,8 +244,11 @@ test_expect_success 'save -q is quiet' '
test_must_be_empty output.out
'
-test_expect_success 'pop -q is quiet' '
+test_expect_success 'pop -q works and is quiet' '
git stash pop -q >output.out 2>&1 &&
+ echo bar >expect &&
+ git show :file >actual &&
+ test_cmp expect actual &&
test_must_be_empty output.out
'
@@ -254,6 +257,8 @@ test_expect_success 'pop -q --index works and is quiet' '
git add file &&
git stash save --quiet &&
git stash pop -q --index >output.out 2>&1 &&
+ git diff-files file2 >file2.diff &&
+ test_must_be_empty file2.diff &&
test foo = "$(git show :file)" &&
test_must_be_empty output.out
'
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index 29ca76f..f075c7f 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -277,8 +277,8 @@ test_expect_success 'stash -u -- <ignored> leaves ignored file alone' '
test_path_is_file ignored.d/bar
'
-test_expect_success 'stash -u -- <non-existant> shows no changes when there are none' '
- git stash push -u -- non-existant >actual &&
+test_expect_success 'stash -u -- <non-existent> shows no changes when there are none' '
+ git stash push -u -- non-existent >actual &&
echo "No local changes to save" >expect &&
test_i18ncmp expect actual
'
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 6f5ef00..c0f4839 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -32,6 +32,7 @@ diffpatterns="
csharp
css
dts
+ elixir
fortran
fountain
golang
diff --git a/t/t4018/elixir-do-not-pick-end b/t/t4018/elixir-do-not-pick-end
new file mode 100644
index 0000000..fae08ba
--- /dev/null
+++ b/t/t4018/elixir-do-not-pick-end
@@ -0,0 +1,5 @@
+defmodule RIGHT do
+end
+#
+#
+# ChangeMe; do not pick up 'end' line
diff --git a/t/t4018/elixir-ex-unit-test b/t/t4018/elixir-ex-unit-test
new file mode 100644
index 0000000..0560a2b
--- /dev/null
+++ b/t/t4018/elixir-ex-unit-test
@@ -0,0 +1,6 @@
+defmodule Test do
+ test "RIGHT" do
+ assert true == true
+ assert ChangeMe
+ end
+end
diff --git a/t/t4018/elixir-function b/t/t4018/elixir-function
new file mode 100644
index 0000000..d452f49
--- /dev/null
+++ b/t/t4018/elixir-function
@@ -0,0 +1,5 @@
+def function(RIGHT, arg) do
+ # comment
+ # comment
+ ChangeMe
+end
diff --git a/t/t4018/elixir-macro b/t/t4018/elixir-macro
new file mode 100644
index 0000000..4f925e9
--- /dev/null
+++ b/t/t4018/elixir-macro
@@ -0,0 +1,5 @@
+defmacro foo(RIGHT) do
+ # Code
+ # Code
+ ChangeMe
+end
diff --git a/t/t4018/elixir-module b/t/t4018/elixir-module
new file mode 100644
index 0000000..91a4e7a
--- /dev/null
+++ b/t/t4018/elixir-module
@@ -0,0 +1,9 @@
+defmodule RIGHT do
+ @moduledoc """
+ Foo bar
+ """
+
+ def ChangeMe(a) where is_map(a) do
+ a
+ end
+end
diff --git a/t/t4018/elixir-module-func b/t/t4018/elixir-module-func
new file mode 100644
index 0000000..c9910d0
--- /dev/null
+++ b/t/t4018/elixir-module-func
@@ -0,0 +1,8 @@
+defmodule Foo do
+ def fun(RIGHT) do
+ # Code
+ # Code
+ # Code
+ ChangeMe
+ end
+end
diff --git a/t/t4018/elixir-nested-module b/t/t4018/elixir-nested-module
new file mode 100644
index 0000000..771ebc5
--- /dev/null
+++ b/t/t4018/elixir-nested-module
@@ -0,0 +1,9 @@
+defmodule MyApp.RIGHT do
+ @moduledoc """
+ Foo bar
+ """
+
+ def ChangeMe(a) where is_map(a) do
+ a
+ end
+end
diff --git a/t/t4018/elixir-private-function b/t/t4018/elixir-private-function
new file mode 100644
index 0000000..1aabe33
--- /dev/null
+++ b/t/t4018/elixir-private-function
@@ -0,0 +1,5 @@
+defp function(RIGHT, arg) do
+ # comment
+ # comment
+ ChangeMe
+end
diff --git a/t/t4018/elixir-protocol b/t/t4018/elixir-protocol
new file mode 100644
index 0000000..7d91736
--- /dev/null
+++ b/t/t4018/elixir-protocol
@@ -0,0 +1,6 @@
+defprotocol RIGHT do
+ @doc """
+ Calculates the size (and not the length!) of a data structure
+ """
+ def size(data, ChangeMe)
+end
diff --git a/t/t4018/elixir-protocol-implementation b/t/t4018/elixir-protocol-implementation
new file mode 100644
index 0000000..f9234bb
--- /dev/null
+++ b/t/t4018/elixir-protocol-implementation
@@ -0,0 +1,5 @@
+defimpl RIGHT do
+ # Docs
+ # Docs
+ def foo(ChangeMe), do: :ok
+end
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 619bf97..f852136 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -284,7 +284,7 @@ test_expect_success 'submodule contains untracked content (all ignored)' '
test_must_be_empty actual
'
-test_expect_success 'submodule contains untracked and modifed content' '
+test_expect_success 'submodule contains untracked and modified content' '
echo new > sm1/foo6 &&
git diff-index -p --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
@@ -294,7 +294,7 @@ test_expect_success 'submodule contains untracked and modifed content' '
test_cmp expected actual
'
-test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' '
+test_expect_success 'submodule contains untracked and modified content (untracked ignored)' '
echo new > sm1/foo6 &&
git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
@@ -303,19 +303,19 @@ test_expect_success 'submodule contains untracked and modifed content (untracked
test_cmp expected actual
'
-test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' '
+test_expect_success 'submodule contains untracked and modified content (dirty ignored)' '
echo new > sm1/foo6 &&
git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
test_must_be_empty actual
'
-test_expect_success 'submodule contains untracked and modifed content (all ignored)' '
+test_expect_success 'submodule contains untracked and modified content (all ignored)' '
echo new > sm1/foo6 &&
git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
test_must_be_empty actual
'
-test_expect_success 'submodule contains modifed content' '
+test_expect_success 'submodule contains modified content' '
rm -f sm1/new-file &&
git diff-index -p --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
@@ -369,7 +369,7 @@ test_expect_success 'modified submodule contains untracked content (all ignored)
test_must_be_empty actual
'
-test_expect_success 'modified submodule contains untracked and modifed content' '
+test_expect_success 'modified submodule contains untracked and modified content' '
echo modification >> sm1/foo6 &&
git diff-index -p --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
@@ -381,7 +381,7 @@ test_expect_success 'modified submodule contains untracked and modifed content'
test_cmp expected actual
'
-test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' '
+test_expect_success 'modified submodule contains untracked and modified content (untracked ignored)' '
echo modification >> sm1/foo6 &&
git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
@@ -392,7 +392,7 @@ test_expect_success 'modified submodule contains untracked and modifed content (
test_cmp expected actual
'
-test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' '
+test_expect_success 'modified submodule contains untracked and modified content (dirty ignored)' '
echo modification >> sm1/foo6 &&
git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
@@ -402,13 +402,13 @@ test_expect_success 'modified submodule contains untracked and modifed content (
test_cmp expected actual
'
-test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' '
+test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '
echo modification >> sm1/foo6 &&
git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
test_must_be_empty actual
'
-test_expect_success 'modified submodule contains modifed content' '
+test_expect_success 'modified submodule contains modified content' '
rm -f sm1/new-file &&
git diff-index -p --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
diff --git a/t/t4057-diff-combined-paths.sh b/t/t4057-diff-combined-paths.sh
index dff36b7..4f4b541 100755
--- a/t/t4057-diff-combined-paths.sh
+++ b/t/t4057-diff-combined-paths.sh
@@ -33,7 +33,7 @@ test_expect_success 'trivial merge - combine-diff empty' '
'
-test_expect_success 'only one trully conflicting path' '
+test_expect_success 'only one truly conflicting path' '
git checkout side &&
for i in $(test_seq 2 9)
do
diff --git a/t/t4100/t-apply-1.patch b/t/t4100/t-apply-1.patch
index 90ab54f..43394f8 100644
--- a/t/t4100/t-apply-1.patch
+++ b/t/t4100/t-apply-1.patch
@@ -75,8 +75,8 @@ diff --git a/Documentation/git.txt b/Documentation/git.txt
+link:git-ssh-pull.html[git-ssh-pull]::
Pulls from a remote repository over ssh connection
- Interogators:
-@@ -156,8 +156,8 @@ Interogators:
+ Interrogators:
+@@ -156,8 +156,8 @@ Interrogators:
link:git-diff-helper.html[git-diff-helper]::
Generates patch format output for git-diff-*
diff --git a/t/t4100/t-apply-3.patch b/t/t4100/t-apply-3.patch
index 90cdbaa..cac172e 100644
--- a/t/t4100/t-apply-3.patch
+++ b/t/t4100/t-apply-3.patch
@@ -211,7 +211,7 @@ dissimilarity index 82%
-
- /* If this is an exact directory match, we may have
- * directory files following this path. Match on them.
-- * Otherwise, we're at a pach subcomponent, and we need
+- * Otherwise, we're at a patch subcomponent, and we need
- * to try to match again.
- */
- if (mtype == 0)
diff --git a/t/t4100/t-apply-5.patch b/t/t4100/t-apply-5.patch
index 5f6ddc1..57ec79d 100644
--- a/t/t4100/t-apply-5.patch
+++ b/t/t4100/t-apply-5.patch
@@ -185,8 +185,8 @@ diff a/Documentation/git.txt b/Documentation/git.txt
+link:git-ssh-pull.html[git-ssh-pull]::
Pulls from a remote repository over ssh connection
- Interogators:
-@@ -156,8 +156,8 @@ Interogators:
+ Interrogators:
+@@ -156,8 +156,8 @@ Interrogators:
link:git-diff-helper.html[git-diff-helper]::
Generates patch format output for git-diff-*
diff --git a/t/t4100/t-apply-7.patch b/t/t4100/t-apply-7.patch
index 07c6589..fa24305 100644
--- a/t/t4100/t-apply-7.patch
+++ b/t/t4100/t-apply-7.patch
@@ -335,7 +335,7 @@ diff a/ls-tree.c b/ls-tree.c
- /* If this is an exact directory match, we may have
- * directory files following this path. Match on them.
-- * Otherwise, we're at a pach subcomponent, and we need
+- * Otherwise, we're at a patch subcomponent, and we need
- * to try to match again.
+ if (e->directory) {
+ /* If this is a directory, we have the following cases:
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index e803ba4..ab0d021 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -667,7 +667,7 @@ cat > expect <<\EOF
* | | fifth
* | | fourth
|/ /
-* | third
+* / third
|/
* second
* initial
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index f42a69f..2f251b2 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -640,7 +640,7 @@ test_expect_success 'pretty format %(trailers:key=foo) multiple keys' '
test_cmp expect actual
'
-test_expect_success '%(trailers:key=nonexistant) becomes empty' '
+test_expect_success '%(trailers:key=nonexistent) becomes empty' '
git log --no-walk --pretty="x%(trailers:key=Nacked-by)x" >actual &&
echo "xx" >expect &&
test_cmp expect actual
diff --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh
index 7f90f58..53a4af3 100755
--- a/t/t4213-log-tabexpand.sh
+++ b/t/t4213-log-tabexpand.sh
@@ -36,7 +36,7 @@ count_expand ()
esac
# Prefix the output with the command line arguments, and
- # replace SP with a dot both in the expecte and actual output
+ # replace SP with a dot both in the expected and actual output
# so that test_cmp would show the difference together with the
# breakage in a way easier to consume by the debugging user.
{
diff --git a/t/t4214-log-graph-octopus.sh b/t/t4214-log-graph-octopus.sh
index 3ae8e51..40d27db 100755
--- a/t/t4214-log-graph-octopus.sh
+++ b/t/t4214-log-graph-octopus.sh
@@ -26,15 +26,14 @@ test_expect_success 'set up merge history' '
test_expect_success 'log --graph with tricky octopus merge, no color' '
cat >expect.uncolored <<-\EOF &&
* left
- | *---. octopus-merge
- | |\ \ \
- |/ / / /
+ | *-. octopus-merge
+ |/|\ \
| | | * 4
| | * | 3
| | |/
- | * | 2
+ | * / 2
| |/
- * | 1
+ * / 1
|/
* initial
EOF
@@ -47,15 +46,14 @@ test_expect_success 'log --graph with tricky octopus merge with colors' '
test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
cat >expect.colors <<-\EOF &&
* left
- <RED>|<RESET> *<BLUE>-<RESET><BLUE>-<RESET><MAGENTA>-<RESET><MAGENTA>.<RESET> octopus-merge
- <RED>|<RESET> <RED>|<RESET><YELLOW>\<RESET> <BLUE>\<RESET> <MAGENTA>\<RESET>
- <RED>|<RESET><RED>/<RESET> <YELLOW>/<RESET> <BLUE>/<RESET> <MAGENTA>/<RESET>
+ <RED>|<RESET> *<MAGENTA>-<RESET><MAGENTA>.<RESET> octopus-merge
+ <RED>|<RESET><RED>/<RESET><YELLOW>|<RESET><BLUE>\<RESET> <MAGENTA>\<RESET>
<RED>|<RESET> <YELLOW>|<RESET> <BLUE>|<RESET> * 4
<RED>|<RESET> <YELLOW>|<RESET> * <MAGENTA>|<RESET> 3
<RED>|<RESET> <YELLOW>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
- <RED>|<RESET> * <MAGENTA>|<RESET> 2
+ <RED>|<RESET> * <MAGENTA>/<RESET> 2
<RED>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
- * <MAGENTA>|<RESET> 1
+ * <MAGENTA>/<RESET> 1
<MAGENTA>|<RESET><MAGENTA>/<RESET>
* initial
EOF
@@ -74,9 +72,9 @@ test_expect_success 'log --graph with normal octopus merge, no color' '
| | | * 4
| | * | 3
| | |/
- | * | 2
+ | * / 2
| |/
- * | 1
+ * / 1
|/
* initial
EOF
@@ -92,9 +90,9 @@ test_expect_success 'log --graph with normal octopus merge with colors' '
<RED>|<RESET> <GREEN>|<RESET> <YELLOW>|<RESET> * 4
<RED>|<RESET> <GREEN>|<RESET> * <BLUE>|<RESET> 3
<RED>|<RESET> <GREEN>|<RESET> <BLUE>|<RESET><BLUE>/<RESET>
- <RED>|<RESET> * <BLUE>|<RESET> 2
+ <RED>|<RESET> * <BLUE>/<RESET> 2
<RED>|<RESET> <BLUE>|<RESET><BLUE>/<RESET>
- * <BLUE>|<RESET> 1
+ * <BLUE>/<RESET> 1
<BLUE>|<RESET><BLUE>/<RESET>
* initial
EOF
@@ -112,9 +110,9 @@ test_expect_success 'log --graph with normal octopus merge and child, no color'
| | | * 4
| | * | 3
| | |/
- | * | 2
+ | * / 2
| |/
- * | 1
+ * / 1
|/
* initial
EOF
@@ -123,7 +121,7 @@ test_expect_success 'log --graph with normal octopus merge and child, no color'
test_cmp expect.uncolored actual
'
-test_expect_failure 'log --graph with normal octopus and child merge with colors' '
+test_expect_success 'log --graph with normal octopus and child merge with colors' '
cat >expect.colors <<-\EOF &&
* after-merge
*<BLUE>-<RESET><BLUE>-<RESET><MAGENTA>-<RESET><MAGENTA>.<RESET> octopus-merge
@@ -131,9 +129,9 @@ test_expect_failure 'log --graph with normal octopus and child merge with colors
<GREEN>|<RESET> <YELLOW>|<RESET> <BLUE>|<RESET> * 4
<GREEN>|<RESET> <YELLOW>|<RESET> * <MAGENTA>|<RESET> 3
<GREEN>|<RESET> <YELLOW>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
- <GREEN>|<RESET> * <MAGENTA>|<RESET> 2
+ <GREEN>|<RESET> * <MAGENTA>/<RESET> 2
<GREEN>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
- * <MAGENTA>|<RESET> 1
+ * <MAGENTA>/<RESET> 1
<MAGENTA>|<RESET><MAGENTA>/<RESET>
* initial
EOF
@@ -147,15 +145,14 @@ test_expect_success 'log --graph with tricky octopus merge and its child, no col
cat >expect.uncolored <<-\EOF &&
* left
| * after-merge
- | *---. octopus-merge
- | |\ \ \
- |/ / / /
+ | *-. octopus-merge
+ |/|\ \
| | | * 4
| | * | 3
| | |/
- | * | 2
+ | * / 2
| |/
- * | 1
+ * / 1
|/
* initial
EOF
@@ -164,20 +161,19 @@ test_expect_success 'log --graph with tricky octopus merge and its child, no col
test_cmp expect.uncolored actual
'
-test_expect_failure 'log --graph with tricky octopus merge and its child with colors' '
+test_expect_success 'log --graph with tricky octopus merge and its child with colors' '
test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
cat >expect.colors <<-\EOF &&
* left
<RED>|<RESET> * after-merge
- <RED>|<RESET> *<MAGENTA>-<RESET><MAGENTA>-<RESET><CYAN>-<RESET><CYAN>.<RESET> octopus-merge
- <RED>|<RESET> <RED>|<RESET><BLUE>\<RESET> <MAGENTA>\<RESET> <CYAN>\<RESET>
- <RED>|<RESET><RED>/<RESET> <BLUE>/<RESET> <MAGENTA>/<RESET> <CYAN>/<RESET>
+ <RED>|<RESET> *<CYAN>-<RESET><CYAN>.<RESET> octopus-merge
+ <RED>|<RESET><RED>/<RESET><BLUE>|<RESET><MAGENTA>\<RESET> <CYAN>\<RESET>
<RED>|<RESET> <BLUE>|<RESET> <MAGENTA>|<RESET> * 4
<RED>|<RESET> <BLUE>|<RESET> * <CYAN>|<RESET> 3
<RED>|<RESET> <BLUE>|<RESET> <CYAN>|<RESET><CYAN>/<RESET>
- <RED>|<RESET> * <CYAN>|<RESET> 2
+ <RED>|<RESET> * <CYAN>/<RESET> 2
<RED>|<RESET> <CYAN>|<RESET><CYAN>/<RESET>
- * <CYAN>|<RESET> 1
+ * <CYAN>/<RESET> 1
<CYAN>|<RESET><CYAN>/<RESET>
* initial
EOF
@@ -209,7 +205,7 @@ test_expect_success 'log --graph with crossover in octopus merge, no color' '
test_cmp expect.uncolored actual
'
-test_expect_failure 'log --graph with crossover in octopus merge with colors' '
+test_expect_success 'log --graph with crossover in octopus merge with colors' '
test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
cat >expect.colors <<-\EOF &&
* after-4
@@ -257,7 +253,7 @@ test_expect_success 'log --graph with crossover in octopus merge and its child,
test_cmp expect.uncolored actual
'
-test_expect_failure 'log --graph with crossover in octopus merge and its child with colors' '
+test_expect_success 'log --graph with crossover in octopus merge and its child with colors' '
test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
cat >expect.colors <<-\EOF &&
* after-4
@@ -353,7 +349,7 @@ test_expect_success 'log --graph with unrelated commit and octopus child, no col
test_cmp expect.uncolored actual
'
-test_expect_failure 'log --graph with unrelated commit and octopus child with colors' '
+test_expect_success 'log --graph with unrelated commit and octopus child with colors' '
test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
cat >expect.colors <<-\EOF &&
* after-initial
diff --git a/t/t4215-log-skewed-merges.sh b/t/t4215-log-skewed-merges.sh
new file mode 100755
index 0000000..18709a7
--- /dev/null
+++ b/t/t4215-log-skewed-merges.sh
@@ -0,0 +1,243 @@
+#!/bin/sh
+
+test_description='git log --graph of skewed merges'
+
+. ./test-lib.sh
+
+check_graph () {
+ cat >expect &&
+ git log --graph --pretty=tformat:%s "$@" >actual.raw &&
+ sed "s/ *$//" actual.raw >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success 'log --graph with merge fusing with its left and right neighbors' '
+ git checkout --orphan _p &&
+ test_commit A &&
+ test_commit B &&
+ git checkout -b _q @^ && test_commit C &&
+ git checkout -b _r @^ && test_commit D &&
+ git checkout _p && git merge --no-ff _q _r -m E &&
+ git checkout _r && test_commit F &&
+ git checkout _p && git merge --no-ff _r -m G &&
+ git checkout @^^ && git merge --no-ff _p -m H &&
+
+ check_graph <<-\EOF
+ * H
+ |\
+ | * G
+ | |\
+ | | * F
+ | * | E
+ |/|\|
+ | | * D
+ | * | C
+ | |/
+ * / B
+ |/
+ * A
+ EOF
+'
+
+test_expect_success 'log --graph with left-skewed merge' '
+ git checkout --orphan 0_p && test_commit 0_A &&
+ git checkout -b 0_q 0_p && test_commit 0_B &&
+ git checkout -b 0_r 0_p &&
+ test_commit 0_C &&
+ test_commit 0_D &&
+ git checkout -b 0_s 0_p && test_commit 0_E &&
+ git checkout -b 0_t 0_p && git merge --no-ff 0_r^ 0_s -m 0_F &&
+ git checkout 0_p && git merge --no-ff 0_s -m 0_G &&
+ git checkout @^ && git merge --no-ff 0_q 0_r 0_t 0_p -m 0_H &&
+
+ check_graph <<-\EOF
+ *-----. 0_H
+ |\ \ \ \
+ | | | | * 0_G
+ | |_|_|/|
+ |/| | | |
+ | | | * | 0_F
+ | |_|/|\|
+ |/| | | |
+ | | | | * 0_E
+ | |_|_|/
+ |/| | |
+ | | * | 0_D
+ | | |/
+ | | * 0_C
+ | |/
+ |/|
+ | * 0_B
+ |/
+ * 0_A
+ EOF
+'
+
+test_expect_success 'log --graph with nested left-skewed merge' '
+ git checkout --orphan 1_p &&
+ test_commit 1_A &&
+ test_commit 1_B &&
+ test_commit 1_C &&
+ git checkout -b 1_q @^ && test_commit 1_D &&
+ git checkout 1_p && git merge --no-ff 1_q -m 1_E &&
+ git checkout -b 1_r @~3 && test_commit 1_F &&
+ git checkout 1_p && git merge --no-ff 1_r -m 1_G &&
+ git checkout @^^ && git merge --no-ff 1_p -m 1_H &&
+
+ check_graph <<-\EOF
+ * 1_H
+ |\
+ | * 1_G
+ | |\
+ | | * 1_F
+ | * | 1_E
+ |/| |
+ | * | 1_D
+ * | | 1_C
+ |/ /
+ * / 1_B
+ |/
+ * 1_A
+ EOF
+'
+
+test_expect_success 'log --graph with nested left-skewed merge following normal merge' '
+ git checkout --orphan 2_p &&
+ test_commit 2_A &&
+ test_commit 2_B &&
+ test_commit 2_C &&
+ git checkout -b 2_q @^^ &&
+ test_commit 2_D &&
+ test_commit 2_E &&
+ git checkout -b 2_r @^ && test_commit 2_F &&
+ git checkout 2_q &&
+ git merge --no-ff 2_r -m 2_G &&
+ git merge --no-ff 2_p^ -m 2_H &&
+ git checkout -b 2_s @^^ && git merge --no-ff 2_q -m 2_J &&
+ git checkout 2_p && git merge --no-ff 2_s -m 2_K &&
+
+ check_graph <<-\EOF
+ * 2_K
+ |\
+ | * 2_J
+ | |\
+ | | * 2_H
+ | | |\
+ | | * | 2_G
+ | |/| |
+ | | * | 2_F
+ | * | | 2_E
+ | |/ /
+ | * | 2_D
+ * | | 2_C
+ | |/
+ |/|
+ * | 2_B
+ |/
+ * 2_A
+ EOF
+'
+
+test_expect_success 'log --graph with nested right-skewed merge following left-skewed merge' '
+ git checkout --orphan 3_p &&
+ test_commit 3_A &&
+ git checkout -b 3_q &&
+ test_commit 3_B &&
+ test_commit 3_C &&
+ git checkout -b 3_r @^ &&
+ test_commit 3_D &&
+ git checkout 3_q && git merge --no-ff 3_r -m 3_E &&
+ git checkout 3_p && git merge --no-ff 3_q -m 3_F &&
+ git checkout 3_r && test_commit 3_G &&
+ git checkout 3_p && git merge --no-ff 3_r -m 3_H &&
+ git checkout @^^ && git merge --no-ff 3_p -m 3_J &&
+
+ check_graph <<-\EOF
+ * 3_J
+ |\
+ | * 3_H
+ | |\
+ | | * 3_G
+ | * | 3_F
+ |/| |
+ | * | 3_E
+ | |\|
+ | | * 3_D
+ | * | 3_C
+ | |/
+ | * 3_B
+ |/
+ * 3_A
+ EOF
+'
+
+test_expect_success 'log --graph with right-skewed merge following a left-skewed one' '
+ git checkout --orphan 4_p &&
+ test_commit 4_A &&
+ test_commit 4_B &&
+ test_commit 4_C &&
+ git checkout -b 4_q @^^ && test_commit 4_D &&
+ git checkout -b 4_r 4_p^ && git merge --no-ff 4_q -m 4_E &&
+ git checkout -b 4_s 4_p^^ &&
+ git merge --no-ff 4_r -m 4_F &&
+ git merge --no-ff 4_p -m 4_G &&
+ git checkout @^^ && git merge --no-ff 4_s -m 4_H &&
+
+ check_graph --date-order <<-\EOF
+ * 4_H
+ |\
+ | * 4_G
+ | |\
+ | * | 4_F
+ |/| |
+ | * | 4_E
+ | |\ \
+ | | * | 4_D
+ | |/ /
+ |/| |
+ | | * 4_C
+ | |/
+ | * 4_B
+ |/
+ * 4_A
+ EOF
+'
+
+test_expect_success 'log --graph with octopus merge with column joining its penultimate parent' '
+ git checkout --orphan 5_p &&
+ test_commit 5_A &&
+ git branch 5_q &&
+ git branch 5_r &&
+ test_commit 5_B &&
+ git checkout 5_q && test_commit 5_C &&
+ git checkout 5_r && test_commit 5_D &&
+ git checkout 5_p &&
+ git merge --no-ff 5_q 5_r -m 5_E &&
+ git checkout 5_q && test_commit 5_F &&
+ git checkout -b 5_s 5_p^ &&
+ git merge --no-ff 5_p 5_q -m 5_G &&
+ git checkout 5_r &&
+ git merge --no-ff 5_s -m 5_H &&
+
+ check_graph <<-\EOF
+ * 5_H
+ |\
+ | *-. 5_G
+ | |\ \
+ | | | * 5_F
+ | | * | 5_E
+ | |/|\ \
+ | |_|/ /
+ |/| | /
+ | | |/
+ * | | 5_D
+ | | * 5_C
+ | |/
+ |/|
+ | * 5_B
+ |/
+ * 5_A
+ EOF
+'
+
+test_done
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index d42b3ef..5a3e4e3 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -85,7 +85,7 @@ graph_read_expect() {
num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
EOF
- git commit-graph read >output &&
+ test-tool read-graph >output &&
test_cmp expect output
}
@@ -660,7 +660,7 @@ test_expect_success 'corrupt commit-graph write (missing tree)' '
git commit-tree -p "$broken" -m "good" "$tree" >good &&
test_must_fail git commit-graph write --stdin-commits \
<good 2>test_err &&
- test_i18ngrep "unable to get tree for" test_err
+ test_i18ngrep "unable to parse commit" test_err
)
'
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 115aabd..c248234 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -25,7 +25,7 @@ graph_read_expect() {
num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata
EOF
- git commit-graph read >output &&
+ test-tool read-graph >output &&
test_cmp expect output
}
diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh
index 4430956..4d1e0c3 100755
--- a/t/t5528-push-default.sh
+++ b/t/t5528-push-default.sh
@@ -163,7 +163,7 @@ test_pushdefault_workflow success current master
# update parent1's foo (which is our upstream)
test_pushdefault_workflow success upstream foo
-# upsream is foo which is not the name of the current branch
+# upstream is foo which is not the name of the current branch
test_pushdefault_workflow failure simple master
# master and foo are updated
diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh
index 8ed58d2..e8f6d23 100755
--- a/t/t5535-fetch-push-symref.sh
+++ b/t/t5535-fetch-push-symref.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-test_description='avoiding conflicting update thru symref aliasing'
+test_description='avoiding conflicting update through symref aliasing'
. ./test-lib.sh
diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh
index 04b34c4..38e6f73 100755
--- a/t/t5545-push-options.sh
+++ b/t/t5545-push-options.sh
@@ -115,7 +115,7 @@ test_expect_success 'push options and submodules' '
git -C parent submodule add ../upstream workbench &&
git -C parent/workbench remote add up ../../upstream &&
- git -C parent commit -m "add submoule" &&
+ git -C parent commit -m "add submodule" &&
test_commit -C parent/workbench two &&
git -C parent add workbench &&
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index eaa33a8..fea56cd 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -304,6 +304,76 @@ test_expect_success 'partial clone with unresolvable sparse filter fails cleanly
test_i18ngrep "unable to parse sparse filter data in" err
'
+setup_triangle () {
+ rm -rf big-blob.txt server client promisor-remote &&
+
+ printf "line %d\n" $(test_seq 1 100) >big-blob.txt &&
+
+ # Create a server with 2 commits: a commit with a big blob and a child
+ # commit with an incremental change. Also, create a partial clone
+ # client that only contains the first commit.
+ git init server &&
+ git -C server config --local uploadpack.allowfilter 1 &&
+ cp big-blob.txt server &&
+ git -C server add big-blob.txt &&
+ git -C server commit -m "initial" &&
+ git clone --bare --filter=tree:0 "file://$(pwd)/server" client &&
+ echo another line >>server/big-blob.txt &&
+ git -C server commit -am "append line to big blob" &&
+
+ # Create a promisor remote that only contains the blob from the first
+ # commit, and set it as the promisor remote of client. Thus, whenever
+ # the client lazy fetches, the lazy fetch will succeed only if it is
+ # for this blob.
+ git init promisor-remote &&
+ test_commit -C promisor-remote one && # so that ref advertisement is not empty
+ git -C promisor-remote config --local uploadpack.allowanysha1inwant 1 &&
+ git -C promisor-remote hash-object -w --stdin <big-blob.txt &&
+ git -C client remote set-url origin "file://$(pwd)/promisor-remote"
+}
+
+# NEEDSWORK: The tests beginning with "fetch lazy-fetches" below only
+# test that "fetch" avoid fetching trees and blobs, but not commits or
+# tags. Revisit this if Git is ever taught to support partial clones
+# with commits and/or tags filtered out.
+
+test_expect_success 'fetch lazy-fetches only to resolve deltas' '
+ setup_triangle &&
+
+ # Exercise to make sure it works. Git will not fetch anything from the
+ # promisor remote other than for the big blob (because it needs to
+ # resolve the delta).
+ GIT_TRACE_PACKET="$(pwd)/trace" git -C client \
+ fetch "file://$(pwd)/server" master &&
+
+ # Verify the assumption that the client needed to fetch the delta base
+ # to resolve the delta.
+ git hash-object big-blob.txt >hash &&
+ grep "want $(cat hash)" trace
+'
+
+test_expect_success 'fetch lazy-fetches only to resolve deltas, protocol v2' '
+ setup_triangle &&
+
+ git -C server config --local protocol.version 2 &&
+ git -C client config --local protocol.version 2 &&
+ git -C promisor-remote config --local protocol.version 2 &&
+
+ # Exercise to make sure it works. Git will not fetch anything from the
+ # promisor remote other than for the big blob (because it needs to
+ # resolve the delta).
+ GIT_TRACE_PACKET="$(pwd)/trace" git -C client \
+ fetch "file://$(pwd)/server" master &&
+
+ # Verify that protocol version 2 was used.
+ grep "fetch< version 2" trace &&
+
+ # Verify the assumption that the client needed to fetch the delta base
+ # to resolve the delta.
+ git hash-object big-blob.txt >hash &&
+ grep "want $(cat hash)" trace
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index ae9175c..e73067d 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -32,7 +32,7 @@ test_expect_success 'list refs with git:// using protocol v2' '
test_cmp expect actual
'
-test_expect_success 'ref advertisment is filtered with ls-remote using protocol v2' '
+test_expect_success 'ref advertisement is filtered with ls-remote using protocol v2' '
test_when_finished "rm -f log" &&
GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
@@ -154,7 +154,7 @@ test_expect_success 'list refs with file:// using protocol v2' '
test_cmp expect actual
'
-test_expect_success 'ref advertisment is filtered with ls-remote using protocol v2' '
+test_expect_success 'ref advertisement is filtered with ls-remote using protocol v2' '
test_when_finished "rm -f log" &&
GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
@@ -225,7 +225,7 @@ test_expect_success 'fetch with file:// using protocol v2' '
grep "fetch< version 2" log
'
-test_expect_success 'ref advertisment is filtered during fetch using protocol v2' '
+test_expect_success 'ref advertisement is filtered during fetch using protocol v2' '
test_when_finished "rm -f log" &&
test_commit -C file_parent three &&
@@ -682,9 +682,9 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" log -1 --format=%s client_branch >expect &&
test_cmp expect actual &&
- # Client didnt request to use protocol v2
+ # Client did not request to use protocol v2
! grep "Git-Protocol: version=2" log &&
- # Server didnt respond using protocol v2
+ # Server did not respond using protocol v2
! grep "git< version 2" log
'
diff --git a/t/t6016-rev-list-graph-simplify-history.sh b/t/t6016-rev-list-graph-simplify-history.sh
index f7181d1..f5e6e92 100755
--- a/t/t6016-rev-list-graph-simplify-history.sh
+++ b/t/t6016-rev-list-graph-simplify-history.sh
@@ -67,11 +67,10 @@ test_expect_success '--graph --all' '
echo "| * $C4" >> expected &&
echo "| * $C3" >> expected &&
echo "* | $A5" >> expected &&
- echo "| | " >> expected &&
- echo "| \\ " >> expected &&
- echo "*-. \\ $A4" >> expected &&
- echo "|\\ \\ \\ " >> expected &&
- echo "| | |/ " >> expected &&
+ echo "| | " >> expected &&
+ echo "| \\ " >> expected &&
+ echo "*-. | $A4" >> expected &&
+ echo "|\\ \\| " >> expected &&
echo "| | * $C2" >> expected &&
echo "| | * $C1" >> expected &&
echo "| * | $B2" >> expected &&
@@ -97,11 +96,10 @@ test_expect_success '--graph --simplify-by-decoration' '
echo "| * $C4" >> expected &&
echo "| * $C3" >> expected &&
echo "* | $A5" >> expected &&
- echo "| | " >> expected &&
- echo "| \\ " >> expected &&
- echo "*-. \\ $A4" >> expected &&
- echo "|\\ \\ \\ " >> expected &&
- echo "| | |/ " >> expected &&
+ echo "| | " >> expected &&
+ echo "| \\ " >> expected &&
+ echo "*-. | $A4" >> expected &&
+ echo "|\\ \\| " >> expected &&
echo "| | * $C2" >> expected &&
echo "| | * $C1" >> expected &&
echo "| * | $B2" >> expected &&
@@ -131,9 +129,8 @@ test_expect_success '--graph --simplify-by-decoration prune branch B' '
echo "| * $C4" >> expected &&
echo "| * $C3" >> expected &&
echo "* | $A5" >> expected &&
- echo "* | $A4" >> expected &&
- echo "|\\ \\ " >> expected &&
- echo "| |/ " >> expected &&
+ echo "* | $A4" >> expected &&
+ echo "|\\| " >> expected &&
echo "| * $C2" >> expected &&
echo "| * $C1" >> expected &&
echo "* | $A3" >> expected &&
@@ -151,9 +148,8 @@ test_expect_success '--graph --full-history -- bar.txt' '
echo "|\\ " >> expected &&
echo "| * $C4" >> expected &&
echo "* | $A5" >> expected &&
- echo "* | $A4" >> expected &&
- echo "|\\ \\ " >> expected &&
- echo "| |/ " >> expected &&
+ echo "* | $A4" >> expected &&
+ echo "|\\| " >> expected &&
echo "* | $A3" >> expected &&
echo "|/ " >> expected &&
echo "* $A2" >> expected &&
@@ -255,7 +251,7 @@ test_expect_success '--graph --boundary ^C3' '
echo "* | | | $A3" >> expected &&
echo "o | | | $A2" >> expected &&
echo "|/ / / " >> expected &&
- echo "o | | $A1" >> expected &&
+ echo "o / / $A1" >> expected &&
echo " / / " >> expected &&
echo "| o $C3" >> expected &&
echo "|/ " >> expected &&
diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 27c7de9..0c9e3c2 100755
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -14,85 +14,90 @@ test_description='Test merge without common ancestors'
GIT_COMMITTER_DATE="2006-12-12 23:28:00 +0100"
export GIT_COMMITTER_DATE
-test_expect_success "setup tests" '
-echo 1 > a1 &&
-git add a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1 &&
-
-git checkout -b A master &&
-echo A > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1 &&
-
-git checkout -b B master &&
-echo B > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1 &&
-
-git checkout -b D A &&
-git rev-parse B > .git/MERGE_HEAD &&
-echo D > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D &&
-
-git symbolic-ref HEAD refs/heads/other &&
-echo 2 > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1 &&
-
-git checkout -b C &&
-echo C > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1 &&
-
-git checkout -b E C &&
-git rev-parse B > .git/MERGE_HEAD &&
-echo E > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E &&
-
-git checkout -b G E &&
-git rev-parse A > .git/MERGE_HEAD &&
-echo G > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G &&
-
-git checkout -b F D &&
-git rev-parse C > .git/MERGE_HEAD &&
-echo F > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
+test_expect_success 'setup tests' '
+ echo 1 >a1 &&
+ git add a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1 &&
+
+ git checkout -b A master &&
+ echo A >a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1 &&
+
+ git checkout -b B master &&
+ echo B >a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1 &&
+
+ git checkout -b D A &&
+ git rev-parse B >.git/MERGE_HEAD &&
+ echo D >a1 &&
+ git update-index a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D &&
+
+ git symbolic-ref HEAD refs/heads/other &&
+ echo 2 >a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1 &&
+
+ git checkout -b C &&
+ echo C >a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1 &&
+
+ git checkout -b E C &&
+ git rev-parse B >.git/MERGE_HEAD &&
+ echo E >a1 &&
+ git update-index a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E &&
+
+ git checkout -b G E &&
+ git rev-parse A >.git/MERGE_HEAD &&
+ echo G >a1 &&
+ git update-index a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G &&
+
+ git checkout -b F D &&
+ git rev-parse C >.git/MERGE_HEAD &&
+ echo F >a1 &&
+ git update-index a1 &&
+ GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
'
test_expect_success 'combined merge conflicts' '
test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git merge -m final G
'
-cat > expect << EOF
-<<<<<<< HEAD
-F
-=======
-G
->>>>>>> G
-EOF
+test_expect_success 'result contains a conflict' '
+ cat >expect <<-\EOF &&
+ <<<<<<< HEAD
+ F
+ =======
+ G
+ >>>>>>> G
+ EOF
-test_expect_success "result contains a conflict" "test_cmp expect a1"
+ test_cmp expect a1
+'
+
+test_expect_success 'virtual trees were processed' '
+ git ls-files --stage >out &&
-git ls-files --stage > out
-cat > expect << EOF
-100644 ec3fe2a791706733f2d8fa7ad45d9a9672031f5e 1 a1
-100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2 a1
-100644 fd7923529855d0b274795ae3349c5e0438333979 3 a1
-EOF
+ cat >expect <<-\EOF &&
+ 100644 ec3fe2a791706733f2d8fa7ad45d9a9672031f5e 1 a1
+ 100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2 a1
+ 100644 fd7923529855d0b274795ae3349c5e0438333979 3 a1
+ EOF
-test_expect_success "virtual trees were processed" "test_cmp expect out"
+ test_cmp expect out
+'
test_expect_success 'refuse to merge binary files' '
git reset --hard &&
- printf "\0" > binary-file &&
+ printf "\0" >binary-file &&
git add binary-file &&
git commit -m binary &&
git checkout G &&
- printf "\0\0" > binary-file &&
+ printf "\0\0" >binary-file &&
git add binary-file &&
git commit -m binary2 &&
- test_must_fail git merge F > merge.out 2> merge.err &&
+ test_must_fail git merge F >merge.out 2>merge.err &&
grep "Cannot merge binary files: binary-file (HEAD vs. F)" merge.err
'
@@ -116,7 +121,6 @@ test_expect_success 'mark rename/delete as unmerged' '
test 1 = $(git ls-files --unmerged | wc -l) &&
test_must_fail git rev-parse --verify :2:a2 &&
git rev-parse --verify :3:a2
-
'
test_done
diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index 7fddcc8..7d73afd 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -1532,7 +1532,7 @@ test_expect_success 'setup nested conflicts' '
mv -f b_R1 b &&
mv -f a_R1 a &&
git add b a &&
- test_tick && git commit -m "verson R1 of files" &&
+ test_tick && git commit -m "version R1 of files" &&
git tag R1 &&
# Create first merge on left side
@@ -1696,7 +1696,7 @@ test_expect_success 'setup virtual merge base with nested conflicts' '
git checkout R &&
echo right >>content &&
git add content &&
- test_tick && git commit -m "verson R1 of content" &&
+ test_tick && git commit -m "version R1 of content" &&
git tag R1 &&
# Create L2
diff --git a/t/t6043-merge-rename-directories.sh b/t/t6043-merge-rename-directories.sh
index bd2f97b..83792c5 100755
--- a/t/t6043-merge-rename-directories.sh
+++ b/t/t6043-merge-rename-directories.sh
@@ -754,7 +754,7 @@ test_expect_success '3b: Avoid implicit rename if involved as source on current
#
# What if we were to attempt to do directory rename detection when someone
# "mostly" moved a directory but still left some files around, or,
-# equivalently, fully renamed a directory in one commmit and then recreated
+# equivalently, fully renamed a directory in one commit and then recreated
# that directory in a later commit adding some new files and then tried to
# merge?
#
@@ -953,7 +953,7 @@ test_expect_success '5a: Merge directories, other side adds files to original an
# Commit B: z/{b,c,d_1,e}, y/d_3
# Expected: y/{b,c,e}, CONFLICT(add/add: y/d_2 vs. y/d_3)
# NOTE: If z/d_1 in commit B were to be involved in dir rename detection, as
-# we normaly would since z/ is being renamed to y/, then this would be
+# we normally would since z/ is being renamed to y/, then this would be
# a rename/delete (z/d_1 -> y/d_1 vs. deleted) AND an add/add/add
# conflict of y/d_1 vs. y/d_2 vs. y/d_3. Add/add/add is not
# representable in the index, so the existence of y/d_3 needs to
@@ -2116,7 +2116,7 @@ test_expect_success '8b: Dual-directory rename, one into the others way, with co
#
# Note: It could easily be argued that the correct resolution here is
# y/{b,c,e}, CONFLICT(rename/delete: z/d -> y/d vs deleted)
-# and that the modifed version of d should be present in y/ after
+# and that the modified version of d should be present in y/ after
# the merge, just marked as conflicted. Indeed, I previously did
# argue that. But applying directory renames to the side of
# history where a file is merely modified results in spurious
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 28611c9..52cde09 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -52,7 +52,7 @@ test_expect_success 'traverse unexpected non-commit parent (lone)' '
'
test_expect_success 'traverse unexpected non-commit parent (seen)' '
- test_must_fail git rev-list --objects $commit $broken_commit \
+ test_must_fail git rev-list --objects $blob $broken_commit \
>output 2>&1 &&
test_i18ngrep "not a commit" output
'
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 80eb13d..4a09bea 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -227,10 +227,10 @@ test_expect_success \
test_expect_success \
'trying to delete two tags, existing and not, should fail in the 2nd' '
tag_exists mytag &&
- ! tag_exists myhead &&
- test_must_fail git tag -d mytag anothertag &&
+ ! tag_exists nonexistingtag &&
+ test_must_fail git tag -d mytag nonexistingtag &&
! tag_exists mytag &&
- ! tag_exists myhead
+ ! tag_exists nonexistingtag
'
test_expect_success 'trying to delete an already deleted tag should fail' \
@@ -1420,7 +1420,7 @@ test_expect_success \
get_tag_header reuse $commit commit $time >expect
echo "An annotation to be reused" >> expect
test_expect_success \
- 'overwriting an annoted tag should use its previous body' '
+ 'overwriting an annotated tag should use its previous body' '
git tag -a -m "An annotation to be reused" reuse &&
GIT_EDITOR=true git tag -f -a reuse &&
get_tag_msg reuse >actual &&
diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh
index 041e319..8f077be 100755
--- a/t/t7030-verify-tag.sh
+++ b/t/t7030-verify-tag.sh
@@ -44,8 +44,8 @@ test_expect_success GPG 'create signed tags' '
test_expect_success GPGSM 'create signed tags x509 ' '
test_config gpg.format x509 &&
test_config user.signingkey $GIT_COMMITTER_EMAIL &&
- echo 9 >file && test_tick && git commit -a -m "nineth gpgsm-signed" &&
- git tag -s -m nineth nineth-signed-x509
+ echo 9 >file && test_tick && git commit -a -m "ninth gpgsm-signed" &&
+ git tag -s -m ninth ninth-signed-x509
'
test_expect_success GPG 'verify and show signatures' '
@@ -80,10 +80,10 @@ test_expect_success GPG 'verify and show signatures' '
'
test_expect_success GPGSM 'verify and show signatures x509' '
- git verify-tag nineth-signed-x509 2>actual &&
+ git verify-tag ninth-signed-x509 2>actual &&
grep "Good signature from" actual &&
! grep "BAD signature from" actual &&
- echo nineth-signed-x509 OK
+ echo ninth-signed-x509 OK
'
test_expect_success GPG 'detect fudged signature' '
@@ -127,10 +127,10 @@ test_expect_success GPG 'verify signatures with --raw' '
'
test_expect_success GPGSM 'verify signatures with --raw x509' '
- git verify-tag --raw nineth-signed-x509 2>actual &&
+ git verify-tag --raw ninth-signed-x509 2>actual &&
grep "GOODSIG" actual &&
! grep "BADSIG" actual &&
- echo nineth-signed-x509 OK
+ echo ninth-signed-x509 OK
'
test_expect_success GPG 'verify multiple tags' '
@@ -147,7 +147,7 @@ test_expect_success GPG 'verify multiple tags' '
'
test_expect_success GPGSM 'verify multiple tags x509' '
- tags="seventh-signed nineth-signed-x509" &&
+ tags="seventh-signed ninth-signed-x509" &&
for i in $tags
do
git verify-tag -v --raw $i || return 1
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 4e676cd..482ce35 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1571,7 +1571,7 @@ test_expect_success '"status.showStash=true" weaker than "--no-show-stash"' '
test_cmp expected_without_stash actual
'
-test_expect_success 'no additionnal info if no stash entries' '
+test_expect_success 'no additional info if no stash entries' '
git stash clear &&
git -c status.showStash=true status >actual &&
test_cmp expected_without_stash actual
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index f19202b..6602790 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -1234,7 +1234,7 @@ test_expect_success 'with simple command' '
test_cmp expected actual
'
-test_expect_success 'with command using commiter information' '
+test_expect_success 'with command using committer information' '
git config trailer.sign.ifExists "addIfDifferent" &&
git config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" &&
cat complex_message_body >expected &&
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index 997d5fb..1e47ed2 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -294,7 +294,7 @@ do
done
done
-# test that splitting the index dosn't interfere
+# test that splitting the index doesn't interfere
test_expect_success 'splitting the index results in the same state' '
write_integration_script &&
dirty_repo &&
diff --git a/t/t7519/fsmonitor-watchman b/t/t7519/fsmonitor-watchman
index 5514edc..d8e7a1e 100755
--- a/t/t7519/fsmonitor-watchman
+++ b/t/t7519/fsmonitor-watchman
@@ -23,7 +23,8 @@ my ($version, $time) = @ARGV;
if ($version == 1) {
# convert nanoseconds to seconds
- $time = int $time / 1000000000;
+ # subtract one second to make sure watchman will return all changes
+ $time = int ($time / 1000000000) - 1;
} else {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
@@ -54,18 +55,12 @@ sub launch_watchman {
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
- # output to file names only. Then we're using the "expression" term to
- # further constrain the results.
- #
- # The category of transient files that we want to ignore will have a
- # creation clock (cclock) newer than $time_t value and will also not
- # currently exist.
+ # output to file names only.
my $query = <<" END";
["query", "$git_work_tree", {
"since": $time,
- "fields": ["name"],
- "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
+ "fields": ["name"]
}]
END
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 997f90b..bd94779 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -1260,7 +1260,7 @@ test_expect_success $PREREQ 'sendemail.identity: --no-identity clears previous i
grep "To: default@example.com" stdout
'
-test_expect_success $PREREQ 'sendemail.identity: bool identity variable existance overrides' '
+test_expect_success $PREREQ 'sendemail.identity: bool identity variable existence overrides' '
git -c sendemail.identity=cloud \
-c sendemail.xmailer=true \
-c sendemail.cloud.xmailer=false \
diff --git a/t/t9301-fast-import-notes.sh b/t/t9301-fast-import-notes.sh
index dadc70b..ca223dc 100755
--- a/t/t9301-fast-import-notes.sh
+++ b/t/t9301-fast-import-notes.sh
@@ -275,7 +275,7 @@ $whitespace
third note for first commit
EXPECT_END
-test_expect_success 'add concatentation notes with M command' '
+test_expect_success 'add concatenation notes with M command' '
git fast-import <input &&
GIT_NOTES_REF=refs/notes/test git log | grep "^ " > actual &&
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 2e4e214..db084fe 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -541,7 +541,7 @@ test_expect_success 'tree_tag' '
# NEEDSWORK: not just check return status, but validate the output
# Note that these tests DO NOTHING other than print a warning that
-# they are ommitting the one tag we asked them to export (because the
+# they are omitting the one tag we asked them to export (because the
# tags resolve to a tree). They exist just to make sure we do not
# abort but instead just warn.
test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj'
diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh
index 0796a43..e38cbc9 100755
--- a/t/t9502-gitweb-standalone-parse-output.sh
+++ b/t/t9502-gitweb-standalone-parse-output.sh
@@ -188,8 +188,8 @@ test_expect_success 'forks: project_index lists all projects (incl. forks)' '
'
xss() {
- echo >&2 "Checking $1..." &&
- gitweb_run "$1" &&
+ echo >&2 "Checking $*..." &&
+ gitweb_run "$@" &&
if grep "$TAG" gitweb.body; then
echo >&2 "xss: $TAG should have been quoted in output"
return 1
@@ -200,7 +200,8 @@ xss() {
test_expect_success 'xss checks' '
TAG="<magic-xss-tag>" &&
xss "a=rss&p=$TAG" &&
- xss "a=rss&p=foo.git&f=$TAG"
+ xss "a=rss&p=foo.git&f=$TAG" &&
+ xss "" "$TAG+"
'
test_done
diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh
index 3cff1fc..9c9710d 100755
--- a/t/t9809-git-p4-client-view.sh
+++ b/t/t9809-git-p4-client-view.sh
@@ -407,7 +407,7 @@ test_expect_success 'reinit depot' '
'
#
-# What happens when two files of the same name are overlayed together?
+# What happens when two files of the same name are overlaid together?
# The last-listed file should take preference.
#
# //depot
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index e90ac56..ec3eccf 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -378,7 +378,7 @@ test_expect_success '__gitdir - finds repo' '
'
-test_expect_success '__gitdir - returns error when cant find repo' '
+test_expect_success '__gitdir - returns error when cannot find repo' '
(
__git_dir="non-existing" &&
test_must_fail __gitdir >"$actual"
@@ -945,7 +945,7 @@ test_expect_success 'setup for filtering matching refs' '
rm -f .git/FETCH_HEAD
'
-test_expect_success '__git_refs - dont filter refs unless told so' '
+test_expect_success '__git_refs - do not filter refs unless told so' '
cat >expected <<-EOF &&
HEAD
master
@@ -1257,7 +1257,7 @@ test_path_completion ()
# In the following tests calling this function we only
# care about how __git_complete_index_file() deals with
# unusual characters in path names. By requesting only
- # untracked files we dont have to bother adding any
+ # untracked files we do not have to bother adding any
# paths to the index in those tests.
__git_complete_index_file --others &&
print_comp
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 46c4440..e8ae150 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1004,6 +1004,12 @@ test_skip () {
to_skip=t
skipped_reason="GIT_SKIP_TESTS"
fi
+ if test -z "$to_skip" && test -n "$run_list" &&
+ ! match_test_selector_list '--run' $test_count "$run_list"
+ then
+ to_skip=t
+ skipped_reason="--run"
+ fi
if test -z "$to_skip" && test -n "$test_prereq" &&
! test_have_prereq "$test_prereq"
then
@@ -1016,12 +1022,6 @@ test_skip () {
fi
skipped_reason="missing $missing_prereq${of_prereq}"
fi
- if test -z "$to_skip" && test -n "$run_list" &&
- ! match_test_selector_list '--run' $test_count "$run_list"
- then
- to_skip=t
- skipped_reason="--run"
- fi
case "$to_skip" in
t)
diff --git a/tag.c b/tag.c
index bfa0e31..71b5444 100644
--- a/tag.c
+++ b/tag.c
@@ -141,7 +141,16 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
if (item->object.parsed)
return 0;
- item->object.parsed = 1;
+
+ if (item->tag) {
+ /*
+ * Presumably left over from a previous failed parse;
+ * clear it out in preparation for re-parsing (we'll probably
+ * hit the same error, which lets us tell our current caller
+ * about the problem).
+ */
+ FREE_AND_NULL(item->tag);
+ }
if (size < the_hash_algo->hexsz + 24)
return -1;
@@ -167,10 +176,15 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
} else if (!strcmp(type, tag_type)) {
item->tagged = (struct object *)lookup_tag(r, &oid);
} else {
- error("Unknown type %s", type);
- item->tagged = NULL;
+ return error("unknown tag type '%s' in %s",
+ type, oid_to_hex(&item->object.oid));
}
+ if (!item->tagged)
+ return error("bad tag pointer to %s in %s",
+ oid_to_hex(&oid),
+ oid_to_hex(&item->object.oid));
+
if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
; /* good */
else
@@ -187,6 +201,7 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
else
item->date = 0;
+ item->object.parsed = 1;
return 0;
}
diff --git a/tar.h b/tar.h
index 3467705..6b258c4 100644
--- a/tar.h
+++ b/tar.h
@@ -1,3 +1,6 @@
+#ifndef TAR_H
+#define TAR_H
+
#define TYPEFLAG_AUTO '\0'
#define TYPEFLAG_REG '0'
#define TYPEFLAG_LNK '2'
@@ -23,3 +26,5 @@ struct ustar_header {
char devminor[8]; /* 337 */
char prefix[155]; /* 345 */
};
+
+#endif /* TAR_H */
diff --git a/templates/hooks--fsmonitor-watchman.sample b/templates/hooks--fsmonitor-watchman.sample
index e673bb3..ef94fa2 100755
--- a/templates/hooks--fsmonitor-watchman.sample
+++ b/templates/hooks--fsmonitor-watchman.sample
@@ -22,7 +22,8 @@ my ($version, $time) = @ARGV;
if ($version == 1) {
# convert nanoseconds to seconds
- $time = int $time / 1000000000;
+ # subtract one second to make sure watchman will return all changes
+ $time = int ($time / 1000000000) - 1;
} else {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
@@ -53,18 +54,12 @@ sub launch_watchman {
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
- # output to file names only. Then we're using the "expression" term to
- # further constrain the results.
- #
- # The category of transient files that we want to ignore will have a
- # creation clock (cclock) newer than $time_t value and will also not
- # currently exist.
+ # output to file names only.
my $query = <<" END";
["query", "$git_work_tree", {
"since": $time,
- "fields": ["name"],
- "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
+ "fields": ["name"]
}]
END
diff --git a/trace2/tr2_sid.c b/trace2/tr2_sid.c
index 6948fd4..dc6e75e 100644
--- a/trace2/tr2_sid.c
+++ b/trace2/tr2_sid.c
@@ -19,7 +19,7 @@ static int tr2sid_nr_git_parents;
* "H<first_8_chars_of_sha1_of_hostname>"
* "Localhost" when no hostname.
*
- * where <process> is a 9 character string containing the least signifcant
+ * where <process> is a 9 character string containing the least significant
* 32 bits in the process-id.
* "P<pid>"
* (This is an abribrary choice. On most systems pid_t is a 32 bit value,
diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
index ffac802..a8018f1 100644
--- a/trace2/tr2_tgt_perf.c
+++ b/trace2/tr2_tgt_perf.c
@@ -26,12 +26,9 @@ static int tr2env_perf_be_brief;
#define TR2FMT_PERF_REPO_WIDTH (3)
#define TR2FMT_PERF_CATEGORY_WIDTH (12)
-#define TR2_DOTS_BUFFER_SIZE (100)
#define TR2_INDENT (2)
#define TR2_INDENT_LENGTH(ctx) (((ctx)->nr_open_regions - 1) * TR2_INDENT)
-static struct strbuf dots = STRBUF_INIT;
-
static int fn_init(void)
{
int want = tr2_dst_trace_want(&tr2dst_perf);
@@ -41,8 +38,6 @@ static int fn_init(void)
if (!want)
return want;
- strbuf_addchars(&dots, '.', TR2_DOTS_BUFFER_SIZE);
-
brief = tr2_sysenv_get(TR2_SYSENV_PERF_BRIEF);
if (brief && *brief &&
((want_brief = git_parse_maybe_bool(brief)) != -1))
@@ -54,8 +49,6 @@ static int fn_init(void)
static void fn_term(void)
{
tr2_dst_trace_disable(&tr2dst_perf);
-
- strbuf_release(&dots);
}
/*
@@ -138,14 +131,8 @@ static void perf_fmt_prepare(const char *event_name,
strbuf_addf(buf, "%-*.*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
TR2FMT_PERF_CATEGORY_WIDTH, (category ? category : ""));
- if (ctx->nr_open_regions > 0) {
- int len_indent = TR2_INDENT_LENGTH(ctx);
- while (len_indent > dots.len) {
- strbuf_addbuf(buf, &dots);
- len_indent -= dots.len;
- }
- strbuf_addf(buf, "%.*s", len_indent, dots.buf);
- }
+ if (ctx->nr_open_regions > 0)
+ strbuf_addchars(buf, '.', TR2_INDENT_LENGTH(ctx));
}
static void perf_io_write_fl(const char *file, int line, const char *event_name,
diff --git a/unpack-trees.c b/unpack-trees.c
index 33ea781..28cbd19 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -275,9 +275,9 @@ static int check_submodule_move_head(const struct cache_entry *ce,
}
/*
- * Preform the loading of the repository's gitmodules file. This function is
+ * Perform the loading of the repository's gitmodules file. This function is
* used by 'check_update()' to perform loading of the gitmodules file in two
- * differnt situations:
+ * different situations:
* (1) before removing entries from the working tree if the gitmodules file has
* been marked for removal. This situation is specified by 'state' == NULL.
* (2) before checking out entries to the working tree if the gitmodules file
diff --git a/url.c b/url.c
index e34e5e7..e04bd60 100644
--- a/url.c
+++ b/url.c
@@ -5,7 +5,7 @@ int is_urlschemechar(int first_flag, int ch)
{
/*
* The set of valid URL schemes, as per STD66 (RFC3986) is
- * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check
+ * '[A-Za-z][A-Za-z0-9+.-]*'. But use slightly looser check
* of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
* of check used '[A-Za-z0-9]+' so not to break any remote
* helpers.
diff --git a/usage.c b/usage.c
index 2fdb200..58fb5ff 100644
--- a/usage.c
+++ b/usage.c
@@ -9,14 +9,26 @@
void vreportf(const char *prefix, const char *err, va_list params)
{
char msg[4096];
- char *p;
+ char *p, *pend = msg + sizeof(msg);
+ size_t prefix_len = strlen(prefix);
- vsnprintf(msg, sizeof(msg), err, params);
- for (p = msg; *p; p++) {
+ if (sizeof(msg) <= prefix_len) {
+ fprintf(stderr, "BUG!!! too long a prefix '%s'\n", prefix);
+ abort();
+ }
+ memcpy(msg, prefix, prefix_len);
+ p = msg + prefix_len;
+ if (vsnprintf(p, pend - p, err, params) < 0)
+ *p = '\0'; /* vsnprintf() failed, clip at prefix */
+
+ for (; p != pend - 1 && *p; p++) {
if (iscntrl(*p) && *p != '\t' && *p != '\n')
*p = '?';
}
- fprintf(stderr, "%s%s\n", prefix, msg);
+
+ *(p++) = '\n'; /* we no longer need a NUL */
+ fflush(stderr);
+ write_in_full(2, msg, p - msg);
}
static NORETURN void usage_builtin(const char *err, va_list params)
diff --git a/userdiff.c b/userdiff.c
index e187d35..577053c 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -32,6 +32,18 @@ PATTERNS("dts",
/* Property names and math operators */
"[a-zA-Z0-9,._+?#-]+"
"|[-+*/%&^|!~]|>>|<<|&&|\\|\\|"),
+PATTERNS("elixir",
+ "^[ \t]*((def(macro|module|impl|protocol|p)?|test)[ \t].*)$",
+ /* Atoms, names, and module attributes */
+ "|[@:]?[a-zA-Z0-9@_?!]+"
+ /* Numbers with specific base */
+ "|[-+]?0[xob][0-9a-fA-F]+"
+ /* Numbers */
+ "|[-+]?[0-9][0-9_.]*([eE][-+]?[0-9_]+)?"
+ /* Operators and atoms that represent them */
+ "|:?(\\+\\+|--|\\.\\.|~~~|<>|\\^\\^\\^|<?\\|>|<<<?|>?>>|<<?~|~>?>|<~>|<=|>=|===?|!==?|=~|&&&?|\\|\\|\\|?|=>|<-|\\\\\\\\|->)"
+ /* Not real operators, but should be grouped */
+ "|:?%[A-Za-z0-9_.]\\{\\}?"),
IPATTERN("fortran",
"!^([C*]|[ \t]*!)\n"
"!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n"
diff --git a/utf8.c b/utf8.c
index 5c8f151..5b39361 100644
--- a/utf8.c
+++ b/utf8.c
@@ -411,11 +411,10 @@ out:
*/
static int same_utf_encoding(const char *src, const char *dst)
{
- if (istarts_with(src, "utf") && istarts_with(dst, "utf")) {
- /* src[3] or dst[3] might be '\0' */
- int i = (src[3] == '-' ? 4 : 3);
- int j = (dst[3] == '-' ? 4 : 3);
- return !strcasecmp(src+i, dst+j);
+ if (skip_iprefix(src, "utf", &src) && skip_iprefix(dst, "utf", &dst)) {
+ skip_prefix(src, "-", &src);
+ skip_prefix(dst, "-", &dst);
+ return !strcasecmp(src, dst);
}
return 0;
}
diff --git a/xdiff-interface.h b/xdiff-interface.h
index ede4246..93df269 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -44,7 +44,7 @@ void discard_hunk_line(void *priv,
* Compare the strings l1 with l2 which are of size s1 and s2 respectively.
* Returns 1 if the strings are deemed equal, 0 otherwise.
* The `flags` given as XDF_WHITESPACE_FLAGS determine how white spaces
- * are treated for the comparision.
+ * are treated for the comparison.
*/
int xdiff_compare_lines(const char *l1, long s1,
const char *l2, long s2, long flags);