summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/RelNotes/1.8.5.4.txt48
-rw-r--r--Documentation/RelNotes/1.8.5.5.txt37
-rw-r--r--Documentation/RelNotes/1.9.0.txt (renamed from Documentation/RelNotes/1.9.txt)71
-rw-r--r--Documentation/config.txt43
-rw-r--r--Documentation/git-am.txt6
-rw-r--r--Documentation/git-blame.txt3
-rw-r--r--Documentation/git-cherry-pick.txt7
-rw-r--r--Documentation/git-clone.txt13
-rw-r--r--Documentation/git-commit-tree.txt5
-rw-r--r--Documentation/git-commit.txt4
-rw-r--r--Documentation/git-diff.txt2
-rw-r--r--Documentation/git-rebase.txt4
-rw-r--r--Documentation/git-remote.txt2
-rw-r--r--Documentation/git-repack.txt9
-rw-r--r--Documentation/git-reset.txt5
-rw-r--r--Documentation/git-rev-list.txt1
-rw-r--r--Documentation/git-revert.txt6
-rw-r--r--Documentation/git-submodule.txt46
-rw-r--r--Documentation/git-tag.txt5
-rw-r--r--Documentation/git.txt9
-rw-r--r--Documentation/gitcli.txt2
-rw-r--r--Documentation/githooks.txt2
-rw-r--r--Documentation/gitmodules.txt4
-rw-r--r--Documentation/gitweb.conf.txt4
-rw-r--r--Documentation/howto/maintain-git.txt18
-rw-r--r--Documentation/merge-strategies.txt2
-rw-r--r--Documentation/rev-list-options.txt8
-rw-r--r--Documentation/technical/api-hash.txt52
-rw-r--r--Documentation/technical/api-hashmap.txt235
-rw-r--r--Documentation/technical/bitmap-format.txt164
-rw-r--r--Documentation/technical/pack-protocol.txt3
-rw-r--r--Documentation/technical/protocol-capabilities.txt18
-rw-r--r--Documentation/user-manual.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile21
l---------RelNotes2
-rw-r--r--bisect.c2
-rw-r--r--block-sha1/sha1.c32
-rw-r--r--builtin/add.c3
-rw-r--r--builtin/apply.c12
-rw-r--r--builtin/blame.c99
-rw-r--r--builtin/checkout.c3
-rw-r--r--builtin/clean.c27
-rw-r--r--builtin/commit-tree.c12
-rw-r--r--builtin/commit.c17
-rw-r--r--builtin/describe.c53
-rw-r--r--builtin/fetch.c2
-rw-r--r--builtin/gc.c5
-rw-r--r--builtin/grep.c6
-rw-r--r--builtin/ls-files.c9
-rw-r--r--builtin/ls-tree.c2
-rw-r--r--builtin/merge.c3
-rw-r--r--builtin/pack-objects.c451
-rw-r--r--builtin/repack.c45
-rw-r--r--builtin/reset.c40
-rw-r--r--builtin/rev-list.c39
-rw-r--r--builtin/rev-parse.c17
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/rm.c4
-rw-r--r--builtin/update-index.c42
-rw-r--r--cache.h30
-rw-r--r--compat/bswap.h112
-rw-r--r--config.c6
-rwxr-xr-xcontrib/git-resurrect.sh1
-rw-r--r--diff-lib.c5
-rw-r--r--diff.c67
-rw-r--r--diffcore-rename.c185
-rw-r--r--diffcore.h2
-rw-r--r--dir.c40
-rw-r--r--dir.h24
-rw-r--r--ewah/bitmap.c221
-rw-r--r--ewah/ewah_bitmap.c714
-rw-r--r--ewah/ewah_io.c204
-rw-r--r--ewah/ewah_rlw.c115
-rw-r--r--ewah/ewok.h233
-rw-r--r--ewah/ewok_rlw.h114
-rw-r--r--fetch-pack.c3
-rwxr-xr-xgit-am.sh26
-rw-r--r--git-compat-util.h6
-rwxr-xr-xgit-instaweb.sh1
-rwxr-xr-xgit-pull.sh30
-rwxr-xr-xgit-quiltimport.sh1
-rw-r--r--git-rebase--am.sh8
-rw-r--r--git-rebase--interactive.sh39
-rw-r--r--git-rebase--merge.sh2
-rwxr-xr-xgit-rebase.sh62
-rwxr-xr-xgit-request-pull.sh1
-rw-r--r--git-sh-setup.sh2
-rwxr-xr-xgit-submodule.sh89
-rw-r--r--hash.c110
-rw-r--r--hash.h50
-rw-r--r--hashmap.c228
-rw-r--r--hashmap.h71
-rw-r--r--khash.h338
-rw-r--r--merge-recursive.c4
-rw-r--r--name-hash.c163
-rw-r--r--pack-bitmap-write.c552
-rw-r--r--pack-bitmap.c1073
-rw-r--r--pack-bitmap.h64
-rw-r--r--pack-objects.c111
-rw-r--r--pack-objects.h68
-rw-r--r--pack-revindex.c43
-rw-r--r--pack-revindex.h9
-rw-r--r--pack-write.c2
-rw-r--r--path.c2
-rw-r--r--pathspec.c2
-rw-r--r--po/de.po1810
-rw-r--r--po/fr.po58
-rw-r--r--po/git.pot29
-rw-r--r--po/sv.po31
-rw-r--r--po/vi.po123
-rw-r--r--po/zh_CN.po63
-rw-r--r--preload-index.c3
-rw-r--r--read-cache.c93
-rw-r--r--rerere.c4
-rw-r--r--resolve-undo.c9
-rw-r--r--revision.c7
-rw-r--r--revision.h2
-rw-r--r--sequencer.c11
-rw-r--r--sequencer.h2
-rw-r--r--setup.c94
-rw-r--r--sha1_file.c6
-rw-r--r--submodule.c25
-rw-r--r--t/lib-git-daemon.sh2
-rw-r--r--t/lib-httpd.sh2
-rwxr-xr-xt/perf/p5310-pack-bitmaps.sh57
-rwxr-xr-xt/t0011-hashmap.sh240
-rwxr-xr-xt/t0060-path-utils.sh21
-rwxr-xr-xt/t3004-ls-files-basic.sh17
-rwxr-xr-xt/t3030-merge-recursive.sh47
-rwxr-xr-xt/t4010-diff-pathspec.sh6
-rw-r--r--t/t4034/ada/expect2
-rwxr-xr-xt/t4035-diff-quiet.sh6
-rwxr-xr-xt/t5310-pack-bitmaps.sh139
-rwxr-xr-xt/t5537-fetch-shallow.sh28
-rwxr-xr-xt/t5538-push-shallow.sh1
-rwxr-xr-xt/t5539-fetch-http-shallow.sh82
-rwxr-xr-xt/t5540-http-push-webdav.sh (renamed from t/t5540-http-push.sh)1
-rwxr-xr-xt/t5541-http-push-smart.sh (renamed from t/t5541-http-push.sh)1
-rwxr-xr-xt/t5550-http-fetch-dumb.sh (renamed from t/t5550-http-fetch.sh)1
-rwxr-xr-xt/t5551-http-fetch-smart.sh (renamed from t/t5551-http-fetch.sh)1
-rwxr-xr-xt/t5561-http-backend.sh1
-rwxr-xr-xt/t5570-git-daemon.sh1
-rwxr-xr-xt/t6131-pathspec-icase.sh6
-rwxr-xr-xt/t7101-reset-empty-subdirs.sh (renamed from t/t7101-reset.sh)0
-rwxr-xr-xt/t7102-reset.sh15
-rwxr-xr-xt/t7104-reset-hard.sh (renamed from t/t7104-reset.sh)0
-rwxr-xr-xt/t7406-submodule-update.sh38
-rwxr-xr-xt/t7510-signed-commit.sh25
-rwxr-xr-xt/t7601-merge-pull-config.sh21
-rw-r--r--test-hashmap.c255
-rw-r--r--unpack-trees.c3
-rw-r--r--userdiff.c4
-rw-r--r--wt-status.c6
155 files changed, 8172 insertions, 2253 deletions
diff --git a/.gitignore b/.gitignore
index b5f9defed3..dc600f9b36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -182,6 +182,7 @@
/test-dump-cache-tree
/test-scrap-cache-tree
/test-genrandom
+/test-hashmap
/test-index-version
/test-line-buffer
/test-match-trees
diff --git a/Documentation/RelNotes/1.8.5.4.txt b/Documentation/RelNotes/1.8.5.4.txt
new file mode 100644
index 0000000000..d18c40389e
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.4.txt
@@ -0,0 +1,48 @@
+Git v1.8.5.4 Release Notes
+==========================
+
+Fixes since v1.8.5.3
+--------------------
+
+ * "git fetch --depth=0" was a no-op, and was silently ignored.
+ Diagnose it as an error.
+
+ * Remote repository URL expressed in scp-style host:path notation are
+ parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks
+ to connect to user's home directory on host at address ::1.
+
+ * SSL-related options were not passed correctly to underlying socket
+ layer in "git send-email".
+
+ * "git commit -v" appends the patch to the log message before
+ editing, and then removes the patch when the editor returned
+ control. However, the patch was not stripped correctly when the
+ first modified path was a submodule.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+
+ * When we figure out how many file descriptors to allocate for
+ keeping packfiles open, a system with non-working getrlimit() could
+ cause us to die(), but because we make this call only to get a
+ rough estimate of how many is available and we do not even attempt
+ to use up all file descriptors available ourselves, it is nicer to
+ fall back to a reasonable low value rather than dying.
+
+ * "git log --decorate" did not handle a tag pointed by another tag
+ nicely.
+
+ * "git add -A" (no other arguments) in a totally empty working tree
+ used to emit an error.
+
+ * There is no reason to have a hardcoded upper limit of the number of
+ parents for an octopus merge, created via the graft mechanism, but
+ there was.
+
+ * The implementation of 'git stash $cmd "stash@{...}"' did not quote
+ the stash argument properly and left it split at IFS whitespace.
+
+ * The documentation to "git pull" hinted there is an "-m" option
+ because it incorrectly shared the documentation with "git merge".
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.5.txt b/Documentation/RelNotes/1.8.5.5.txt
new file mode 100644
index 0000000000..9191ce948f
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.5.txt
@@ -0,0 +1,37 @@
+Git v1.8.5.5 Release Notes
+==========================
+
+Fixes since v1.8.5.4
+--------------------
+
+ * The pathspec matching code, while comparing two trees (e.g. "git
+ diff A B -- path1 path2") was too aggressive and failed to match
+ some paths when multiple pathspecs were involved.
+
+ * "git repack --max-pack-size=8g" stopped being parsed correctly when
+ the command was reimplemented in C.
+
+ * A recent update to "git send-email" broke platforms where
+ /etc/ssl/certs/ directory exists but cannot be used as SSL_ca_path
+ (e.g. Fedora rawhide).
+
+ * A handful of bugs around interpreting $branch@{upstream} notation
+ and its lookalike, when $branch part has interesting characters,
+ e.g. "@", and ":", have been fixed.
+
+ * "git clone" would fail to clone from a repository that has a ref
+ directly under "refs/", e.g. "refs/stash", because different
+ validation paths do different things on such a refname. Loosen the
+ client side's validation to allow such a ref.
+
+ * "git log --left-right A...B" lost the "leftness" of commits
+ reachable from A when A is a tag as a side effect of a recent
+ bugfix. This is a regression in 1.8.4.x series.
+
+ * "git merge-base --octopus" used to leave cleaning up suboptimal
+ result to the caller, but now it does the clean-up itself.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.9.txt b/Documentation/RelNotes/1.9.0.txt
index 43c7b682a6..752d79127a 100644
--- a/Documentation/RelNotes/1.9.txt
+++ b/Documentation/RelNotes/1.9.0.txt
@@ -1,5 +1,5 @@
-Git v1.9 Release Notes
-======================
+Git v1.9.0 Release Notes
+========================
Backward compatibility notes
----------------------------
@@ -7,19 +7,19 @@ Backward compatibility notes
"git submodule foreach $cmd $args" used to treat "$cmd $args" the same
way "ssh" did, concatenating them into a single string and letting the
shell unquote. Careless users who forget to sufficiently quote $args
-gets their argument split at $IFS whitespaces by the shell, and got
+get their argument split at $IFS whitespaces by the shell, and got
unexpected results due to this. Starting from this release, the
command line is passed directly to the shell, if it has an argument.
Read-only support for experimental loose-object format, in which users
-could optionally choose to write in their loose objects for a short
-while between v1.4.3 to v1.5.3 era, has been dropped.
+could optionally choose to write their loose objects for a short
+while between v1.4.3 and v1.5.3 era, has been dropped.
-The meanings of "--tags" option to "git fetch" has changed; the
-command fetches tags _in addition to_ what are fetched by the same
+The meanings of the "--tags" option to "git fetch" has changed; the
+command fetches tags _in addition to_ what is fetched by the same
command line without the option.
-The way "git push $there $what" interprets $what part given on the
+The way "git push $there $what" interprets the $what part given on the
command line, when it does not have a colon that explicitly tells us
what ref at the $there repository is to be updated, has been enhanced.
@@ -27,8 +27,8 @@ A handful of ancient commands that have long been deprecated are
finally gone (repo-config, tar-tree, lost-found, and peek-remote).
-Backward compatibility notes (for Git 2.0)
-------------------------------------------
+Backward compatibility notes (for Git 2.0.0)
+--------------------------------------------
When "git push [$there]" does not say what to push, we have used the
traditional "matching" semantics so far (all your branches were sent
@@ -96,7 +96,7 @@ UI, Workflows & Features
primarily because the codepaths involved were not carefully vetted
and we did not bother supporting such usage. This release attempts
to allow object transfer out of a shallowly-cloned repository in a
- more controlled way (i.e. the receiver become a shallow repository
+ more controlled way (i.e. the receiver becomes a shallow repository
with a truncated history).
* Just like we give a reasonable default for "less" via the LESS
@@ -107,12 +107,12 @@ UI, Workflows & Features
hierarchies, whose variables are predominantly three-level, were
not completed by hitting a <TAB> in bash and zsh completions.
- * Fetching 'frotz' branch with "git fetch", while 'frotz/nitfol'
+ * Fetching a 'frotz' branch with "git fetch", while a 'frotz/nitfol'
remote-tracking branch from an earlier fetch was still there, would
error out, primarily because the command was not told that it is
allowed to lose any information on our side. "git fetch --prune"
- now can be used to remove 'frotz/nitfol' to make room to fetch and
- store 'frotz' remote-tracking branch.
+ now can be used to remove 'frotz/nitfol' to make room for fetching and
+ storing the 'frotz' remote-tracking branch.
* "diff.orderfile=<file>" configuration variable can be used to
pretend as if the "-O<file>" option were given from the command
@@ -218,42 +218,35 @@ track are contained in this release (see the maintenance releases' notes
for details).
* The pathspec matching code, while comparing two trees (e.g. "git
- diff A B -- path1 path2") was too agrresive and failed to match
+ diff A B -- path1 path2") was too aggressive and failed to match
some paths when multiple pathspecs were involved.
- (merge e4ddb05 as/tree-walk-fix-aggressive-short-cut later to maint).
* "git repack --max-pack-size=8g" stopped being parsed correctly when
the command was reimplemented in C.
- (merge b861e23 sb/repack-in-c later to maint).
* An earlier update in v1.8.4.x to "git rev-list --objects" with
- negative ref had performance regression.
+ negative ref had a performance regression.
(merge 200abe7 jk/mark-edges-uninteresting later to maint).
* A recent update to "git send-email" broke platforms where
- /etc/ssl/certs/ directory exists, but it cannot used as SSL_ca_path
+ /etc/ssl/certs/ directory exists but cannot be used as SSL_ca_path
(e.g. Fedora rawhide).
- (merge 01645b7 rk/send-email-ssl-cert later to maint).
* A handful of bugs around interpreting $branch@{upstream} notation
and its lookalike, when $branch part has interesting characters,
e.g. "@", and ":", have been fixed.
- (merge 9892d5d jk/interpret-branch-name-fix later to maint).
* "git clone" would fail to clone from a repository that has a ref
directly under "refs/", e.g. "refs/stash", because different
validation paths do different things on such a refname. Loosen the
client side's validation to allow such a ref.
- (merge 4c22408 jk/allow-fetch-onelevel-refname later to maint).
* "git log --left-right A...B" lost the "leftness" of commits
reachable from A when A is a tag as a side effect of a recent
bugfix. This is a regression in 1.8.4.x series.
- (merge a743528 jc/revision-range-unpeel later to maint).
* documentations to "git pull" hinted there is an "-m" option because
it incorrectly shared the documentation with "git merge".
- (merge 08f19cf jc/maint-pull-docfix later to maint).
* "git diff A B submod" and "git diff A B submod/" ought to have done
the same for a submodule "submod", but didn't.
@@ -268,17 +261,14 @@ for details).
* The implementation of 'git stash $cmd "stash@{...}"' did not quote
the stash argument properly and left it split at IFS whitespace.
- (merge 2a07e43 ow/stash-with-ifs later to maint).
* The "--[no-]informative-errors" options to "git daemon" were parsed
a bit too loosely, allowing any other string after these option
names.
- (merge 82246b7 nd/daemon-informative-errors-typofix later to maint).
- * There is no reason to have a hardcoded upper limit of the number of
- parents for an octopus merge, created via the graft mechanism, but
+ * There is no reason to have a hardcoded upper limit for the number of
+ parents of an octopus merge, created via the graft mechanism, but
there was.
- (merge e228c17 js/lift-parent-count-limit later to maint).
* The basic test used to leave unnecessary trash directories in the
t/ directory.
@@ -286,30 +276,24 @@ for details).
* "git merge-base --octopus" used to leave cleaning up suboptimal
result to the caller, but now it does the clean-up itself.
- (merge 8f29299 bm/merge-base-octopus-dedup later to maint).
* A "gc" process running as a different user should be able to stop a
new "gc" process from starting, but it didn't.
- (merge ed7eda8 km/gc-eperm later to maint).
* An earlier "clean-up" introduced an unnecessary memory leak.
- (merge e1c1a32 jk/credential-plug-leak later to maint).
* "git add -A" (no other arguments) in a totally empty working tree
used to emit an error.
- (merge 64ed07c nd/add-empty-fix later to maint).
* "git log --decorate" did not handle a tag pointed by another tag
nicely.
- (merge 5e1361c bc/log-decoration later to maint).
* When we figure out how many file descriptors to allocate for
keeping packfiles open, a system with non-working getrlimit() could
cause us to die(), but because we make this call only to get a
- rough estimate of how many is available and we do not even attempt
- to use up all file descriptors available ourselves, it is nicer to
+ rough estimate of how many are available and we do not even attempt
+ to use up all available file descriptors ourselves, it is nicer to
fall back to a reasonable low value rather than dying.
- (merge 491a8de jh/rlimit-nofile-fallback later to maint).
* read_sha1_file(), that is the workhorse to read the contents given
an object name, honoured object replacements, but there was no
@@ -320,16 +304,13 @@ for details).
* "git cat-file --batch=", an admittedly useless command, did not
behave very well.
- (merge 6554dfa jk/cat-file-regression-fix later to maint).
* "git rev-parse <revs> -- <paths>" did not implement the usual
disambiguation rules the commands in the "git log" family used in
the same way.
- (merge 62f162f jk/rev-parse-double-dashes later to maint).
* "git mv A B/", when B does not exist as a directory, should error
out, but it didn't.
- (merge c57f628 mm/mv-file-to-no-such-dir-with-slash later to maint).
* A workaround to an old bug in glibc prior to glibc 2.17 has been
retired; this would remove a side effect of the workaround that
@@ -337,36 +318,28 @@ for details).
* SSL-related options were not passed correctly to underlying socket
layer in "git send-email".
- (merge 5508f3e tr/send-email-ssl later to maint).
* "git commit -v" appends the patch to the log message before
editing, and then removes the patch when the editor returned
control. However, the patch was not stripped correctly when the
first modified path was a submodule.
- (merge 1a72cfd jl/commit-v-strip-marker later to maint).
* "git fetch --depth=0" was a no-op, and was silently ignored.
Diagnose it as an error.
- (merge 5594bca nd/transport-positive-depth-only later to maint).
- * Remote repository URL expressed in scp-style host:path notation are
+ * Remote repository URLs expressed in scp-style host:path notation are
parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks
to connect to user's home directory on host at address ::1.
- (merge a2036d7 tb/clone-ssh-with-colon-for-port later to maint).
* "git diff -- ':(icase)makefile'" was unnecessarily rejected at the
command line parser.
- (merge 887c6c1 nd/magic-pathspec later to maint).
* "git cat-file --batch-check=ok" did not check the existence of
the named object.
- (merge 4ef8d1d sb/sha1-loose-object-info-check-existence later to maint).
* "git am --abort" sometimes complained about not being able to write
a tree with an 0{40} object in it.
- (merge 77b43ca jk/two-way-merge-corner-case-fix later to maint).
* Two processes creating loose objects at the same time could have
failed unnecessarily when the name of their new objects started
with the same byte value, due to a race condition.
- (merge b2476a6 jh/loose-object-dirs-creation-race later to maint).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5f4d7939ed..040197b10e 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -992,6 +992,14 @@ commit.cleanup::
have to remove the help lines that begin with `#` in the commit log
template yourself, if you do this).
+commit.gpgsign::
+
+ A boolean to specify whether all commits should be GPG signed.
+ Use of this option when doing operations such as rebase can
+ result in a large number of commits being signed. It may be
+ convenient to use an agent to avoid typing your GPG passphrase
+ several times.
+
commit.status::
A boolean to enable/disable inclusion of status information in the
commit message template when using an editor to prepare the commit
@@ -1862,6 +1870,31 @@ pack.packSizeLimit::
Common unit suffixes of 'k', 'm', or 'g' are
supported.
+pack.useBitmaps::
+ When true, git will use pack bitmaps (if available) when packing
+ to stdout (e.g., during the server side of a fetch). Defaults to
+ true. You should not generally need to turn this off unless
+ you are debugging pack bitmaps.
+
+pack.writebitmaps::
+ When true, git will write a bitmap index when packing all
+ objects to disk (e.g., when `git repack -a` is run). This
+ index can speed up the "counting objects" phase of subsequent
+ packs created for clones and fetches, at the cost of some disk
+ space and extra time spent on the initial repack. Defaults to
+ false.
+
+pack.writeBitmapHashCache::
+ When true, git will include a "hash cache" section in the bitmap
+ index (if one is written). This cache can be used to feed git's
+ delta heuristics, potentially leading to better deltas between
+ bitmapped and non-bitmapped objects (e.g., when serving a fetch
+ between an older, bitmapped pack and objects that have been
+ pushed since the last gc). The downside is that it consumes 4
+ bytes per object of disk space, and that JGit's bitmap
+ implementation does not understand it, causing it to complain if
+ Git and JGit are used on the same repository. Defaults to false.
+
pager.<cmd>::
If the value is boolean, turns on or off pagination of the
output of a particular Git subcommand when writing to a tty.
@@ -1881,6 +1914,16 @@ pretty.<name>::
Note that an alias with the same name as a built-in format
will be silently ignored.
+pull.ff::
+ By default, Git does not create an extra merge commit when merging
+ a commit that is a descendant of the current commit. Instead, the
+ tip of the current branch is fast-forwarded. When set to `false`,
+ this variable tells Git to create an extra merge commit in such
+ a case (equivalent to giving the `--no-ff` option from the command
+ line). When set to `only`, only such fast-forward merges are
+ allowed (equivalent to giving the `--ff-only` option from the
+ command line).
+
pull.rebase::
When true, rebase branches on top of the fetched branch, instead
of merging the default branch from the default remote when "git
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 54d8461d61..17924d0f3f 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -14,7 +14,7 @@ SYNOPSIS
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
- [--[no-]scissors]
+ [--[no-]scissors] [-S[<keyid>]]
[(<mbox> | <Maildir>)...]
'git am' (--continue | --skip | --abort)
@@ -119,6 +119,10 @@ default. You can use `--no-utf8` to override this.
Skip the current patch. This is only meaningful when
restarting an aborted patch.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
--continue::
-r::
--resolved::
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 8e70a61840..9f23a861ce 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -35,7 +35,8 @@ Apart from supporting file annotation, Git also supports searching the
development history for when a code snippet occurred in a change. This makes it
possible to track when a code snippet was added to a file, moved or copied
between files, and eventually deleted or replaced. It works by searching for
-a text string in the diff. A small example:
+a text string in the diff. A small example of the pickaxe interface
+that searches for `blame_usage`:
-----------------------------------------------------------------------------
$ git log --pretty=oneline -S'blame_usage'
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index c205d2363e..f1e6b2fd6d 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -8,7 +8,8 @@ git-cherry-pick - Apply the changes introduced by some existing commits
SYNOPSIS
--------
[verse]
-'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...
+'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
+ [-S[<keyid>]] <commit>...
'git cherry-pick' --continue
'git cherry-pick' --quit
'git cherry-pick' --abort
@@ -100,6 +101,10 @@ effect to your index in a row.
--signoff::
Add Signed-off-by line at the end of the commit message.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
--ff::
If the current HEAD is the same as the parent of the
cherry-pick'ed commit, then a fast forward to this commit will
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 49878570bf..0363d0039b 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -55,15 +55,12 @@ repository is specified as a URL, then this flag is ignored (and we
never use the local optimizations). Specifying `--no-local` will
override the default when `/path/to/repo` is given, using the regular
Git transport instead.
-+
-To force copying instead of hardlinking (which may be desirable if you
-are trying to make a back-up of your repository), but still avoid the
-usual "Git aware" transport mechanism, `--no-hardlinks` can be used.
--no-hardlinks::
- Optimize the cloning process from a repository on a
- local filesystem by copying files under `.git/objects`
- directory.
+ Force the cloning process from a repository on a local
+ filesystem to copy the files under the `.git/objects`
+ directory instead of using hardlinks. This may be desirable
+ if you are trying to make a back-up of your repository.
--shared::
-s::
@@ -208,7 +205,7 @@ objects from the source repository into a pack in the cloned repository.
--separate-git-dir=<git dir>::
Instead of placing the cloned repository where it is supposed
to be, place the cloned repository at the specified directory,
- then make a filesytem-agnostic Git symbolic link to there.
+ then make a filesystem-agnostic Git symbolic link to there.
The result is Git repository can be separated from working
tree.
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index cafdc9642d..a469eab066 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -55,8 +55,13 @@ OPTIONS
from the standard input.
-S[<keyid>]::
+--gpg-sign[=<keyid>]::
GPG-sign commit.
+--no-gpg-sign::
+ Countermand `commit.gpgsign` configuration variable that is
+ set to force each and every commit to be signed.
+
Commit Information
------------------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 1a7616c73a..7c42e9cabc 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -302,6 +302,10 @@ configuration variable documented in linkgit:git-config[1].
--gpg-sign[=<keyid>]::
GPG-sign commit.
+--no-gpg-sign::
+ Countermand `commit.gpgsign` configuration variable that is
+ set to force each and every commit to be signed.
+
\--::
Do not interpret any more arguments as options.
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 33fbd8c56f..56fb7e5322 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -44,7 +44,7 @@ two blob objects, or changes between two files on disk.
commit relative to the named <commit>. Typically you
would want comparison with the latest commit, so if you
do not give <commit>, it defaults to HEAD.
- If HEAD does not exist (e.g. unborned branches) and
+ If HEAD does not exist (e.g. unborn branches) and
<commit> is not given, it shows all staged changes.
--staged is a synonym of --cached.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 2889be6bdc..2a93c645bd 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -281,6 +281,10 @@ which makes little sense.
specified, `-s recursive`. Note the reversal of 'ours' and
'theirs' as noted above for the `-m` option.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
-q::
--quiet::
Be quiet. Implies --no-stat.
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 2507c8bd91..cb103c8b6f 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -3,7 +3,7 @@ git-remote(1)
NAME
----
-git-remote - manage set of tracked repositories
+git-remote - Manage set of tracked repositories
SYNOPSIS
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 509cf73e50..002cfd5eb9 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -9,7 +9,7 @@ git-repack - Pack unpacked objects in a repository
SYNOPSIS
--------
[verse]
-'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [--window=<n>] [--depth=<n>]
+'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [--window=<n>] [--depth=<n>]
DESCRIPTION
-----------
@@ -110,6 +110,13 @@ other objects in that pack they already have locally.
The default is unlimited, unless the config variable
`pack.packSizeLimit` is set.
+-b::
+--write-bitmap-index::
+ Write a reachability bitmap index as part of the repack. This
+ only makes sense when used with `-a` or `-A`, as the bitmaps
+ must be able to refer to all reachable objects. This option
+ overrides the setting of `pack.writebitmaps`.
+
Configuration
-------------
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index f445cb38fa..a077ba0ddc 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git reset' [-q] [<tree-ish>] [--] <paths>...
'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
-'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
+'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
DESCRIPTION
-----------
@@ -60,6 +60,9 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
Resets the index but not the working tree (i.e., the changed files
are preserved but not marked for commit) and reports what has not
been updated. This is the default action.
++
+If `-N` is specified, removed paths are marked as intent-to-add (see
+linkgit:git-add[1]).
--hard::
Resets the index and working tree. Any changes to tracked files in the
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 045b37b82e..7a1585def0 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -55,6 +55,7 @@ SYNOPSIS
[ \--reverse ]
[ \--walk-reflogs ]
[ \--no-walk ] [ \--do-walk ]
+ [ \--use-bitmap-index ]
<commit>... [ \-- <paths>... ]
DESCRIPTION
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 2de67a5496..9eb83f01a4 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -8,7 +8,7 @@ git-revert - Revert some existing commits
SYNOPSIS
--------
[verse]
-'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] <commit>...
+'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
'git revert' --continue
'git revert' --quit
'git revert' --abort
@@ -80,6 +80,10 @@ more details.
This is useful when reverting more than one commits'
effect to your index in a row.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
-s::
--signoff::
Add Signed-off-by line at the end of the commit message.
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index bfef8a0c62..21cb59a6d6 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -15,8 +15,8 @@ SYNOPSIS
'git submodule' [--quiet] init [--] [<path>...]
'git submodule' [--quiet] deinit [-f|--force] [--] <path>...
'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch]
- [-f|--force] [--rebase] [--reference <repository>] [--depth <depth>]
- [--merge] [--recursive] [--] [<path>...]
+ [-f|--force] [--rebase|--merge|--checkout] [--reference <repository>]
+ [--depth <depth>] [--recursive] [--] [<path>...]
'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
[commit] [--] [<path>...]
'git submodule' [--quiet] foreach [--recursive] <command>
@@ -155,13 +155,31 @@ it contains local modifications.
update::
Update the registered submodules, i.e. clone missing submodules and
- checkout the commit specified in the index of the containing repository.
- This will make the submodules HEAD be detached unless `--rebase` or
- `--merge` is specified or the key `submodule.$name.update` is set to
- `rebase`, `merge` or `none`. `none` can be overridden by specifying
- `--checkout`. Setting the key `submodule.$name.update` to `!command`
- will cause `command` to be run. `command` can be any arbitrary shell
- command that takes a single argument, namely the sha1 to update to.
+ checkout the commit specified in the index of the containing
+ repository. The update mode defaults to `checkout`, but can be
+ configured with the `submodule.<name>.update` setting or the
+ `--rebase`, `--merge`, or `--checkout` options.
++
+For updates that clone missing submodules, checkout-mode updates will
+create submodules with detached HEADs; all other modes will create
+submodules with a local branch named after `submodule.<path>.branch`.
++
+For updates that do not clone missing submodules, the submodule's HEAD
+is only touched when the remote reference does not match the
+submodule's HEAD (for none-mode updates, the submodule is never
+touched). The remote reference is usually the gitlinked commit from
+the superproject's tree, but with `--remote` it is the upstream
+subproject's `submodule.<name>.branch`. This remote reference is
+integrated with the submodule's HEAD using the specified update mode.
+For checkout-mode updates, that will result in a detached HEAD. For
+rebase- and merge-mode updates, the commit referenced by the
+submodule's HEAD may change, but the symbolic reference will remain
+unchanged (i.e. checked-out branches will still be checked-out
+branches, and detached HEADs will still be detached HEADs). If none
+of the builtin modes fit your needs, set `submodule.<name>.update` to
+`!command` to configure a custom integration command. `command` can
+be any arbitrary shell command that takes a single argument, namely
+the sha1 to update to.
+
If the submodule is not yet initialized, and you just want to use the
setting as stored in .gitmodules, you can automatically initialize the
@@ -281,6 +299,16 @@ In order to ensure a current tracking branch state, `update --remote`
fetches the submodule's remote repository before calculating the
SHA-1. If you don't want to fetch, you should use `submodule update
--remote --no-fetch`.
++
+Use this option to integrate changes from the upstream subproject with
+your submodule's current HEAD. Alternatively, you can run `git pull`
+from the submodule, which is equivalent except for the remote branch
+name: `update --remote` uses the default upstream repository and
+`submodule.<name>.branch`, while `git pull` uses the submodule's
+`branch.<name>.merge`. Prefer `submodule.<name>.branch` if you want
+to distribute the default upstream branch with the superproject and
+`branch.<name>.merge` if you want a more native feel while working in
+the submodule itself.
-N::
--no-fetch::
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index c418c44d40..404257df9f 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -103,8 +103,9 @@ OPTIONS
+
This option is only applicable when listing tags without annotation lines.
---contains <commit>::
- Only list tags which contain the specified commit.
+--contains [<commit>]::
+ Only list tags which contain the specified commit (HEAD if not
+ specified).
--points-at <object>::
Only list tags of the given object.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 274d816b43..02bbc084b8 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,16 @@ unreleased) version of Git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.8.5.3/git.html[documentation for release 1.8.5.3]
+* link:v1.9.0/git.html[documentation for release 1.9.0]
* release notes for
+ link:RelNotes/1.9.0.txt[1.9.0].
+
+* link:v1.8.5.5/git.html[documentation for release 1.8.5.5]
+
+* release notes for
+ link:RelNotes/1.8.5.5.txt[1.8.5.5],
+ link:RelNotes/1.8.5.4.txt[1.8.5.4],
link:RelNotes/1.8.5.3.txt[1.8.5.3],
link:RelNotes/1.8.5.2.txt[1.8.5.2],
link:RelNotes/1.8.5.1.txt[1.8.5.1],
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 3f33ca5507..1c3e109cb3 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -28,7 +28,7 @@ arguments. Here are the rules:
they can be disambiguated by placing `--` between them.
E.g. `git diff -- HEAD` is, "I have a file called HEAD in my work
tree. Please show changes between the version I staged in the index
- and what I have in the work tree for that file". not "show difference
+ and what I have in the work tree for that file", not "show difference
between the HEAD commit and the work tree as a whole". You can say
`git diff HEAD --` to ask for the latter.
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index d48bf4d6fa..d954bf6ba8 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -251,7 +251,7 @@ three parameters:
- the name of the ref being updated,
- the old object name stored in the ref,
- - and the new objectname to be stored in the ref.
+ - and the new object name to be stored in the ref.
A zero exit from the update hook allows the ref to be updated.
Exiting with a non-zero status prevents 'git-receive-pack'
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 347a9f76ee..f539e3f66a 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -55,6 +55,10 @@ submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
If the option is not specified, it defaults to 'master'. See the
`--remote` documentation in linkgit:git-submodule[1] for details.
++
+This branch name is also used for the local branch created by
+non-checkout cloning updates. See the `update` documentation in
+linkgit:git-submodule[1] for details.
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index db4154f9d5..952f503afb 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -630,13 +630,13 @@ need to set this element to empty list i.e. `[]`.
override::
If this field has a true value then the given feature is
- overriddable, which means that it can be configured
+ overridable, which means that it can be configured
(or enabled/disabled) on a per-repository basis.
+
Usually given "<feature>" is configurable via the `gitweb.<feature>`
config variable in the per-repository Git configuration file.
+
-*Note* that no feature is overriddable by default.
+*Note* that no feature is overridable by default.
sub::
Internal detail of implementation. What is important is that
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index 33ae69c11f..ca4378740c 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -39,26 +39,26 @@ The policy on Integration is informally mentioned in "A Note
from the maintainer" message, which is periodically posted to
this mailing list after each feature release is made.
- - Feature releases are numbered as vX.Y.Z and are meant to
+ - Feature releases are numbered as vX.Y.0 and are meant to
contain bugfixes and enhancements in any area, including
functionality, performance and usability, without regression.
- One release cycle for a feature release is expected to last for
eight to ten weeks.
- - Maintenance releases are numbered as vX.Y.Z.W and are meant
- to contain only bugfixes for the corresponding vX.Y.Z feature
- release and earlier maintenance releases vX.Y.Z.V (V < W).
+ - Maintenance releases are numbered as vX.Y.Z and are meant
+ to contain only bugfixes for the corresponding vX.Y.0 feature
+ release and earlier maintenance releases vX.Y.W (W < Z).
- 'master' branch is used to prepare for the next feature
release. In other words, at some point, the tip of 'master'
- branch is tagged with vX.Y.Z.
+ branch is tagged with vX.Y.0.
- 'maint' branch is used to prepare for the next maintenance
- release. After the feature release vX.Y.Z is made, the tip
+ release. After the feature release vX.Y.0 is made, the tip
of 'maint' branch is set to that release, and bugfixes will
accumulate on the branch, and at some point, the tip of the
- branch is tagged with vX.Y.Z.1, vX.Y.Z.2, and so on.
+ branch is tagged with vX.Y.1, vX.Y.2, and so on.
- 'next' branch is used to publish changes (both enhancements
and fixes) that (1) have worthwhile goal, (2) are in a fairly
@@ -86,6 +86,10 @@ this mailing list after each feature release is made.
users are encouraged to test it so that regressions and bugs
are found before new topics are merged to 'master'.
+Note that before v1.9.0 release, the version numbers used to be
+structured slightly differently. vX.Y.Z were feature releases while
+vX.Y.Z.W were maintenance releases for vX.Y.Z.
+
A Typical Git Day
-----------------
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index fb6e593e7c..350949810e 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -20,7 +20,7 @@ recursive::
merged tree of the common ancestors and uses that as
the reference tree for the 3-way merge. This has been
reported to result in fewer merge conflicts without
- causing mis-merges by tests done on actual merge commits
+ causing mismerges by tests done on actual merge commits
taken from Linux 2.6 kernel development history.
Additionally this can detect and handle merges involving
renames. This is the default merge strategy when
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 03533af715..9a3da3646e 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -257,6 +257,14 @@ See also linkgit:git-reflog[1].
Output excluded boundary commits. Boundary commits are
prefixed with `-`.
+ifdef::git-rev-list[]
+--use-bitmap-index::
+
+ Try to speed up the traversal using the pack bitmap index (if
+ one is available). Note that when traversing with `--objects`,
+ trees and blobs will not have their associated path printed.
+endif::git-rev-list[]
+
--
History Simplification
diff --git a/Documentation/technical/api-hash.txt b/Documentation/technical/api-hash.txt
deleted file mode 100644
index e5061e0677..0000000000
--- a/Documentation/technical/api-hash.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-hash API
-========
-
-The hash API is a collection of simple hash table functions. Users are expected
-to implement their own hashing.
-
-Data Structures
----------------
-
-`struct hash_table`::
-
- The hash table structure. The `array` member points to the hash table
- entries. The `size` member counts the total number of valid and invalid
- entries in the table. The `nr` member keeps track of the number of
- valid entries.
-
-`struct hash_table_entry`::
-
- An opaque structure representing an entry in the hash table. The `hash`
- member is the entry's hash key and the `ptr` member is the entry's
- value.
-
-Functions
----------
-
-`init_hash`::
-
- Initialize the hash table.
-
-`free_hash`::
-
- Release memory associated with the hash table.
-
-`insert_hash`::
-
- Insert a pointer into the hash table. If an entry with that hash
- already exists, a pointer to the existing entry's value is returned.
- Otherwise NULL is returned. This allows callers to implement
- chaining, etc.
-
-`lookup_hash`::
-
- Lookup an entry in the hash table. If an entry with that hash exists
- the entry's value is returned. Otherwise NULL is returned.
-
-`for_each_hash`::
-
- Call a function for each entry in the hash table. The function is
- expected to take the entry's value as its only argument and return an
- int. If the function returns a negative int the loop is aborted
- immediately. Otherwise, the return value is accumulated and the sum
- returned upon completion of the loop.
diff --git a/Documentation/technical/api-hashmap.txt b/Documentation/technical/api-hashmap.txt
new file mode 100644
index 0000000000..42ca2347ed
--- /dev/null
+++ b/Documentation/technical/api-hashmap.txt
@@ -0,0 +1,235 @@
+hashmap API
+===========
+
+The hashmap API is a generic implementation of hash-based key-value mappings.
+
+Data Structures
+---------------
+
+`struct hashmap`::
+
+ The hash table structure.
++
+The `size` member keeps track of the total number of entries. The `cmpfn`
+member is a function used to compare two entries for equality. The `table` and
+`tablesize` members store the hash table and its size, respectively.
+
+`struct hashmap_entry`::
+
+ An opaque structure representing an entry in the hash table, which must
+ be used as first member of user data structures. Ideally it should be
+ followed by an int-sized member to prevent unused memory on 64-bit
+ systems due to alignment.
++
+The `hash` member is the entry's hash code and the `next` member points to the
+next entry in case of collisions (i.e. if multiple entries map to the same
+bucket).
+
+`struct hashmap_iter`::
+
+ An iterator structure, to be used with hashmap_iter_* functions.
+
+Types
+-----
+
+`int (*hashmap_cmp_fn)(const void *entry, const void *entry_or_key, const void *keydata)`::
+
+ User-supplied function to test two hashmap entries for equality. Shall
+ return 0 if the entries are equal.
++
+This function is always called with non-NULL `entry` / `entry_or_key`
+parameters that have the same hash code. When looking up an entry, the `key`
+and `keydata` parameters to hashmap_get and hashmap_remove are always passed
+as second and third argument, respectively. Otherwise, `keydata` is NULL.
+
+Functions
+---------
+
+`unsigned int strhash(const char *buf)`::
+`unsigned int strihash(const char *buf)`::
+`unsigned int memhash(const void *buf, size_t len)`::
+`unsigned int memihash(const void *buf, size_t len)`::
+
+ Ready-to-use hash functions for strings, using the FNV-1 algorithm (see
+ http://www.isthe.com/chongo/tech/comp/fnv).
++
+`strhash` and `strihash` take 0-terminated strings, while `memhash` and
+`memihash` operate on arbitrary-length memory.
++
+`strihash` and `memihash` are case insensitive versions.
+
+`void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, size_t initial_size)`::
+
+ Initializes a hashmap structure.
++
+`map` is the hashmap to initialize.
++
+The `equals_function` can be specified to compare two entries for equality.
+If NULL, entries are considered equal if their hash codes are equal.
++
+If the total number of entries is known in advance, the `initial_size`
+parameter may be used to preallocate a sufficiently large table and thus
+prevent expensive resizing. If 0, the table is dynamically resized.
+
+`void hashmap_free(struct hashmap *map, int free_entries)`::
+
+ Frees a hashmap structure and allocated memory.
++
+`map` is the hashmap to free.
++
+If `free_entries` is true, each hashmap_entry in the map is freed as well
+(using stdlib's free()).
+
+`void hashmap_entry_init(void *entry, unsigned int hash)`::
+
+ Initializes a hashmap_entry structure.
++
+`entry` points to the entry to initialize.
++
+`hash` is the hash code of the entry.
+
+`void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata)`::
+
+ Returns the hashmap entry for the specified key, or NULL if not found.
++
+`map` is the hashmap structure.
++
+`key` is a hashmap_entry structure (or user data structure that starts with
+hashmap_entry) that has at least been initialized with the proper hash code
+(via `hashmap_entry_init`).
++
+If an entry with matching hash code is found, `key` and `keydata` are passed
+to `hashmap_cmp_fn` to decide whether the entry matches the key.
+
+`void *hashmap_get_next(const struct hashmap *map, const void *entry)`::
+
+ Returns the next equal hashmap entry, or NULL if not found. This can be
+ used to iterate over duplicate entries (see `hashmap_add`).
++
+`map` is the hashmap structure.
++
+`entry` is the hashmap_entry to start the search from, obtained via a previous
+call to `hashmap_get` or `hashmap_get_next`.
+
+`void hashmap_add(struct hashmap *map, void *entry)`::
+
+ Adds a hashmap entry. This allows to add duplicate entries (i.e.
+ separate values with the same key according to hashmap_cmp_fn).
++
+`map` is the hashmap structure.
++
+`entry` is the entry to add.
+
+`void *hashmap_put(struct hashmap *map, void *entry)`::
+
+ Adds or replaces a hashmap entry. If the hashmap contains duplicate
+ entries equal to the specified entry, only one of them will be replaced.
++
+`map` is the hashmap structure.
++
+`entry` is the entry to add or replace.
++
+Returns the replaced entry, or NULL if not found (i.e. the entry was added).
+
+`void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)`::
+
+ Removes a hashmap entry matching the specified key. If the hashmap
+ contains duplicate entries equal to the specified key, only one of
+ them will be removed.
++
+`map` is the hashmap structure.
++
+`key` is a hashmap_entry structure (or user data structure that starts with
+hashmap_entry) that has at least been initialized with the proper hash code
+(via `hashmap_entry_init`).
++
+If an entry with matching hash code is found, `key` and `keydata` are
+passed to `hashmap_cmp_fn` to decide whether the entry matches the key.
++
+Returns the removed entry, or NULL if not found.
+
+`void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter)`::
+`void *hashmap_iter_next(struct hashmap_iter *iter)`::
+`void *hashmap_iter_first(struct hashmap *map, struct hashmap_iter *iter)`::
+
+ Used to iterate over all entries of a hashmap.
++
+`hashmap_iter_init` initializes a `hashmap_iter` structure.
++
+`hashmap_iter_next` returns the next hashmap_entry, or NULL if there are no
+more entries.
++
+`hashmap_iter_first` is a combination of both (i.e. initializes the iterator
+and returns the first entry, if any).
+
+Usage example
+-------------
+
+Here's a simple usage example that maps long keys to double values.
+[source,c]
+------------
+struct hashmap map;
+
+struct long2double {
+ struct hashmap_entry ent; /* must be the first member! */
+ long key;
+ double value;
+};
+
+static int long2double_cmp(const struct long2double *e1, const struct long2double *e2, const void *unused)
+{
+ return !(e1->key == e2->key);
+}
+
+void long2double_init(void)
+{
+ hashmap_init(&map, (hashmap_cmp_fn) long2double_cmp, 0);
+}
+
+void long2double_free(void)
+{
+ hashmap_free(&map, 1);
+}
+
+static struct long2double *find_entry(long key)
+{
+ struct long2double k;
+ hashmap_entry_init(&k, memhash(&key, sizeof(long)));
+ k.key = key;
+ return hashmap_get(&map, &k, NULL);
+}
+
+double get_value(long key)
+{
+ struct long2double *e = find_entry(key);
+ return e ? e->value : 0;
+}
+
+void set_value(long key, double value)
+{
+ struct long2double *e = find_entry(key);
+ if (!e) {
+ e = malloc(sizeof(struct long2double));
+ hashmap_entry_init(e, memhash(&key, sizeof(long)));
+ e->key = key;
+ hashmap_add(&map, e);
+ }
+ e->value = value;
+}
+------------
+
+Using variable-sized keys
+-------------------------
+
+The `hashmap_entry_get` and `hashmap_entry_remove` functions expect an ordinary
+`hashmap_entry` structure as key to find the correct entry. If the key data is
+variable-sized (e.g. a FLEX_ARRAY string) or quite large, it is undesirable
+to create a full-fledged entry structure on the heap and copy all the key data
+into the structure.
+
+In this case, the `keydata` parameter can be used to pass
+variable-sized key data directly to the comparison function, and the `key`
+parameter can be a stripped-down, fixed size entry structure allocated on the
+stack.
+
+See test-hashmap.c for an example using arbitrary-length strings as keys.
diff --git a/Documentation/technical/bitmap-format.txt b/Documentation/technical/bitmap-format.txt
new file mode 100644
index 0000000000..f8c18a0f7a
--- /dev/null
+++ b/Documentation/technical/bitmap-format.txt
@@ -0,0 +1,164 @@
+GIT bitmap v1 format
+====================
+
+ - A header appears at the beginning:
+
+ 4-byte signature: {'B', 'I', 'T', 'M'}
+
+ 2-byte version number (network byte order)
+ The current implementation only supports version 1
+ of the bitmap index (the same one as JGit).
+
+ 2-byte flags (network byte order)
+
+ The following flags are supported:
+
+ - BITMAP_OPT_FULL_DAG (0x1) REQUIRED
+ This flag must always be present. It implies that the bitmap
+ index has been generated for a packfile with full closure
+ (i.e. where every single object in the packfile can find
+ its parent links inside the same packfile). This is a
+ requirement for the bitmap index format, also present in JGit,
+ that greatly reduces the complexity of the implementation.
+
+ - BITMAP_OPT_HASH_CACHE (0x4)
+ If present, the end of the bitmap file contains
+ `N` 32-bit name-hash values, one per object in the
+ pack. The format and meaning of the name-hash is
+ described below.
+
+ 4-byte entry count (network byte order)
+
+ The total count of entries (bitmapped commits) in this bitmap index.
+
+ 20-byte checksum
+
+ The SHA1 checksum of the pack this bitmap index belongs to.
+
+ - 4 EWAH bitmaps that act as type indexes
+
+ Type indexes are serialized after the hash cache in the shape
+ of four EWAH bitmaps stored consecutively (see Appendix A for
+ the serialization format of an EWAH bitmap).
+
+ There is a bitmap for each Git object type, stored in the following
+ order:
+
+ - Commits
+ - Trees
+ - Blobs
+ - Tags
+
+ In each bitmap, the `n`th bit is set to true if the `n`th object
+ in the packfile is of that type.
+
+ The obvious consequence is that the OR of all 4 bitmaps will result
+ in a full set (all bits set), and the AND of all 4 bitmaps will
+ result in an empty bitmap (no bits set).
+
+ - N entries with compressed bitmaps, one for each indexed commit
+
+ Where `N` is the total amount of entries in this bitmap index.
+ Each entry contains the following:
+
+ - 4-byte object position (network byte order)
+ The position **in the index for the packfile** where the
+ bitmap for this commit is found.
+
+ - 1-byte XOR-offset
+ The xor offset used to compress this bitmap. For an entry
+ in position `x`, a XOR offset of `y` means that the actual
+ bitmap representing this commit is composed by XORing the
+ bitmap for this entry with the bitmap in entry `x-y` (i.e.
+ the bitmap `y` entries before this one).
+
+ Note that this compression can be recursive. In order to
+ XOR this entry with a previous one, the previous entry needs
+ to be decompressed first, and so on.
+
+ The hard-limit for this offset is 160 (an entry can only be
+ xor'ed against one of the 160 entries preceding it). This
+ number is always positive, and hence entries are always xor'ed
+ with **previous** bitmaps, not bitmaps that will come afterwards
+ in the index.
+
+ - 1-byte flags for this bitmap
+ At the moment the only available flag is `0x1`, which hints
+ that this bitmap can be re-used when rebuilding bitmap indexes
+ for the repository.
+
+ - The compressed bitmap itself, see Appendix A.
+
+== Appendix A: Serialization format for an EWAH bitmap
+
+Ewah bitmaps are serialized in the same protocol as the JAVAEWAH
+library, making them backwards compatible with the JGit
+implementation:
+
+ - 4-byte number of bits of the resulting UNCOMPRESSED bitmap
+
+ - 4-byte number of words of the COMPRESSED bitmap, when stored
+
+ - N x 8-byte words, as specified by the previous field
+
+ This is the actual content of the compressed bitmap.
+
+ - 4-byte position of the current RLW for the compressed
+ bitmap
+
+All words are stored in network byte order for their corresponding
+sizes.
+
+The compressed bitmap is stored in a form of run-length encoding, as
+follows. It consists of a concatenation of an arbitrary number of
+chunks. Each chunk consists of one or more 64-bit words
+
+ H L_1 L_2 L_3 .... L_M
+
+H is called RLW (run length word). It consists of (from lower to higher
+order bits):
+
+ - 1 bit: the repeated bit B
+
+ - 32 bits: repetition count K (unsigned)
+
+ - 31 bits: literal word count M (unsigned)
+
+The bitstream represented by the above chunk is then:
+
+ - K repetitions of B
+
+ - The bits stored in `L_1` through `L_M`. Within a word, bits at
+ lower order come earlier in the stream than those at higher
+ order.
+
+The next word after `L_M` (if any) must again be a RLW, for the next
+chunk. For efficient appending to the bitstream, the EWAH stores a
+pointer to the last RLW in the stream.
+
+
+== Appendix B: Optional Bitmap Sections
+
+These sections may or may not be present in the `.bitmap` file; their
+presence is indicated by the header flags section described above.
+
+Name-hash cache
+---------------
+
+If the BITMAP_OPT_HASH_CACHE flag is set, the end of the bitmap contains
+a cache of 32-bit values, one per object in the pack. The value at
+position `i` is the hash of the pathname at which the `i`th object
+(counting in index order) in the pack can be found. This can be fed
+into the delta heuristics to compare objects with similar pathnames.
+
+The hash algorithm used is:
+
+ hash = 0;
+ while ((c = *name++))
+ if (!isspace(c))
+ hash = (hash >> 2) + (c << 24);
+
+Note that this hashing scheme is tied to the BITMAP_OPT_HASH_CACHE flag.
+If implementations want to choose a different hashing scheme, they are
+free to do so, but MUST allocate a new header flag (because comparing
+hashes made under two different schemes would be pointless).
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index c73b62f5e1..39c64105a6 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -338,7 +338,8 @@ during a prior round. This helps to ensure that at least one common
ancestor is found before we give up entirely.
Once the 'done' line is read from the client, the server will either
-send a final 'ACK obj-id' or it will send a 'NAK'. The server only sends
+send a final 'ACK obj-id' or it will send a 'NAK'. 'obj-id' is the object
+name of the last commit determined to be common. The server only sends
ACK after 'done' if there is at least one common base and multi_ack or
multi_ack_detailed is enabled. The server always sends NAK after 'done'
if there is no common base found.
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index e3e792476e..e174343847 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -69,6 +69,24 @@ ends.
Without multi_ack the client would have sent that c-b-a chain anyway,
interleaved with S-R-Q.
+multi_ack_detailed
+------------------
+This is an extension of multi_ack that permits client to better
+understand the server's in-memory state. See pack-protocol.txt,
+section "Packfile Negotiation" for more information.
+
+no-done
+-------
+This capability should only be used with the smart HTTP protocol. If
+multi_ack_detailed and no-done are both present, then the sender is
+free to immediately send a pack following its first "ACK obj-id ready"
+message.
+
+Without no-done in the smart HTTP protocol, the server session would
+end and the client has to make another trip to send "done" before
+the server can send the pack. no-done removes the last round and
+thus slightly reduces latency.
+
thin-pack
---------
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 248dcabd50..d4f9804462 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -3795,7 +3795,7 @@ like so:
$ git update-index filename
-------------------------------------------------
-but to avoid common mistakes with filename globbing etc, the command
+but to avoid common mistakes with filename globbing etc., the command
will not normally add totally new entries or remove old entries,
i.e. it will normally just update existing cache entries.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 38b939b636..2b97352dd3 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.9-rc2
+DEF_VER=v1.9.0
LF='
'
diff --git a/Makefile b/Makefile
index dddaf4f287..d4ce53a71b 100644
--- a/Makefile
+++ b/Makefile
@@ -555,6 +555,7 @@ TEST_PROGRAMS_NEED_X += test-date
TEST_PROGRAMS_NEED_X += test-delta
TEST_PROGRAMS_NEED_X += test-dump-cache-tree
TEST_PROGRAMS_NEED_X += test-genrandom
+TEST_PROGRAMS_NEED_X += test-hashmap
TEST_PROGRAMS_NEED_X += test-index-version
TEST_PROGRAMS_NEED_X += test-line-buffer
TEST_PROGRAMS_NEED_X += test-match-trees
@@ -663,6 +664,8 @@ LIB_H += diff.h
LIB_H += diffcore.h
LIB_H += dir.h
LIB_H += exec_cmd.h
+LIB_H += ewah/ewok.h
+LIB_H += ewah/ewok_rlw.h
LIB_H += fetch-pack.h
LIB_H += fmt-merge-msg.h
LIB_H += fsck.h
@@ -671,7 +674,7 @@ LIB_H += git-compat-util.h
LIB_H += gpg-interface.h
LIB_H += graph.h
LIB_H += grep.h
-LIB_H += hash.h
+LIB_H += hashmap.h
LIB_H += help.h
LIB_H += http.h
LIB_H += kwset.h
@@ -690,8 +693,10 @@ LIB_H += notes-merge.h
LIB_H += notes-utils.h
LIB_H += notes.h
LIB_H += object.h
+LIB_H += pack-objects.h
LIB_H += pack-revindex.h
LIB_H += pack.h
+LIB_H += pack-bitmap.h
LIB_H += parse-options.h
LIB_H += patch-ids.h
LIB_H += pathspec.h
@@ -795,6 +800,10 @@ LIB_OBJS += dir.o
LIB_OBJS += editor.o
LIB_OBJS += entry.o
LIB_OBJS += environment.o
+LIB_OBJS += ewah/bitmap.o
+LIB_OBJS += ewah/ewah_bitmap.o
+LIB_OBJS += ewah/ewah_io.o
+LIB_OBJS += ewah/ewah_rlw.o
LIB_OBJS += exec_cmd.o
LIB_OBJS += fetch-pack.o
LIB_OBJS += fsck.o
@@ -802,7 +811,7 @@ LIB_OBJS += gettext.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
-LIB_OBJS += hash.o
+LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
LIB_OBJS += ident.o
@@ -826,7 +835,10 @@ LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
LIB_OBJS += notes-utils.o
LIB_OBJS += object.o
+LIB_OBJS += pack-bitmap.o
+LIB_OBJS += pack-bitmap-write.o
LIB_OBJS += pack-check.o
+LIB_OBJS += pack-objects.o
LIB_OBJS += pack-revindex.o
LIB_OBJS += pack-write.o
LIB_OBJS += pager.o
@@ -2479,8 +2491,9 @@ profile-clean:
$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
clean: profile-clean coverage-clean
- $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
- builtin/*.o $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
+ $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o
+ $(RM) xdiff/*.o vcs-svn/*.o ewah/*.o builtin/*.o
+ $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
$(RM) -r bin-wrappers $(dep_dirs)
diff --git a/RelNotes b/RelNotes
index c300119d96..bb52cf9476 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.9.txt \ No newline at end of file
+Documentation/RelNotes/1.9.0.txt \ No newline at end of file
diff --git a/bisect.c b/bisect.c
index 37200b41f1..8448d27877 100644
--- a/bisect.c
+++ b/bisect.c
@@ -685,7 +685,6 @@ static void mark_expected_rev(char *bisect_rev_hex)
static int bisect_checkout(char *bisect_rev_hex, int no_checkout)
{
- int res;
mark_expected_rev(bisect_rev_hex);
@@ -696,6 +695,7 @@ static int bisect_checkout(char *bisect_rev_hex, int no_checkout)
die("update-ref --no-deref HEAD failed on %s",
bisect_rev_hex);
} else {
+ int res;
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
if (res)
exit(res);
diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c
index e1a1eb6097..22b125cf8c 100644
--- a/block-sha1/sha1.c
+++ b/block-sha1/sha1.c
@@ -62,38 +62,6 @@
#define setW(x, val) (W(x) = (val))
#endif
-/*
- * Performance might be improved if the CPU architecture is OK with
- * unaligned 32-bit loads and a fast ntohl() is available.
- * Otherwise fall back to byte loads and shifts which is portable,
- * and is faster on architectures with memory alignment issues.
- */
-
-#if defined(__i386__) || defined(__x86_64__) || \
- defined(_M_IX86) || defined(_M_X64) || \
- defined(__ppc__) || defined(__ppc64__) || \
- defined(__powerpc__) || defined(__powerpc64__) || \
- defined(__s390__) || defined(__s390x__)
-
-#define get_be32(p) ntohl(*(unsigned int *)(p))
-#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
-
-#else
-
-#define get_be32(p) ( \
- (*((unsigned char *)(p) + 0) << 24) | \
- (*((unsigned char *)(p) + 1) << 16) | \
- (*((unsigned char *)(p) + 2) << 8) | \
- (*((unsigned char *)(p) + 3) << 0) )
-#define put_be32(p, v) do { \
- unsigned int __v = (v); \
- *((unsigned char *)(p) + 0) = __v >> 24; \
- *((unsigned char *)(p) + 1) = __v >> 16; \
- *((unsigned char *)(p) + 2) = __v >> 8; \
- *((unsigned char *)(p) + 3) = __v >> 0; } while (0)
-
-#endif
-
/* This "rolls" over the 512-bit array */
#define W(x) (array[(x)&15])
diff --git a/builtin/add.c b/builtin/add.c
index 2a2722fa10..672adc01ff 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -208,8 +208,7 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
- if (match_pathspec_depth(pathspec, entry->name, entry->len,
- prefix, seen))
+ if (dir_path_match(entry, pathspec, prefix, seen))
*dst++ = entry;
else if (flag & WARN_IMPLICIT_DOT)
/*
diff --git a/builtin/apply.c b/builtin/apply.c
index b0d0986226..a7e72d57ab 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1943,13 +1943,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
size - offset - hdrsize, patch);
if (!patchsize) {
- static const char *binhdr[] = {
- "Binary files ",
- "Files ",
- NULL,
- };
static const char git_binary[] = "GIT binary patch\n";
- int i;
int hd = hdrsize + offset;
unsigned long llen = linelen(buffer + hd, size - hd);
@@ -1965,6 +1959,12 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
patchsize = 0;
}
else if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) {
+ static const char *binhdr[] = {
+ "Binary files ",
+ "Files ",
+ NULL,
+ };
+ int i;
for (i = 0; binhdr[i]; i++) {
int len = strlen(binhdr[i]);
if (len < size - hd &&
diff --git a/builtin/blame.c b/builtin/blame.c
index e44a6bb30a..e5b5d71bad 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -197,7 +197,6 @@ static void drop_origin_blob(struct origin *o)
* scoreboard structure, sorted by the target line number.
*/
struct blame_entry {
- struct blame_entry *prev;
struct blame_entry *next;
/* the first line of this group in the final image;
@@ -256,15 +255,6 @@ struct scoreboard {
int *lineno;
};
-static inline int same_suspect(struct origin *a, struct origin *b)
-{
- if (a == b)
- return 1;
- if (a->commit != b->commit)
- return 0;
- return !strcmp(a->path, b->path);
-}
-
static void sanity_check_refcnt(struct scoreboard *);
/*
@@ -277,13 +267,11 @@ static void coalesce(struct scoreboard *sb)
struct blame_entry *ent, *next;
for (ent = sb->ent; ent && (next = ent->next); ent = next) {
- if (same_suspect(ent->suspect, next->suspect) &&
+ if (ent->suspect == next->suspect &&
ent->guilty == next->guilty &&
ent->s_lno + ent->num_lines == next->s_lno) {
ent->num_lines += next->num_lines;
ent->next = next->next;
- if (ent->next)
- ent->next->prev = ent;
origin_decref(next->suspect);
free(next);
ent->score = 0;
@@ -534,7 +522,7 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
prev = ent;
/* prev, if not NULL, is the last one that is below e */
- e->prev = prev;
+
if (prev) {
e->next = prev->next;
prev->next = e;
@@ -543,8 +531,6 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
e->next = sb->ent;
sb->ent = e;
}
- if (e->next)
- e->next->prev = e;
}
/*
@@ -555,14 +541,12 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
*/
static void dup_entry(struct blame_entry *dst, struct blame_entry *src)
{
- struct blame_entry *p, *n;
+ struct blame_entry *n;
- p = dst->prev;
n = dst->next;
origin_incref(src->suspect);
origin_decref(dst->suspect);
memcpy(dst, src, sizeof(*src));
- dst->prev = p;
dst->next = n;
dst->score = 0;
}
@@ -742,7 +726,7 @@ static int find_last_in_target(struct scoreboard *sb, struct origin *target)
int last_in_target = -1;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || !same_suspect(e->suspect, target))
+ if (e->guilty || e->suspect != target)
continue;
if (last_in_target < e->s_lno + e->num_lines)
last_in_target = e->s_lno + e->num_lines;
@@ -762,7 +746,7 @@ static void blame_chunk(struct scoreboard *sb,
struct blame_entry *e;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || !same_suspect(e->suspect, target))
+ if (e->guilty || e->suspect != target)
continue;
if (same <= e->s_lno)
continue;
@@ -939,7 +923,6 @@ static void find_copy_in_blob(struct scoreboard *sb,
mmfile_t *file_p)
{
const char *cp;
- int cnt;
mmfile_t file_o;
struct handle_split_cb_data d;
@@ -950,13 +933,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
*/
cp = nth_line(sb, ent->lno);
file_o.ptr = (char *) cp;
- cnt = ent->num_lines;
-
- while (cnt && cp < sb->final_buf + sb->final_buf_size) {
- if (*cp++ == '\n')
- cnt--;
- }
- file_o.size = cp - file_o.ptr;
+ file_o.size = nth_line(sb, ent->lno + ent->num_lines) - cp;
/*
* file_o is a part of final image we are annotating.
@@ -992,7 +969,7 @@ static int find_move_in_parent(struct scoreboard *sb,
while (made_progress) {
made_progress = 0;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || !same_suspect(e->suspect, target) ||
+ if (e->guilty || e->suspect != target ||
ent_score(sb, e) < blame_move_score)
continue;
find_copy_in_blob(sb, e, parent, split, &file_p);
@@ -1027,14 +1004,14 @@ static struct blame_list *setup_blame_list(struct scoreboard *sb,
for (e = sb->ent, num_ents = 0; e; e = e->next)
if (!e->scanned && !e->guilty &&
- same_suspect(e->suspect, target) &&
+ e->suspect == target &&
min_score < ent_score(sb, e))
num_ents++;
if (num_ents) {
blame_list = xcalloc(num_ents, sizeof(struct blame_list));
for (e = sb->ent, i = 0; e; e = e->next)
if (!e->scanned && !e->guilty &&
- same_suspect(e->suspect, target) &&
+ e->suspect == target &&
min_score < ent_score(sb, e))
blame_list[i++].ent = e;
}
@@ -1178,7 +1155,7 @@ static void pass_whole_blame(struct scoreboard *sb,
origin->file.ptr = NULL;
}
for (e = sb->ent; e; e = e->next) {
- if (!same_suspect(e->suspect, origin))
+ if (e->suspect != origin)
continue;
origin_incref(porigin);
origin_decref(e->suspect);
@@ -1567,7 +1544,7 @@ static void assign_blame(struct scoreboard *sb, int opt)
/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
- if (same_suspect(ent->suspect, suspect))
+ if (ent->suspect == suspect)
found_guilty_entry(ent);
origin_decref(suspect);
@@ -1580,14 +1557,14 @@ static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
- const char *time_str;
- int time_len;
- int tz;
if (show_raw_time) {
snprintf(time_buf, sizeof(time_buf), "%lu %s", time, tz_str);
}
else {
+ const char *time_str;
+ int time_len;
+ int tz;
tz = atoi(tz_str);
time_str = show_date(time, tz, blame_date_mode);
time_len = strlen(time_str);
@@ -1772,25 +1749,41 @@ static int prepare_lines(struct scoreboard *sb)
{
const char *buf = sb->final_buf;
unsigned long len = sb->final_buf_size;
- int num = 0, incomplete = 0, bol = 1;
+ const char *end = buf + len;
+ const char *p;
+ int *lineno;
+ int num = 0, incomplete = 0;
- if (len && buf[len-1] != '\n')
- incomplete++; /* incomplete line at the end */
- while (len--) {
- if (bol) {
- sb->lineno = xrealloc(sb->lineno,
- sizeof(int *) * (num + 1));
- sb->lineno[num] = buf - sb->final_buf;
- bol = 0;
- }
- if (*buf++ == '\n') {
+ for (p = buf;;) {
+ p = memchr(p, '\n', end - p);
+ if (p) {
+ p++;
num++;
- bol = 1;
+ continue;
}
+ break;
}
- sb->lineno = xrealloc(sb->lineno,
- sizeof(int *) * (num + incomplete + 1));
- sb->lineno[num + incomplete] = buf - sb->final_buf;
+
+ if (len && end[-1] != '\n')
+ incomplete++; /* incomplete line at the end */
+
+ sb->lineno = xmalloc(sizeof(*sb->lineno) * (num + incomplete + 1));
+ lineno = sb->lineno;
+
+ *lineno++ = 0;
+ for (p = buf;;) {
+ p = memchr(p, '\n', end - p);
+ if (p) {
+ p++;
+ *lineno++ = p - buf;
+ continue;
+ }
+ break;
+ }
+
+ if (incomplete)
+ *lineno++ = len;
+
sb->num_lines = num + incomplete;
return sb->num_lines;
}
@@ -2502,8 +2495,6 @@ parse_done:
ent->suspect = o;
ent->s_lno = bottom;
ent->next = next;
- if (next)
- next->prev = ent;
origin_incref(o);
}
origin_decref(o);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5df3837e31..ada51fa70f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -297,8 +297,7 @@ static int checkout_paths(const struct checkout_opts *opts,
* match_pathspec() for _all_ entries when
* opts->source_tree != NULL.
*/
- if (match_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce),
- 0, ps_matched))
+ if (ce_path_match(ce, &opts->pathspec, ps_matched))
ce->ce_flags |= CE_MATCHED;
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 2f26297142..114d7bf879 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -154,7 +154,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
DIR *dir;
struct strbuf quoted = STRBUF_INIT;
struct dirent *e;
- int res = 0, ret = 0, gone = 1, original_len = path->len, len, i;
+ int res = 0, ret = 0, gone = 1, original_len = path->len, len;
unsigned char submodule_head[20];
struct string_list dels = STRING_LIST_INIT_DUP;
@@ -242,6 +242,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
}
if (!*dir_gone && !quiet) {
+ int i;
for (i = 0; i < dels.nr; i++)
printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string);
}
@@ -933,36 +934,18 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
- int len, pos;
int matches = 0;
- const struct cache_entry *ce;
struct stat st;
const char *rel;
- /*
- * Remove the '/' at the end that directory
- * walking adds for directory entries.
- */
- len = ent->len;
- if (len && ent->name[len-1] == '/')
- len--;
- pos = cache_name_pos(ent->name, len);
- if (0 <= pos)
- continue; /* exact match */
- pos = -pos - 1;
- if (pos < active_nr) {
- ce = active_cache[pos];
- if (ce_namelen(ce) == len &&
- !memcmp(ce->name, ent->name, len))
- continue; /* Yup, this one exists unmerged */
- }
+ if (!cache_name_is_other(ent->name, ent->len))
+ continue;
if (lstat(ent->name, &st))
die_errno("Cannot lstat '%s'", ent->name);
if (pathspec.nr)
- matches = match_pathspec_depth(&pathspec, ent->name,
- len, 0, NULL);
+ matches = dir_path_match(ent, &pathspec, 0, NULL);
if (S_ISDIR(st.st_mode)) {
if (remove_directories || (matches == MATCHED_EXACTLY)) {
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index f641ff2a89..987a4c3d73 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -12,6 +12,8 @@
static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-S[<keyid>]] [-m <message>] [-F <file>] <sha1> <changelog";
+static const char *sign_commit;
+
static void new_parent(struct commit *parent, struct commit_list **parents_p)
{
unsigned char *sha1 = parent->object.sha1;
@@ -31,6 +33,10 @@ static int commit_tree_config(const char *var, const char *value, void *cb)
int status = git_gpg_config(var, value, NULL);
if (status)
return status;
+ if (!strcmp(var, "commit.gpgsign")) {
+ sign_commit = git_config_bool(var, value) ? "" : NULL;
+ return 0;
+ }
return git_default_config(var, value, cb);
}
@@ -41,7 +47,6 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
unsigned char tree_sha1[20];
unsigned char commit_sha1[20];
struct strbuf buffer = STRBUF_INIT;
- const char *sign_commit = NULL;
git_config(commit_tree_config, NULL);
@@ -66,6 +71,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
continue;
}
+ if (!strcmp(arg, "--no-gpg-sign")) {
+ sign_commit = NULL;
+ continue;
+ }
+
if (!strcmp(arg, "-m")) {
if (argc <= ++i)
usage(commit_tree_usage);
diff --git a/builtin/commit.c b/builtin/commit.c
index 3767478c6d..3783bcadcd 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -234,7 +234,7 @@ static int list_paths(struct string_list *list, const char *with_tree,
if (ce->ce_flags & CE_UPDATE)
continue;
- if (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))
+ if (!ce_path_match(ce, pattern, m))
continue;
item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
@@ -307,7 +307,6 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
int fd;
struct string_list partial;
struct pathspec pathspec;
- char *old_index_env = NULL;
int refresh_flags = REFRESH_QUIET;
if (is_status)
@@ -320,6 +319,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
die(_("index file corrupt"));
if (interactive) {
+ char *old_index_env = NULL;
fd = hold_locked_index(&index_lock, 1);
refresh_cache_or_die(refresh_flags);
@@ -600,12 +600,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
{
struct stat statbuf;
struct strbuf committer_ident = STRBUF_INIT;
- int commitable, saved_color_setting;
+ int commitable;
struct strbuf sb = STRBUF_INIT;
- char *buffer;
const char *hook_arg1 = NULL;
const char *hook_arg2 = NULL;
- int ident_shown = 0;
int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
int old_display_comment_prefix;
@@ -649,6 +647,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
logfile);
hook_arg1 = "message";
} else if (use_message) {
+ char *buffer;
buffer = strstr(use_message_buffer, "\n\n");
if (!use_editor && (!buffer || buffer[2] == '\0'))
die(_("commit has empty message"));
@@ -753,6 +752,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
/* This checks if committer ident is explicitly given */
strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));
if (use_editor && include_status) {
+ int ident_shown = 0;
+ int saved_color_setting;
char *ai_tmp, *ci_tmp;
if (whence != FROM_COMMIT)
status_printf_ln(s, GIT_COLOR_NORMAL,
@@ -1406,6 +1407,10 @@ static int git_commit_config(const char *k, const char *v, void *cb)
}
if (!strcmp(k, "commit.cleanup"))
return git_config_string(&cleanup_arg, k, v);
+ if (!strcmp(k, "commit.gpgsign")) {
+ sign_commit = git_config_bool(k, v) ? "" : NULL;
+ return 0;
+ }
status = git_gpg_config(k, v, NULL);
if (status)
@@ -1510,7 +1515,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct ref_lock *ref_lock;
struct commit_list *parents = NULL, **pptr = &parents;
struct stat statbuf;
- int allow_fast_forward = 1;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
@@ -1558,6 +1562,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
} else if (whence == FROM_MERGE) {
struct strbuf m = STRBUF_INIT;
FILE *fp;
+ int allow_fast_forward = 1;
if (!reflog_msg)
reflog_msg = "commit (merge)";
diff --git a/builtin/describe.c b/builtin/describe.c
index 7db43dae1b..dadd999c41 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -6,7 +6,7 @@
#include "exec_cmd.h"
#include "parse-options.h"
#include "diff.h"
-#include "hash.h"
+#include "hashmap.h"
#include "argv-array.h"
#define SEEN (1u << 0)
@@ -25,7 +25,7 @@ static int longformat;
static int first_parent;
static int abbrev = -1; /* unspecified */
static int max_candidates = 10;
-static struct hash_table names;
+static struct hashmap names;
static int have_util;
static const char *pattern;
static int always;
@@ -37,7 +37,7 @@ static const char *diff_index_args[] = {
};
struct commit_name {
- struct commit_name *next;
+ struct hashmap_entry entry;
unsigned char peeled[20];
struct tag *tag;
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
@@ -50,6 +50,12 @@ static const char *prio_names[] = {
"head", "lightweight", "annotated",
};
+static int commit_name_cmp(const struct commit_name *cn1,
+ const struct commit_name *cn2, const void *peeled)
+{
+ return hashcmp(cn1->peeled, peeled ? peeled : cn2->peeled);
+}
+
static inline unsigned int hash_sha1(const unsigned char *sha1)
{
unsigned int hash;
@@ -59,21 +65,9 @@ static inline unsigned int hash_sha1(const unsigned char *sha1)
static inline struct commit_name *find_commit_name(const unsigned char *peeled)
{
- struct commit_name *n = lookup_hash(hash_sha1(peeled), &names);
- while (n && !!hashcmp(peeled, n->peeled))
- n = n->next;
- return n;
-}
-
-static int set_util(void *chain, void *data)
-{
- struct commit_name *n;
- for (n = chain; n; n = n->next) {
- struct commit *c = lookup_commit_reference_gently(n->peeled, 1);
- if (c)
- c->util = n;
- }
- return 0;
+ struct commit_name key;
+ hashmap_entry_init(&key, hash_sha1(peeled));
+ return hashmap_get(&names, &key, peeled);
}
static int replace_name(struct commit_name *e,
@@ -118,16 +112,10 @@ static void add_to_known_names(const char *path,
struct tag *tag = NULL;
if (replace_name(e, prio, sha1, &tag)) {
if (!e) {
- void **pos;
e = xmalloc(sizeof(struct commit_name));
hashcpy(e->peeled, peeled);
- pos = insert_hash(hash_sha1(peeled), e, &names);
- if (pos) {
- e->next = *pos;
- *pos = e;
- } else {
- e->next = NULL;
- }
+ hashmap_entry_init(e, hash_sha1(peeled));
+ hashmap_add(&names, e);
e->path = NULL;
}
e->tag = tag;
@@ -292,7 +280,14 @@ static void describe(const char *arg, int last_one)
fprintf(stderr, _("searching to describe %s\n"), arg);
if (!have_util) {
- for_each_hash(&names, set_util, NULL);
+ struct hashmap_iter iter;
+ struct commit *c;
+ struct commit_name *n = hashmap_iter_first(&names, &iter);
+ for (; n; n = hashmap_iter_next(&iter)) {
+ c = lookup_commit_reference_gently(n->peeled, 1);
+ if (c)
+ c->util = n;
+ }
have_util = 1;
}
@@ -463,9 +458,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
return cmd_name_rev(args.argc, args.argv, prefix);
}
- init_hash(&names);
+ hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, 0);
for_each_rawref(get_name, NULL);
- if (!names.nr && !always)
+ if (!names.size && !always)
die(_("No names found, cannot describe anything."));
if (argc == 0) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 025bc3e38d..55f457c04f 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1026,7 +1026,6 @@ static int fetch_multiple(struct string_list *list)
static int fetch_one(struct remote *remote, int argc, const char **argv)
{
- int i;
static const char **refs = NULL;
struct refspec *refspec;
int ref_nr = 0;
@@ -1050,6 +1049,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
if (argc > 0) {
int j = 0;
+ int i;
refs = xcalloc(argc + 1, sizeof(const char *));
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "tag")) {
diff --git a/builtin/gc.c b/builtin/gc.c
index c19545d49e..5bbb5e3cc6 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -188,13 +188,12 @@ static int need_to_gc(void)
static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
{
static struct lock_file lock;
- static char locking_host[128];
char my_host[128];
struct strbuf sb = STRBUF_INIT;
struct stat st;
uintmax_t pid;
FILE *fp;
- int fd, should_exit;
+ int fd;
if (pidfile)
/* already locked */
@@ -206,6 +205,8 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
fd = hold_lock_file_for_update(&lock, git_path("gc.pid"),
LOCK_DIE_ON_ERROR);
if (!force) {
+ static char locking_host[128];
+ int should_exit;
fp = fopen(git_path("gc.pid"), "r");
memset(locking_host, 0, sizeof(locking_host));
should_exit =
diff --git a/builtin/grep.c b/builtin/grep.c
index 63f86032d9..69ac2d8797 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -379,7 +379,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
const struct cache_entry *ce = active_cache[nr];
if (!S_ISREG(ce->ce_mode))
continue;
- if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
+ if (!ce_path_match(ce, pathspec, NULL))
continue;
/*
* If CE_VALID is on, we assume worktree file and its cache entry
@@ -524,9 +524,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
fill_directory(&dir, pathspec);
for (i = 0; i < dir.nr; i++) {
- const char *name = dir.entries[i]->name;
- int namelen = strlen(name);
- if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
+ if (!dir_path_match(dir.entries[i], pathspec, 0, NULL))
continue;
hit |= grep_file(opt, dir.entries[i]->name);
if (hit && opt->status_only)
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index e1cf6d8547..47c38808a2 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -64,7 +64,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
if (len >= ent->len)
die("git ls-files: internal error - directory entry not superset of prefix");
- if (!match_pathspec_depth(&pathspec, ent->name, ent->len, len, ps_matched))
+ if (!dir_path_match(ent, &pathspec, len, ps_matched))
return;
fputs(tag, stdout);
@@ -139,7 +139,9 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)
if (len >= ce_namelen(ce))
die("git ls-files: internal error - cache entry not superset of prefix");
- if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), len, ps_matched))
+ if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
+ len, ps_matched,
+ S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
return;
if (tag && *tag && show_valid_bit &&
@@ -195,7 +197,8 @@ static void show_ru_info(void)
len = strlen(path);
if (len < max_prefix_len)
continue; /* outside of the prefix */
- if (!match_pathspec_depth(&pathspec, path, len, max_prefix_len, ps_matched))
+ if (!match_pathspec(&pathspec, path, len,
+ max_prefix_len, ps_matched, 0))
continue; /* uninterested */
for (i = 0; i < 3; i++) {
if (!ui->mode[i])
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 65ec931846..51184dfa2e 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -171,7 +171,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
* show_recursive() rolls its own matching code and is
* generally ignorant of 'struct pathspec'. The magic mask
* cannot be lifted until it is converted to use
- * match_pathspec_depth() or tree_entry_interesting()
+ * match_pathspec() or tree_entry_interesting()
*/
parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
PATHSPEC_PREFER_CWD,
diff --git a/builtin/merge.c b/builtin/merge.c
index e576a7fdc6..f0cf1205fa 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -597,6 +597,9 @@ static int git_merge_config(const char *k, const char *v, void *cb)
} else if (!strcmp(k, "merge.defaulttoupstream")) {
default_to_upstream = git_config_bool(k, v);
return 0;
+ } else if (!strcmp(k, "commit.gpgsign")) {
+ sign_commit = git_config_bool(k, v) ? "" : NULL;
+ return 0;
}
status = fmt_merge_msg_config(k, v, cb);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 541667f102..c73337931b 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -14,10 +14,12 @@
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
+#include "pack-objects.h"
#include "progress.h"
#include "refs.h"
#include "streaming.h"
#include "thread-utils.h"
+#include "pack-bitmap.h"
static const char *pack_usage[] = {
N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
@@ -25,42 +27,15 @@ static const char *pack_usage[] = {
NULL
};
-struct object_entry {
- struct pack_idx_entry idx;
- unsigned long size; /* uncompressed size */
- struct packed_git *in_pack; /* already in pack */
- off_t in_pack_offset;
- struct object_entry *delta; /* delta base object */
- struct object_entry *delta_child; /* deltified objects who bases me */
- struct object_entry *delta_sibling; /* other deltified objects who
- * uses the same base as me
- */
- void *delta_data; /* cached delta (uncompressed) */
- unsigned long delta_size; /* delta data size (uncompressed) */
- unsigned long z_delta_size; /* delta data size (compressed) */
- enum object_type type;
- enum object_type in_pack_type; /* could be delta */
- uint32_t hash; /* name hint hash */
- unsigned char in_pack_header_size;
- unsigned preferred_base:1; /*
- * we do not pack this, but is available
- * to be used as the base object to delta
- * objects against.
- */
- unsigned no_try_delta:1;
- unsigned tagged:1; /* near the very tip of refs */
- unsigned filled:1; /* assigned write-order */
-};
-
/*
- * Objects we are going to pack are collected in objects array (dynamically
- * expanded). nr_objects & nr_alloc controls this array. They are stored
- * in the order we see -- typically rev-list --objects order that gives us
- * nice "minimum seek" order.
+ * Objects we are going to pack are collected in the `to_pack` structure.
+ * It contains an array (dynamically expanded) of the object data, and a map
+ * that can resolve SHA1s to their position in the array.
*/
-static struct object_entry *objects;
+static struct packing_data to_pack;
+
static struct pack_idx_entry **written_list;
-static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
+static uint32_t nr_result, nr_written;
static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
@@ -83,6 +58,14 @@ static struct progress *progress_state;
static int pack_compression_level = Z_DEFAULT_COMPRESSION;
static int pack_compression_seen;
+static struct packed_git *reuse_packfile;
+static uint32_t reuse_packfile_objects;
+static off_t reuse_packfile_offset;
+
+static int use_bitmap_index = 1;
+static int write_bitmap_index;
+static uint16_t write_bitmap_options;
+
static unsigned long delta_cache_size = 0;
static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
static unsigned long cache_max_small_delta_size = 1000;
@@ -90,20 +73,28 @@ static unsigned long cache_max_small_delta_size = 1000;
static unsigned long window_memory_limit = 0;
/*
- * The object names in objects array are hashed with this hashtable,
- * to help looking up the entry by object name.
- * This hashtable is built after all the objects are seen.
- */
-static int *object_ix;
-static int object_ix_hashsz;
-static struct object_entry *locate_object_entry(const unsigned char *sha1);
-
-/*
* stats
*/
static uint32_t written, written_delta;
static uint32_t reused, reused_delta;
+/*
+ * Indexed commits
+ */
+static struct commit **indexed_commits;
+static unsigned int indexed_commits_nr;
+static unsigned int indexed_commits_alloc;
+
+static void index_commit_for_bitmap(struct commit *commit)
+{
+ if (indexed_commits_nr >= indexed_commits_alloc) {
+ indexed_commits_alloc = (indexed_commits_alloc + 32) * 2;
+ indexed_commits = xrealloc(indexed_commits,
+ indexed_commits_alloc * sizeof(struct commit *));
+ }
+
+ indexed_commits[indexed_commits_nr++] = commit;
+}
static void *get_delta(struct object_entry *entry)
{
@@ -553,12 +544,12 @@ static int mark_tagged(const char *path, const unsigned char *sha1, int flag,
void *cb_data)
{
unsigned char peeled[20];
- struct object_entry *entry = locate_object_entry(sha1);
+ struct object_entry *entry = packlist_find(&to_pack, sha1, NULL);
if (entry)
entry->tagged = 1;
if (!peel_ref(path, peeled)) {
- entry = locate_object_entry(peeled);
+ entry = packlist_find(&to_pack, peeled, NULL);
if (entry)
entry->tagged = 1;
}
@@ -633,9 +624,10 @@ static struct object_entry **compute_write_order(void)
{
unsigned int i, wo_end, last_untagged;
- struct object_entry **wo = xmalloc(nr_objects * sizeof(*wo));
+ struct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo));
+ struct object_entry *objects = to_pack.objects;
- for (i = 0; i < nr_objects; i++) {
+ for (i = 0; i < to_pack.nr_objects; i++) {
objects[i].tagged = 0;
objects[i].filled = 0;
objects[i].delta_child = NULL;
@@ -647,7 +639,7 @@ static struct object_entry **compute_write_order(void)
* Make sure delta_sibling is sorted in the original
* recency order.
*/
- for (i = nr_objects; i > 0;) {
+ for (i = to_pack.nr_objects; i > 0;) {
struct object_entry *e = &objects[--i];
if (!e->delta)
continue;
@@ -665,7 +657,7 @@ static struct object_entry **compute_write_order(void)
* Give the objects in the original recency order until
* we see a tagged tip.
*/
- for (i = wo_end = 0; i < nr_objects; i++) {
+ for (i = wo_end = 0; i < to_pack.nr_objects; i++) {
if (objects[i].tagged)
break;
add_to_write_order(wo, &wo_end, &objects[i]);
@@ -675,7 +667,7 @@ static struct object_entry **compute_write_order(void)
/*
* Then fill all the tagged tips.
*/
- for (; i < nr_objects; i++) {
+ for (; i < to_pack.nr_objects; i++) {
if (objects[i].tagged)
add_to_write_order(wo, &wo_end, &objects[i]);
}
@@ -683,7 +675,7 @@ static struct object_entry **compute_write_order(void)
/*
* And then all remaining commits and tags.
*/
- for (i = last_untagged; i < nr_objects; i++) {
+ for (i = last_untagged; i < to_pack.nr_objects; i++) {
if (objects[i].type != OBJ_COMMIT &&
objects[i].type != OBJ_TAG)
continue;
@@ -693,7 +685,7 @@ static struct object_entry **compute_write_order(void)
/*
* And then all the trees.
*/
- for (i = last_untagged; i < nr_objects; i++) {
+ for (i = last_untagged; i < to_pack.nr_objects; i++) {
if (objects[i].type != OBJ_TREE)
continue;
add_to_write_order(wo, &wo_end, &objects[i]);
@@ -702,17 +694,57 @@ static struct object_entry **compute_write_order(void)
/*
* Finally all the rest in really tight order
*/
- for (i = last_untagged; i < nr_objects; i++) {
+ for (i = last_untagged; i < to_pack.nr_objects; i++) {
if (!objects[i].filled)
add_family_to_write_order(wo, &wo_end, &objects[i]);
}
- if (wo_end != nr_objects)
- die("ordered %u objects, expected %"PRIu32, wo_end, nr_objects);
+ if (wo_end != to_pack.nr_objects)
+ die("ordered %u objects, expected %"PRIu32, wo_end, to_pack.nr_objects);
return wo;
}
+static off_t write_reused_pack(struct sha1file *f)
+{
+ unsigned char buffer[8192];
+ off_t to_write;
+ int fd;
+
+ if (!is_pack_valid(reuse_packfile))
+ die("packfile is invalid: %s", reuse_packfile->pack_name);
+
+ fd = git_open_noatime(reuse_packfile->pack_name);
+ if (fd < 0)
+ die_errno("unable to open packfile for reuse: %s",
+ reuse_packfile->pack_name);
+
+ if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1)
+ die_errno("unable to seek in reused packfile");
+
+ if (reuse_packfile_offset < 0)
+ reuse_packfile_offset = reuse_packfile->pack_size - 20;
+
+ to_write = reuse_packfile_offset - sizeof(struct pack_header);
+
+ while (to_write) {
+ int read_pack = xread(fd, buffer, sizeof(buffer));
+
+ if (read_pack <= 0)
+ die_errno("unable to read from reused packfile");
+
+ if (read_pack > to_write)
+ read_pack = to_write;
+
+ sha1write(f, buffer, read_pack);
+ to_write -= read_pack;
+ }
+
+ close(fd);
+ written += reuse_packfile_objects;
+ return reuse_packfile_offset - sizeof(struct pack_header);
+}
+
static void write_pack_file(void)
{
uint32_t i = 0, j;
@@ -724,7 +756,7 @@ static void write_pack_file(void)
if (progress > pack_to_stdout)
progress_state = start_progress("Writing objects", nr_result);
- written_list = xmalloc(nr_objects * sizeof(*written_list));
+ written_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));
write_order = compute_write_order();
do {
@@ -737,8 +769,17 @@ static void write_pack_file(void)
f = create_tmp_packfile(&pack_tmp_name);
offset = write_pack_header(f, nr_remaining);
+
+ if (reuse_packfile) {
+ off_t packfile_size;
+ assert(pack_to_stdout);
+
+ packfile_size = write_reused_pack(f);
+ offset += packfile_size;
+ }
+
nr_written = 0;
- for (; i < nr_objects; i++) {
+ for (; i < to_pack.nr_objects; i++) {
struct object_entry *e = write_order[i];
if (write_one(f, e, &offset) == WRITE_ONE_BREAK)
break;
@@ -789,9 +830,31 @@ static void write_pack_file(void)
if (sizeof(tmpname) <= strlen(base_name) + 50)
die("pack base name '%s' too long", base_name);
snprintf(tmpname, sizeof(tmpname), "%s-", base_name);
+
+ if (write_bitmap_index) {
+ bitmap_writer_set_checksum(sha1);
+ bitmap_writer_build_type_index(written_list, nr_written);
+ }
+
finish_tmp_packfile(tmpname, pack_tmp_name,
written_list, nr_written,
&pack_idx_opts, sha1);
+
+ if (write_bitmap_index) {
+ char *end_of_name_prefix = strrchr(tmpname, 0);
+ sprintf(end_of_name_prefix, "%s.bitmap", sha1_to_hex(sha1));
+
+ stop_progress(&progress_state);
+
+ bitmap_writer_show_progress(progress);
+ bitmap_writer_reuse_bitmaps(&to_pack);
+ bitmap_writer_select_commits(indexed_commits, indexed_commits_nr, -1);
+ bitmap_writer_build(&to_pack);
+ bitmap_writer_finish(written_list, nr_written,
+ tmpname, write_bitmap_options);
+ write_bitmap_index = 0;
+ }
+
free(pack_tmp_name);
puts(sha1_to_hex(sha1));
}
@@ -801,7 +864,7 @@ static void write_pack_file(void)
written_list[j]->offset = (off_t)-1;
}
nr_remaining -= nr_written;
- } while (nr_remaining && i < nr_objects);
+ } while (nr_remaining && i < to_pack.nr_objects);
free(written_list);
free(write_order);
@@ -811,73 +874,6 @@ static void write_pack_file(void)
written, nr_result);
}
-static int locate_object_entry_hash(const unsigned char *sha1)
-{
- int i;
- unsigned int ui;
- memcpy(&ui, sha1, sizeof(unsigned int));
- i = ui % object_ix_hashsz;
- while (0 < object_ix[i]) {
- if (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))
- return i;
- if (++i == object_ix_hashsz)
- i = 0;
- }
- return -1 - i;
-}
-
-static struct object_entry *locate_object_entry(const unsigned char *sha1)
-{
- int i;
-
- if (!object_ix_hashsz)
- return NULL;
-
- i = locate_object_entry_hash(sha1);
- if (0 <= i)
- return &objects[object_ix[i]-1];
- return NULL;
-}
-
-static void rehash_objects(void)
-{
- uint32_t i;
- struct object_entry *oe;
-
- object_ix_hashsz = nr_objects * 3;
- if (object_ix_hashsz < 1024)
- object_ix_hashsz = 1024;
- object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
- memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
- for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
- int ix = locate_object_entry_hash(oe->idx.sha1);
- if (0 <= ix)
- continue;
- ix = -1 - ix;
- object_ix[ix] = i + 1;
- }
-}
-
-static uint32_t name_hash(const char *name)
-{
- uint32_t c, hash = 0;
-
- if (!name)
- return 0;
-
- /*
- * This effectively just creates a sortable number from the
- * last sixteen non-whitespace characters. Last characters
- * count "most", so things that end in ".c" sort together.
- */
- while ((c = *name++) != 0) {
- if (isspace(c))
- continue;
- hash = (hash >> 2) + (c << 24);
- }
- return hash;
-}
-
static void setup_delta_attr_check(struct git_attr_check *check)
{
static struct git_attr *attr_delta;
@@ -900,42 +896,69 @@ static int no_try_delta(const char *path)
return 0;
}
-static int add_object_entry(const unsigned char *sha1, enum object_type type,
- const char *name, int exclude)
+/*
+ * When adding an object, check whether we have already added it
+ * to our packing list. If so, we can skip. However, if we are
+ * being asked to excludei t, but the previous mention was to include
+ * it, make sure to adjust its flags and tweak our numbers accordingly.
+ *
+ * As an optimization, we pass out the index position where we would have
+ * found the item, since that saves us from having to look it up again a
+ * few lines later when we want to add the new entry.
+ */
+static int have_duplicate_entry(const unsigned char *sha1,
+ int exclude,
+ uint32_t *index_pos)
{
struct object_entry *entry;
- struct packed_git *p, *found_pack = NULL;
- off_t found_offset = 0;
- int ix;
- uint32_t hash = name_hash(name);
-
- ix = nr_objects ? locate_object_entry_hash(sha1) : -1;
- if (ix >= 0) {
- if (exclude) {
- entry = objects + object_ix[ix] - 1;
- if (!entry->preferred_base)
- nr_result--;
- entry->preferred_base = 1;
- }
+
+ entry = packlist_find(&to_pack, sha1, index_pos);
+ if (!entry)
return 0;
+
+ if (exclude) {
+ if (!entry->preferred_base)
+ nr_result--;
+ entry->preferred_base = 1;
}
+ return 1;
+}
+
+/*
+ * Check whether we want the object in the pack (e.g., we do not want
+ * objects found in non-local stores if the "--local" option was used).
+ *
+ * As a side effect of this check, we will find the packed version of this
+ * object, if any. We therefore pass out the pack information to avoid having
+ * to look it up again later.
+ */
+static int want_object_in_pack(const unsigned char *sha1,
+ int exclude,
+ struct packed_git **found_pack,
+ off_t *found_offset)
+{
+ struct packed_git *p;
+
if (!exclude && local && has_loose_object_nonlocal(sha1))
return 0;
+ *found_pack = NULL;
+ *found_offset = 0;
+
for (p = packed_git; p; p = p->next) {
off_t offset = find_pack_entry_one(sha1, p);
if (offset) {
- if (!found_pack) {
+ if (!*found_pack) {
if (!is_pack_valid(p)) {
warning("packfile %s cannot be accessed", p->pack_name);
continue;
}
- found_offset = offset;
- found_pack = p;
+ *found_offset = offset;
+ *found_pack = p;
}
if (exclude)
- break;
+ return 1;
if (incremental)
return 0;
if (local && !p->pack_local)
@@ -945,14 +968,21 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
}
}
- if (nr_objects >= nr_alloc) {
- nr_alloc = (nr_alloc + 1024) * 3 / 2;
- objects = xrealloc(objects, nr_alloc * sizeof(*entry));
- }
+ return 1;
+}
+
+static void create_object_entry(const unsigned char *sha1,
+ enum object_type type,
+ uint32_t hash,
+ int exclude,
+ int no_try_delta,
+ uint32_t index_pos,
+ struct packed_git *found_pack,
+ off_t found_offset)
+{
+ struct object_entry *entry;
- entry = objects + nr_objects++;
- memset(entry, 0, sizeof(*entry));
- hashcpy(entry->idx.sha1, sha1);
+ entry = packlist_alloc(&to_pack, sha1, index_pos);
entry->hash = hash;
if (type)
entry->type = type;
@@ -965,16 +995,43 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
entry->in_pack_offset = found_offset;
}
- if (object_ix_hashsz * 3 <= nr_objects * 4)
- rehash_objects();
- else
- object_ix[-1 - ix] = nr_objects;
+ entry->no_try_delta = no_try_delta;
+}
+
+static int add_object_entry(const unsigned char *sha1, enum object_type type,
+ const char *name, int exclude)
+{
+ struct packed_git *found_pack;
+ off_t found_offset;
+ uint32_t index_pos;
- display_progress(progress_state, nr_objects);
+ if (have_duplicate_entry(sha1, exclude, &index_pos))
+ return 0;
+
+ if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset))
+ return 0;
- if (name && no_try_delta(name))
- entry->no_try_delta = 1;
+ create_object_entry(sha1, type, pack_name_hash(name),
+ exclude, name && no_try_delta(name),
+ index_pos, found_pack, found_offset);
+ display_progress(progress_state, to_pack.nr_objects);
+ return 1;
+}
+
+static int add_object_entry_from_bitmap(const unsigned char *sha1,
+ enum object_type type,
+ int flags, uint32_t name_hash,
+ struct packed_git *pack, off_t offset)
+{
+ uint32_t index_pos;
+
+ if (have_duplicate_entry(sha1, 0, &index_pos))
+ return 0;
+
+ create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset);
+
+ display_progress(progress_state, to_pack.nr_objects);
return 1;
}
@@ -1175,7 +1232,7 @@ static void add_preferred_base_object(const char *name)
{
struct pbase_tree *it;
int cmplen;
- unsigned hash = name_hash(name);
+ unsigned hash = pack_name_hash(name);
if (!num_preferred_base || check_pbase_path(hash))
return;
@@ -1327,7 +1384,7 @@ static void check_object(struct object_entry *entry)
break;
}
- if (base_ref && (base_entry = locate_object_entry(base_ref))) {
+ if (base_ref && (base_entry = packlist_find(&to_pack, base_ref, NULL))) {
/*
* If base_ref was set above that means we wish to
* reuse delta data, and we even found that base
@@ -1401,12 +1458,12 @@ static void get_object_details(void)
uint32_t i;
struct object_entry **sorted_by_offset;
- sorted_by_offset = xcalloc(nr_objects, sizeof(struct object_entry *));
- for (i = 0; i < nr_objects; i++)
- sorted_by_offset[i] = objects + i;
- qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
+ sorted_by_offset = xcalloc(to_pack.nr_objects, sizeof(struct object_entry *));
+ for (i = 0; i < to_pack.nr_objects; i++)
+ sorted_by_offset[i] = to_pack.objects + i;
+ qsort(sorted_by_offset, to_pack.nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
- for (i = 0; i < nr_objects; i++) {
+ for (i = 0; i < to_pack.nr_objects; i++) {
struct object_entry *entry = sorted_by_offset[i];
check_object(entry);
if (big_file_threshold < entry->size)
@@ -2032,7 +2089,7 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo
if (starts_with(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, peeled) && /* peelable? */
- locate_object_entry(peeled)) /* object packed? */
+ packlist_find(&to_pack, peeled, NULL)) /* object packed? */
add_object_entry(sha1, OBJ_TAG, NULL, 0);
return 0;
}
@@ -2055,14 +2112,14 @@ static void prepare_pack(int window, int depth)
if (!pack_to_stdout)
do_check_packed_object_crc = 1;
- if (!nr_objects || !window || !depth)
+ if (!to_pack.nr_objects || !window || !depth)
return;
- delta_list = xmalloc(nr_objects * sizeof(*delta_list));
+ delta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list));
nr_deltas = n = 0;
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *entry = objects + i;
+ for (i = 0; i < to_pack.nr_objects; i++) {
+ struct object_entry *entry = to_pack.objects + i;
if (entry->delta)
/* This happens if we decided to reuse existing
@@ -2140,6 +2197,20 @@ static int git_pack_config(const char *k, const char *v, void *cb)
cache_max_small_delta_size = git_config_int(k, v);
return 0;
}
+ if (!strcmp(k, "pack.writebitmaps")) {
+ write_bitmap_index = git_config_bool(k, v);
+ return 0;
+ }
+ if (!strcmp(k, "pack.writebitmaphashcache")) {
+ if (git_config_bool(k, v))
+ write_bitmap_options |= BITMAP_OPT_HASH_CACHE;
+ else
+ write_bitmap_options &= ~BITMAP_OPT_HASH_CACHE;
+ }
+ if (!strcmp(k, "pack.usebitmaps")) {
+ use_bitmap_index = git_config_bool(k, v);
+ return 0;
+ }
if (!strcmp(k, "pack.threads")) {
delta_search_threads = git_config_int(k, v);
if (delta_search_threads < 0)
@@ -2198,6 +2269,9 @@ static void show_commit(struct commit *commit, void *data)
{
add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
commit->object.flags |= OBJECT_ADDED;
+
+ if (write_bitmap_index)
+ index_commit_for_bitmap(commit);
}
static void show_object(struct object *obj,
@@ -2340,7 +2414,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
for (i = 0; i < p->num_objects; i++) {
sha1 = nth_packed_object_sha1(p, i);
- if (!locate_object_entry(sha1) &&
+ if (!packlist_find(&to_pack, sha1, NULL) &&
!has_sha1_pack_kept_or_nonlocal(sha1))
if (force_object_loose(sha1, p->mtime))
die("unable to force loose object");
@@ -2348,6 +2422,29 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
}
}
+static int get_object_list_from_bitmap(struct rev_info *revs)
+{
+ if (prepare_bitmap_walk(revs) < 0)
+ return -1;
+
+ if (!reuse_partial_packfile_from_bitmap(
+ &reuse_packfile,
+ &reuse_packfile_objects,
+ &reuse_packfile_offset)) {
+ assert(reuse_packfile_objects);
+ nr_result += reuse_packfile_objects;
+
+ if (progress) {
+ fprintf(stderr, "Reusing existing pack: %d, done.\n",
+ reuse_packfile_objects);
+ fflush(stderr);
+ }
+ }
+
+ traverse_bitmap_commit_list(&add_object_entry_from_bitmap);
+ return 0;
+}
+
static void get_object_list(int ac, const char **av)
{
struct rev_info revs;
@@ -2367,6 +2464,7 @@ static void get_object_list(int ac, const char **av)
if (*line == '-') {
if (!strcmp(line, "--not")) {
flags ^= UNINTERESTING;
+ write_bitmap_index = 0;
continue;
}
die("not a rev '%s'", line);
@@ -2375,6 +2473,9 @@ static void get_object_list(int ac, const char **av)
die("bad revision '%s'", line);
}
+ if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
+ return;
+
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
mark_edges_uninteresting(&revs, show_edge);
@@ -2504,6 +2605,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("pack compression level")),
OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
N_("do not hide commits by grafts"), 0),
+ OPT_BOOL(0, "use-bitmap-index", &use_bitmap_index,
+ N_("use a bitmap index if available to speed up counting objects")),
+ OPT_BOOL(0, "write-bitmap-index", &write_bitmap_index,
+ N_("write a bitmap index together with the pack index")),
OPT_END(),
};
@@ -2570,6 +2675,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (keep_unreachable && unpack_unreachable)
die("--keep-unreachable and --unpack-unreachable are incompatible.");
+ if (!use_internal_rev_list || !pack_to_stdout || is_repository_shallow())
+ use_bitmap_index = 0;
+
+ if (pack_to_stdout || !rev_list_all)
+ write_bitmap_index = 0;
+
if (progress && all_progress_implied)
progress = 2;
diff --git a/builtin/repack.c b/builtin/repack.c
index 6284846d82..49f5857627 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -94,7 +94,7 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
static void remove_redundant_pack(const char *dir_name, const char *base_name)
{
- const char *exts[] = {".pack", ".idx", ".keep"};
+ const char *exts[] = {".pack", ".idx", ".keep", ".bitmap"};
int i;
struct strbuf buf = STRBUF_INIT;
size_t plen;
@@ -115,7 +115,14 @@ static void remove_redundant_pack(const char *dir_name, const char *base_name)
int cmd_repack(int argc, const char **argv, const char *prefix)
{
- const char *exts[2] = {".pack", ".idx"};
+ struct {
+ const char *name;
+ unsigned optional:1;
+ } exts[] = {
+ {".pack"},
+ {".idx"},
+ {".bitmap", 1},
+ };
struct child_process cmd;
struct string_list_item *item;
struct argv_array cmd_args = ARGV_ARRAY_INIT;
@@ -137,6 +144,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
int no_update_server_info = 0;
int quiet = 0;
int local = 0;
+ int write_bitmap = -1;
struct option builtin_repack_options[] = {
OPT_BIT('a', NULL, &pack_everything,
@@ -155,6 +163,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("be quiet")),
OPT_BOOL('l', "local", &local,
N_("pass --local to git-pack-objects")),
+ OPT_BOOL('b', "write-bitmap-index", &write_bitmap,
+ N_("write bitmap index")),
OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
N_("with -A, do not loosen objects older than this")),
OPT_STRING(0, "window", &window, N_("n"),
@@ -196,6 +206,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_pushf(&cmd_args, "--no-reuse-delta");
if (no_reuse_object)
argv_array_pushf(&cmd_args, "--no-reuse-object");
+ if (write_bitmap >= 0)
+ argv_array_pushf(&cmd_args, "--%swrite-bitmap-index",
+ write_bitmap ? "" : "no-");
if (pack_everything & ALL_INTO_ONE) {
get_non_kept_pack_filenames(&existing_packs);
@@ -256,17 +269,17 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
*/
failed = 0;
for_each_string_list_item(item, &names) {
- for (ext = 0; ext < 2; ext++) {
+ for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname, *fname_old;
- fname = mkpathdup("%s/%s%s", packdir,
- item->string, exts[ext]);
+ fname = mkpathdup("%s/pack-%s%s", packdir,
+ item->string, exts[ext].name);
if (!file_exists(fname)) {
free(fname);
continue;
}
fname_old = mkpath("%s/old-%s%s", packdir,
- item->string, exts[ext]);
+ item->string, exts[ext].name);
if (file_exists(fname_old))
if (unlink(fname_old))
failed = 1;
@@ -313,19 +326,23 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
/* Now the ones with the same name are out of the way... */
for_each_string_list_item(item, &names) {
- for (ext = 0; ext < 2; ext++) {
+ for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname, *fname_old;
struct stat statbuffer;
+ int exists = 0;
fname = mkpathdup("%s/pack-%s%s",
- packdir, item->string, exts[ext]);
+ packdir, item->string, exts[ext].name);
fname_old = mkpathdup("%s-%s%s",
- packtmp, item->string, exts[ext]);
+ packtmp, item->string, exts[ext].name);
if (!stat(fname_old, &statbuffer)) {
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
chmod(fname_old, statbuffer.st_mode);
+ exists = 1;
+ }
+ if (exists || !exts[ext].optional) {
+ if (rename(fname_old, fname))
+ die_errno(_("renaming '%s' failed"), fname_old);
}
- if (rename(fname_old, fname))
- die_errno(_("renaming '%s' failed"), fname_old);
free(fname);
free(fname_old);
}
@@ -333,12 +350,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
/* Remove the "old-" files */
for_each_string_list_item(item, &names) {
- for (ext = 0; ext < 2; ext++) {
+ for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname;
- fname = mkpath("%s/old-pack-%s%s",
+ fname = mkpath("%s/old-%s%s",
packdir,
item->string,
- exts[ext]);
+ exts[ext].name);
if (remove_path(fname))
warning(_("removing '%s' failed"), fname);
}
diff --git a/builtin/reset.c b/builtin/reset.c
index 60048030dd..4fd1c6c51d 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -116,25 +116,34 @@ static void update_index_from_diff(struct diff_queue_struct *q,
struct diff_options *opt, void *data)
{
int i;
+ int intent_to_add = *(int *)data;
for (i = 0; i < q->nr; i++) {
struct diff_filespec *one = q->queue[i]->one;
- if (one->mode && !is_null_sha1(one->sha1)) {
- struct cache_entry *ce;
- ce = make_cache_entry(one->mode, one->sha1, one->path,
- 0, 0);
- if (!ce)
- die(_("make_cache_entry failed for path '%s'"),
- one->path);
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
- ADD_CACHE_OK_TO_REPLACE);
- } else
+ int is_missing = !(one->mode && !is_null_sha1(one->sha1));
+ struct cache_entry *ce;
+
+ if (is_missing && !intent_to_add) {
remove_file_from_cache(one->path);
+ continue;
+ }
+
+ ce = make_cache_entry(one->mode, one->sha1, one->path,
+ 0, 0);
+ if (!ce)
+ die(_("make_cache_entry failed for path '%s'"),
+ one->path);
+ if (is_missing) {
+ ce->ce_flags |= CE_INTENT_TO_ADD;
+ set_object_name_for_intent_to_add_entry(ce);
+ }
+ add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
}
static int read_from_tree(const struct pathspec *pathspec,
- unsigned char *tree_sha1)
+ unsigned char *tree_sha1,
+ int intent_to_add)
{
struct diff_options opt;
@@ -142,6 +151,7 @@ static int read_from_tree(const struct pathspec *pathspec,
copy_pathspec(&opt.pathspec, pathspec);
opt.output_format = DIFF_FORMAT_CALLBACK;
opt.format_callback = update_index_from_diff;
+ opt.format_callback_data = &intent_to_add;
if (do_diff_cache(tree_sha1, &opt))
return 1;
@@ -258,6 +268,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
const char *rev;
unsigned char sha1[20];
struct pathspec pathspec;
+ int intent_to_add = 0;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_SET_INT(0, "mixed", &reset_type,
@@ -270,6 +281,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
OPT_SET_INT(0, "keep", &reset_type,
N_("reset HEAD but keep local changes"), KEEP),
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
+ OPT_BOOL('N', "intent-to-add", &intent_to_add,
+ N_("record only the fact that removed paths will be added later")),
OPT_END()
};
@@ -327,6 +340,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die(_("%s reset is not allowed in a bare repository"),
_(reset_type_names[reset_type]));
+ if (intent_to_add && reset_type != MIXED)
+ die(_("-N can only be used with --mixed"));
+
/* Soft reset does not touch the index file nor the working tree
* at all, but requires them in a good order. Other resets reset
* the index file to the tree object we are switching to. */
@@ -338,7 +354,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
int newfd = hold_locked_index(lock, 1);
if (reset_type == MIXED) {
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
- if (read_from_tree(&pathspec, sha1))
+ if (read_from_tree(&pathspec, sha1, intent_to_add))
return 1;
refresh_index(&the_index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 0745e2d053..9f92905379 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -3,6 +3,8 @@
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
+#include "pack.h"
+#include "pack-bitmap.h"
#include "builtin.h"
#include "log-tree.h"
#include "graph.h"
@@ -257,6 +259,18 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
return 0;
}
+static int show_object_fast(
+ const unsigned char *sha1,
+ enum object_type type,
+ int exclude,
+ uint32_t name_hash,
+ struct packed_git *found_pack,
+ off_t found_offset)
+{
+ fprintf(stdout, "%s\n", sha1_to_hex(sha1));
+ return 1;
+}
+
int cmd_rev_list(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@@ -265,6 +279,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
int bisect_list = 0;
int bisect_show_vars = 0;
int bisect_find_all = 0;
+ int use_bitmap_index = 0;
git_config(git_default_config, NULL);
init_revisions(&revs, prefix);
@@ -306,6 +321,14 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
bisect_show_vars = 1;
continue;
}
+ if (!strcmp(arg, "--use-bitmap-index")) {
+ use_bitmap_index = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--test-bitmap")) {
+ test_bitmap_walk(&revs);
+ return 0;
+ }
usage(rev_list_usage);
}
@@ -333,6 +356,22 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (bisect_list)
revs.limited = 1;
+ if (use_bitmap_index) {
+ if (revs.count && !revs.left_right && !revs.cherry_mark) {
+ uint32_t commit_count;
+ if (!prepare_bitmap_walk(&revs)) {
+ count_bitmap_commit_list(&commit_count, NULL, NULL, NULL);
+ printf("%d\n", commit_count);
+ return 0;
+ }
+ } else if (revs.tag_objects && revs.tree_objects && revs.blob_objects) {
+ if (!prepare_bitmap_walk(&revs)) {
+ traverse_bitmap_commit_list(&show_object_fast);
+ return 0;
+ }
+ }
+ }
+
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
if (revs.tree_objects)
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index aaeb611a97..45901df371 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -547,15 +547,17 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--default")) {
- def = argv[i+1];
- i++;
+ def = argv[++i];
+ if (!def)
+ die("--default requires an argument");
continue;
}
if (!strcmp(arg, "--prefix")) {
- prefix = argv[i+1];
+ prefix = argv[++i];
+ if (!prefix)
+ die("--prefix requires an argument");
startup_info->prefix = prefix;
output_prefix = 1;
- i++;
continue;
}
if (!strcmp(arg, "--revs-only")) {
@@ -738,9 +740,12 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--resolve-git-dir")) {
- const char *gitdir = resolve_gitdir(argv[i+1]);
+ const char *gitdir = argv[++i];
if (!gitdir)
- die("not a gitdir '%s'", argv[i+1]);
+ die("--resolve-git-dir requires an argument");
+ gitdir = resolve_gitdir(gitdir);
+ if (!gitdir)
+ die("not a gitdir '%s'", argv[i]);
puts(gitdir);
continue;
}
diff --git a/builtin/revert.c b/builtin/revert.c
index 87659c9fdb..065d88dd05 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -89,6 +89,8 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
N_("option for merge strategy"), option_parse_x),
+ { OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key id"),
+ N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END(),
OPT_END(),
OPT_END(),
diff --git a/builtin/rm.c b/builtin/rm.c
index 3a0e0eaab7..960634dd0c 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -308,10 +308,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
- if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), 0, seen))
+ if (!ce_path_match(ce, &pathspec, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
- list.entry[list.nr].name = ce->name;
+ list.entry[list.nr].name = xstrdup(ce->name);
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
!is_staging_gitmodules_ok())
diff --git a/builtin/update-index.c b/builtin/update-index.c
index e3a10d706d..d12ad95f3e 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -12,6 +12,7 @@
#include "resolve-undo.h"
#include "parse-options.h"
#include "pathspec.h"
+#include "dir.h"
/*
* Default to not allowing changes to the list of files. The
@@ -274,36 +275,32 @@ static void chmod_path(int flip, const char *path)
die("git update-index: cannot chmod %cx '%s'", flip, path);
}
-static void update_one(const char *path, const char *prefix, int prefix_length)
+static void update_one(const char *path)
{
- const char *p = prefix_path(prefix, prefix_length, path);
- if (!verify_path(p)) {
+ if (!verify_path(path)) {
fprintf(stderr, "Ignoring path %s\n", path);
- goto free_return;
+ return;
}
if (mark_valid_only) {
- if (mark_ce_flags(p, CE_VALID, mark_valid_only == MARK_FLAG))
+ if (mark_ce_flags(path, CE_VALID, mark_valid_only == MARK_FLAG))
die("Unable to mark file %s", path);
- goto free_return;
+ return;
}
if (mark_skip_worktree_only) {
- if (mark_ce_flags(p, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
+ if (mark_ce_flags(path, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
die("Unable to mark file %s", path);
- goto free_return;
+ return;
}
if (force_remove) {
- if (remove_file_from_cache(p))
+ if (remove_file_from_cache(path))
die("git update-index: unable to remove %s", path);
report("remove '%s'", path);
- goto free_return;
+ return;
}
- if (process_path(p))
+ if (process_path(path))
die("Unable to process path %s", path);
report("add '%s'", path);
- free_return:
- if (p < path || p > path + strlen(path))
- free((char *)p);
}
static void read_index_info(int line_termination)
@@ -563,8 +560,9 @@ static int do_reupdate(int ac, const char **av,
const struct cache_entry *ce = active_cache[pos];
struct cache_entry *old = NULL;
int save_nr;
+ char *path;
- if (ce_stage(ce) || !ce_path_match(ce, &pathspec))
+ if (ce_stage(ce) || !ce_path_match(ce, &pathspec, NULL))
continue;
if (has_head)
old = read_one_ent(NULL, head_sha1,
@@ -579,7 +577,9 @@ static int do_reupdate(int ac, const char **av,
* or worse yet 'allow_replace', active_nr may decrease.
*/
save_nr = active_nr;
- update_one(ce->name + prefix_length, prefix, prefix_length);
+ path = xstrdup(ce->name);
+ update_one(path);
+ free(path);
if (save_nr != active_nr)
goto redo;
}
@@ -836,11 +836,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
setup_work_tree();
p = prefix_path(prefix, prefix_length, path);
- update_one(p, NULL, 0);
+ update_one(p);
if (set_executable_bit)
chmod_path(set_executable_bit, p);
- if (p < path || p > path + strlen(path))
- free((char *)p);
+ free((char *)p);
ctx.argc--;
ctx.argv++;
break;
@@ -879,11 +878,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
strbuf_swap(&buf, &nbuf);
}
p = prefix_path(prefix, prefix_length, buf.buf);
- update_one(p, NULL, 0);
+ update_one(p);
if (set_executable_bit)
chmod_path(set_executable_bit, p);
- if (p < buf.buf || p > buf.buf + buf.len)
- free((char *)p);
+ free((char *)p);
}
strbuf_release(&nbuf);
strbuf_release(&buf);
diff --git a/cache.h b/cache.h
index dc040fb1aa..db223e8048 100644
--- a/cache.h
+++ b/cache.h
@@ -3,7 +3,7 @@
#include "git-compat-util.h"
#include "strbuf.h"
-#include "hash.h"
+#include "hashmap.h"
#include "advice.h"
#include "gettext.h"
#include "convert.h"
@@ -130,12 +130,12 @@ struct stat_data {
};
struct cache_entry {
+ struct hashmap_entry ent;
struct stat_data ce_stat_data;
unsigned int ce_mode;
unsigned int ce_flags;
unsigned int ce_namelen;
unsigned char sha1[20];
- struct cache_entry *next;
char name[FLEX_ARRAY]; /* more */
};
@@ -159,7 +159,6 @@ struct cache_entry {
#define CE_ADDED (1 << 19)
#define CE_HASHED (1 << 20)
-#define CE_UNHASHED (1 << 21)
#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
#define CE_CONFLICTED (1 << 23)
@@ -195,17 +194,18 @@ struct pathspec;
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
*/
-#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
static inline void copy_cache_entry(struct cache_entry *dst,
const struct cache_entry *src)
{
- unsigned int state = dst->ce_flags & CE_STATE_MASK;
+ unsigned int state = dst->ce_flags & CE_HASHED;
/* Don't copy hash chain and name */
- memcpy(dst, src, offsetof(struct cache_entry, next));
+ memcpy(&dst->ce_stat_data, &src->ce_stat_data,
+ offsetof(struct cache_entry, name) -
+ offsetof(struct cache_entry, ce_stat_data));
/* Restore the hash state */
- dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
+ dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
}
static inline unsigned create_ce_flags(unsigned stage)
@@ -277,8 +277,8 @@ struct index_state {
struct cache_time timestamp;
unsigned name_hash_initialized : 1,
initialized : 1;
- struct hash_table name_hash;
- struct hash_table dir_hash;
+ struct hashmap name_hash;
+ struct hashmap dir_hash;
};
extern struct index_state the_index;
@@ -316,7 +316,6 @@ extern void free_name_hash(struct index_state *istate);
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
#define cache_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))
#define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))
-#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
#define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
@@ -467,7 +466,6 @@ extern int unmerged_index(const struct index_state *);
extern int verify_path(const char *path);
extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
-extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
extern int index_name_pos(const struct index_state *, const char *name, int namelen);
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
@@ -487,8 +485,9 @@ extern int remove_file_from_index(struct index_state *, const char *path);
#define ADD_CACHE_IMPLICIT_DOT 32 /* internal to "git add -u/-A" */
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
extern int add_file_to_index(struct index_state *, const char *path, int flags);
-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
+extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
+extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
extern int index_name_is_other(const struct index_state *, const char *, int);
extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
@@ -498,11 +497,13 @@ extern void *read_blob_data_from_index(struct index_state *, const char *, unsig
#define CE_MATCH_RACY_IS_DIRTY 02
/* do stat comparison even if CE_SKIP_WORKTREE is true */
#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
+/* ignore non-existent files during stat update */
+#define CE_MATCH_IGNORE_MISSING 0x08
+/* enable stat refresh */
+#define CE_MATCH_REFRESH 0x10
extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
-extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
-
#define HASH_WRITE_OBJECT 1
#define HASH_FORMAT_CHECK 2
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
@@ -808,6 +809,7 @@ extern int hash_sha1_file(const void *buf, unsigned long len, const char *type,
extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
+extern int git_open_noatime(const char *name);
extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
diff --git a/compat/bswap.h b/compat/bswap.h
index 5061214f73..120c6c1d37 100644
--- a/compat/bswap.h
+++ b/compat/bswap.h
@@ -17,7 +17,20 @@ static inline uint32_t default_swab32(uint32_t val)
((val & 0x000000ff) << 24));
}
+static inline uint64_t default_bswap64(uint64_t val)
+{
+ return (((val & (uint64_t)0x00000000000000ffULL) << 56) |
+ ((val & (uint64_t)0x000000000000ff00ULL) << 40) |
+ ((val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+ ((val & (uint64_t)0x00000000ff000000ULL) << 8) |
+ ((val & (uint64_t)0x000000ff00000000ULL) >> 8) |
+ ((val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+ ((val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+ ((val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
#undef bswap32
+#undef bswap64
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
@@ -32,15 +45,42 @@ static inline uint32_t git_bswap32(uint32_t x)
return result;
}
+#define bswap64 git_bswap64
+#if defined(__x86_64__)
+static inline uint64_t git_bswap64(uint64_t x)
+{
+ uint64_t result;
+ if (__builtin_constant_p(x))
+ result = default_bswap64(x);
+ else
+ __asm__("bswap %q0" : "=r" (result) : "0" (x));
+ return result;
+}
+#else
+static inline uint64_t git_bswap64(uint64_t x)
+{
+ union { uint64_t i64; uint32_t i32[2]; } tmp, result;
+ if (__builtin_constant_p(x))
+ result.i64 = default_bswap64(x);
+ else {
+ tmp.i64 = x;
+ result.i32[0] = git_bswap32(tmp.i32[1]);
+ result.i32[1] = git_bswap32(tmp.i32[0]);
+ }
+ return result.i64;
+}
+#endif
+
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#include <stdlib.h>
#define bswap32(x) _byteswap_ulong(x)
+#define bswap64(x) _byteswap_uint64(x)
#endif
-#ifdef bswap32
+#if defined(bswap32)
#undef ntohl
#undef htonl
@@ -48,3 +88,73 @@ static inline uint32_t git_bswap32(uint32_t x)
#define htonl(x) bswap32(x)
#endif
+
+#if defined(bswap64)
+
+#undef ntohll
+#undef htonll
+#define ntohll(x) bswap64(x)
+#define htonll(x) bswap64(x)
+
+#else
+
+#undef ntohll
+#undef htonll
+
+#if !defined(__BYTE_ORDER)
+# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+# define __BYTE_ORDER BYTE_ORDER
+# define __LITTLE_ENDIAN LITTLE_ENDIAN
+# define __BIG_ENDIAN BIG_ENDIAN
+# endif
+#endif
+
+#if !defined(__BYTE_ORDER)
+# error "Cannot determine endianness"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(n) (n)
+# define htonll(n) (n)
+#else
+# define ntohll(n) default_bswap64(n)
+# define htonll(n) default_bswap64(n)
+#endif
+
+#endif
+
+/*
+ * Performance might be improved if the CPU architecture is OK with
+ * unaligned 32-bit loads and a fast ntohl() is available.
+ * Otherwise fall back to byte loads and shifts which is portable,
+ * and is faster on architectures with memory alignment issues.
+ */
+
+#if defined(__i386__) || defined(__x86_64__) || \
+ defined(_M_IX86) || defined(_M_X64) || \
+ defined(__ppc__) || defined(__ppc64__) || \
+ defined(__powerpc__) || defined(__powerpc64__) || \
+ defined(__s390__) || defined(__s390x__)
+
+#define get_be16(p) ntohs(*(unsigned short *)(p))
+#define get_be32(p) ntohl(*(unsigned int *)(p))
+#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
+
+#else
+
+#define get_be16(p) ( \
+ (*((unsigned char *)(p) + 0) << 8) | \
+ (*((unsigned char *)(p) + 1) << 0) )
+#define get_be32(p) ( \
+ (*((unsigned char *)(p) + 0) << 24) | \
+ (*((unsigned char *)(p) + 1) << 16) | \
+ (*((unsigned char *)(p) + 2) << 8) | \
+ (*((unsigned char *)(p) + 3) << 0) )
+#define put_be32(p, v) do { \
+ unsigned int __v = (v); \
+ *((unsigned char *)(p) + 0) = __v >> 24; \
+ *((unsigned char *)(p) + 1) = __v >> 16; \
+ *((unsigned char *)(p) + 2) = __v >> 8; \
+ *((unsigned char *)(p) + 3) = __v >> 0; } while (0)
+
+#endif
diff --git a/config.c b/config.c
index d969a5aefc..314d8ee740 100644
--- a/config.c
+++ b/config.c
@@ -84,8 +84,12 @@ static int handle_path_include(const char *path, struct config_include_data *inc
{
int ret = 0;
struct strbuf buf = STRBUF_INIT;
- char *expanded = expand_user_path(path);
+ char *expanded;
+ if (!path)
+ return config_error_nonbool("include.path");
+
+ expanded = expand_user_path(path);
if (!expanded)
return error("Could not expand include path '%s'", path);
path = expanded;
diff --git a/contrib/git-resurrect.sh b/contrib/git-resurrect.sh
index a4ed4c3c62..d7e97bbc76 100755
--- a/contrib/git-resurrect.sh
+++ b/contrib/git-resurrect.sh
@@ -10,6 +10,7 @@ is rather slow but allows you to resurrect other people's topic
branches."
OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=
OPTIONS_SPEC="\
git resurrect $USAGE
--
diff --git a/diff-lib.c b/diff-lib.c
index bf624e7716..ec5f722eff 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -11,6 +11,7 @@
#include "unpack-trees.h"
#include "refs.h"
#include "submodule.h"
+#include "dir.h"
/*
* diff-files
@@ -108,7 +109,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
if (diff_can_quit_early(&revs->diffopt))
break;
- if (!ce_path_match(ce, &revs->prune_data))
+ if (!ce_path_match(ce, &revs->prune_data, NULL))
continue;
if (ce_stage(ce)) {
@@ -436,7 +437,7 @@ static int oneway_diff(const struct cache_entry * const *src,
if (tree == o->df_conflict_entry)
tree = NULL;
- if (ce_path_match(idx ? idx : tree, &revs->prune_data)) {
+ if (ce_path_match(idx ? idx : tree, &revs->prune_data, NULL)) {
do_oneway_diff(o, idx, tree);
if (diff_can_quit_early(&revs->diffopt)) {
o->exiting_early = 1;
diff --git a/diff.c b/diff.c
index 8e4a6a9105..e8006666d8 100644
--- a/diff.c
+++ b/diff.c
@@ -4697,6 +4697,38 @@ static int diff_filespec_is_identical(struct diff_filespec *one,
return !memcmp(one->data, two->data, one->size);
}
+static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
+{
+ if (p->done_skip_stat_unmatch)
+ return p->skip_stat_unmatch_result;
+
+ p->done_skip_stat_unmatch = 1;
+ p->skip_stat_unmatch_result = 0;
+ /*
+ * 1. Entries that come from stat info dirtiness
+ * always have both sides (iow, not create/delete),
+ * one side of the object name is unknown, with
+ * the same mode and size. Keep the ones that
+ * do not match these criteria. They have real
+ * differences.
+ *
+ * 2. At this point, the file is known to be modified,
+ * with the same mode and size, and the object
+ * name of one side is unknown. Need to inspect
+ * the identical contents.
+ */
+ if (!DIFF_FILE_VALID(p->one) || /* (1) */
+ !DIFF_FILE_VALID(p->two) ||
+ (p->one->sha1_valid && p->two->sha1_valid) ||
+ (p->one->mode != p->two->mode) ||
+ diff_populate_filespec(p->one, 1) ||
+ diff_populate_filespec(p->two, 1) ||
+ (p->one->size != p->two->size) ||
+ !diff_filespec_is_identical(p->one, p->two)) /* (2) */
+ p->skip_stat_unmatch_result = 1;
+ return p->skip_stat_unmatch_result;
+}
+
static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
{
int i;
@@ -4707,27 +4739,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- /*
- * 1. Entries that come from stat info dirtiness
- * always have both sides (iow, not create/delete),
- * one side of the object name is unknown, with
- * the same mode and size. Keep the ones that
- * do not match these criteria. They have real
- * differences.
- *
- * 2. At this point, the file is known to be modified,
- * with the same mode and size, and the object
- * name of one side is unknown. Need to inspect
- * the identical contents.
- */
- if (!DIFF_FILE_VALID(p->one) || /* (1) */
- !DIFF_FILE_VALID(p->two) ||
- (p->one->sha1_valid && p->two->sha1_valid) ||
- (p->one->mode != p->two->mode) ||
- diff_populate_filespec(p->one, 1) ||
- diff_populate_filespec(p->two, 1) ||
- (p->one->size != p->two->size) ||
- !diff_filespec_is_identical(p->one, p->two)) /* (2) */
+ if (diff_filespec_check_stat_unmatch(p))
diff_q(&outq, p);
else {
/*
@@ -4890,6 +4902,7 @@ void diff_change(struct diff_options *options,
unsigned old_dirty_submodule, unsigned new_dirty_submodule)
{
struct diff_filespec *one, *two;
+ struct diff_filepair *p;
if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&
is_submodule_ignored(concatpath, options))
@@ -4916,10 +4929,16 @@ void diff_change(struct diff_options *options,
fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
one->dirty_submodule = old_dirty_submodule;
two->dirty_submodule = new_dirty_submodule;
+ p = diff_queue(&diff_queued_diff, one, two);
- diff_queue(&diff_queued_diff, one, two);
- if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
- DIFF_OPT_SET(options, HAS_CHANGES);
+ if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
+ return;
+
+ if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
+ !diff_filespec_check_stat_unmatch(p))
+ return;
+
+ DIFF_OPT_SET(options, HAS_CHANGES);
}
struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 6c7a72fbe7..9b4f068eb3 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -4,7 +4,7 @@
#include "cache.h"
#include "diff.h"
#include "diffcore.h"
-#include "hash.h"
+#include "hashmap.h"
#include "progress.h"
/* Table of rename/copy destinations */
@@ -243,137 +243,82 @@ static int score_compare(const void *a_, const void *b_)
}
struct file_similarity {
- int src_dst, index;
+ struct hashmap_entry entry;
+ int index;
struct diff_filespec *filespec;
- struct file_similarity *next;
};
-static int find_identical_files(struct file_similarity *src,
- struct file_similarity *dst,
+static unsigned int hash_filespec(struct diff_filespec *filespec)
+{
+ unsigned int hash;
+ if (!filespec->sha1_valid) {
+ if (diff_populate_filespec(filespec, 0))
+ return 0;
+ hash_sha1_file(filespec->data, filespec->size, "blob", filespec->sha1);
+ }
+ memcpy(&hash, filespec->sha1, sizeof(hash));
+ return hash;
+}
+
+static int find_identical_files(struct hashmap *srcs,
+ int dst_index,
struct diff_options *options)
{
int renames = 0;
+ struct diff_filespec *target = rename_dst[dst_index].two;
+ struct file_similarity *p, *best, dst;
+ int i = 100, best_score = -1;
+
/*
- * Walk over all the destinations ...
+ * Find the best source match for specified destination.
*/
- do {
- struct diff_filespec *target = dst->filespec;
- struct file_similarity *p, *best;
- int i = 100, best_score = -1;
-
- /*
- * .. to find the best source match
- */
- best = NULL;
- for (p = src; p; p = p->next) {
- int score;
- struct diff_filespec *source = p->filespec;
-
- /* False hash collision? */
- if (hashcmp(source->sha1, target->sha1))
- continue;
- /* Non-regular files? If so, the modes must match! */
- if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
- if (source->mode != target->mode)
- continue;
- }
- /* Give higher scores to sources that haven't been used already */
- score = !source->rename_used;
- if (source->rename_used && options->detect_rename != DIFF_DETECT_COPY)
+ best = NULL;
+ hashmap_entry_init(&dst, hash_filespec(target));
+ for (p = hashmap_get(srcs, &dst, NULL); p; p = hashmap_get_next(srcs, p)) {
+ int score;
+ struct diff_filespec *source = p->filespec;
+
+ /* False hash collision? */
+ if (hashcmp(source->sha1, target->sha1))
+ continue;
+ /* Non-regular files? If so, the modes must match! */
+ if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
+ if (source->mode != target->mode)
continue;
- score += basename_same(source, target);
- if (score > best_score) {
- best = p;
- best_score = score;
- if (score == 2)
- break;
- }
-
- /* Too many identical alternatives? Pick one */
- if (!--i)
- break;
}
- if (best) {
- record_rename_pair(dst->index, best->index, MAX_SCORE);
- renames++;
+ /* Give higher scores to sources that haven't been used already */
+ score = !source->rename_used;
+ if (source->rename_used && options->detect_rename != DIFF_DETECT_COPY)
+ continue;
+ score += basename_same(source, target);
+ if (score > best_score) {
+ best = p;
+ best_score = score;
+ if (score == 2)
+ break;
}
- } while ((dst = dst->next) != NULL);
- return renames;
-}
-static void free_similarity_list(struct file_similarity *p)
-{
- while (p) {
- struct file_similarity *entry = p;
- p = p->next;
- free(entry);
+ /* Too many identical alternatives? Pick one */
+ if (!--i)
+ break;
}
-}
-
-static int find_same_files(void *ptr, void *data)
-{
- int ret;
- struct file_similarity *p = ptr;
- struct file_similarity *src = NULL, *dst = NULL;
- struct diff_options *options = data;
-
- /* Split the hash list up into sources and destinations */
- do {
- struct file_similarity *entry = p;
- p = p->next;
- if (entry->src_dst < 0) {
- entry->next = src;
- src = entry;
- } else {
- entry->next = dst;
- dst = entry;
- }
- } while (p);
-
- /*
- * If we have both sources *and* destinations, see if
- * we can match them up
- */
- ret = (src && dst) ? find_identical_files(src, dst, options) : 0;
-
- /* Free the hashes and return the number of renames found */
- free_similarity_list(src);
- free_similarity_list(dst);
- return ret;
-}
-
-static unsigned int hash_filespec(struct diff_filespec *filespec)
-{
- unsigned int hash;
- if (!filespec->sha1_valid) {
- if (diff_populate_filespec(filespec, 0))
- return 0;
- hash_sha1_file(filespec->data, filespec->size, "blob", filespec->sha1);
+ if (best) {
+ record_rename_pair(dst_index, best->index, MAX_SCORE);
+ renames++;
}
- memcpy(&hash, filespec->sha1, sizeof(hash));
- return hash;
+ return renames;
}
-static void insert_file_table(struct hash_table *table, int src_dst, int index, struct diff_filespec *filespec)
+static void insert_file_table(struct hashmap *table, int index, struct diff_filespec *filespec)
{
- void **pos;
- unsigned int hash;
struct file_similarity *entry = xmalloc(sizeof(*entry));
- entry->src_dst = src_dst;
entry->index = index;
entry->filespec = filespec;
- entry->next = NULL;
-
- hash = hash_filespec(filespec);
- pos = insert_hash(hash, entry, table);
- /* We already had an entry there? */
- if (pos) {
- entry->next = *pos;
- *pos = entry;
- }
+ hashmap_entry_init(entry, hash_filespec(filespec));
+ hashmap_add(table, entry);
}
/*
@@ -385,24 +330,22 @@ static void insert_file_table(struct hash_table *table, int src_dst, int index,
*/
static int find_exact_renames(struct diff_options *options)
{
- int i;
- struct hash_table file_table;
+ int i, renames = 0;
+ struct hashmap file_table;
- init_hash(&file_table);
- preallocate_hash(&file_table, rename_src_nr + rename_dst_nr);
+ /* Add all sources to the hash table */
+ hashmap_init(&file_table, NULL, rename_src_nr);
for (i = 0; i < rename_src_nr; i++)
- insert_file_table(&file_table, -1, i, rename_src[i].p->one);
+ insert_file_table(&file_table, i, rename_src[i].p->one);
+ /* Walk the destinations and find best source match */
for (i = 0; i < rename_dst_nr; i++)
- insert_file_table(&file_table, 1, i, rename_dst[i].two);
-
- /* Find the renames */
- i = for_each_hash(&file_table, find_same_files, options);
+ renames += find_identical_files(&file_table, i, options);
- /* .. and free the hash data structure */
- free_hash(&file_table);
+ /* Free the hash data structure and entries */
+ hashmap_free(&file_table, 1);
- return i;
+ return renames;
}
#define NUM_CANDIDATE_PER_DST 4
diff --git a/diffcore.h b/diffcore.h
index cbe9e62b49..92788ee4de 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -68,6 +68,8 @@ struct diff_filepair {
unsigned broken_pair : 1;
unsigned renamed_pair : 1;
unsigned is_unmerged : 1;
+ unsigned done_skip_stat_unmatch : 1;
+ unsigned skip_stat_unmatch_result : 1;
};
#define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged)
diff --git a/dir.c b/dir.c
index b35b6330f8..98bb50fbab 100644
--- a/dir.c
+++ b/dir.c
@@ -195,6 +195,9 @@ int within_depth(const char *name, int namelen,
return 1;
}
+#define DO_MATCH_EXCLUDE 1
+#define DO_MATCH_DIRECTORY 2
+
/*
* Does 'match' match the given name?
* A match is found if
@@ -208,7 +211,7 @@ int within_depth(const char *name, int namelen,
* It returns 0 when there is no match.
*/
static int match_pathspec_item(const struct pathspec_item *item, int prefix,
- const char *name, int namelen)
+ const char *name, int namelen, unsigned flags)
{
/* name/namelen has prefix cut off by caller */
const char *match = item->match + prefix;
@@ -218,7 +221,7 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
* The normal call pattern is:
* 1. prefix = common_prefix_len(ps);
* 2. prune something, or fill_directory
- * 3. match_pathspec_depth()
+ * 3. match_pathspec()
*
* 'prefix' at #1 may be shorter than the command's prefix and
* it's ok for #2 to match extra files. Those extras will be
@@ -257,7 +260,11 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
if (match[matchlen-1] == '/' || name[matchlen] == '/')
return MATCHED_RECURSIVELY;
- }
+ } else if ((flags & DO_MATCH_DIRECTORY) &&
+ match[matchlen - 1] == '/' &&
+ namelen == matchlen - 1 &&
+ !ps_strncmp(item, match, name, namelen))
+ return MATCHED_EXACTLY;
if (item->nowildcard_len < item->len &&
!git_fnmatch(item, match, name,
@@ -282,12 +289,12 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
* pathspec did not match any names, which could indicate that the
* user mistyped the nth pathspec.
*/
-static int match_pathspec_depth_1(const struct pathspec *ps,
- const char *name, int namelen,
- int prefix, char *seen,
- int exclude)
+static int do_match_pathspec(const struct pathspec *ps,
+ const char *name, int namelen,
+ int prefix, char *seen,
+ unsigned flags)
{
- int i, retval = 0;
+ int i, retval = 0, exclude = flags & DO_MATCH_EXCLUDE;
GUARD_PATHSPEC(ps,
PATHSPEC_FROMTOP |
@@ -327,7 +334,8 @@ static int match_pathspec_depth_1(const struct pathspec *ps,
*/
if (seen && ps->items[i].magic & PATHSPEC_EXCLUDE)
seen[i] = MATCHED_FNMATCH;
- how = match_pathspec_item(ps->items+i, prefix, name, namelen);
+ how = match_pathspec_item(ps->items+i, prefix, name,
+ namelen, flags);
if (ps->recursive &&
(ps->magic & PATHSPEC_MAXDEPTH) &&
ps->max_depth != -1 &&
@@ -350,15 +358,19 @@ static int match_pathspec_depth_1(const struct pathspec *ps,
return retval;
}
-int match_pathspec_depth(const struct pathspec *ps,
- const char *name, int namelen,
- int prefix, char *seen)
+int match_pathspec(const struct pathspec *ps,
+ const char *name, int namelen,
+ int prefix, char *seen, int is_dir)
{
int positive, negative;
- positive = match_pathspec_depth_1(ps, name, namelen, prefix, seen, 0);
+ unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
+ positive = do_match_pathspec(ps, name, namelen,
+ prefix, seen, flags);
if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)
return positive;
- negative = match_pathspec_depth_1(ps, name, namelen, prefix, seen, 1);
+ negative = do_match_pathspec(ps, name, namelen,
+ prefix, seen,
+ flags | DO_MATCH_EXCLUDE);
return negative ? 0 : positive;
}
diff --git a/dir.h b/dir.h
index 9b7e4e77d8..55e53456af 100644
--- a/dir.h
+++ b/dir.h
@@ -132,9 +132,9 @@ struct dir_struct {
extern int simple_length(const char *match);
extern int no_wildcard(const char *string);
extern char *common_prefix(const struct pathspec *pathspec);
-extern int match_pathspec_depth(const struct pathspec *pathspec,
- const char *name, int namelen,
- int prefix, char *seen);
+extern int match_pathspec(const struct pathspec *pathspec,
+ const char *name, int namelen,
+ int prefix, char *seen, int is_dir);
extern int within_depth(const char *name, int namelen, int depth, int max_depth);
extern int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec);
@@ -205,4 +205,22 @@ extern int git_fnmatch(const struct pathspec_item *item,
const char *pattern, const char *string,
int prefix);
+static inline int ce_path_match(const struct cache_entry *ce,
+ const struct pathspec *pathspec,
+ char *seen)
+{
+ return match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen,
+ S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));
+}
+
+static inline int dir_path_match(const struct dir_entry *ent,
+ const struct pathspec *pathspec,
+ int prefix, char *seen)
+{
+ int has_trailing_dir = ent->len && ent->name[ent->len - 1] == '/';
+ int len = has_trailing_dir ? ent->len - 1 : ent->len;
+ return match_pathspec(pathspec, ent->name, len, prefix, seen,
+ has_trailing_dir);
+}
+
#endif
diff --git a/ewah/bitmap.c b/ewah/bitmap.c
new file mode 100644
index 0000000000..710e58c1bf
--- /dev/null
+++ b/ewah/bitmap.c
@@ -0,0 +1,221 @@
+/**
+ * Copyright 2013, GitHub, Inc
+ * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
+ * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "git-compat-util.h"
+#include "ewok.h"
+
+#define MASK(x) ((eword_t)1 << (x % BITS_IN_WORD))
+#define BLOCK(x) (x / BITS_IN_WORD)
+
+struct bitmap *bitmap_new(void)
+{
+ struct bitmap *bitmap = ewah_malloc(sizeof(struct bitmap));
+ bitmap->words = ewah_calloc(32, sizeof(eword_t));
+ bitmap->word_alloc = 32;
+ return bitmap;
+}
+
+void bitmap_set(struct bitmap *self, size_t pos)
+{
+ size_t block = BLOCK(pos);
+
+ if (block >= self->word_alloc) {
+ size_t old_size = self->word_alloc;
+ self->word_alloc = block * 2;
+ self->words = ewah_realloc(self->words,
+ self->word_alloc * sizeof(eword_t));
+
+ memset(self->words + old_size, 0x0,
+ (self->word_alloc - old_size) * sizeof(eword_t));
+ }
+
+ self->words[block] |= MASK(pos);
+}
+
+void bitmap_clear(struct bitmap *self, size_t pos)
+{
+ size_t block = BLOCK(pos);
+
+ if (block < self->word_alloc)
+ self->words[block] &= ~MASK(pos);
+}
+
+int bitmap_get(struct bitmap *self, size_t pos)
+{
+ size_t block = BLOCK(pos);
+ return block < self->word_alloc &&
+ (self->words[block] & MASK(pos)) != 0;
+}
+
+struct ewah_bitmap *bitmap_to_ewah(struct bitmap *bitmap)
+{
+ struct ewah_bitmap *ewah = ewah_new();
+ size_t i, running_empty_words = 0;
+ eword_t last_word = 0;
+
+ for (i = 0; i < bitmap->word_alloc; ++i) {
+ if (bitmap->words[i] == 0) {
+ running_empty_words++;
+ continue;
+ }
+
+ if (last_word != 0)
+ ewah_add(ewah, last_word);
+
+ if (running_empty_words > 0) {
+ ewah_add_empty_words(ewah, 0, running_empty_words);
+ running_empty_words = 0;
+ }
+
+ last_word = bitmap->words[i];
+ }
+
+ ewah_add(ewah, last_word);
+ return ewah;
+}
+
+struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)
+{
+ struct bitmap *bitmap = bitmap_new();
+ struct ewah_iterator it;
+ eword_t blowup;
+ size_t i = 0;
+
+ ewah_iterator_init(&it, ewah);
+
+ while (ewah_iterator_next(&blowup, &it)) {
+ if (i >= bitmap->word_alloc) {
+ bitmap->word_alloc *= 1.5;
+ bitmap->words = ewah_realloc(
+ bitmap->words, bitmap->word_alloc * sizeof(eword_t));
+ }
+
+ bitmap->words[i++] = blowup;
+ }
+
+ bitmap->word_alloc = i;
+ return bitmap;
+}
+
+void bitmap_and_not(struct bitmap *self, struct bitmap *other)
+{
+ const size_t count = (self->word_alloc < other->word_alloc) ?
+ self->word_alloc : other->word_alloc;
+
+ size_t i;
+
+ for (i = 0; i < count; ++i)
+ self->words[i] &= ~other->words[i];
+}
+
+void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)
+{
+ size_t original_size = self->word_alloc;
+ size_t other_final = (other->bit_size / BITS_IN_WORD) + 1;
+ size_t i = 0;
+ struct ewah_iterator it;
+ eword_t word;
+
+ if (self->word_alloc < other_final) {
+ self->word_alloc = other_final;
+ self->words = ewah_realloc(self->words,
+ self->word_alloc * sizeof(eword_t));
+ memset(self->words + original_size, 0x0,
+ (self->word_alloc - original_size) * sizeof(eword_t));
+ }
+
+ ewah_iterator_init(&it, other);
+
+ while (ewah_iterator_next(&word, &it))
+ self->words[i++] |= word;
+}
+
+void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data)
+{
+ size_t pos = 0, i;
+
+ for (i = 0; i < self->word_alloc; ++i) {
+ eword_t word = self->words[i];
+ uint32_t offset;
+
+ if (word == (eword_t)~0) {
+ for (offset = 0; offset < BITS_IN_WORD; ++offset)
+ callback(pos++, data);
+ } else {
+ for (offset = 0; offset < BITS_IN_WORD; ++offset) {
+ if ((word >> offset) == 0)
+ break;
+
+ offset += ewah_bit_ctz64(word >> offset);
+ callback(pos + offset, data);
+ }
+ pos += BITS_IN_WORD;
+ }
+ }
+}
+
+size_t bitmap_popcount(struct bitmap *self)
+{
+ size_t i, count = 0;
+
+ for (i = 0; i < self->word_alloc; ++i)
+ count += ewah_bit_popcount64(self->words[i]);
+
+ return count;
+}
+
+int bitmap_equals(struct bitmap *self, struct bitmap *other)
+{
+ struct bitmap *big, *small;
+ size_t i;
+
+ if (self->word_alloc < other->word_alloc) {
+ small = self;
+ big = other;
+ } else {
+ small = other;
+ big = self;
+ }
+
+ for (i = 0; i < small->word_alloc; ++i) {
+ if (small->words[i] != big->words[i])
+ return 0;
+ }
+
+ for (; i < big->word_alloc; ++i) {
+ if (big->words[i] != 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+void bitmap_reset(struct bitmap *bitmap)
+{
+ memset(bitmap->words, 0x0, bitmap->word_alloc * sizeof(eword_t));
+}
+
+void bitmap_free(struct bitmap *bitmap)
+{
+ if (bitmap == NULL)
+ return;
+
+ free(bitmap->words);
+ free(bitmap);
+}
diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c
new file mode 100644
index 0000000000..9ced2dadfe
--- /dev/null
+++ b/ewah/ewah_bitmap.c
@@ -0,0 +1,714 @@
+/**
+ * Copyright 2013, GitHub, Inc
+ * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
+ * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "git-compat-util.h"
+#include "ewok.h"
+#include "ewok_rlw.h"
+
+static inline size_t min_size(size_t a, size_t b)
+{
+ return a < b ? a : b;
+}
+
+static inline size_t max_size(size_t a, size_t b)
+{
+ return a > b ? a : b;
+}
+
+static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)
+{
+ size_t rlw_offset = (uint8_t *)self->rlw - (uint8_t *)self->buffer;
+
+ if (self->alloc_size >= new_size)
+ return;
+
+ self->alloc_size = new_size;
+ self->buffer = ewah_realloc(self->buffer,
+ self->alloc_size * sizeof(eword_t));
+ self->rlw = self->buffer + (rlw_offset / sizeof(size_t));
+}
+
+static inline void buffer_push(struct ewah_bitmap *self, eword_t value)
+{
+ if (self->buffer_size + 1 >= self->alloc_size)
+ buffer_grow(self, self->buffer_size * 3 / 2);
+
+ self->buffer[self->buffer_size++] = value;
+}
+
+static void buffer_push_rlw(struct ewah_bitmap *self, eword_t value)
+{
+ buffer_push(self, value);
+ self->rlw = self->buffer + self->buffer_size - 1;
+}
+
+static size_t add_empty_words(struct ewah_bitmap *self, int v, size_t number)
+{
+ size_t added = 0;
+ eword_t runlen, can_add;
+
+ if (rlw_get_run_bit(self->rlw) != v && rlw_size(self->rlw) == 0) {
+ rlw_set_run_bit(self->rlw, v);
+ } else if (rlw_get_literal_words(self->rlw) != 0 ||
+ rlw_get_run_bit(self->rlw) != v) {
+ buffer_push_rlw(self, 0);
+ if (v) rlw_set_run_bit(self->rlw, v);
+ added++;
+ }
+
+ runlen = rlw_get_running_len(self->rlw);
+ can_add = min_size(number, RLW_LARGEST_RUNNING_COUNT - runlen);
+
+ rlw_set_running_len(self->rlw, runlen + can_add);
+ number -= can_add;
+
+ while (number >= RLW_LARGEST_RUNNING_COUNT) {
+ buffer_push_rlw(self, 0);
+ added++;
+ if (v) rlw_set_run_bit(self->rlw, v);
+ rlw_set_running_len(self->rlw, RLW_LARGEST_RUNNING_COUNT);
+ number -= RLW_LARGEST_RUNNING_COUNT;
+ }
+
+ if (number > 0) {
+ buffer_push_rlw(self, 0);
+ added++;
+
+ if (v) rlw_set_run_bit(self->rlw, v);
+ rlw_set_running_len(self->rlw, number);
+ }
+
+ return added;
+}
+
+size_t ewah_add_empty_words(struct ewah_bitmap *self, int v, size_t number)
+{
+ if (number == 0)
+ return 0;
+
+ self->bit_size += number * BITS_IN_WORD;
+ return add_empty_words(self, v, number);
+}
+
+static size_t add_literal(struct ewah_bitmap *self, eword_t new_data)
+{
+ eword_t current_num = rlw_get_literal_words(self->rlw);
+
+ if (current_num >= RLW_LARGEST_LITERAL_COUNT) {
+ buffer_push_rlw(self, 0);
+
+ rlw_set_literal_words(self->rlw, 1);
+ buffer_push(self, new_data);
+ return 2;
+ }
+
+ rlw_set_literal_words(self->rlw, current_num + 1);
+
+ /* sanity check */
+ assert(rlw_get_literal_words(self->rlw) == current_num + 1);
+
+ buffer_push(self, new_data);
+ return 1;
+}
+
+void ewah_add_dirty_words(
+ struct ewah_bitmap *self, const eword_t *buffer,
+ size_t number, int negate)
+{
+ size_t literals, can_add;
+
+ while (1) {
+ literals = rlw_get_literal_words(self->rlw);
+ can_add = min_size(number, RLW_LARGEST_LITERAL_COUNT - literals);
+
+ rlw_set_literal_words(self->rlw, literals + can_add);
+
+ if (self->buffer_size + can_add >= self->alloc_size)
+ buffer_grow(self, (self->buffer_size + can_add) * 3 / 2);
+
+ if (negate) {
+ size_t i;
+ for (i = 0; i < can_add; ++i)
+ self->buffer[self->buffer_size++] = ~buffer[i];
+ } else {
+ memcpy(self->buffer + self->buffer_size,
+ buffer, can_add * sizeof(eword_t));
+ self->buffer_size += can_add;
+ }
+
+ self->bit_size += can_add * BITS_IN_WORD;
+
+ if (number - can_add == 0)
+ break;
+
+ buffer_push_rlw(self, 0);
+ buffer += can_add;
+ number -= can_add;
+ }
+}
+
+static size_t add_empty_word(struct ewah_bitmap *self, int v)
+{
+ int no_literal = (rlw_get_literal_words(self->rlw) == 0);
+ eword_t run_len = rlw_get_running_len(self->rlw);
+
+ if (no_literal && run_len == 0) {
+ rlw_set_run_bit(self->rlw, v);
+ assert(rlw_get_run_bit(self->rlw) == v);
+ }
+
+ if (no_literal && rlw_get_run_bit(self->rlw) == v &&
+ run_len < RLW_LARGEST_RUNNING_COUNT) {
+ rlw_set_running_len(self->rlw, run_len + 1);
+ assert(rlw_get_running_len(self->rlw) == run_len + 1);
+ return 0;
+ } else {
+ buffer_push_rlw(self, 0);
+
+ assert(rlw_get_running_len(self->rlw) == 0);
+ assert(rlw_get_run_bit(self->rlw) == 0);
+ assert(rlw_get_literal_words(self->rlw) == 0);
+
+ rlw_set_run_bit(self->rlw, v);
+ assert(rlw_get_run_bit(self->rlw) == v);
+
+ rlw_set_running_len(self->rlw, 1);
+ assert(rlw_get_running_len(self->rlw) == 1);
+ assert(rlw_get_literal_words(self->rlw) == 0);
+ return 1;
+ }
+}
+
+size_t ewah_add(struct ewah_bitmap *self, eword_t word)
+{
+ self->bit_size += BITS_IN_WORD;
+
+ if (word == 0)
+ return add_empty_word(self, 0);
+
+ if (word == (eword_t)(~0))
+ return add_empty_word(self, 1);
+
+ return add_literal(self, word);
+}
+
+void ewah_set(struct ewah_bitmap *self, size_t i)
+{
+ const size_t dist =
+ (i + BITS_IN_WORD) / BITS_IN_WORD -
+ (self->bit_size + BITS_IN_WORD - 1) / BITS_IN_WORD;
+
+ assert(i >= self->bit_size);
+
+ self->bit_size = i + 1;
+
+ if (dist > 0) {
+ if (dist > 1)
+ add_empty_words(self, 0, dist - 1);
+
+ add_literal(self, (eword_t)1 << (i % BITS_IN_WORD));
+ return;
+ }
+
+ if (rlw_get_literal_words(self->rlw) == 0) {
+ rlw_set_running_len(self->rlw,
+ rlw_get_running_len(self->rlw) - 1);
+ add_literal(self, (eword_t)1 << (i % BITS_IN_WORD));
+ return;
+ }
+
+ self->buffer[self->buffer_size - 1] |=
+ ((eword_t)1 << (i % BITS_IN_WORD));
+
+ /* check if we just completed a stream of 1s */
+ if (self->buffer[self->buffer_size - 1] == (eword_t)(~0)) {
+ self->buffer[--self->buffer_size] = 0;
+ rlw_set_literal_words(self->rlw,
+ rlw_get_literal_words(self->rlw) - 1);
+ add_empty_word(self, 1);
+ }
+}
+
+void ewah_each_bit(struct ewah_bitmap *self, void (*callback)(size_t, void*), void *payload)
+{
+ size_t pos = 0;
+ size_t pointer = 0;
+ size_t k;
+
+ while (pointer < self->buffer_size) {
+ eword_t *word = &self->buffer[pointer];
+
+ if (rlw_get_run_bit(word)) {
+ size_t len = rlw_get_running_len(word) * BITS_IN_WORD;
+ for (k = 0; k < len; ++k, ++pos)
+ callback(pos, payload);
+ } else {
+ pos += rlw_get_running_len(word) * BITS_IN_WORD;
+ }
+
+ ++pointer;
+
+ for (k = 0; k < rlw_get_literal_words(word); ++k) {
+ int c;
+
+ /* todo: zero count optimization */
+ for (c = 0; c < BITS_IN_WORD; ++c, ++pos) {
+ if ((self->buffer[pointer] & ((eword_t)1 << c)) != 0)
+ callback(pos, payload);
+ }
+
+ ++pointer;
+ }
+ }
+}
+
+struct ewah_bitmap *ewah_new(void)
+{
+ struct ewah_bitmap *self;
+
+ self = ewah_malloc(sizeof(struct ewah_bitmap));
+ if (self == NULL)
+ return NULL;
+
+ self->buffer = ewah_malloc(32 * sizeof(eword_t));
+ self->alloc_size = 32;
+
+ ewah_clear(self);
+ return self;
+}
+
+void ewah_clear(struct ewah_bitmap *self)
+{
+ self->buffer_size = 1;
+ self->buffer[0] = 0;
+ self->bit_size = 0;
+ self->rlw = self->buffer;
+}
+
+void ewah_free(struct ewah_bitmap *self)
+{
+ if (!self)
+ return;
+
+ if (self->alloc_size)
+ free(self->buffer);
+
+ free(self);
+}
+
+static void read_new_rlw(struct ewah_iterator *it)
+{
+ const eword_t *word = NULL;
+
+ it->literals = 0;
+ it->compressed = 0;
+
+ while (1) {
+ word = &it->buffer[it->pointer];
+
+ it->rl = rlw_get_running_len(word);
+ it->lw = rlw_get_literal_words(word);
+ it->b = rlw_get_run_bit(word);
+
+ if (it->rl || it->lw)
+ return;
+
+ if (it->pointer < it->buffer_size - 1) {
+ it->pointer++;
+ } else {
+ it->pointer = it->buffer_size;
+ return;
+ }
+ }
+}
+
+int ewah_iterator_next(eword_t *next, struct ewah_iterator *it)
+{
+ if (it->pointer >= it->buffer_size)
+ return 0;
+
+ if (it->compressed < it->rl) {
+ it->compressed++;
+ *next = it->b ? (eword_t)(~0) : 0;
+ } else {
+ assert(it->literals < it->lw);
+
+ it->literals++;
+ it->pointer++;
+
+ assert(it->pointer < it->buffer_size);
+
+ *next = it->buffer[it->pointer];
+ }
+
+ if (it->compressed == it->rl && it->literals == it->lw) {
+ if (++it->pointer < it->buffer_size)
+ read_new_rlw(it);
+ }
+
+ return 1;
+}
+
+void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent)
+{
+ it->buffer = parent->buffer;
+ it->buffer_size = parent->buffer_size;
+ it->pointer = 0;
+
+ it->lw = 0;
+ it->rl = 0;
+ it->compressed = 0;
+ it->literals = 0;
+ it->b = 0;
+
+ if (it->pointer < it->buffer_size)
+ read_new_rlw(it);
+}
+
+void ewah_not(struct ewah_bitmap *self)
+{
+ size_t pointer = 0;
+
+ while (pointer < self->buffer_size) {
+ eword_t *word = &self->buffer[pointer];
+ size_t literals, k;
+
+ rlw_xor_run_bit(word);
+ ++pointer;
+
+ literals = rlw_get_literal_words(word);
+ for (k = 0; k < literals; ++k) {
+ self->buffer[pointer] = ~self->buffer[pointer];
+ ++pointer;
+ }
+ }
+}
+
+void ewah_xor(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out)
+{
+ struct rlw_iterator rlw_i;
+ struct rlw_iterator rlw_j;
+ size_t literals;
+
+ rlwit_init(&rlw_i, ewah_i);
+ rlwit_init(&rlw_j, ewah_j);
+
+ while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
+ while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
+ struct rlw_iterator *prey, *predator;
+ size_t index;
+ int negate_words;
+
+ if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
+ prey = &rlw_i;
+ predator = &rlw_j;
+ } else {
+ prey = &rlw_j;
+ predator = &rlw_i;
+ }
+
+ negate_words = !!predator->rlw.running_bit;
+ index = rlwit_discharge(prey, out,
+ predator->rlw.running_len, negate_words);
+
+ ewah_add_empty_words(out, negate_words,
+ predator->rlw.running_len - index);
+
+ rlwit_discard_first_words(predator,
+ predator->rlw.running_len);
+ }
+
+ literals = min_size(
+ rlw_i.rlw.literal_words,
+ rlw_j.rlw.literal_words);
+
+ if (literals) {
+ size_t k;
+
+ for (k = 0; k < literals; ++k) {
+ ewah_add(out,
+ rlw_i.buffer[rlw_i.literal_word_start + k] ^
+ rlw_j.buffer[rlw_j.literal_word_start + k]
+ );
+ }
+
+ rlwit_discard_first_words(&rlw_i, literals);
+ rlwit_discard_first_words(&rlw_j, literals);
+ }
+ }
+
+ if (rlwit_word_size(&rlw_i) > 0)
+ rlwit_discharge(&rlw_i, out, ~0, 0);
+ else
+ rlwit_discharge(&rlw_j, out, ~0, 0);
+
+ out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
+}
+
+void ewah_and(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out)
+{
+ struct rlw_iterator rlw_i;
+ struct rlw_iterator rlw_j;
+ size_t literals;
+
+ rlwit_init(&rlw_i, ewah_i);
+ rlwit_init(&rlw_j, ewah_j);
+
+ while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
+ while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
+ struct rlw_iterator *prey, *predator;
+
+ if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
+ prey = &rlw_i;
+ predator = &rlw_j;
+ } else {
+ prey = &rlw_j;
+ predator = &rlw_i;
+ }
+
+ if (predator->rlw.running_bit == 0) {
+ ewah_add_empty_words(out, 0,
+ predator->rlw.running_len);
+ rlwit_discard_first_words(prey,
+ predator->rlw.running_len);
+ rlwit_discard_first_words(predator,
+ predator->rlw.running_len);
+ } else {
+ size_t index = rlwit_discharge(prey, out,
+ predator->rlw.running_len, 0);
+ ewah_add_empty_words(out, 0,
+ predator->rlw.running_len - index);
+ rlwit_discard_first_words(predator,
+ predator->rlw.running_len);
+ }
+ }
+
+ literals = min_size(
+ rlw_i.rlw.literal_words,
+ rlw_j.rlw.literal_words);
+
+ if (literals) {
+ size_t k;
+
+ for (k = 0; k < literals; ++k) {
+ ewah_add(out,
+ rlw_i.buffer[rlw_i.literal_word_start + k] &
+ rlw_j.buffer[rlw_j.literal_word_start + k]
+ );
+ }
+
+ rlwit_discard_first_words(&rlw_i, literals);
+ rlwit_discard_first_words(&rlw_j, literals);
+ }
+ }
+
+ if (rlwit_word_size(&rlw_i) > 0)
+ rlwit_discharge_empty(&rlw_i, out);
+ else
+ rlwit_discharge_empty(&rlw_j, out);
+
+ out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
+}
+
+void ewah_and_not(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out)
+{
+ struct rlw_iterator rlw_i;
+ struct rlw_iterator rlw_j;
+ size_t literals;
+
+ rlwit_init(&rlw_i, ewah_i);
+ rlwit_init(&rlw_j, ewah_j);
+
+ while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
+ while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
+ struct rlw_iterator *prey, *predator;
+
+ if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
+ prey = &rlw_i;
+ predator = &rlw_j;
+ } else {
+ prey = &rlw_j;
+ predator = &rlw_i;
+ }
+
+ if ((predator->rlw.running_bit && prey == &rlw_i) ||
+ (!predator->rlw.running_bit && prey != &rlw_i)) {
+ ewah_add_empty_words(out, 0,
+ predator->rlw.running_len);
+ rlwit_discard_first_words(prey,
+ predator->rlw.running_len);
+ rlwit_discard_first_words(predator,
+ predator->rlw.running_len);
+ } else {
+ size_t index;
+ int negate_words;
+
+ negate_words = (&rlw_i != prey);
+ index = rlwit_discharge(prey, out,
+ predator->rlw.running_len, negate_words);
+ ewah_add_empty_words(out, negate_words,
+ predator->rlw.running_len - index);
+ rlwit_discard_first_words(predator,
+ predator->rlw.running_len);
+ }
+ }
+
+ literals = min_size(
+ rlw_i.rlw.literal_words,
+ rlw_j.rlw.literal_words);
+
+ if (literals) {
+ size_t k;
+
+ for (k = 0; k < literals; ++k) {
+ ewah_add(out,
+ rlw_i.buffer[rlw_i.literal_word_start + k] &
+ ~(rlw_j.buffer[rlw_j.literal_word_start + k])
+ );
+ }
+
+ rlwit_discard_first_words(&rlw_i, literals);
+ rlwit_discard_first_words(&rlw_j, literals);
+ }
+ }
+
+ if (rlwit_word_size(&rlw_i) > 0)
+ rlwit_discharge(&rlw_i, out, ~0, 0);
+ else
+ rlwit_discharge_empty(&rlw_j, out);
+
+ out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
+}
+
+void ewah_or(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out)
+{
+ struct rlw_iterator rlw_i;
+ struct rlw_iterator rlw_j;
+ size_t literals;
+
+ rlwit_init(&rlw_i, ewah_i);
+ rlwit_init(&rlw_j, ewah_j);
+
+ while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
+ while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
+ struct rlw_iterator *prey, *predator;
+
+ if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
+ prey = &rlw_i;
+ predator = &rlw_j;
+ } else {
+ prey = &rlw_j;
+ predator = &rlw_i;
+ }
+
+ if (predator->rlw.running_bit) {
+ ewah_add_empty_words(out, 0,
+ predator->rlw.running_len);
+ rlwit_discard_first_words(prey,
+ predator->rlw.running_len);
+ rlwit_discard_first_words(predator,
+ predator->rlw.running_len);
+ } else {
+ size_t index = rlwit_discharge(prey, out,
+ predator->rlw.running_len, 0);
+ ewah_add_empty_words(out, 0,
+ predator->rlw.running_len - index);
+ rlwit_discard_first_words(predator,
+ predator->rlw.running_len);
+ }
+ }
+
+ literals = min_size(
+ rlw_i.rlw.literal_words,
+ rlw_j.rlw.literal_words);
+
+ if (literals) {
+ size_t k;
+
+ for (k = 0; k < literals; ++k) {
+ ewah_add(out,
+ rlw_i.buffer[rlw_i.literal_word_start + k] |
+ rlw_j.buffer[rlw_j.literal_word_start + k]
+ );
+ }
+
+ rlwit_discard_first_words(&rlw_i, literals);
+ rlwit_discard_first_words(&rlw_j, literals);
+ }
+ }
+
+ if (rlwit_word_size(&rlw_i) > 0)
+ rlwit_discharge(&rlw_i, out, ~0, 0);
+ else
+ rlwit_discharge(&rlw_j, out, ~0, 0);
+
+ out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
+}
+
+
+#define BITMAP_POOL_MAX 16
+static struct ewah_bitmap *bitmap_pool[BITMAP_POOL_MAX];
+static size_t bitmap_pool_size;
+
+struct ewah_bitmap *ewah_pool_new(void)
+{
+ if (bitmap_pool_size)
+ return bitmap_pool[--bitmap_pool_size];
+
+ return ewah_new();
+}
+
+void ewah_pool_free(struct ewah_bitmap *self)
+{
+ if (self == NULL)
+ return;
+
+ if (bitmap_pool_size == BITMAP_POOL_MAX ||
+ self->alloc_size == 0) {
+ ewah_free(self);
+ return;
+ }
+
+ ewah_clear(self);
+ bitmap_pool[bitmap_pool_size++] = self;
+}
+
+uint32_t ewah_checksum(struct ewah_bitmap *self)
+{
+ const uint8_t *p = (uint8_t *)self->buffer;
+ uint32_t crc = (uint32_t)self->bit_size;
+ size_t size = self->buffer_size * sizeof(eword_t);
+
+ while (size--)
+ crc = (crc << 5) - crc + (uint32_t)*p++;
+
+ return crc;
+}
diff --git a/ewah/ewah_io.c b/ewah/ewah_io.c
new file mode 100644
index 0000000000..f7f700ef51
--- /dev/null
+++ b/ewah/ewah_io.c
@@ -0,0 +1,204 @@
+/**
+ * Copyright 2013, GitHub, Inc
+ * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
+ * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "git-compat-util.h"
+#include "ewok.h"
+
+int ewah_serialize_native(struct ewah_bitmap *self, int fd)
+{
+ uint32_t write32;
+ size_t to_write = self->buffer_size * 8;
+
+ /* 32 bit -- bit size for the map */
+ write32 = (uint32_t)self->bit_size;
+ if (write(fd, &write32, 4) != 4)
+ return -1;
+
+ /** 32 bit -- number of compressed 64-bit words */
+ write32 = (uint32_t)self->buffer_size;
+ if (write(fd, &write32, 4) != 4)
+ return -1;
+
+ if (write(fd, self->buffer, to_write) != to_write)
+ return -1;
+
+ /** 32 bit -- position for the RLW */
+ write32 = self->rlw - self->buffer;
+ if (write(fd, &write32, 4) != 4)
+ return -1;
+
+ return (3 * 4) + to_write;
+}
+
+int ewah_serialize_to(struct ewah_bitmap *self,
+ int (*write_fun)(void *, const void *, size_t),
+ void *data)
+{
+ size_t i;
+ eword_t dump[2048];
+ const size_t words_per_dump = sizeof(dump) / sizeof(eword_t);
+ uint32_t bitsize, word_count, rlw_pos;
+
+ const eword_t *buffer;
+ size_t words_left;
+
+ /* 32 bit -- bit size for the map */
+ bitsize = htonl((uint32_t)self->bit_size);
+ if (write_fun(data, &bitsize, 4) != 4)
+ return -1;
+
+ /** 32 bit -- number of compressed 64-bit words */
+ word_count = htonl((uint32_t)self->buffer_size);
+ if (write_fun(data, &word_count, 4) != 4)
+ return -1;
+
+ /** 64 bit x N -- compressed words */
+ buffer = self->buffer;
+ words_left = self->buffer_size;
+
+ while (words_left >= words_per_dump) {
+ for (i = 0; i < words_per_dump; ++i, ++buffer)
+ dump[i] = htonll(*buffer);
+
+ if (write_fun(data, dump, sizeof(dump)) != sizeof(dump))
+ return -1;
+
+ words_left -= words_per_dump;
+ }
+
+ if (words_left) {
+ for (i = 0; i < words_left; ++i, ++buffer)
+ dump[i] = htonll(*buffer);
+
+ if (write_fun(data, dump, words_left * 8) != words_left * 8)
+ return -1;
+ }
+
+ /** 32 bit -- position for the RLW */
+ rlw_pos = (uint8_t*)self->rlw - (uint8_t *)self->buffer;
+ rlw_pos = htonl(rlw_pos / sizeof(eword_t));
+
+ if (write_fun(data, &rlw_pos, 4) != 4)
+ return -1;
+
+ return (3 * 4) + (self->buffer_size * 8);
+}
+
+static int write_helper(void *fd, const void *buf, size_t len)
+{
+ return write((intptr_t)fd, buf, len);
+}
+
+int ewah_serialize(struct ewah_bitmap *self, int fd)
+{
+ return ewah_serialize_to(self, write_helper, (void *)(intptr_t)fd);
+}
+
+int ewah_read_mmap(struct ewah_bitmap *self, void *map, size_t len)
+{
+ uint8_t *ptr = map;
+ size_t i;
+
+ self->bit_size = get_be32(ptr);
+ ptr += sizeof(uint32_t);
+
+ self->buffer_size = self->alloc_size = get_be32(ptr);
+ ptr += sizeof(uint32_t);
+
+ self->buffer = ewah_realloc(self->buffer,
+ self->alloc_size * sizeof(eword_t));
+
+ if (!self->buffer)
+ return -1;
+
+ /*
+ * Copy the raw data for the bitmap as a whole chunk;
+ * if we're in a little-endian platform, we'll perform
+ * the endianness conversion in a separate pass to ensure
+ * we're loading 8-byte aligned words.
+ */
+ memcpy(self->buffer, ptr, self->buffer_size * sizeof(uint64_t));
+ ptr += self->buffer_size * sizeof(uint64_t);
+
+ for (i = 0; i < self->buffer_size; ++i)
+ self->buffer[i] = ntohll(self->buffer[i]);
+
+ self->rlw = self->buffer + get_be32(ptr);
+
+ return (3 * 4) + (self->buffer_size * 8);
+}
+
+int ewah_deserialize(struct ewah_bitmap *self, int fd)
+{
+ size_t i;
+ eword_t dump[2048];
+ const size_t words_per_dump = sizeof(dump) / sizeof(eword_t);
+ uint32_t bitsize, word_count, rlw_pos;
+
+ eword_t *buffer = NULL;
+ size_t words_left;
+
+ ewah_clear(self);
+
+ /* 32 bit -- bit size for the map */
+ if (read(fd, &bitsize, 4) != 4)
+ return -1;
+
+ self->bit_size = (size_t)ntohl(bitsize);
+
+ /** 32 bit -- number of compressed 64-bit words */
+ if (read(fd, &word_count, 4) != 4)
+ return -1;
+
+ self->buffer_size = self->alloc_size = (size_t)ntohl(word_count);
+ self->buffer = ewah_realloc(self->buffer,
+ self->alloc_size * sizeof(eword_t));
+
+ if (!self->buffer)
+ return -1;
+
+ /** 64 bit x N -- compressed words */
+ buffer = self->buffer;
+ words_left = self->buffer_size;
+
+ while (words_left >= words_per_dump) {
+ if (read(fd, dump, sizeof(dump)) != sizeof(dump))
+ return -1;
+
+ for (i = 0; i < words_per_dump; ++i, ++buffer)
+ *buffer = ntohll(dump[i]);
+
+ words_left -= words_per_dump;
+ }
+
+ if (words_left) {
+ if (read(fd, dump, words_left * 8) != words_left * 8)
+ return -1;
+
+ for (i = 0; i < words_left; ++i, ++buffer)
+ *buffer = ntohll(dump[i]);
+ }
+
+ /** 32 bit -- position for the RLW */
+ if (read(fd, &rlw_pos, 4) != 4)
+ return -1;
+
+ self->rlw = self->buffer + ntohl(rlw_pos);
+ return 0;
+}
diff --git a/ewah/ewah_rlw.c b/ewah/ewah_rlw.c
new file mode 100644
index 0000000000..c723f1aefd
--- /dev/null
+++ b/ewah/ewah_rlw.c
@@ -0,0 +1,115 @@
+/**
+ * Copyright 2013, GitHub, Inc
+ * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
+ * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "git-compat-util.h"
+#include "ewok.h"
+#include "ewok_rlw.h"
+
+static inline int next_word(struct rlw_iterator *it)
+{
+ if (it->pointer >= it->size)
+ return 0;
+
+ it->rlw.word = &it->buffer[it->pointer];
+ it->pointer += rlw_get_literal_words(it->rlw.word) + 1;
+
+ it->rlw.literal_words = rlw_get_literal_words(it->rlw.word);
+ it->rlw.running_len = rlw_get_running_len(it->rlw.word);
+ it->rlw.running_bit = rlw_get_run_bit(it->rlw.word);
+ it->rlw.literal_word_offset = 0;
+
+ return 1;
+}
+
+void rlwit_init(struct rlw_iterator *it, struct ewah_bitmap *from_ewah)
+{
+ it->buffer = from_ewah->buffer;
+ it->size = from_ewah->buffer_size;
+ it->pointer = 0;
+
+ next_word(it);
+
+ it->literal_word_start = rlwit_literal_words(it) +
+ it->rlw.literal_word_offset;
+}
+
+void rlwit_discard_first_words(struct rlw_iterator *it, size_t x)
+{
+ while (x > 0) {
+ size_t discard;
+
+ if (it->rlw.running_len > x) {
+ it->rlw.running_len -= x;
+ return;
+ }
+
+ x -= it->rlw.running_len;
+ it->rlw.running_len = 0;
+
+ discard = (x > it->rlw.literal_words) ? it->rlw.literal_words : x;
+
+ it->literal_word_start += discard;
+ it->rlw.literal_words -= discard;
+ x -= discard;
+
+ if (x > 0 || rlwit_word_size(it) == 0) {
+ if (!next_word(it))
+ break;
+
+ it->literal_word_start =
+ rlwit_literal_words(it) + it->rlw.literal_word_offset;
+ }
+ }
+}
+
+size_t rlwit_discharge(
+ struct rlw_iterator *it, struct ewah_bitmap *out, size_t max, int negate)
+{
+ size_t index = 0;
+
+ while (index < max && rlwit_word_size(it) > 0) {
+ size_t pd, pl = it->rlw.running_len;
+
+ if (index + pl > max)
+ pl = max - index;
+
+ ewah_add_empty_words(out, it->rlw.running_bit ^ negate, pl);
+ index += pl;
+
+ pd = it->rlw.literal_words;
+ if (pd + index > max)
+ pd = max - index;
+
+ ewah_add_dirty_words(out,
+ it->buffer + it->literal_word_start, pd, negate);
+
+ rlwit_discard_first_words(it, pd + pl);
+ index += pd;
+ }
+
+ return index;
+}
+
+void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out)
+{
+ while (rlwit_word_size(it) > 0) {
+ ewah_add_empty_words(out, 0, rlwit_word_size(it));
+ rlwit_discard_first_words(it, rlwit_word_size(it));
+ }
+}
diff --git a/ewah/ewok.h b/ewah/ewok.h
new file mode 100644
index 0000000000..43adeb5c68
--- /dev/null
+++ b/ewah/ewok.h
@@ -0,0 +1,233 @@
+/**
+ * Copyright 2013, GitHub, Inc
+ * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
+ * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef __EWOK_BITMAP_H__
+#define __EWOK_BITMAP_H__
+
+#ifndef ewah_malloc
+# define ewah_malloc xmalloc
+#endif
+#ifndef ewah_realloc
+# define ewah_realloc xrealloc
+#endif
+#ifndef ewah_calloc
+# define ewah_calloc xcalloc
+#endif
+
+typedef uint64_t eword_t;
+#define BITS_IN_WORD (sizeof(eword_t) * 8)
+
+/**
+ * Do not use __builtin_popcountll. The GCC implementation
+ * is notoriously slow on all platforms.
+ *
+ * See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36041
+ */
+static inline uint32_t ewah_bit_popcount64(uint64_t x)
+{
+ x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL);
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+ x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL);
+ return (x * 0x0101010101010101ULL) >> 56;
+}
+
+#ifdef __GNUC__
+#define ewah_bit_ctz64(x) __builtin_ctzll(x)
+#else
+static inline int ewah_bit_ctz64(uint64_t x)
+{
+ int n = 0;
+ if ((x & 0xffffffff) == 0) { x >>= 32; n += 32; }
+ if ((x & 0xffff) == 0) { x >>= 16; n += 16; }
+ if ((x & 0xff) == 0) { x >>= 8; n += 8; }
+ if ((x & 0xf) == 0) { x >>= 4; n += 4; }
+ if ((x & 0x3) == 0) { x >>= 2; n += 2; }
+ if ((x & 0x1) == 0) { x >>= 1; n += 1; }
+ return n + !x;
+}
+#endif
+
+struct ewah_bitmap {
+ eword_t *buffer;
+ size_t buffer_size;
+ size_t alloc_size;
+ size_t bit_size;
+ eword_t *rlw;
+};
+
+typedef void (*ewah_callback)(size_t pos, void *);
+
+struct ewah_bitmap *ewah_pool_new(void);
+void ewah_pool_free(struct ewah_bitmap *self);
+
+/**
+ * Allocate a new EWAH Compressed bitmap
+ */
+struct ewah_bitmap *ewah_new(void);
+
+/**
+ * Clear all the bits in the bitmap. Does not free or resize
+ * memory.
+ */
+void ewah_clear(struct ewah_bitmap *self);
+
+/**
+ * Free all the memory of the bitmap
+ */
+void ewah_free(struct ewah_bitmap *self);
+
+int ewah_serialize_to(struct ewah_bitmap *self,
+ int (*write_fun)(void *out, const void *buf, size_t len),
+ void *out);
+int ewah_serialize(struct ewah_bitmap *self, int fd);
+int ewah_serialize_native(struct ewah_bitmap *self, int fd);
+
+int ewah_deserialize(struct ewah_bitmap *self, int fd);
+int ewah_read_mmap(struct ewah_bitmap *self, void *map, size_t len);
+int ewah_read_mmap_native(struct ewah_bitmap *self, void *map, size_t len);
+
+uint32_t ewah_checksum(struct ewah_bitmap *self);
+
+/**
+ * Logical not (bitwise negation) in-place on the bitmap
+ *
+ * This operation is linear time based on the size of the bitmap.
+ */
+void ewah_not(struct ewah_bitmap *self);
+
+/**
+ * Call the given callback with the position of every single bit
+ * that has been set on the bitmap.
+ *
+ * This is an efficient operation that does not fully decompress
+ * the bitmap.
+ */
+void ewah_each_bit(struct ewah_bitmap *self, ewah_callback callback, void *payload);
+
+/**
+ * Set a given bit on the bitmap.
+ *
+ * The bit at position `pos` will be set to true. Because of the
+ * way that the bitmap is compressed, a set bit cannot be unset
+ * later on.
+ *
+ * Furthermore, since the bitmap uses streaming compression, bits
+ * can only set incrementally.
+ *
+ * E.g.
+ * ewah_set(bitmap, 1); // ok
+ * ewah_set(bitmap, 76); // ok
+ * ewah_set(bitmap, 77); // ok
+ * ewah_set(bitmap, 8712800127); // ok
+ * ewah_set(bitmap, 25); // failed, assert raised
+ */
+void ewah_set(struct ewah_bitmap *self, size_t i);
+
+struct ewah_iterator {
+ const eword_t *buffer;
+ size_t buffer_size;
+
+ size_t pointer;
+ eword_t compressed, literals;
+ eword_t rl, lw;
+ int b;
+};
+
+/**
+ * Initialize a new iterator to run through the bitmap in uncompressed form.
+ *
+ * The iterator can be stack allocated. The underlying bitmap must not be freed
+ * before the iteration is over.
+ *
+ * E.g.
+ *
+ * struct ewah_bitmap *bitmap = ewah_new();
+ * struct ewah_iterator it;
+ *
+ * ewah_iterator_init(&it, bitmap);
+ */
+void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent);
+
+/**
+ * Yield every single word in the bitmap in uncompressed form. This is:
+ * yield single words (32-64 bits) where each bit represents an actual
+ * bit from the bitmap.
+ *
+ * Return: true if a word was yield, false if there are no words left
+ */
+int ewah_iterator_next(eword_t *next, struct ewah_iterator *it);
+
+void ewah_or(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out);
+
+void ewah_and_not(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out);
+
+void ewah_xor(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out);
+
+void ewah_and(
+ struct ewah_bitmap *ewah_i,
+ struct ewah_bitmap *ewah_j,
+ struct ewah_bitmap *out);
+
+/**
+ * Direct word access
+ */
+size_t ewah_add_empty_words(struct ewah_bitmap *self, int v, size_t number);
+void ewah_add_dirty_words(
+ struct ewah_bitmap *self, const eword_t *buffer, size_t number, int negate);
+size_t ewah_add(struct ewah_bitmap *self, eword_t word);
+
+
+/**
+ * Uncompressed, old-school bitmap that can be efficiently compressed
+ * into an `ewah_bitmap`.
+ */
+struct bitmap {
+ eword_t *words;
+ size_t word_alloc;
+};
+
+struct bitmap *bitmap_new(void);
+void bitmap_set(struct bitmap *self, size_t pos);
+void bitmap_clear(struct bitmap *self, size_t pos);
+int bitmap_get(struct bitmap *self, size_t pos);
+void bitmap_reset(struct bitmap *self);
+void bitmap_free(struct bitmap *self);
+int bitmap_equals(struct bitmap *self, struct bitmap *other);
+int bitmap_is_subset(struct bitmap *self, struct bitmap *super);
+
+struct ewah_bitmap * bitmap_to_ewah(struct bitmap *bitmap);
+struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah);
+
+void bitmap_and_not(struct bitmap *self, struct bitmap *other);
+void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other);
+void bitmap_or(struct bitmap *self, const struct bitmap *other);
+
+void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data);
+size_t bitmap_popcount(struct bitmap *self);
+
+#endif
diff --git a/ewah/ewok_rlw.h b/ewah/ewok_rlw.h
new file mode 100644
index 0000000000..63efdf9698
--- /dev/null
+++ b/ewah/ewok_rlw.h
@@ -0,0 +1,114 @@
+/**
+ * Copyright 2013, GitHub, Inc
+ * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
+ * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef __EWOK_RLW_H__
+#define __EWOK_RLW_H__
+
+#define RLW_RUNNING_BITS (sizeof(eword_t) * 4)
+#define RLW_LITERAL_BITS (sizeof(eword_t) * 8 - 1 - RLW_RUNNING_BITS)
+
+#define RLW_LARGEST_RUNNING_COUNT (((eword_t)1 << RLW_RUNNING_BITS) - 1)
+#define RLW_LARGEST_LITERAL_COUNT (((eword_t)1 << RLW_LITERAL_BITS) - 1)
+
+#define RLW_LARGEST_RUNNING_COUNT_SHIFT (RLW_LARGEST_RUNNING_COUNT << 1)
+
+#define RLW_RUNNING_LEN_PLUS_BIT (((eword_t)1 << (RLW_RUNNING_BITS + 1)) - 1)
+
+static int rlw_get_run_bit(const eword_t *word)
+{
+ return *word & (eword_t)1;
+}
+
+static inline void rlw_set_run_bit(eword_t *word, int b)
+{
+ if (b) {
+ *word |= (eword_t)1;
+ } else {
+ *word &= (eword_t)(~1);
+ }
+}
+
+static inline void rlw_xor_run_bit(eword_t *word)
+{
+ if (*word & 1) {
+ *word &= (eword_t)(~1);
+ } else {
+ *word |= (eword_t)1;
+ }
+}
+
+static inline void rlw_set_running_len(eword_t *word, eword_t l)
+{
+ *word |= RLW_LARGEST_RUNNING_COUNT_SHIFT;
+ *word &= (l << 1) | (~RLW_LARGEST_RUNNING_COUNT_SHIFT);
+}
+
+static inline eword_t rlw_get_running_len(const eword_t *word)
+{
+ return (*word >> 1) & RLW_LARGEST_RUNNING_COUNT;
+}
+
+static inline eword_t rlw_get_literal_words(const eword_t *word)
+{
+ return *word >> (1 + RLW_RUNNING_BITS);
+}
+
+static inline void rlw_set_literal_words(eword_t *word, eword_t l)
+{
+ *word |= ~RLW_RUNNING_LEN_PLUS_BIT;
+ *word &= (l << (RLW_RUNNING_BITS + 1)) | RLW_RUNNING_LEN_PLUS_BIT;
+}
+
+static inline eword_t rlw_size(const eword_t *self)
+{
+ return rlw_get_running_len(self) + rlw_get_literal_words(self);
+}
+
+struct rlw_iterator {
+ const eword_t *buffer;
+ size_t size;
+ size_t pointer;
+ size_t literal_word_start;
+
+ struct {
+ const eword_t *word;
+ int literal_words;
+ int running_len;
+ int literal_word_offset;
+ int running_bit;
+ } rlw;
+};
+
+void rlwit_init(struct rlw_iterator *it, struct ewah_bitmap *bitmap);
+void rlwit_discard_first_words(struct rlw_iterator *it, size_t x);
+size_t rlwit_discharge(
+ struct rlw_iterator *it, struct ewah_bitmap *out, size_t max, int negate);
+void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out);
+
+static inline size_t rlwit_word_size(struct rlw_iterator *it)
+{
+ return it->rlw.running_len + it->rlw.literal_words;
+}
+
+static inline size_t rlwit_literal_words(struct rlw_iterator *it)
+{
+ return it->pointer - it->rlw.literal_words;
+}
+
+#endif
diff --git a/fetch-pack.c b/fetch-pack.c
index 90fdd49821..f061f1fe85 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -439,7 +439,8 @@ done:
}
strbuf_release(&req_buf);
- consume_shallow_list(args, fd[0]);
+ if (!got_ready || !no_done)
+ consume_shallow_list(args, fd[0]);
while (flushes || multi_ack) {
int ack = get_ack(fd[0], result_sha1);
if (ack) {
diff --git a/git-am.sh b/git-am.sh
index bbea43075b..78517f254f 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -4,6 +4,7 @@
SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=t
OPTIONS_SPEC="\
git am [options] [(<mbox>|<Maildir>)...]
git am [options] (--continue | --skip | --abort)
@@ -37,6 +38,7 @@ abort restore the original branch and abort the patching operation.
committer-date-is-author-date lie about committer date
ignore-date use current timestamp for author date
rerere-autoupdate update the index with reused conflict resolution if possible
+S,gpg-sign? GPG-sign commits
rebasing* (internal use for git-rebase)"
. git-sh-setup
@@ -374,6 +376,7 @@ git_apply_opt=
committer_date_is_author_date=
ignore_date=
allow_rerere_autoupdate=
+gpg_sign_opt=
if test "$(git config --bool --get am.keepcr)" = true
then
@@ -413,14 +416,14 @@ it will be removed. Please do not use it anymore."
abort=t ;;
--rebasing)
rebasing=t threeway=t ;;
- --resolvemsg)
- shift; resolvemsg=$1 ;;
- --whitespace|--directory|--exclude|--include)
- git_apply_opt="$git_apply_opt $(sq "$1=$2")"; shift ;;
- -C|-p)
- git_apply_opt="$git_apply_opt $(sq "$1$2")"; shift ;;
- --patch-format)
- shift ; patch_format="$1" ;;
+ --resolvemsg=*)
+ resolvemsg="${1#--resolvemsg=}" ;;
+ --whitespace=*|--directory=*|--exclude=*|--include=*)
+ git_apply_opt="$git_apply_opt $(sq "$1")" ;;
+ -C*|-p*)
+ git_apply_opt="$git_apply_opt $(sq "$1")" ;;
+ --patch-format=*)
+ patch_format="${1#--patch-format=}" ;;
--reject|--ignore-whitespace|--ignore-space-change)
git_apply_opt="$git_apply_opt $1" ;;
--committer-date-is-author-date)
@@ -435,6 +438,10 @@ it will be removed. Please do not use it anymore."
keepcr=t ;;
--no-keep-cr)
keepcr=f ;;
+ --gpg-sign)
+ gpg_sign_opt=-S ;;
+ --gpg-sign=*)
+ gpg_sign_opt="-S${1#--gpg-sign=}" ;;
--)
shift; break ;;
*)
@@ -899,7 +906,8 @@ did you forget to use 'git add'?"
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
export GIT_COMMITTER_DATE
fi &&
- git commit-tree $tree ${parent:+-p} $parent <"$dotest/final-commit"
+ git commit-tree ${parent:+-p} $parent ${gpg_sign_opt:+"$gpg_sign_opt"} $tree \
+ <"$dotest/final-commit"
) &&
git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent ||
stop_here $this
diff --git a/git-compat-util.h b/git-compat-util.h
index cbd86c37f5..614a5e95bd 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -480,9 +480,15 @@ extern FILE *git_fopen(const char*, const char*);
#endif
#ifdef SNPRINTF_RETURNS_BOGUS
+#ifdef snprintf
+#undef snprintf
+#endif
#define snprintf git_snprintf
extern int git_snprintf(char *str, size_t maxsize,
const char *format, ...);
+#ifdef vsnprintf
+#undef vsnprintf
+#endif
#define vsnprintf git_vsnprintf
extern int git_vsnprintf(char *str, size_t maxsize,
const char *format, va_list ap);
diff --git a/git-instaweb.sh b/git-instaweb.sh
index e93a238675..4aa3eb80fd 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -5,6 +5,7 @@
PERL='@@PERL@@'
OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=
OPTIONS_SPEC="\
git instaweb [options] (--start | --stop | --restart)
--
diff --git a/git-pull.sh b/git-pull.sh
index 0a5aa2c821..6cd8ebc534 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -4,7 +4,7 @@
#
# Fetch one or more remote refs and merge it/them into the current HEAD.
-USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'
+USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff|--ff-only] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'
LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'
SUBDIRECTORY_OK=Yes
OPTIONS_SPEC=
@@ -52,6 +52,21 @@ if test -z "$rebase"
then
rebase=$(bool_or_string_config pull.rebase)
fi
+
+# Setup default fast-forward options via `pull.ff`
+pull_ff=$(git config pull.ff)
+case "$pull_ff" in
+false)
+ no_ff=--no-ff
+ break
+ ;;
+only)
+ ff_only=--ff-only
+ break
+ ;;
+esac
+
+
dry_run=
while :
do
@@ -138,6 +153,15 @@ do
--no-verify-signatures)
verify_signatures=--no-verify-signatures
;;
+ --gpg-sign|-S)
+ gpg_sign_args=-S
+ ;;
+ --gpg-sign=*)
+ gpg_sign_args=$(git rev-parse --sq-quote "-S${1#--gpg-sign=}")
+ ;;
+ -S*)
+ gpg_sign_args=$(git rev-parse --sq-quote "$1")
+ ;;
--d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
dry_run=--dry-run
;;
@@ -305,11 +329,13 @@ merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
case "$rebase" in
true)
eval="git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity"
+ eval="$eval $gpg_sign_args"
eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
;;
*)
eval="git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only"
- eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress"
+ eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress"
+ eval="$eval $gpg_sign_args"
eval="$eval \"\$merge_name\" HEAD $merge_head"
;;
esac
diff --git a/git-quiltimport.sh b/git-quiltimport.sh
index 8e17525dd8..167d79fea8 100755
--- a/git-quiltimport.sh
+++ b/git-quiltimport.sh
@@ -1,5 +1,6 @@
#!/bin/sh
OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=
OPTIONS_SPEC="\
git quiltimport [options]
--
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index a4f683a5d7..df46f4ca96 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -6,7 +6,8 @@
case "$action" in
continue)
- git am --resolved --resolvemsg="$resolvemsg" &&
+ git am --resolved --resolvemsg="$resolvemsg" \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} &&
move_to_original_branch
return
;;
@@ -26,7 +27,7 @@ then
# empty commits and even if it didn't the format doesn't really lend
# itself well to recording empty patches. fortunately, cherry-pick
# makes this easy
- git cherry-pick --allow-empty "$revisions"
+ git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty "$revisions"
ret=$?
else
rm -f "$GIT_DIR/rebased-patches"
@@ -60,7 +61,8 @@ else
return $?
fi
- git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" <"$GIT_DIR/rebased-patches"
+ git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} <"$GIT_DIR/rebased-patches"
ret=$?
rm -f "$GIT_DIR/rebased-patches"
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 43c19e0829..a1adae8313 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -179,9 +179,10 @@ exit_with_patch () {
echo "$1" > "$state_dir"/stopped-sha
make_patch $1
git rev-parse --verify HEAD > "$amend"
+ gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
warn "You can amend the commit now, with"
warn
- warn " git commit --amend"
+ warn " git commit --amend $gpg_sign_opt_quoted"
warn
warn "Once you are satisfied with your changes, run"
warn
@@ -248,7 +249,9 @@ pick_one () {
test -d "$rewritten" &&
pick_one_preserving_merges "$@" && return
- output eval git cherry-pick "$strategy_args" $empty_args $ff "$@"
+ output eval git cherry-pick \
+ ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
+ "$strategy_args" $empty_args $ff "$@"
}
pick_one_preserving_merges () {
@@ -351,7 +354,8 @@ pick_one_preserving_merges () {
new_parents=${new_parents# $first_parent}
merge_args="--no-log --no-ff"
if ! do_with_author output eval \
- 'git merge $merge_args $strategy_args -m "$msg_content" $new_parents'
+ 'git merge ${gpg_sign_opt:+"$gpg_sign_opt"} \
+ $merge_args $strategy_args -m "$msg_content" $new_parents'
then
printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
die_with_patch $sha1 "Error redoing merge $sha1"
@@ -359,7 +363,9 @@ pick_one_preserving_merges () {
echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list"
;;
*)
- output eval git cherry-pick "$strategy_args" "$@" ||
+ output eval git cherry-pick \
+ ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
+ "$strategy_args" "$@" ||
die_with_patch $sha1 "Could not pick $sha1"
;;
esac
@@ -470,7 +476,8 @@ do_pick () {
--no-post-rewrite -n -q -C $1 &&
pick_one -n $1 &&
git commit --allow-empty --allow-empty-message \
- --amend --no-post-rewrite -n -q -C $1 ||
+ --amend --no-post-rewrite -n -q -C $1 \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} ||
die_with_patch $1 "Could not apply $1... $2"
else
pick_one $1 ||
@@ -497,7 +504,7 @@ do_next () {
mark_action_done
do_pick $sha1 "$rest"
- git commit --amend --no-post-rewrite || {
+ git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
warn "Could not amend commit after successfully picking $sha1... $rest"
warn "This is most likely due to an empty commit message, or the pre-commit hook"
warn "failed. If the pre-commit hook failed, you may need to resolve the issue before"
@@ -542,19 +549,22 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only be
# used in case of trouble. So use the long version:
- do_with_author output git commit --amend --no-verify -F "$squash_msg" ||
+ do_with_author output git commit --amend --no-verify -F "$squash_msg" \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} ||
die_failed_squash $sha1 "$rest"
;;
*)
# This is the final command of this squash/fixup group
if test -f "$fixup_msg"
then
- do_with_author git commit --amend --no-verify -F "$fixup_msg" ||
+ do_with_author git commit --amend --no-verify -F "$fixup_msg" \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} ||
die_failed_squash $sha1 "$rest"
else
cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
rm -f "$GIT_DIR"/MERGE_MSG
- do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e ||
+ do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} ||
die_failed_squash $sha1 "$rest"
fi
rm -f "$squash_msg" "$fixup_msg"
@@ -819,14 +829,15 @@ continue)
else
if ! test -f "$author_script"
then
+ gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
die "You have staged changes in your working tree. If these changes are meant to be
squashed into the previous commit, run:
- git commit --amend
+ git commit --amend $gpg_sign_opt_quoted
If they are meant to go into a new commit, run:
- git commit
+ git commit $gpg_sign_opt_quoted
In both case, once you're done, continue with:
@@ -842,10 +853,12 @@ In both case, once you're done, continue with:
die "\
You have uncommitted changes in your working tree. Please, commit them
first and then run 'git rebase --continue' again."
- do_with_author git commit --amend --no-verify -F "$msg" -e ||
+ do_with_author git commit --amend --no-verify -F "$msg" -e \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} ||
die "Could not commit staged changes."
else
- do_with_author git commit --no-verify -F "$msg" -e ||
+ do_with_author git commit --no-verify -F "$msg" -e \
+ ${gpg_sign_opt:+"$gpg_sign_opt"} ||
die "Could not commit staged changes."
fi
fi
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index e7d96de9ad..5381857c59 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -27,7 +27,7 @@ continue_merge () {
cmt=`cat "$state_dir/current"`
if ! git diff-index --quiet --ignore-submodules HEAD --
then
- if ! git commit --no-verify -C "$cmt"
+ if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt"
then
echo "Commit failed, please do not call \"git commit\""
echo "directly, but instead do one of the following: "
diff --git a/git-rebase.sh b/git-rebase.sh
index 8a3efa2983..5f6732bf3d 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -5,6 +5,7 @@
SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=t
OPTIONS_SPEC="\
git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
@@ -36,6 +37,7 @@ ignore-date! passed to 'git am'
whitespace=! passed to 'git apply'
ignore-whitespace! passed to 'git apply'
C=! passed to 'git apply'
+S,gpg-sign? GPG-sign commits
Actions:
continue! continue
abort! abort and check out the original branch
@@ -84,6 +86,7 @@ preserve_merges=
autosquash=
keep_empty=
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
+gpg_sign_opt=
read_basic_state () {
test -f "$state_dir/head-name" &&
@@ -106,6 +109,8 @@ read_basic_state () {
strategy_opts="$(cat "$state_dir"/strategy_opts)"
test -f "$state_dir"/allow_rerere_autoupdate &&
allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
+ test -f "$state_dir"/gpg_sign_opt &&
+ gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
}
write_basic_state () {
@@ -119,6 +124,7 @@ write_basic_state () {
"$state_dir"/strategy_opts
test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
"$state_dir"/allow_rerere_autoupdate
+ test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt
}
output () {
@@ -236,23 +242,19 @@ do
test $total_argc -eq 2 || usage
action=${1##--}
;;
- --onto)
- test 2 -le "$#" || usage
- onto="$2"
- shift
+ --onto=*)
+ onto="${1#--onto=}"
;;
- -x)
- test 2 -le "$#" || usage
- cmd="${cmd}exec $2${LF}"
- shift
+ --exec=*)
+ cmd="${cmd}exec ${1#--exec=}${LF}"
;;
- -i)
+ --interactive)
interactive_rebase=explicit
;;
- -k)
+ --keep-empty)
keep_empty=yes
;;
- -p)
+ --preserve-merges)
preserve_merges=t
test -z "$interactive_rebase" && interactive_rebase=implied
;;
@@ -268,21 +270,19 @@ do
--no-fork-point)
fork_point=
;;
- -M|-m)
+ --merge)
do_merge=t
;;
- -X)
- shift
- strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$1")"
+ --strategy-option=*)
+ strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}")"
do_merge=t
test -z "$strategy" && strategy=recursive
;;
- -s)
- shift
- strategy="$1"
+ --strategy=*)
+ strategy="${1#--strategy=}"
do_merge=t
;;
- -n)
+ --no-stat)
diffstat=
;;
--stat)
@@ -291,21 +291,20 @@ do
--autostash)
autostash=true
;;
- -v)
+ --verbose)
verbose=t
diffstat=t
GIT_QUIET=
;;
- -q)
+ --quiet)
GIT_QUIET=t
git_am_opt="$git_am_opt -q"
verbose=
diffstat=
;;
- --whitespace)
- shift
- git_am_opt="$git_am_opt --whitespace=$1"
- case "$1" in
+ --whitespace=*)
+ git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
+ case "${1#--whitespace=}" in
fix|strip)
force_rebase=t
;;
@@ -318,19 +317,24 @@ do
git_am_opt="$git_am_opt $1"
force_rebase=t
;;
- -C)
- shift
- git_am_opt="$git_am_opt -C$1"
+ -C*)
+ git_am_opt="$git_am_opt $1"
;;
--root)
rebase_root=t
;;
- -f|--no-ff)
+ --force-rebase|--no-ff)
force_rebase=t
;;
--rerere-autoupdate|--no-rerere-autoupdate)
allow_rerere_autoupdate="$1"
;;
+ --gpg-sign)
+ gpg_sign_opt=-S
+ ;;
+ --gpg-sign=*)
+ gpg_sign_opt="-S${1#--gpg-sign=}"
+ ;;
--)
shift
break
diff --git a/git-request-pull.sh b/git-request-pull.sh
index fe21d5db63..cf4f1505a5 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -9,6 +9,7 @@ LONG_USAGE='Summarizes the changes between two commits to the standard output,
and includes the given URL in the generated summary.'
SUBDIRECTORY_OK='Yes'
OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=
OPTIONS_SPEC='git request-pull [options] start url [end]
--
p show patch text as well
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index fffa3c72d7..5f28b32dc7 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -72,6 +72,8 @@ if test -n "$OPTIONS_SPEC"; then
parseopt_extra=
[ -n "$OPTIONS_KEEPDASHDASH" ] &&
parseopt_extra="--keep-dashdash"
+ [ -n "$OPTIONS_STUCKLONG" ] &&
+ parseopt_extra="$parseopt_extra --stuck-long"
eval "$(
echo "$OPTIONS_SPEC" |
diff --git a/git-submodule.sh b/git-submodule.sh
index 4a30087768..a33f68d27c 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -241,6 +241,15 @@ module_name()
#
# Clone a submodule
#
+# $1 = submodule path
+# $2 = submodule name
+# $3 = URL to clone
+# $4 = reference repository to reuse (empty for independent)
+# $5 = depth argument for shallow clones (empty for deep)
+# $6 = (remote-tracking) starting point for the local branch (empty for HEAD)
+# $7 = local branch to create (empty for a detached HEAD, unless $6 is
+# also empty, in which case the local branch is left unchanged)
+#
# Prior to calling, cmd_update checks that a possibly existing
# path is not a git repository.
# Likewise, cmd_add checks that path does not exist at all,
@@ -253,6 +262,8 @@ module_clone()
url=$3
reference="$4"
depth="$5"
+ start_point="$6"
+ local_branch="$7"
quiet=
if test -n "$GIT_QUIET"
then
@@ -306,7 +317,16 @@ module_clone()
echo "gitdir: $rel/$a" >"$sm_path/.git"
rel=$(echo $a | sed -e 's|[^/][^/]*|..|g')
- (clear_local_git_env; cd "$sm_path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b")
+ (
+ clear_local_git_env
+ cd "$sm_path" &&
+ GIT_WORK_TREE=. git config core.worktree "$rel/$b" &&
+ # ash fails to wordsplit ${local_branch:+-B "$local_branch"...}
+ case "$local_branch" in
+ '') git checkout -f -q ${start_point:+"$start_point"} ;;
+ ?*) git checkout -f -q -B "$local_branch" ${start_point:+"$start_point"} ;;
+ esac
+ ) || die "$(eval_gettext "Unable to setup cloned submodule '\$sm_path'")"
}
isnumber()
@@ -469,16 +489,15 @@ Use -f if you really want to add it." >&2
echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
fi
fi
- module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" || exit
- (
- clear_local_git_env
- cd "$sm_path" &&
- # ash fails to wordsplit ${branch:+-b "$branch"...}
- case "$branch" in
- '') git checkout -f -q ;;
- ?*) git checkout -f -q -B "$branch" "origin/$branch" ;;
- esac
- ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
+ if test -n "$branch"
+ then
+ start_point="origin/$branch"
+ local_branch="$branch"
+ else
+ start_point=""
+ local_branch=""
+ fi
+ module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" "$start_point" "$local_branch" || exit
fi
git config submodule."$sm_name".url "$realrepo"
@@ -799,32 +818,35 @@ cmd_update()
fi
name=$(module_name "$sm_path") || exit
url=$(git config submodule."$name".url)
- branch=$(get_submodule_config "$name" branch master)
+ config_branch=$(get_submodule_config "$name" branch)
+ branch="${config_branch:-master}"
+ local_branch="$branch"
if ! test -z "$update"
then
update_module=$update
else
update_module=$(git config submodule."$name".update)
- case "$update_module" in
- '')
- ;; # Unset update mode
- checkout | rebase | merge | none)
- ;; # Known update modes
- !*)
- ;; # Custom update command
- *)
- die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
- ;;
- esac
+ if test -z "$update_module"
+ then
+ update_module="checkout"
+ fi
fi
displaypath=$(relative_path "$prefix$sm_path")
- if test "$update_module" = "none"
- then
+ case "$update_module" in
+ none)
echo "Skipping submodule '$displaypath'"
continue
- fi
+ ;;
+ checkout)
+ local_branch=""
+ ;;
+ rebase | merge | !*)
+ ;;
+ *)
+ die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
+ esac
if test -z "$url"
then
@@ -838,7 +860,8 @@ Maybe you want to use 'update --init'?")"
if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
then
- module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit
+ start_point="origin/${branch}"
+ module_clone "$sm_path" "$name" "$url" "$reference" "$depth" "$start_point" "$local_branch" || exit
cloned_modules="$cloned_modules;$name"
subsha1=
else
@@ -884,11 +907,16 @@ Maybe you want to use 'update --init'?")"
case ";$cloned_modules;" in
*";$name;"*)
# then there is no local change to integrate
- update_module= ;;
+ update_module='!git reset --hard -q'
esac
must_die_on_failure=
case "$update_module" in
+ checkout)
+ command="git checkout $subforce -q"
+ die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
+ say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
+ ;;
rebase)
command="git rebase"
die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$displaypath'")"
@@ -908,10 +936,7 @@ Maybe you want to use 'update --init'?")"
must_die_on_failure=yes
;;
*)
- command="git checkout $subforce -q"
- die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
- say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
- ;;
+ die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
esac
if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
diff --git a/hash.c b/hash.c
deleted file mode 100644
index 749ecfe484..0000000000
--- a/hash.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Some generic hashing helpers.
- */
-#include "cache.h"
-#include "hash.h"
-
-/*
- * Look up a hash entry in the hash table. Return the pointer to
- * the existing entry, or the empty slot if none existed. The caller
- * can then look at the (*ptr) to see whether it existed or not.
- */
-static struct hash_table_entry *lookup_hash_entry(unsigned int hash, const struct hash_table *table)
-{
- unsigned int size = table->size, nr = hash % size;
- struct hash_table_entry *array = table->array;
-
- while (array[nr].ptr) {
- if (array[nr].hash == hash)
- break;
- nr++;
- if (nr >= size)
- nr = 0;
- }
- return array + nr;
-}
-
-
-/*
- * Insert a new hash entry pointer into the table.
- *
- * If that hash entry already existed, return the pointer to
- * the existing entry (and the caller can create a list of the
- * pointers or do anything else). If it didn't exist, return
- * NULL (and the caller knows the pointer has been inserted).
- */
-static void **insert_hash_entry(unsigned int hash, void *ptr, struct hash_table *table)
-{
- struct hash_table_entry *entry = lookup_hash_entry(hash, table);
-
- if (!entry->ptr) {
- entry->ptr = ptr;
- entry->hash = hash;
- table->nr++;
- return NULL;
- }
- return &entry->ptr;
-}
-
-static void grow_hash_table(struct hash_table *table)
-{
- unsigned int i;
- unsigned int old_size = table->size, new_size;
- struct hash_table_entry *old_array = table->array, *new_array;
-
- new_size = alloc_nr(old_size);
- new_array = xcalloc(sizeof(struct hash_table_entry), new_size);
- table->size = new_size;
- table->array = new_array;
- table->nr = 0;
- for (i = 0; i < old_size; i++) {
- unsigned int hash = old_array[i].hash;
- void *ptr = old_array[i].ptr;
- if (ptr)
- insert_hash_entry(hash, ptr, table);
- }
- free(old_array);
-}
-
-void *lookup_hash(unsigned int hash, const struct hash_table *table)
-{
- if (!table->array)
- return NULL;
- return lookup_hash_entry(hash, table)->ptr;
-}
-
-void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table)
-{
- unsigned int nr = table->nr;
- if (nr >= table->size/2)
- grow_hash_table(table);
- return insert_hash_entry(hash, ptr, table);
-}
-
-int for_each_hash(const struct hash_table *table, int (*fn)(void *, void *), void *data)
-{
- int sum = 0;
- unsigned int i;
- unsigned int size = table->size;
- struct hash_table_entry *array = table->array;
-
- for (i = 0; i < size; i++) {
- void *ptr = array->ptr;
- array++;
- if (ptr) {
- int val = fn(ptr, data);
- if (val < 0)
- return val;
- sum += val;
- }
- }
- return sum;
-}
-
-void free_hash(struct hash_table *table)
-{
- free(table->array);
- table->array = NULL;
- table->size = 0;
- table->nr = 0;
-}
diff --git a/hash.h b/hash.h
deleted file mode 100644
index 1d43ac0ba0..0000000000
--- a/hash.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef HASH_H
-#define HASH_H
-
-/*
- * These are some simple generic hash table helper functions.
- * Not necessarily suitable for all users, but good for things
- * where you want to just keep track of a list of things, and
- * have a good hash to use on them.
- *
- * It keeps the hash table at roughly 50-75% free, so the memory
- * cost of the hash table itself is roughly
- *
- * 3 * 2*sizeof(void *) * nr_of_objects
- *
- * bytes.
- *
- * FIXME: on 64-bit architectures, we waste memory. It would be
- * good to have just 32-bit pointers, requiring a special allocator
- * for hashed entries or something.
- */
-struct hash_table_entry {
- unsigned int hash;
- void *ptr;
-};
-
-struct hash_table {
- unsigned int size, nr;
- struct hash_table_entry *array;
-};
-
-extern void *lookup_hash(unsigned int hash, const struct hash_table *table);
-extern void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table);
-extern int for_each_hash(const struct hash_table *table, int (*fn)(void *, void *), void *data);
-extern void free_hash(struct hash_table *table);
-
-static inline void init_hash(struct hash_table *table)
-{
- table->size = 0;
- table->nr = 0;
- table->array = NULL;
-}
-
-static inline void preallocate_hash(struct hash_table *table, unsigned int elts)
-{
- assert(table->size == 0 && table->nr == 0 && table->array == NULL);
- table->size = elts * 2;
- table->array = xcalloc(sizeof(struct hash_table_entry), table->size);
-}
-
-#endif
diff --git a/hashmap.c b/hashmap.c
new file mode 100644
index 0000000000..d1b8056d8d
--- /dev/null
+++ b/hashmap.c
@@ -0,0 +1,228 @@
+/*
+ * Generic implementation of hash-based key value mappings.
+ */
+#include "cache.h"
+#include "hashmap.h"
+
+#define FNV32_BASE ((unsigned int) 0x811c9dc5)
+#define FNV32_PRIME ((unsigned int) 0x01000193)
+
+unsigned int strhash(const char *str)
+{
+ unsigned int c, hash = FNV32_BASE;
+ while ((c = (unsigned char) *str++))
+ hash = (hash * FNV32_PRIME) ^ c;
+ return hash;
+}
+
+unsigned int strihash(const char *str)
+{
+ unsigned int c, hash = FNV32_BASE;
+ while ((c = (unsigned char) *str++)) {
+ if (c >= 'a' && c <= 'z')
+ c -= 'a' - 'A';
+ hash = (hash * FNV32_PRIME) ^ c;
+ }
+ return hash;
+}
+
+unsigned int memhash(const void *buf, size_t len)
+{
+ unsigned int hash = FNV32_BASE;
+ unsigned char *ucbuf = (unsigned char *) buf;
+ while (len--) {
+ unsigned int c = *ucbuf++;
+ hash = (hash * FNV32_PRIME) ^ c;
+ }
+ return hash;
+}
+
+unsigned int memihash(const void *buf, size_t len)
+{
+ unsigned int hash = FNV32_BASE;
+ unsigned char *ucbuf = (unsigned char *) buf;
+ while (len--) {
+ unsigned int c = *ucbuf++;
+ if (c >= 'a' && c <= 'z')
+ c -= 'a' - 'A';
+ hash = (hash * FNV32_PRIME) ^ c;
+ }
+ return hash;
+}
+
+#define HASHMAP_INITIAL_SIZE 64
+/* grow / shrink by 2^2 */
+#define HASHMAP_RESIZE_BITS 2
+/* load factor in percent */
+#define HASHMAP_LOAD_FACTOR 80
+
+static void alloc_table(struct hashmap *map, unsigned int size)
+{
+ map->tablesize = size;
+ map->table = xcalloc(size, sizeof(struct hashmap_entry *));
+
+ /* calculate resize thresholds for new size */
+ map->grow_at = (unsigned int) ((uint64_t) size * HASHMAP_LOAD_FACTOR / 100);
+ if (size <= HASHMAP_INITIAL_SIZE)
+ map->shrink_at = 0;
+ else
+ /*
+ * The shrink-threshold must be slightly smaller than
+ * (grow-threshold / resize-factor) to prevent erratic resizing,
+ * thus we divide by (resize-factor + 1).
+ */
+ map->shrink_at = map->grow_at / ((1 << HASHMAP_RESIZE_BITS) + 1);
+}
+
+static inline int entry_equals(const struct hashmap *map,
+ const struct hashmap_entry *e1, const struct hashmap_entry *e2,
+ const void *keydata)
+{
+ return (e1 == e2) || (e1->hash == e2->hash && !map->cmpfn(e1, e2, keydata));
+}
+
+static inline unsigned int bucket(const struct hashmap *map,
+ const struct hashmap_entry *key)
+{
+ return key->hash & (map->tablesize - 1);
+}
+
+static void rehash(struct hashmap *map, unsigned int newsize)
+{
+ unsigned int i, oldsize = map->tablesize;
+ struct hashmap_entry **oldtable = map->table;
+
+ alloc_table(map, newsize);
+ for (i = 0; i < oldsize; i++) {
+ struct hashmap_entry *e = oldtable[i];
+ while (e) {
+ struct hashmap_entry *next = e->next;
+ unsigned int b = bucket(map, e);
+ e->next = map->table[b];
+ map->table[b] = e;
+ e = next;
+ }
+ }
+ free(oldtable);
+}
+
+static inline struct hashmap_entry **find_entry_ptr(const struct hashmap *map,
+ const struct hashmap_entry *key, const void *keydata)
+{
+ struct hashmap_entry **e = &map->table[bucket(map, key)];
+ while (*e && !entry_equals(map, *e, key, keydata))
+ e = &(*e)->next;
+ return e;
+}
+
+static int always_equal(const void *unused1, const void *unused2, const void *unused3)
+{
+ return 0;
+}
+
+void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function,
+ size_t initial_size)
+{
+ unsigned int size = HASHMAP_INITIAL_SIZE;
+ map->size = 0;
+ map->cmpfn = equals_function ? equals_function : always_equal;
+
+ /* calculate initial table size and allocate the table */
+ initial_size = (unsigned int) ((uint64_t) initial_size * 100
+ / HASHMAP_LOAD_FACTOR);
+ while (initial_size > size)
+ size <<= HASHMAP_RESIZE_BITS;
+ alloc_table(map, size);
+}
+
+void hashmap_free(struct hashmap *map, int free_entries)
+{
+ if (!map || !map->table)
+ return;
+ if (free_entries) {
+ struct hashmap_iter iter;
+ struct hashmap_entry *e;
+ hashmap_iter_init(map, &iter);
+ while ((e = hashmap_iter_next(&iter)))
+ free(e);
+ }
+ free(map->table);
+ memset(map, 0, sizeof(*map));
+}
+
+void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata)
+{
+ return *find_entry_ptr(map, key, keydata);
+}
+
+void *hashmap_get_next(const struct hashmap *map, const void *entry)
+{
+ struct hashmap_entry *e = ((struct hashmap_entry *) entry)->next;
+ for (; e; e = e->next)
+ if (entry_equals(map, entry, e, NULL))
+ return e;
+ return NULL;
+}
+
+void hashmap_add(struct hashmap *map, void *entry)
+{
+ unsigned int b = bucket(map, entry);
+
+ /* add entry */
+ ((struct hashmap_entry *) entry)->next = map->table[b];
+ map->table[b] = entry;
+
+ /* fix size and rehash if appropriate */
+ map->size++;
+ if (map->size > map->grow_at)
+ rehash(map, map->tablesize << HASHMAP_RESIZE_BITS);
+}
+
+void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)
+{
+ struct hashmap_entry *old;
+ struct hashmap_entry **e = find_entry_ptr(map, key, keydata);
+ if (!*e)
+ return NULL;
+
+ /* remove existing entry */
+ old = *e;
+ *e = old->next;
+ old->next = NULL;
+
+ /* fix size and rehash if appropriate */
+ map->size--;
+ if (map->size < map->shrink_at)
+ rehash(map, map->tablesize >> HASHMAP_RESIZE_BITS);
+ return old;
+}
+
+void *hashmap_put(struct hashmap *map, void *entry)
+{
+ struct hashmap_entry *old = hashmap_remove(map, entry, NULL);
+ hashmap_add(map, entry);
+ return old;
+}
+
+void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter)
+{
+ iter->map = map;
+ iter->tablepos = 0;
+ iter->next = NULL;
+}
+
+void *hashmap_iter_next(struct hashmap_iter *iter)
+{
+ struct hashmap_entry *current = iter->next;
+ for (;;) {
+ if (current) {
+ iter->next = current->next;
+ return current;
+ }
+
+ if (iter->tablepos >= iter->map->tablesize)
+ return NULL;
+
+ current = iter->map->table[iter->tablepos++];
+ }
+}
diff --git a/hashmap.h b/hashmap.h
new file mode 100644
index 0000000000..a816ad47b1
--- /dev/null
+++ b/hashmap.h
@@ -0,0 +1,71 @@
+#ifndef HASHMAP_H
+#define HASHMAP_H
+
+/*
+ * Generic implementation of hash-based key-value mappings.
+ * See Documentation/technical/api-hashmap.txt.
+ */
+
+/* FNV-1 functions */
+
+extern unsigned int strhash(const char *buf);
+extern unsigned int strihash(const char *buf);
+extern unsigned int memhash(const void *buf, size_t len);
+extern unsigned int memihash(const void *buf, size_t len);
+
+/* data structures */
+
+struct hashmap_entry {
+ struct hashmap_entry *next;
+ unsigned int hash;
+};
+
+typedef int (*hashmap_cmp_fn)(const void *entry, const void *entry_or_key,
+ const void *keydata);
+
+struct hashmap {
+ struct hashmap_entry **table;
+ hashmap_cmp_fn cmpfn;
+ unsigned int size, tablesize, grow_at, shrink_at;
+};
+
+struct hashmap_iter {
+ struct hashmap *map;
+ struct hashmap_entry *next;
+ unsigned int tablepos;
+};
+
+/* hashmap functions */
+
+extern void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function,
+ size_t initial_size);
+extern void hashmap_free(struct hashmap *map, int free_entries);
+
+/* hashmap_entry functions */
+
+static inline void hashmap_entry_init(void *entry, unsigned int hash)
+{
+ struct hashmap_entry *e = entry;
+ e->hash = hash;
+ e->next = NULL;
+}
+extern void *hashmap_get(const struct hashmap *map, const void *key,
+ const void *keydata);
+extern void *hashmap_get_next(const struct hashmap *map, const void *entry);
+extern void hashmap_add(struct hashmap *map, void *entry);
+extern void *hashmap_put(struct hashmap *map, void *entry);
+extern void *hashmap_remove(struct hashmap *map, const void *key,
+ const void *keydata);
+
+/* hashmap_iter functions */
+
+extern void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter);
+extern void *hashmap_iter_next(struct hashmap_iter *iter);
+static inline void *hashmap_iter_first(struct hashmap *map,
+ struct hashmap_iter *iter)
+{
+ hashmap_iter_init(map, iter);
+ return hashmap_iter_next(iter);
+}
+
+#endif
diff --git a/khash.h b/khash.h
new file mode 100644
index 0000000000..57ff6038c5
--- /dev/null
+++ b/khash.h
@@ -0,0 +1,338 @@
+/* The MIT License
+
+ Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#ifndef __AC_KHASH_H
+#define __AC_KHASH_H
+
+#define AC_VERSION_KHASH_H "0.2.8"
+
+typedef uint32_t khint32_t;
+typedef uint64_t khint64_t;
+
+typedef khint32_t khint_t;
+typedef khint_t khiter_t;
+
+#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
+#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
+#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
+#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
+#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
+#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
+#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
+
+#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
+
+#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
+
+static inline khint_t __ac_X31_hash_string(const char *s)
+{
+ khint_t h = (khint_t)*s;
+ if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
+ return h;
+}
+
+#define kh_str_hash_func(key) __ac_X31_hash_string(key)
+#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
+
+static const double __ac_HASH_UPPER = 0.77;
+
+#define __KHASH_TYPE(name, khkey_t, khval_t) \
+ typedef struct { \
+ khint_t n_buckets, size, n_occupied, upper_bound; \
+ khint32_t *flags; \
+ khkey_t *keys; \
+ khval_t *vals; \
+ } kh_##name##_t;
+
+#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
+ extern kh_##name##_t *kh_init_##name(void); \
+ extern void kh_destroy_##name(kh_##name##_t *h); \
+ extern void kh_clear_##name(kh_##name##_t *h); \
+ extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
+ extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
+ extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
+ extern void kh_del_##name(kh_##name##_t *h, khint_t x);
+
+#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
+ SCOPE kh_##name##_t *kh_init_##name(void) { \
+ return (kh_##name##_t*)xcalloc(1, sizeof(kh_##name##_t)); \
+ } \
+ SCOPE void kh_destroy_##name(kh_##name##_t *h) \
+ { \
+ if (h) { \
+ free((void *)h->keys); free(h->flags); \
+ free((void *)h->vals); \
+ free(h); \
+ } \
+ } \
+ SCOPE void kh_clear_##name(kh_##name##_t *h) \
+ { \
+ if (h && h->flags) { \
+ memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
+ h->size = h->n_occupied = 0; \
+ } \
+ } \
+ SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
+ { \
+ if (h->n_buckets) { \
+ khint_t k, i, last, mask, step = 0; \
+ mask = h->n_buckets - 1; \
+ k = __hash_func(key); i = k & mask; \
+ last = i; \
+ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
+ i = (i + (++step)) & mask; \
+ if (i == last) return h->n_buckets; \
+ } \
+ return __ac_iseither(h->flags, i)? h->n_buckets : i; \
+ } else return 0; \
+ } \
+ SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
+ { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
+ khint32_t *new_flags = NULL; \
+ khint_t j = 1; \
+ { \
+ kroundup32(new_n_buckets); \
+ if (new_n_buckets < 4) new_n_buckets = 4; \
+ if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
+ else { /* hash table size to be changed (shrink or expand); rehash */ \
+ new_flags = (khint32_t*)xmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
+ if (!new_flags) return -1; \
+ memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
+ if (h->n_buckets < new_n_buckets) { /* expand */ \
+ khkey_t *new_keys = (khkey_t*)xrealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
+ if (!new_keys) return -1; \
+ h->keys = new_keys; \
+ if (kh_is_map) { \
+ khval_t *new_vals = (khval_t*)xrealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
+ if (!new_vals) return -1; \
+ h->vals = new_vals; \
+ } \
+ } /* otherwise shrink */ \
+ } \
+ } \
+ if (j) { /* rehashing is needed */ \
+ for (j = 0; j != h->n_buckets; ++j) { \
+ if (__ac_iseither(h->flags, j) == 0) { \
+ khkey_t key = h->keys[j]; \
+ khval_t val; \
+ khint_t new_mask; \
+ new_mask = new_n_buckets - 1; \
+ if (kh_is_map) val = h->vals[j]; \
+ __ac_set_isdel_true(h->flags, j); \
+ while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
+ khint_t k, i, step = 0; \
+ k = __hash_func(key); \
+ i = k & new_mask; \
+ while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
+ __ac_set_isempty_false(new_flags, i); \
+ if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
+ { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
+ if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
+ __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
+ } else { /* write the element and jump out of the loop */ \
+ h->keys[i] = key; \
+ if (kh_is_map) h->vals[i] = val; \
+ break; \
+ } \
+ } \
+ } \
+ } \
+ if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
+ h->keys = (khkey_t*)xrealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
+ if (kh_is_map) h->vals = (khval_t*)xrealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
+ } \
+ free(h->flags); /* free the working space */ \
+ h->flags = new_flags; \
+ h->n_buckets = new_n_buckets; \
+ h->n_occupied = h->size; \
+ h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
+ } \
+ return 0; \
+ } \
+ SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
+ { \
+ khint_t x; \
+ if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
+ if (h->n_buckets > (h->size<<1)) { \
+ if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
+ *ret = -1; return h->n_buckets; \
+ } \
+ } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
+ *ret = -1; return h->n_buckets; \
+ } \
+ } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
+ { \
+ khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
+ x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
+ if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
+ else { \
+ last = i; \
+ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
+ if (__ac_isdel(h->flags, i)) site = i; \
+ i = (i + (++step)) & mask; \
+ if (i == last) { x = site; break; } \
+ } \
+ if (x == h->n_buckets) { \
+ if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
+ else x = i; \
+ } \
+ } \
+ } \
+ if (__ac_isempty(h->flags, x)) { /* not present at all */ \
+ h->keys[x] = key; \
+ __ac_set_isboth_false(h->flags, x); \
+ ++h->size; ++h->n_occupied; \
+ *ret = 1; \
+ } else if (__ac_isdel(h->flags, x)) { /* deleted */ \
+ h->keys[x] = key; \
+ __ac_set_isboth_false(h->flags, x); \
+ ++h->size; \
+ *ret = 2; \
+ } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
+ return x; \
+ } \
+ SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
+ { \
+ if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
+ __ac_set_isdel_true(h->flags, x); \
+ --h->size; \
+ } \
+ }
+
+#define KHASH_DECLARE(name, khkey_t, khval_t) \
+ __KHASH_TYPE(name, khkey_t, khval_t) \
+ __KHASH_PROTOTYPES(name, khkey_t, khval_t)
+
+#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
+ __KHASH_TYPE(name, khkey_t, khval_t) \
+ __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
+
+#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
+ KHASH_INIT2(name, static inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
+
+/* Other convenient macros... */
+
+/*! @function
+ @abstract Test whether a bucket contains data.
+ @param h Pointer to the hash table [khash_t(name)*]
+ @param x Iterator to the bucket [khint_t]
+ @return 1 if containing data; 0 otherwise [int]
+ */
+#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
+
+/*! @function
+ @abstract Get key given an iterator
+ @param h Pointer to the hash table [khash_t(name)*]
+ @param x Iterator to the bucket [khint_t]
+ @return Key [type of keys]
+ */
+#define kh_key(h, x) ((h)->keys[x])
+
+/*! @function
+ @abstract Get value given an iterator
+ @param h Pointer to the hash table [khash_t(name)*]
+ @param x Iterator to the bucket [khint_t]
+ @return Value [type of values]
+ @discussion For hash sets, calling this results in segfault.
+ */
+#define kh_val(h, x) ((h)->vals[x])
+
+/*! @function
+ @abstract Alias of kh_val()
+ */
+#define kh_value(h, x) ((h)->vals[x])
+
+/*! @function
+ @abstract Get the start iterator
+ @param h Pointer to the hash table [khash_t(name)*]
+ @return The start iterator [khint_t]
+ */
+#define kh_begin(h) (khint_t)(0)
+
+/*! @function
+ @abstract Get the end iterator
+ @param h Pointer to the hash table [khash_t(name)*]
+ @return The end iterator [khint_t]
+ */
+#define kh_end(h) ((h)->n_buckets)
+
+/*! @function
+ @abstract Get the number of elements in the hash table
+ @param h Pointer to the hash table [khash_t(name)*]
+ @return Number of elements in the hash table [khint_t]
+ */
+#define kh_size(h) ((h)->size)
+
+/*! @function
+ @abstract Get the number of buckets in the hash table
+ @param h Pointer to the hash table [khash_t(name)*]
+ @return Number of buckets in the hash table [khint_t]
+ */
+#define kh_n_buckets(h) ((h)->n_buckets)
+
+/*! @function
+ @abstract Iterate over the entries in the hash table
+ @param h Pointer to the hash table [khash_t(name)*]
+ @param kvar Variable to which key will be assigned
+ @param vvar Variable to which value will be assigned
+ @param code Block of code to execute
+ */
+#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
+ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
+ if (!kh_exist(h,__i)) continue; \
+ (kvar) = kh_key(h,__i); \
+ (vvar) = kh_val(h,__i); \
+ code; \
+ } }
+
+/*! @function
+ @abstract Iterate over the values in the hash table
+ @param h Pointer to the hash table [khash_t(name)*]
+ @param vvar Variable to which value will be assigned
+ @param code Block of code to execute
+ */
+#define kh_foreach_value(h, vvar, code) { khint_t __i; \
+ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
+ if (!kh_exist(h,__i)) continue; \
+ (vvar) = kh_val(h,__i); \
+ code; \
+ } }
+
+static inline khint_t __kh_oid_hash(const unsigned char *oid)
+{
+ khint_t hash;
+ memcpy(&hash, oid, sizeof(hash));
+ return hash;
+}
+
+#define __kh_oid_cmp(a, b) (hashcmp(a, b) == 0)
+
+KHASH_INIT(sha1, const unsigned char *, void *, 1, __kh_oid_hash, __kh_oid_cmp)
+typedef kh_sha1_t khash_sha1;
+
+KHASH_INIT(sha1_pos, const unsigned char *, int, 1, __kh_oid_hash, __kh_oid_cmp)
+typedef kh_sha1_pos_t khash_sha1_pos;
+
+#endif /* __AC_KHASH_H */
diff --git a/merge-recursive.c b/merge-recursive.c
index 8400a8e937..4177092942 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -201,7 +201,9 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
const char *path, int stage, int refresh, int options)
{
struct cache_entry *ce;
- ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
+ ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage,
+ (refresh ? (CE_MATCH_REFRESH |
+ CE_MATCH_IGNORE_MISSING) : 0 ));
if (!ce)
return error(_("addinfo_cache failed for path '%s'"), path);
return add_cache_entry(ce, options);
diff --git a/name-hash.c b/name-hash.c
index e5b6e1ad23..97444d0201 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -8,49 +8,28 @@
#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
-/*
- * This removes bit 5 if bit 6 is set.
- *
- * That will make US-ASCII characters hash to their upper-case
- * equivalent. We could easily do this one whole word at a time,
- * but that's for future worries.
- */
-static inline unsigned char icase_hash(unsigned char c)
-{
- return c & ~((c & 0x40) >> 1);
-}
-
-static unsigned int hash_name(const char *name, int namelen)
-{
- unsigned int hash = 0x123;
-
- while (namelen--) {
- unsigned char c = *name++;
- c = icase_hash(c);
- hash = hash*101 + c;
- }
- return hash;
-}
-
struct dir_entry {
- struct dir_entry *next;
+ struct hashmap_entry ent;
struct dir_entry *parent;
struct cache_entry *ce;
int nr;
unsigned int namelen;
};
+static int dir_entry_cmp(const struct dir_entry *e1,
+ const struct dir_entry *e2, const char *name)
+{
+ return e1->namelen != e2->namelen || strncasecmp(e1->ce->name,
+ name ? name : e2->ce->name, e1->namelen);
+}
+
static struct dir_entry *find_dir_entry(struct index_state *istate,
const char *name, unsigned int namelen)
{
- unsigned int hash = hash_name(name, namelen);
- struct dir_entry *dir;
-
- for (dir = lookup_hash(hash, &istate->dir_hash); dir; dir = dir->next)
- if (dir->namelen == namelen &&
- !strncasecmp(dir->ce->name, name, namelen))
- return dir;
- return NULL;
+ struct dir_entry key;
+ hashmap_entry_init(&key, memihash(name, namelen));
+ key.namelen = namelen;
+ return hashmap_get(&istate->dir_hash, &key, name);
}
static struct dir_entry *hash_dir_entry(struct index_state *istate,
@@ -84,18 +63,11 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,
dir = find_dir_entry(istate, ce->name, namelen);
if (!dir) {
/* not found, create it and add to hash table */
- void **pdir;
- unsigned int hash = hash_name(ce->name, namelen);
-
dir = xcalloc(1, sizeof(struct dir_entry));
+ hashmap_entry_init(dir, memihash(ce->name, namelen));
dir->namelen = namelen;
dir->ce = ce;
-
- pdir = insert_hash(hash, dir, &istate->dir_hash);
- if (pdir) {
- dir->next = *pdir;
- *pdir = dir;
- }
+ hashmap_add(&istate->dir_hash, dir);
/* recursively add missing parent directories */
dir->parent = hash_dir_entry(istate, ce, namelen);
@@ -114,45 +86,50 @@ static void add_dir_entry(struct index_state *istate, struct cache_entry *ce)
static void remove_dir_entry(struct index_state *istate, struct cache_entry *ce)
{
/*
- * Release reference to the directory entry (and parents if 0).
- *
- * Note: we do not remove / free the entry because there's no
- * hash.[ch]::remove_hash and dir->next may point to other entries
- * that are still valid, so we must not free the memory.
+ * Release reference to the directory entry. If 0, remove and continue
+ * with parent directory.
*/
struct dir_entry *dir = hash_dir_entry(istate, ce, ce_namelen(ce));
- while (dir && dir->nr && !(--dir->nr))
- dir = dir->parent;
+ while (dir && !(--dir->nr)) {
+ struct dir_entry *parent = dir->parent;
+ hashmap_remove(&istate->dir_hash, dir, NULL);
+ free(dir);
+ dir = parent;
+ }
}
static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
{
- void **pos;
- unsigned int hash;
-
if (ce->ce_flags & CE_HASHED)
return;
ce->ce_flags |= CE_HASHED;
- ce->next = NULL;
- hash = hash_name(ce->name, ce_namelen(ce));
- pos = insert_hash(hash, ce, &istate->name_hash);
- if (pos) {
- ce->next = *pos;
- *pos = ce;
- }
+ hashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce)));
+ hashmap_add(&istate->name_hash, ce);
- if (ignore_case && !(ce->ce_flags & CE_UNHASHED))
+ if (ignore_case)
add_dir_entry(istate, ce);
}
+static int cache_entry_cmp(const struct cache_entry *ce1,
+ const struct cache_entry *ce2, const void *remove)
+{
+ /*
+ * For remove_name_hash, find the exact entry (pointer equality); for
+ * index_file_exists, find all entries with matching hash code and
+ * decide whether the entry matches in same_name.
+ */
+ return remove ? !(ce1 == ce2) : 0;
+}
+
static void lazy_init_name_hash(struct index_state *istate)
{
int nr;
if (istate->name_hash_initialized)
return;
- if (istate->cache_nr)
- preallocate_hash(&istate->name_hash, istate->cache_nr);
+ hashmap_init(&istate->name_hash, (hashmap_cmp_fn) cache_entry_cmp,
+ istate->cache_nr);
+ hashmap_init(&istate->dir_hash, (hashmap_cmp_fn) dir_entry_cmp, 0);
for (nr = 0; nr < istate->cache_nr; nr++)
hash_index_entry(istate, istate->cache[nr]);
istate->name_hash_initialized = 1;
@@ -160,31 +137,19 @@ static void lazy_init_name_hash(struct index_state *istate)
void add_name_hash(struct index_state *istate, struct cache_entry *ce)
{
- /* if already hashed, add reference to directory entries */
- if (ignore_case && (ce->ce_flags & CE_STATE_MASK) == CE_STATE_MASK)
- add_dir_entry(istate, ce);
-
- ce->ce_flags &= ~CE_UNHASHED;
if (istate->name_hash_initialized)
hash_index_entry(istate, ce);
}
-/*
- * We don't actually *remove* it, we can just mark it invalid so that
- * we won't find it in lookups.
- *
- * Not only would we have to search the lists (simple enough), but
- * we'd also have to rehash other hash buckets in case this makes the
- * hash bucket empty (common). So it's much better to just mark
- * it.
- */
void remove_name_hash(struct index_state *istate, struct cache_entry *ce)
{
- /* if already hashed, release reference to directory entries */
- if (ignore_case && (ce->ce_flags & CE_STATE_MASK) == CE_HASHED)
- remove_dir_entry(istate, ce);
+ if (!istate->name_hash_initialized || !(ce->ce_flags & CE_HASHED))
+ return;
+ ce->ce_flags &= ~CE_HASHED;
+ hashmap_remove(&istate->name_hash, ce, ce);
- ce->ce_flags |= CE_UNHASHED;
+ if (ignore_case)
+ remove_dir_entry(istate, ce);
}
static int slow_same_name(const char *name1, int len1, const char *name2, int len2)
@@ -247,49 +212,27 @@ struct cache_entry *index_dir_exists(struct index_state *istate, const char *nam
struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)
{
- unsigned int hash = hash_name(name, namelen);
struct cache_entry *ce;
+ struct hashmap_entry key;
lazy_init_name_hash(istate);
- ce = lookup_hash(hash, &istate->name_hash);
+ hashmap_entry_init(&key, memihash(name, namelen));
+ ce = hashmap_get(&istate->name_hash, &key, NULL);
while (ce) {
- if (!(ce->ce_flags & CE_UNHASHED)) {
- if (same_name(ce, name, namelen, icase))
- return ce;
- }
- ce = ce->next;
+ if (same_name(ce, name, namelen, icase))
+ return ce;
+ ce = hashmap_get_next(&istate->name_hash, ce);
}
return NULL;
}
-struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)
-{
- if (namelen > 0 && name[namelen - 1] == '/')
- return index_dir_exists(istate, name, namelen - 1);
- return index_file_exists(istate, name, namelen, icase);
-}
-
-static int free_dir_entry(void *entry, void *unused)
-{
- struct dir_entry *dir = entry;
- while (dir) {
- struct dir_entry *next = dir->next;
- free(dir);
- dir = next;
- }
- return 0;
-}
-
void free_name_hash(struct index_state *istate)
{
if (!istate->name_hash_initialized)
return;
istate->name_hash_initialized = 0;
- if (ignore_case)
- /* free directory entries */
- for_each_hash(&istate->dir_hash, free_dir_entry, NULL);
- free_hash(&istate->name_hash);
- free_hash(&istate->dir_hash);
+ hashmap_free(&istate->name_hash, 0);
+ hashmap_free(&istate->dir_hash, 1);
}
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
new file mode 100644
index 0000000000..1218befaf2
--- /dev/null
+++ b/pack-bitmap-write.c
@@ -0,0 +1,552 @@
+#include "cache.h"
+#include "commit.h"
+#include "tag.h"
+#include "diff.h"
+#include "revision.h"
+#include "list-objects.h"
+#include "progress.h"
+#include "pack-revindex.h"
+#include "pack.h"
+#include "pack-bitmap.h"
+#include "sha1-lookup.h"
+#include "pack-objects.h"
+
+struct bitmapped_commit {
+ struct commit *commit;
+ struct ewah_bitmap *bitmap;
+ struct ewah_bitmap *write_as;
+ int flags;
+ int xor_offset;
+ uint32_t commit_pos;
+};
+
+struct bitmap_writer {
+ struct ewah_bitmap *commits;
+ struct ewah_bitmap *trees;
+ struct ewah_bitmap *blobs;
+ struct ewah_bitmap *tags;
+
+ khash_sha1 *bitmaps;
+ khash_sha1 *reused;
+ struct packing_data *to_pack;
+
+ struct bitmapped_commit *selected;
+ unsigned int selected_nr, selected_alloc;
+
+ struct progress *progress;
+ int show_progress;
+ unsigned char pack_checksum[20];
+};
+
+static struct bitmap_writer writer;
+
+void bitmap_writer_show_progress(int show)
+{
+ writer.show_progress = show;
+}
+
+/**
+ * Build the initial type index for the packfile
+ */
+void bitmap_writer_build_type_index(struct pack_idx_entry **index,
+ uint32_t index_nr)
+{
+ uint32_t i;
+
+ writer.commits = ewah_new();
+ writer.trees = ewah_new();
+ writer.blobs = ewah_new();
+ writer.tags = ewah_new();
+
+ for (i = 0; i < index_nr; ++i) {
+ struct object_entry *entry = (struct object_entry *)index[i];
+ enum object_type real_type;
+
+ entry->in_pack_pos = i;
+
+ switch (entry->type) {
+ case OBJ_COMMIT:
+ case OBJ_TREE:
+ case OBJ_BLOB:
+ case OBJ_TAG:
+ real_type = entry->type;
+ break;
+
+ default:
+ real_type = sha1_object_info(entry->idx.sha1, NULL);
+ break;
+ }
+
+ switch (real_type) {
+ case OBJ_COMMIT:
+ ewah_set(writer.commits, i);
+ break;
+
+ case OBJ_TREE:
+ ewah_set(writer.trees, i);
+ break;
+
+ case OBJ_BLOB:
+ ewah_set(writer.blobs, i);
+ break;
+
+ case OBJ_TAG:
+ ewah_set(writer.tags, i);
+ break;
+
+ default:
+ die("Missing type information for %s (%d/%d)",
+ sha1_to_hex(entry->idx.sha1), real_type, entry->type);
+ }
+ }
+}
+
+/**
+ * Compute the actual bitmaps
+ */
+static struct object **seen_objects;
+static unsigned int seen_objects_nr, seen_objects_alloc;
+
+static inline void push_bitmapped_commit(struct commit *commit, struct ewah_bitmap *reused)
+{
+ if (writer.selected_nr >= writer.selected_alloc) {
+ writer.selected_alloc = (writer.selected_alloc + 32) * 2;
+ writer.selected = xrealloc(writer.selected,
+ writer.selected_alloc * sizeof(struct bitmapped_commit));
+ }
+
+ writer.selected[writer.selected_nr].commit = commit;
+ writer.selected[writer.selected_nr].bitmap = reused;
+ writer.selected[writer.selected_nr].flags = 0;
+
+ writer.selected_nr++;
+}
+
+static inline void mark_as_seen(struct object *object)
+{
+ ALLOC_GROW(seen_objects, seen_objects_nr + 1, seen_objects_alloc);
+ seen_objects[seen_objects_nr++] = object;
+}
+
+static inline void reset_all_seen(void)
+{
+ unsigned int i;
+ for (i = 0; i < seen_objects_nr; ++i) {
+ seen_objects[i]->flags &= ~(SEEN | ADDED | SHOWN);
+ }
+ seen_objects_nr = 0;
+}
+
+static uint32_t find_object_pos(const unsigned char *sha1)
+{
+ struct object_entry *entry = packlist_find(writer.to_pack, sha1, NULL);
+
+ if (!entry) {
+ die("Failed to write bitmap index. Packfile doesn't have full closure "
+ "(object %s is missing)", sha1_to_hex(sha1));
+ }
+
+ return entry->in_pack_pos;
+}
+
+static void show_object(struct object *object, const struct name_path *path,
+ const char *last, void *data)
+{
+ struct bitmap *base = data;
+ bitmap_set(base, find_object_pos(object->sha1));
+ mark_as_seen(object);
+}
+
+static void show_commit(struct commit *commit, void *data)
+{
+ mark_as_seen((struct object *)commit);
+}
+
+static int
+add_to_include_set(struct bitmap *base, struct commit *commit)
+{
+ khiter_t hash_pos;
+ uint32_t bitmap_pos = find_object_pos(commit->object.sha1);
+
+ if (bitmap_get(base, bitmap_pos))
+ return 0;
+
+ hash_pos = kh_get_sha1(writer.bitmaps, commit->object.sha1);
+ if (hash_pos < kh_end(writer.bitmaps)) {
+ struct bitmapped_commit *bc = kh_value(writer.bitmaps, hash_pos);
+ bitmap_or_ewah(base, bc->bitmap);
+ return 0;
+ }
+
+ bitmap_set(base, bitmap_pos);
+ return 1;
+}
+
+static int
+should_include(struct commit *commit, void *_data)
+{
+ struct bitmap *base = _data;
+
+ if (!add_to_include_set(base, commit)) {
+ struct commit_list *parent = commit->parents;
+
+ mark_as_seen((struct object *)commit);
+
+ while (parent) {
+ parent->item->object.flags |= SEEN;
+ mark_as_seen((struct object *)parent->item);
+ parent = parent->next;
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static void compute_xor_offsets(void)
+{
+ static const int MAX_XOR_OFFSET_SEARCH = 10;
+
+ int i, next = 0;
+
+ while (next < writer.selected_nr) {
+ struct bitmapped_commit *stored = &writer.selected[next];
+
+ int best_offset = 0;
+ struct ewah_bitmap *best_bitmap = stored->bitmap;
+ struct ewah_bitmap *test_xor;
+
+ for (i = 1; i <= MAX_XOR_OFFSET_SEARCH; ++i) {
+ int curr = next - i;
+
+ if (curr < 0)
+ break;
+
+ test_xor = ewah_pool_new();
+ ewah_xor(writer.selected[curr].bitmap, stored->bitmap, test_xor);
+
+ if (test_xor->buffer_size < best_bitmap->buffer_size) {
+ if (best_bitmap != stored->bitmap)
+ ewah_pool_free(best_bitmap);
+
+ best_bitmap = test_xor;
+ best_offset = i;
+ } else {
+ ewah_pool_free(test_xor);
+ }
+ }
+
+ stored->xor_offset = best_offset;
+ stored->write_as = best_bitmap;
+
+ next++;
+ }
+}
+
+void bitmap_writer_build(struct packing_data *to_pack)
+{
+ static const double REUSE_BITMAP_THRESHOLD = 0.2;
+
+ int i, reuse_after, need_reset;
+ struct bitmap *base = bitmap_new();
+ struct rev_info revs;
+
+ writer.bitmaps = kh_init_sha1();
+ writer.to_pack = to_pack;
+
+ if (writer.show_progress)
+ writer.progress = start_progress("Building bitmaps", writer.selected_nr);
+
+ init_revisions(&revs, NULL);
+ revs.tag_objects = 1;
+ revs.tree_objects = 1;
+ revs.blob_objects = 1;
+ revs.no_walk = 0;
+
+ revs.include_check = should_include;
+ reset_revision_walk();
+
+ reuse_after = writer.selected_nr * REUSE_BITMAP_THRESHOLD;
+ need_reset = 0;
+
+ for (i = writer.selected_nr - 1; i >= 0; --i) {
+ struct bitmapped_commit *stored;
+ struct object *object;
+
+ khiter_t hash_pos;
+ int hash_ret;
+
+ stored = &writer.selected[i];
+ object = (struct object *)stored->commit;
+
+ if (stored->bitmap == NULL) {
+ if (i < writer.selected_nr - 1 &&
+ (need_reset ||
+ !in_merge_bases(writer.selected[i + 1].commit,
+ stored->commit))) {
+ bitmap_reset(base);
+ reset_all_seen();
+ }
+
+ add_pending_object(&revs, object, "");
+ revs.include_check_data = base;
+
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
+
+ traverse_commit_list(&revs, show_commit, show_object, base);
+
+ revs.pending.nr = 0;
+ revs.pending.alloc = 0;
+ revs.pending.objects = NULL;
+
+ stored->bitmap = bitmap_to_ewah(base);
+ need_reset = 0;
+ } else
+ need_reset = 1;
+
+ if (i >= reuse_after)
+ stored->flags |= BITMAP_FLAG_REUSE;
+
+ hash_pos = kh_put_sha1(writer.bitmaps, object->sha1, &hash_ret);
+ if (hash_ret == 0)
+ die("Duplicate entry when writing index: %s",
+ sha1_to_hex(object->sha1));
+
+ kh_value(writer.bitmaps, hash_pos) = stored;
+ display_progress(writer.progress, writer.selected_nr - i);
+ }
+
+ bitmap_free(base);
+ stop_progress(&writer.progress);
+
+ compute_xor_offsets();
+}
+
+/**
+ * Select the commits that will be bitmapped
+ */
+static inline unsigned int next_commit_index(unsigned int idx)
+{
+ static const unsigned int MIN_COMMITS = 100;
+ static const unsigned int MAX_COMMITS = 5000;
+
+ static const unsigned int MUST_REGION = 100;
+ static const unsigned int MIN_REGION = 20000;
+
+ unsigned int offset, next;
+
+ if (idx <= MUST_REGION)
+ return 0;
+
+ if (idx <= MIN_REGION) {
+ offset = idx - MUST_REGION;
+ return (offset < MIN_COMMITS) ? offset : MIN_COMMITS;
+ }
+
+ offset = idx - MIN_REGION;
+ next = (offset < MAX_COMMITS) ? offset : MAX_COMMITS;
+
+ return (next > MIN_COMMITS) ? next : MIN_COMMITS;
+}
+
+static int date_compare(const void *_a, const void *_b)
+{
+ struct commit *a = *(struct commit **)_a;
+ struct commit *b = *(struct commit **)_b;
+ return (long)b->date - (long)a->date;
+}
+
+void bitmap_writer_reuse_bitmaps(struct packing_data *to_pack)
+{
+ if (prepare_bitmap_git() < 0)
+ return;
+
+ writer.reused = kh_init_sha1();
+ rebuild_existing_bitmaps(to_pack, writer.reused, writer.show_progress);
+}
+
+static struct ewah_bitmap *find_reused_bitmap(const unsigned char *sha1)
+{
+ khiter_t hash_pos;
+
+ if (!writer.reused)
+ return NULL;
+
+ hash_pos = kh_get_sha1(writer.reused, sha1);
+ if (hash_pos >= kh_end(writer.reused))
+ return NULL;
+
+ return kh_value(writer.reused, hash_pos);
+}
+
+void bitmap_writer_select_commits(struct commit **indexed_commits,
+ unsigned int indexed_commits_nr,
+ int max_bitmaps)
+{
+ unsigned int i = 0, j, next;
+
+ qsort(indexed_commits, indexed_commits_nr, sizeof(indexed_commits[0]),
+ date_compare);
+
+ if (writer.show_progress)
+ writer.progress = start_progress("Selecting bitmap commits", 0);
+
+ if (indexed_commits_nr < 100) {
+ for (i = 0; i < indexed_commits_nr; ++i)
+ push_bitmapped_commit(indexed_commits[i], NULL);
+ return;
+ }
+
+ for (;;) {
+ struct ewah_bitmap *reused_bitmap = NULL;
+ struct commit *chosen = NULL;
+
+ next = next_commit_index(i);
+
+ if (i + next >= indexed_commits_nr)
+ break;
+
+ if (max_bitmaps > 0 && writer.selected_nr >= max_bitmaps) {
+ writer.selected_nr = max_bitmaps;
+ break;
+ }
+
+ if (next == 0) {
+ chosen = indexed_commits[i];
+ reused_bitmap = find_reused_bitmap(chosen->object.sha1);
+ } else {
+ chosen = indexed_commits[i + next];
+
+ for (j = 0; j <= next; ++j) {
+ struct commit *cm = indexed_commits[i + j];
+
+ reused_bitmap = find_reused_bitmap(cm->object.sha1);
+ if (reused_bitmap || (cm->object.flags & NEEDS_BITMAP) != 0) {
+ chosen = cm;
+ break;
+ }
+
+ if (cm->parents && cm->parents->next)
+ chosen = cm;
+ }
+ }
+
+ push_bitmapped_commit(chosen, reused_bitmap);
+
+ i += next + 1;
+ display_progress(writer.progress, i);
+ }
+
+ stop_progress(&writer.progress);
+}
+
+
+static int sha1write_ewah_helper(void *f, const void *buf, size_t len)
+{
+ /* sha1write will die on error */
+ sha1write(f, buf, len);
+ return len;
+}
+
+/**
+ * Write the bitmap index to disk
+ */
+static inline void dump_bitmap(struct sha1file *f, struct ewah_bitmap *bitmap)
+{
+ if (ewah_serialize_to(bitmap, sha1write_ewah_helper, f) < 0)
+ die("Failed to write bitmap index");
+}
+
+static const unsigned char *sha1_access(size_t pos, void *table)
+{
+ struct pack_idx_entry **index = table;
+ return index[pos]->sha1;
+}
+
+static void write_selected_commits_v1(struct sha1file *f,
+ struct pack_idx_entry **index,
+ uint32_t index_nr)
+{
+ int i;
+
+ for (i = 0; i < writer.selected_nr; ++i) {
+ struct bitmapped_commit *stored = &writer.selected[i];
+ struct bitmap_disk_entry on_disk;
+
+ int commit_pos =
+ sha1_pos(stored->commit->object.sha1, index, index_nr, sha1_access);
+
+ if (commit_pos < 0)
+ die("BUG: trying to write commit not in index");
+
+ on_disk.object_pos = htonl(commit_pos);
+ on_disk.xor_offset = stored->xor_offset;
+ on_disk.flags = stored->flags;
+
+ sha1write(f, &on_disk, sizeof(on_disk));
+ dump_bitmap(f, stored->write_as);
+ }
+}
+
+static void write_hash_cache(struct sha1file *f,
+ struct pack_idx_entry **index,
+ uint32_t index_nr)
+{
+ uint32_t i;
+
+ for (i = 0; i < index_nr; ++i) {
+ struct object_entry *entry = (struct object_entry *)index[i];
+ uint32_t hash_value = htonl(entry->hash);
+ sha1write(f, &hash_value, sizeof(hash_value));
+ }
+}
+
+void bitmap_writer_set_checksum(unsigned char *sha1)
+{
+ hashcpy(writer.pack_checksum, sha1);
+}
+
+void bitmap_writer_finish(struct pack_idx_entry **index,
+ uint32_t index_nr,
+ const char *filename,
+ uint16_t options)
+{
+ static char tmp_file[PATH_MAX];
+ static uint16_t default_version = 1;
+ static uint16_t flags = BITMAP_OPT_FULL_DAG;
+ struct sha1file *f;
+
+ struct bitmap_disk_header header;
+
+ int fd = odb_mkstemp(tmp_file, sizeof(tmp_file), "pack/tmp_bitmap_XXXXXX");
+
+ if (fd < 0)
+ die_errno("unable to create '%s'", tmp_file);
+ f = sha1fd(fd, tmp_file);
+
+ memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE));
+ header.version = htons(default_version);
+ header.options = htons(flags | options);
+ header.entry_count = htonl(writer.selected_nr);
+ memcpy(header.checksum, writer.pack_checksum, 20);
+
+ sha1write(f, &header, sizeof(header));
+ dump_bitmap(f, writer.commits);
+ dump_bitmap(f, writer.trees);
+ dump_bitmap(f, writer.blobs);
+ dump_bitmap(f, writer.tags);
+ write_selected_commits_v1(f, index, index_nr);
+
+ if (options & BITMAP_OPT_HASH_CACHE)
+ write_hash_cache(f, index, index_nr);
+
+ sha1close(f, NULL, CSUM_FSYNC);
+
+ if (adjust_shared_perm(tmp_file))
+ die_errno("unable to make temporary bitmap file readable");
+
+ if (rename(tmp_file, filename))
+ die_errno("unable to rename temporary bitmap file to '%s'", filename);
+}
diff --git a/pack-bitmap.c b/pack-bitmap.c
new file mode 100644
index 0000000000..ae0b57b950
--- /dev/null
+++ b/pack-bitmap.c
@@ -0,0 +1,1073 @@
+#include "cache.h"
+#include "commit.h"
+#include "tag.h"
+#include "diff.h"
+#include "revision.h"
+#include "progress.h"
+#include "list-objects.h"
+#include "pack.h"
+#include "pack-bitmap.h"
+#include "pack-revindex.h"
+#include "pack-objects.h"
+
+/*
+ * An entry on the bitmap index, representing the bitmap for a given
+ * commit.
+ */
+struct stored_bitmap {
+ unsigned char sha1[20];
+ struct ewah_bitmap *root;
+ struct stored_bitmap *xor;
+ int flags;
+};
+
+/*
+ * The currently active bitmap index. By design, repositories only have
+ * a single bitmap index available (the index for the biggest packfile in
+ * the repository), since bitmap indexes need full closure.
+ *
+ * If there is more than one bitmap index available (e.g. because of alternates),
+ * the active bitmap index is the largest one.
+ */
+static struct bitmap_index {
+ /* Packfile to which this bitmap index belongs to */
+ struct packed_git *pack;
+
+ /* reverse index for the packfile */
+ struct pack_revindex *reverse_index;
+
+ /*
+ * Mark the first `reuse_objects` in the packfile as reused:
+ * they will be sent as-is without using them for repacking
+ * calculations
+ */
+ uint32_t reuse_objects;
+
+ /* mmapped buffer of the whole bitmap index */
+ unsigned char *map;
+ size_t map_size; /* size of the mmaped buffer */
+ size_t map_pos; /* current position when loading the index */
+
+ /*
+ * Type indexes.
+ *
+ * Each bitmap marks which objects in the packfile are of the given
+ * type. This provides type information when yielding the objects from
+ * the packfile during a walk, which allows for better delta bases.
+ */
+ struct ewah_bitmap *commits;
+ struct ewah_bitmap *trees;
+ struct ewah_bitmap *blobs;
+ struct ewah_bitmap *tags;
+
+ /* Map from SHA1 -> `stored_bitmap` for all the bitmapped comits */
+ khash_sha1 *bitmaps;
+
+ /* Number of bitmapped commits */
+ uint32_t entry_count;
+
+ /* Name-hash cache (or NULL if not present). */
+ uint32_t *hashes;
+
+ /*
+ * Extended index.
+ *
+ * When trying to perform bitmap operations with objects that are not
+ * packed in `pack`, these objects are added to this "fake index" and
+ * are assumed to appear at the end of the packfile for all operations
+ */
+ struct eindex {
+ struct object **objects;
+ uint32_t *hashes;
+ uint32_t count, alloc;
+ khash_sha1_pos *positions;
+ } ext_index;
+
+ /* Bitmap result of the last performed walk */
+ struct bitmap *result;
+
+ /* Version of the bitmap index */
+ unsigned int version;
+
+ unsigned loaded : 1;
+
+} bitmap_git;
+
+static struct ewah_bitmap *lookup_stored_bitmap(struct stored_bitmap *st)
+{
+ struct ewah_bitmap *parent;
+ struct ewah_bitmap *composed;
+
+ if (st->xor == NULL)
+ return st->root;
+
+ composed = ewah_pool_new();
+ parent = lookup_stored_bitmap(st->xor);
+ ewah_xor(st->root, parent, composed);
+
+ ewah_pool_free(st->root);
+ st->root = composed;
+ st->xor = NULL;
+
+ return composed;
+}
+
+/*
+ * Read a bitmap from the current read position on the mmaped
+ * index, and increase the read position accordingly
+ */
+static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index)
+{
+ struct ewah_bitmap *b = ewah_pool_new();
+
+ int bitmap_size = ewah_read_mmap(b,
+ index->map + index->map_pos,
+ index->map_size - index->map_pos);
+
+ if (bitmap_size < 0) {
+ error("Failed to load bitmap index (corrupted?)");
+ ewah_pool_free(b);
+ return NULL;
+ }
+
+ index->map_pos += bitmap_size;
+ return b;
+}
+
+static int load_bitmap_header(struct bitmap_index *index)
+{
+ struct bitmap_disk_header *header = (void *)index->map;
+
+ if (index->map_size < sizeof(*header) + 20)
+ return error("Corrupted bitmap index (missing header data)");
+
+ if (memcmp(header->magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)) != 0)
+ return error("Corrupted bitmap index file (wrong header)");
+
+ index->version = ntohs(header->version);
+ if (index->version != 1)
+ return error("Unsupported version for bitmap index file (%d)", index->version);
+
+ /* Parse known bitmap format options */
+ {
+ uint32_t flags = ntohs(header->options);
+
+ if ((flags & BITMAP_OPT_FULL_DAG) == 0)
+ return error("Unsupported options for bitmap index file "
+ "(Git requires BITMAP_OPT_FULL_DAG)");
+
+ if (flags & BITMAP_OPT_HASH_CACHE) {
+ unsigned char *end = index->map + index->map_size - 20;
+ index->hashes = ((uint32_t *)end) - index->pack->num_objects;
+ }
+ }
+
+ index->entry_count = ntohl(header->entry_count);
+ index->map_pos += sizeof(*header);
+ return 0;
+}
+
+static struct stored_bitmap *store_bitmap(struct bitmap_index *index,
+ struct ewah_bitmap *root,
+ const unsigned char *sha1,
+ struct stored_bitmap *xor_with,
+ int flags)
+{
+ struct stored_bitmap *stored;
+ khiter_t hash_pos;
+ int ret;
+
+ stored = xmalloc(sizeof(struct stored_bitmap));
+ stored->root = root;
+ stored->xor = xor_with;
+ stored->flags = flags;
+ hashcpy(stored->sha1, sha1);
+
+ hash_pos = kh_put_sha1(index->bitmaps, stored->sha1, &ret);
+
+ /* a 0 return code means the insertion succeeded with no changes,
+ * because the SHA1 already existed on the map. this is bad, there
+ * shouldn't be duplicated commits in the index */
+ if (ret == 0) {
+ error("Duplicate entry in bitmap index: %s", sha1_to_hex(sha1));
+ return NULL;
+ }
+
+ kh_value(index->bitmaps, hash_pos) = stored;
+ return stored;
+}
+
+static int load_bitmap_entries_v1(struct bitmap_index *index)
+{
+ static const size_t MAX_XOR_OFFSET = 160;
+
+ uint32_t i;
+ struct stored_bitmap **recent_bitmaps;
+ struct bitmap_disk_entry *entry;
+
+ recent_bitmaps = xcalloc(MAX_XOR_OFFSET, sizeof(struct stored_bitmap));
+
+ for (i = 0; i < index->entry_count; ++i) {
+ int xor_offset, flags;
+ struct ewah_bitmap *bitmap = NULL;
+ struct stored_bitmap *xor_bitmap = NULL;
+ uint32_t commit_idx_pos;
+ const unsigned char *sha1;
+
+ entry = (struct bitmap_disk_entry *)(index->map + index->map_pos);
+ index->map_pos += sizeof(struct bitmap_disk_entry);
+
+ commit_idx_pos = ntohl(entry->object_pos);
+ sha1 = nth_packed_object_sha1(index->pack, commit_idx_pos);
+
+ xor_offset = (int)entry->xor_offset;
+ flags = (int)entry->flags;
+
+ bitmap = read_bitmap_1(index);
+ if (!bitmap)
+ return -1;
+
+ if (xor_offset > MAX_XOR_OFFSET || xor_offset > i)
+ return error("Corrupted bitmap pack index");
+
+ if (xor_offset > 0) {
+ xor_bitmap = recent_bitmaps[(i - xor_offset) % MAX_XOR_OFFSET];
+
+ if (xor_bitmap == NULL)
+ return error("Invalid XOR offset in bitmap pack index");
+ }
+
+ recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap(
+ index, bitmap, sha1, xor_bitmap, flags);
+ }
+
+ return 0;
+}
+
+static int open_pack_bitmap_1(struct packed_git *packfile)
+{
+ int fd;
+ struct stat st;
+ char *idx_name;
+
+ if (open_pack_index(packfile))
+ return -1;
+
+ idx_name = pack_bitmap_filename(packfile);
+ fd = git_open_noatime(idx_name);
+ free(idx_name);
+
+ if (fd < 0)
+ return -1;
+
+ if (fstat(fd, &st)) {
+ close(fd);
+ return -1;
+ }
+
+ if (bitmap_git.pack) {
+ warning("ignoring extra bitmap file: %s", packfile->pack_name);
+ close(fd);
+ return -1;
+ }
+
+ bitmap_git.pack = packfile;
+ bitmap_git.map_size = xsize_t(st.st_size);
+ bitmap_git.map = xmmap(NULL, bitmap_git.map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ bitmap_git.map_pos = 0;
+ close(fd);
+
+ if (load_bitmap_header(&bitmap_git) < 0) {
+ munmap(bitmap_git.map, bitmap_git.map_size);
+ bitmap_git.map = NULL;
+ bitmap_git.map_size = 0;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int load_pack_bitmap(void)
+{
+ assert(bitmap_git.map && !bitmap_git.loaded);
+
+ bitmap_git.bitmaps = kh_init_sha1();
+ bitmap_git.ext_index.positions = kh_init_sha1_pos();
+ bitmap_git.reverse_index = revindex_for_pack(bitmap_git.pack);
+
+ if (!(bitmap_git.commits = read_bitmap_1(&bitmap_git)) ||
+ !(bitmap_git.trees = read_bitmap_1(&bitmap_git)) ||
+ !(bitmap_git.blobs = read_bitmap_1(&bitmap_git)) ||
+ !(bitmap_git.tags = read_bitmap_1(&bitmap_git)))
+ goto failed;
+
+ if (load_bitmap_entries_v1(&bitmap_git) < 0)
+ goto failed;
+
+ bitmap_git.loaded = 1;
+ return 0;
+
+failed:
+ munmap(bitmap_git.map, bitmap_git.map_size);
+ bitmap_git.map = NULL;
+ bitmap_git.map_size = 0;
+ return -1;
+}
+
+char *pack_bitmap_filename(struct packed_git *p)
+{
+ char *idx_name;
+ int len;
+
+ len = strlen(p->pack_name) - strlen(".pack");
+ idx_name = xmalloc(len + strlen(".bitmap") + 1);
+
+ memcpy(idx_name, p->pack_name, len);
+ memcpy(idx_name + len, ".bitmap", strlen(".bitmap") + 1);
+
+ return idx_name;
+}
+
+static int open_pack_bitmap(void)
+{
+ struct packed_git *p;
+ int ret = -1;
+
+ assert(!bitmap_git.map && !bitmap_git.loaded);
+
+ prepare_packed_git();
+ for (p = packed_git; p; p = p->next) {
+ if (open_pack_bitmap_1(p) == 0)
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int prepare_bitmap_git(void)
+{
+ if (bitmap_git.loaded)
+ return 0;
+
+ if (!open_pack_bitmap())
+ return load_pack_bitmap();
+
+ return -1;
+}
+
+struct include_data {
+ struct bitmap *base;
+ struct bitmap *seen;
+};
+
+static inline int bitmap_position_extended(const unsigned char *sha1)
+{
+ khash_sha1_pos *positions = bitmap_git.ext_index.positions;
+ khiter_t pos = kh_get_sha1_pos(positions, sha1);
+
+ if (pos < kh_end(positions)) {
+ int bitmap_pos = kh_value(positions, pos);
+ return bitmap_pos + bitmap_git.pack->num_objects;
+ }
+
+ return -1;
+}
+
+static inline int bitmap_position_packfile(const unsigned char *sha1)
+{
+ off_t offset = find_pack_entry_one(sha1, bitmap_git.pack);
+ if (!offset)
+ return -1;
+
+ return find_revindex_position(bitmap_git.reverse_index, offset);
+}
+
+static int bitmap_position(const unsigned char *sha1)
+{
+ int pos = bitmap_position_packfile(sha1);
+ return (pos >= 0) ? pos : bitmap_position_extended(sha1);
+}
+
+static int ext_index_add_object(struct object *object, const char *name)
+{
+ struct eindex *eindex = &bitmap_git.ext_index;
+
+ khiter_t hash_pos;
+ int hash_ret;
+ int bitmap_pos;
+
+ hash_pos = kh_put_sha1_pos(eindex->positions, object->sha1, &hash_ret);
+ if (hash_ret > 0) {
+ if (eindex->count >= eindex->alloc) {
+ eindex->alloc = (eindex->alloc + 16) * 3 / 2;
+ eindex->objects = xrealloc(eindex->objects,
+ eindex->alloc * sizeof(struct object *));
+ eindex->hashes = xrealloc(eindex->hashes,
+ eindex->alloc * sizeof(uint32_t));
+ }
+
+ bitmap_pos = eindex->count;
+ eindex->objects[eindex->count] = object;
+ eindex->hashes[eindex->count] = pack_name_hash(name);
+ kh_value(eindex->positions, hash_pos) = bitmap_pos;
+ eindex->count++;
+ } else {
+ bitmap_pos = kh_value(eindex->positions, hash_pos);
+ }
+
+ return bitmap_pos + bitmap_git.pack->num_objects;
+}
+
+static void show_object(struct object *object, const struct name_path *path,
+ const char *last, void *data)
+{
+ struct bitmap *base = data;
+ int bitmap_pos;
+
+ bitmap_pos = bitmap_position(object->sha1);
+
+ if (bitmap_pos < 0) {
+ char *name = path_name(path, last);
+ bitmap_pos = ext_index_add_object(object, name);
+ free(name);
+ }
+
+ bitmap_set(base, bitmap_pos);
+}
+
+static void show_commit(struct commit *commit, void *data)
+{
+}
+
+static int add_to_include_set(struct include_data *data,
+ const unsigned char *sha1,
+ int bitmap_pos)
+{
+ khiter_t hash_pos;
+
+ if (data->seen && bitmap_get(data->seen, bitmap_pos))
+ return 0;
+
+ if (bitmap_get(data->base, bitmap_pos))
+ return 0;
+
+ hash_pos = kh_get_sha1(bitmap_git.bitmaps, sha1);
+ if (hash_pos < kh_end(bitmap_git.bitmaps)) {
+ struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, hash_pos);
+ bitmap_or_ewah(data->base, lookup_stored_bitmap(st));
+ return 0;
+ }
+
+ bitmap_set(data->base, bitmap_pos);
+ return 1;
+}
+
+static int should_include(struct commit *commit, void *_data)
+{
+ struct include_data *data = _data;
+ int bitmap_pos;
+
+ bitmap_pos = bitmap_position(commit->object.sha1);
+ if (bitmap_pos < 0)
+ bitmap_pos = ext_index_add_object((struct object *)commit, NULL);
+
+ if (!add_to_include_set(data, commit->object.sha1, bitmap_pos)) {
+ struct commit_list *parent = commit->parents;
+
+ while (parent) {
+ parent->item->object.flags |= SEEN;
+ parent = parent->next;
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct bitmap *find_objects(struct rev_info *revs,
+ struct object_list *roots,
+ struct bitmap *seen)
+{
+ struct bitmap *base = NULL;
+ int needs_walk = 0;
+
+ struct object_list *not_mapped = NULL;
+
+ /*
+ * Go through all the roots for the walk. The ones that have bitmaps
+ * on the bitmap index will be `or`ed together to form an initial
+ * global reachability analysis.
+ *
+ * The ones without bitmaps in the index will be stored in the
+ * `not_mapped_list` for further processing.
+ */
+ while (roots) {
+ struct object *object = roots->item;
+ roots = roots->next;
+
+ if (object->type == OBJ_COMMIT) {
+ khiter_t pos = kh_get_sha1(bitmap_git.bitmaps, object->sha1);
+
+ if (pos < kh_end(bitmap_git.bitmaps)) {
+ struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, pos);
+ struct ewah_bitmap *or_with = lookup_stored_bitmap(st);
+
+ if (base == NULL)
+ base = ewah_to_bitmap(or_with);
+ else
+ bitmap_or_ewah(base, or_with);
+
+ object->flags |= SEEN;
+ continue;
+ }
+ }
+
+ object_list_insert(object, &not_mapped);
+ }
+
+ /*
+ * Best case scenario: We found bitmaps for all the roots,
+ * so the resulting `or` bitmap has the full reachability analysis
+ */
+ if (not_mapped == NULL)
+ return base;
+
+ roots = not_mapped;
+
+ /*
+ * Let's iterate through all the roots that don't have bitmaps to
+ * check if we can determine them to be reachable from the existing
+ * global bitmap.
+ *
+ * If we cannot find them in the existing global bitmap, we'll need
+ * to push them to an actual walk and run it until we can confirm
+ * they are reachable
+ */
+ while (roots) {
+ struct object *object = roots->item;
+ int pos;
+
+ roots = roots->next;
+ pos = bitmap_position(object->sha1);
+
+ if (pos < 0 || base == NULL || !bitmap_get(base, pos)) {
+ object->flags &= ~UNINTERESTING;
+ add_pending_object(revs, object, "");
+ needs_walk = 1;
+ } else {
+ object->flags |= SEEN;
+ }
+ }
+
+ if (needs_walk) {
+ struct include_data incdata;
+
+ if (base == NULL)
+ base = bitmap_new();
+
+ incdata.base = base;
+ incdata.seen = seen;
+
+ revs->include_check = should_include;
+ revs->include_check_data = &incdata;
+
+ if (prepare_revision_walk(revs))
+ die("revision walk setup failed");
+
+ traverse_commit_list(revs, show_commit, show_object, base);
+ }
+
+ return base;
+}
+
+static void show_extended_objects(struct bitmap *objects,
+ show_reachable_fn show_reach)
+{
+ struct eindex *eindex = &bitmap_git.ext_index;
+ uint32_t i;
+
+ for (i = 0; i < eindex->count; ++i) {
+ struct object *obj;
+
+ if (!bitmap_get(objects, bitmap_git.pack->num_objects + i))
+ continue;
+
+ obj = eindex->objects[i];
+ show_reach(obj->sha1, obj->type, 0, eindex->hashes[i], NULL, 0);
+ }
+}
+
+static void show_objects_for_type(
+ struct bitmap *objects,
+ struct ewah_bitmap *type_filter,
+ enum object_type object_type,
+ show_reachable_fn show_reach)
+{
+ size_t pos = 0, i = 0;
+ uint32_t offset;
+
+ struct ewah_iterator it;
+ eword_t filter;
+
+ if (bitmap_git.reuse_objects == bitmap_git.pack->num_objects)
+ return;
+
+ ewah_iterator_init(&it, type_filter);
+
+ while (i < objects->word_alloc && ewah_iterator_next(&filter, &it)) {
+ eword_t word = objects->words[i] & filter;
+
+ for (offset = 0; offset < BITS_IN_WORD; ++offset) {
+ const unsigned char *sha1;
+ struct revindex_entry *entry;
+ uint32_t hash = 0;
+
+ if ((word >> offset) == 0)
+ break;
+
+ offset += ewah_bit_ctz64(word >> offset);
+
+ if (pos + offset < bitmap_git.reuse_objects)
+ continue;
+
+ entry = &bitmap_git.reverse_index->revindex[pos + offset];
+ sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr);
+
+ if (bitmap_git.hashes)
+ hash = ntohl(bitmap_git.hashes[entry->nr]);
+
+ show_reach(sha1, object_type, 0, hash, bitmap_git.pack, entry->offset);
+ }
+
+ pos += BITS_IN_WORD;
+ i++;
+ }
+}
+
+static int in_bitmapped_pack(struct object_list *roots)
+{
+ while (roots) {
+ struct object *object = roots->item;
+ roots = roots->next;
+
+ if (find_pack_entry_one(object->sha1, bitmap_git.pack) > 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+int prepare_bitmap_walk(struct rev_info *revs)
+{
+ unsigned int i;
+ unsigned int pending_nr = revs->pending.nr;
+ struct object_array_entry *pending_e = revs->pending.objects;
+
+ struct object_list *wants = NULL;
+ struct object_list *haves = NULL;
+
+ struct bitmap *wants_bitmap = NULL;
+ struct bitmap *haves_bitmap = NULL;
+
+ if (!bitmap_git.loaded) {
+ /* try to open a bitmapped pack, but don't parse it yet
+ * because we may not need to use it */
+ if (open_pack_bitmap() < 0)
+ return -1;
+ }
+
+ for (i = 0; i < pending_nr; ++i) {
+ struct object *object = pending_e[i].item;
+
+ if (object->type == OBJ_NONE)
+ parse_object_or_die(object->sha1, NULL);
+
+ while (object->type == OBJ_TAG) {
+ struct tag *tag = (struct tag *) object;
+
+ if (object->flags & UNINTERESTING)
+ object_list_insert(object, &haves);
+ else
+ object_list_insert(object, &wants);
+
+ if (!tag->tagged)
+ die("bad tag");
+ object = parse_object_or_die(tag->tagged->sha1, NULL);
+ }
+
+ if (object->flags & UNINTERESTING)
+ object_list_insert(object, &haves);
+ else
+ object_list_insert(object, &wants);
+ }
+
+ /*
+ * if we have a HAVES list, but none of those haves is contained
+ * in the packfile that has a bitmap, we don't have anything to
+ * optimize here
+ */
+ if (haves && !in_bitmapped_pack(haves))
+ return -1;
+
+ /* if we don't want anything, we're done here */
+ if (!wants)
+ return -1;
+
+ /*
+ * now we're going to use bitmaps, so load the actual bitmap entries
+ * from disk. this is the point of no return; after this the rev_list
+ * becomes invalidated and we must perform the revwalk through bitmaps
+ */
+ if (!bitmap_git.loaded && load_pack_bitmap() < 0)
+ return -1;
+
+ revs->pending.nr = 0;
+ revs->pending.alloc = 0;
+ revs->pending.objects = NULL;
+
+ if (haves) {
+ haves_bitmap = find_objects(revs, haves, NULL);
+ reset_revision_walk();
+
+ if (haves_bitmap == NULL)
+ die("BUG: failed to perform bitmap walk");
+ }
+
+ wants_bitmap = find_objects(revs, wants, haves_bitmap);
+
+ if (!wants_bitmap)
+ die("BUG: failed to perform bitmap walk");
+
+ if (haves_bitmap)
+ bitmap_and_not(wants_bitmap, haves_bitmap);
+
+ bitmap_git.result = wants_bitmap;
+
+ bitmap_free(haves_bitmap);
+ return 0;
+}
+
+int reuse_partial_packfile_from_bitmap(struct packed_git **packfile,
+ uint32_t *entries,
+ off_t *up_to)
+{
+ /*
+ * Reuse the packfile content if we need more than
+ * 90% of its objects
+ */
+ static const double REUSE_PERCENT = 0.9;
+
+ struct bitmap *result = bitmap_git.result;
+ uint32_t reuse_threshold;
+ uint32_t i, reuse_objects = 0;
+
+ assert(result);
+
+ for (i = 0; i < result->word_alloc; ++i) {
+ if (result->words[i] != (eword_t)~0) {
+ reuse_objects += ewah_bit_ctz64(~result->words[i]);
+ break;
+ }
+
+ reuse_objects += BITS_IN_WORD;
+ }
+
+#ifdef GIT_BITMAP_DEBUG
+ {
+ const unsigned char *sha1;
+ struct revindex_entry *entry;
+
+ entry = &bitmap_git.reverse_index->revindex[reuse_objects];
+ sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr);
+
+ fprintf(stderr, "Failed to reuse at %d (%016llx)\n",
+ reuse_objects, result->words[i]);
+ fprintf(stderr, " %s\n", sha1_to_hex(sha1));
+ }
+#endif
+
+ if (!reuse_objects)
+ return -1;
+
+ if (reuse_objects >= bitmap_git.pack->num_objects) {
+ bitmap_git.reuse_objects = *entries = bitmap_git.pack->num_objects;
+ *up_to = -1; /* reuse the full pack */
+ *packfile = bitmap_git.pack;
+ return 0;
+ }
+
+ reuse_threshold = bitmap_popcount(bitmap_git.result) * REUSE_PERCENT;
+
+ if (reuse_objects < reuse_threshold)
+ return -1;
+
+ bitmap_git.reuse_objects = *entries = reuse_objects;
+ *up_to = bitmap_git.reverse_index->revindex[reuse_objects].offset;
+ *packfile = bitmap_git.pack;
+
+ return 0;
+}
+
+void traverse_bitmap_commit_list(show_reachable_fn show_reachable)
+{
+ assert(bitmap_git.result);
+
+ show_objects_for_type(bitmap_git.result, bitmap_git.commits,
+ OBJ_COMMIT, show_reachable);
+ show_objects_for_type(bitmap_git.result, bitmap_git.trees,
+ OBJ_TREE, show_reachable);
+ show_objects_for_type(bitmap_git.result, bitmap_git.blobs,
+ OBJ_BLOB, show_reachable);
+ show_objects_for_type(bitmap_git.result, bitmap_git.tags,
+ OBJ_TAG, show_reachable);
+
+ show_extended_objects(bitmap_git.result, show_reachable);
+
+ bitmap_free(bitmap_git.result);
+ bitmap_git.result = NULL;
+}
+
+static uint32_t count_object_type(struct bitmap *objects,
+ enum object_type type)
+{
+ struct eindex *eindex = &bitmap_git.ext_index;
+
+ uint32_t i = 0, count = 0;
+ struct ewah_iterator it;
+ eword_t filter;
+
+ switch (type) {
+ case OBJ_COMMIT:
+ ewah_iterator_init(&it, bitmap_git.commits);
+ break;
+
+ case OBJ_TREE:
+ ewah_iterator_init(&it, bitmap_git.trees);
+ break;
+
+ case OBJ_BLOB:
+ ewah_iterator_init(&it, bitmap_git.blobs);
+ break;
+
+ case OBJ_TAG:
+ ewah_iterator_init(&it, bitmap_git.tags);
+ break;
+
+ default:
+ return 0;
+ }
+
+ while (i < objects->word_alloc && ewah_iterator_next(&filter, &it)) {
+ eword_t word = objects->words[i++] & filter;
+ count += ewah_bit_popcount64(word);
+ }
+
+ for (i = 0; i < eindex->count; ++i) {
+ if (eindex->objects[i]->type == type &&
+ bitmap_get(objects, bitmap_git.pack->num_objects + i))
+ count++;
+ }
+
+ return count;
+}
+
+void count_bitmap_commit_list(uint32_t *commits, uint32_t *trees,
+ uint32_t *blobs, uint32_t *tags)
+{
+ assert(bitmap_git.result);
+
+ if (commits)
+ *commits = count_object_type(bitmap_git.result, OBJ_COMMIT);
+
+ if (trees)
+ *trees = count_object_type(bitmap_git.result, OBJ_TREE);
+
+ if (blobs)
+ *blobs = count_object_type(bitmap_git.result, OBJ_BLOB);
+
+ if (tags)
+ *tags = count_object_type(bitmap_git.result, OBJ_TAG);
+}
+
+struct bitmap_test_data {
+ struct bitmap *base;
+ struct progress *prg;
+ size_t seen;
+};
+
+static void test_show_object(struct object *object,
+ const struct name_path *path,
+ const char *last, void *data)
+{
+ struct bitmap_test_data *tdata = data;
+ int bitmap_pos;
+
+ bitmap_pos = bitmap_position(object->sha1);
+ if (bitmap_pos < 0)
+ die("Object not in bitmap: %s\n", sha1_to_hex(object->sha1));
+
+ bitmap_set(tdata->base, bitmap_pos);
+ display_progress(tdata->prg, ++tdata->seen);
+}
+
+static void test_show_commit(struct commit *commit, void *data)
+{
+ struct bitmap_test_data *tdata = data;
+ int bitmap_pos;
+
+ bitmap_pos = bitmap_position(commit->object.sha1);
+ if (bitmap_pos < 0)
+ die("Object not in bitmap: %s\n", sha1_to_hex(commit->object.sha1));
+
+ bitmap_set(tdata->base, bitmap_pos);
+ display_progress(tdata->prg, ++tdata->seen);
+}
+
+void test_bitmap_walk(struct rev_info *revs)
+{
+ struct object *root;
+ struct bitmap *result = NULL;
+ khiter_t pos;
+ size_t result_popcnt;
+ struct bitmap_test_data tdata;
+
+ if (prepare_bitmap_git())
+ die("failed to load bitmap indexes");
+
+ if (revs->pending.nr != 1)
+ die("you must specify exactly one commit to test");
+
+ fprintf(stderr, "Bitmap v%d test (%d entries loaded)\n",
+ bitmap_git.version, bitmap_git.entry_count);
+
+ root = revs->pending.objects[0].item;
+ pos = kh_get_sha1(bitmap_git.bitmaps, root->sha1);
+
+ if (pos < kh_end(bitmap_git.bitmaps)) {
+ struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, pos);
+ struct ewah_bitmap *bm = lookup_stored_bitmap(st);
+
+ fprintf(stderr, "Found bitmap for %s. %d bits / %08x checksum\n",
+ sha1_to_hex(root->sha1), (int)bm->bit_size, ewah_checksum(bm));
+
+ result = ewah_to_bitmap(bm);
+ }
+
+ if (result == NULL)
+ die("Commit %s doesn't have an indexed bitmap", sha1_to_hex(root->sha1));
+
+ revs->tag_objects = 1;
+ revs->tree_objects = 1;
+ revs->blob_objects = 1;
+
+ result_popcnt = bitmap_popcount(result);
+
+ if (prepare_revision_walk(revs))
+ die("revision walk setup failed");
+
+ tdata.base = bitmap_new();
+ tdata.prg = start_progress("Verifying bitmap entries", result_popcnt);
+ tdata.seen = 0;
+
+ traverse_commit_list(revs, &test_show_commit, &test_show_object, &tdata);
+
+ stop_progress(&tdata.prg);
+
+ if (bitmap_equals(result, tdata.base))
+ fprintf(stderr, "OK!\n");
+ else
+ fprintf(stderr, "Mismatch!\n");
+}
+
+static int rebuild_bitmap(uint32_t *reposition,
+ struct ewah_bitmap *source,
+ struct bitmap *dest)
+{
+ uint32_t pos = 0;
+ struct ewah_iterator it;
+ eword_t word;
+
+ ewah_iterator_init(&it, source);
+
+ while (ewah_iterator_next(&word, &it)) {
+ uint32_t offset, bit_pos;
+
+ for (offset = 0; offset < BITS_IN_WORD; ++offset) {
+ if ((word >> offset) == 0)
+ break;
+
+ offset += ewah_bit_ctz64(word >> offset);
+
+ bit_pos = reposition[pos + offset];
+ if (bit_pos > 0)
+ bitmap_set(dest, bit_pos - 1);
+ else /* can't reuse, we don't have the object */
+ return -1;
+ }
+
+ pos += BITS_IN_WORD;
+ }
+ return 0;
+}
+
+int rebuild_existing_bitmaps(struct packing_data *mapping,
+ khash_sha1 *reused_bitmaps,
+ int show_progress)
+{
+ uint32_t i, num_objects;
+ uint32_t *reposition;
+ struct bitmap *rebuild;
+ struct stored_bitmap *stored;
+ struct progress *progress = NULL;
+
+ khiter_t hash_pos;
+ int hash_ret;
+
+ if (prepare_bitmap_git() < 0)
+ return -1;
+
+ num_objects = bitmap_git.pack->num_objects;
+ reposition = xcalloc(num_objects, sizeof(uint32_t));
+
+ for (i = 0; i < num_objects; ++i) {
+ const unsigned char *sha1;
+ struct revindex_entry *entry;
+ struct object_entry *oe;
+
+ entry = &bitmap_git.reverse_index->revindex[i];
+ sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr);
+ oe = packlist_find(mapping, sha1, NULL);
+
+ if (oe)
+ reposition[i] = oe->in_pack_pos + 1;
+ }
+
+ rebuild = bitmap_new();
+ i = 0;
+
+ if (show_progress)
+ progress = start_progress("Reusing bitmaps", 0);
+
+ kh_foreach_value(bitmap_git.bitmaps, stored, {
+ if (stored->flags & BITMAP_FLAG_REUSE) {
+ if (!rebuild_bitmap(reposition,
+ lookup_stored_bitmap(stored),
+ rebuild)) {
+ hash_pos = kh_put_sha1(reused_bitmaps,
+ stored->sha1,
+ &hash_ret);
+ kh_value(reused_bitmaps, hash_pos) =
+ bitmap_to_ewah(rebuild);
+ }
+ bitmap_reset(rebuild);
+ display_progress(progress, ++i);
+ }
+ });
+
+ stop_progress(&progress);
+
+ free(reposition);
+ bitmap_free(rebuild);
+ return 0;
+}
diff --git a/pack-bitmap.h b/pack-bitmap.h
new file mode 100644
index 0000000000..8b7f4e9f0d
--- /dev/null
+++ b/pack-bitmap.h
@@ -0,0 +1,64 @@
+#ifndef PACK_BITMAP_H
+#define PACK_BITMAP_H
+
+#include "ewah/ewok.h"
+#include "khash.h"
+#include "pack-objects.h"
+
+struct bitmap_disk_entry {
+ uint32_t object_pos;
+ uint8_t xor_offset;
+ uint8_t flags;
+} __attribute__((packed));
+
+struct bitmap_disk_header {
+ char magic[4];
+ uint16_t version;
+ uint16_t options;
+ uint32_t entry_count;
+ unsigned char checksum[20];
+};
+
+static const char BITMAP_IDX_SIGNATURE[] = {'B', 'I', 'T', 'M'};
+
+#define NEEDS_BITMAP (1u<<22)
+
+enum pack_bitmap_opts {
+ BITMAP_OPT_FULL_DAG = 1,
+ BITMAP_OPT_HASH_CACHE = 4,
+};
+
+enum pack_bitmap_flags {
+ BITMAP_FLAG_REUSE = 0x1
+};
+
+typedef int (*show_reachable_fn)(
+ const unsigned char *sha1,
+ enum object_type type,
+ int flags,
+ uint32_t hash,
+ struct packed_git *found_pack,
+ off_t found_offset);
+
+int prepare_bitmap_git(void);
+void count_bitmap_commit_list(uint32_t *commits, uint32_t *trees, uint32_t *blobs, uint32_t *tags);
+void traverse_bitmap_commit_list(show_reachable_fn show_reachable);
+void test_bitmap_walk(struct rev_info *revs);
+char *pack_bitmap_filename(struct packed_git *p);
+int prepare_bitmap_walk(struct rev_info *revs);
+int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, uint32_t *entries, off_t *up_to);
+int rebuild_existing_bitmaps(struct packing_data *mapping, khash_sha1 *reused_bitmaps, int show_progress);
+
+void bitmap_writer_show_progress(int show);
+void bitmap_writer_set_checksum(unsigned char *sha1);
+void bitmap_writer_build_type_index(struct pack_idx_entry **index, uint32_t index_nr);
+void bitmap_writer_reuse_bitmaps(struct packing_data *to_pack);
+void bitmap_writer_select_commits(struct commit **indexed_commits,
+ unsigned int indexed_commits_nr, int max_bitmaps);
+void bitmap_writer_build(struct packing_data *to_pack);
+void bitmap_writer_finish(struct pack_idx_entry **index,
+ uint32_t index_nr,
+ const char *filename,
+ uint16_t options);
+
+#endif
diff --git a/pack-objects.c b/pack-objects.c
new file mode 100644
index 0000000000..d01d851ce9
--- /dev/null
+++ b/pack-objects.c
@@ -0,0 +1,111 @@
+#include "cache.h"
+#include "object.h"
+#include "pack.h"
+#include "pack-objects.h"
+
+static uint32_t locate_object_entry_hash(struct packing_data *pdata,
+ const unsigned char *sha1,
+ int *found)
+{
+ uint32_t i, hash, mask = (pdata->index_size - 1);
+
+ memcpy(&hash, sha1, sizeof(uint32_t));
+ i = hash & mask;
+
+ while (pdata->index[i] > 0) {
+ uint32_t pos = pdata->index[i] - 1;
+
+ if (!hashcmp(sha1, pdata->objects[pos].idx.sha1)) {
+ *found = 1;
+ return i;
+ }
+
+ i = (i + 1) & mask;
+ }
+
+ *found = 0;
+ return i;
+}
+
+static inline uint32_t closest_pow2(uint32_t v)
+{
+ v = v - 1;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return v + 1;
+}
+
+static void rehash_objects(struct packing_data *pdata)
+{
+ uint32_t i;
+ struct object_entry *entry;
+
+ pdata->index_size = closest_pow2(pdata->nr_objects * 3);
+ if (pdata->index_size < 1024)
+ pdata->index_size = 1024;
+
+ pdata->index = xrealloc(pdata->index, sizeof(uint32_t) * pdata->index_size);
+ memset(pdata->index, 0, sizeof(int) * pdata->index_size);
+
+ entry = pdata->objects;
+
+ for (i = 0; i < pdata->nr_objects; i++) {
+ int found;
+ uint32_t ix = locate_object_entry_hash(pdata, entry->idx.sha1, &found);
+
+ if (found)
+ die("BUG: Duplicate object in hash");
+
+ pdata->index[ix] = i + 1;
+ entry++;
+ }
+}
+
+struct object_entry *packlist_find(struct packing_data *pdata,
+ const unsigned char *sha1,
+ uint32_t *index_pos)
+{
+ uint32_t i;
+ int found;
+
+ if (!pdata->index_size)
+ return NULL;
+
+ i = locate_object_entry_hash(pdata, sha1, &found);
+
+ if (index_pos)
+ *index_pos = i;
+
+ if (!found)
+ return NULL;
+
+ return &pdata->objects[pdata->index[i] - 1];
+}
+
+struct object_entry *packlist_alloc(struct packing_data *pdata,
+ const unsigned char *sha1,
+ uint32_t index_pos)
+{
+ struct object_entry *new_entry;
+
+ if (pdata->nr_objects >= pdata->nr_alloc) {
+ pdata->nr_alloc = (pdata->nr_alloc + 1024) * 3 / 2;
+ pdata->objects = xrealloc(pdata->objects,
+ pdata->nr_alloc * sizeof(*new_entry));
+ }
+
+ new_entry = pdata->objects + pdata->nr_objects++;
+
+ memset(new_entry, 0, sizeof(*new_entry));
+ hashcpy(new_entry->idx.sha1, sha1);
+
+ if (pdata->index_size * 3 <= pdata->nr_objects * 4)
+ rehash_objects(pdata);
+ else
+ pdata->index[index_pos] = pdata->nr_objects;
+
+ return new_entry;
+}
diff --git a/pack-objects.h b/pack-objects.h
new file mode 100644
index 0000000000..d1b98b30ff
--- /dev/null
+++ b/pack-objects.h
@@ -0,0 +1,68 @@
+#ifndef PACK_OBJECTS_H
+#define PACK_OBJECTS_H
+
+struct object_entry {
+ struct pack_idx_entry idx;
+ unsigned long size; /* uncompressed size */
+ struct packed_git *in_pack; /* already in pack */
+ off_t in_pack_offset;
+ struct object_entry *delta; /* delta base object */
+ struct object_entry *delta_child; /* deltified objects who bases me */
+ struct object_entry *delta_sibling; /* other deltified objects who
+ * uses the same base as me
+ */
+ void *delta_data; /* cached delta (uncompressed) */
+ unsigned long delta_size; /* delta data size (uncompressed) */
+ unsigned long z_delta_size; /* delta data size (compressed) */
+ enum object_type type;
+ enum object_type in_pack_type; /* could be delta */
+ uint32_t hash; /* name hint hash */
+ unsigned int in_pack_pos;
+ unsigned char in_pack_header_size;
+ unsigned preferred_base:1; /*
+ * we do not pack this, but is available
+ * to be used as the base object to delta
+ * objects against.
+ */
+ unsigned no_try_delta:1;
+ unsigned tagged:1; /* near the very tip of refs */
+ unsigned filled:1; /* assigned write-order */
+};
+
+struct packing_data {
+ struct object_entry *objects;
+ uint32_t nr_objects, nr_alloc;
+
+ int32_t *index;
+ uint32_t index_size;
+};
+
+struct object_entry *packlist_alloc(struct packing_data *pdata,
+ const unsigned char *sha1,
+ uint32_t index_pos);
+
+struct object_entry *packlist_find(struct packing_data *pdata,
+ const unsigned char *sha1,
+ uint32_t *index_pos);
+
+static inline uint32_t pack_name_hash(const char *name)
+{
+ uint32_t c, hash = 0;
+
+ if (!name)
+ return 0;
+
+ /*
+ * This effectively just creates a sortable number from the
+ * last sixteen non-whitespace characters. Last characters
+ * count "most", so things that end in ".c" sort together.
+ */
+ while ((c = *name++) != 0) {
+ if (isspace(c))
+ continue;
+ hash = (hash >> 2) + (c << 24);
+ }
+ return hash;
+}
+
+#endif
diff --git a/pack-revindex.c b/pack-revindex.c
index b4d2b35bb3..5bd7c61980 100644
--- a/pack-revindex.c
+++ b/pack-revindex.c
@@ -16,11 +16,6 @@
* get the object sha1 from the main index.
*/
-struct pack_revindex {
- struct packed_git *p;
- struct revindex_entry *revindex;
-};
-
static struct pack_revindex *pack_revindex;
static int pack_revindex_hashsz;
@@ -201,15 +196,14 @@ static void create_pack_revindex(struct pack_revindex *rix)
sort_revindex(rix->revindex, num_ent, p->pack_size);
}
-struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
+struct pack_revindex *revindex_for_pack(struct packed_git *p)
{
int num;
- unsigned lo, hi;
struct pack_revindex *rix;
- struct revindex_entry *revindex;
if (!pack_revindex_hashsz)
init_pack_revindex();
+
num = pack_revindex_ix(p);
if (num < 0)
die("internal error: pack revindex fubar");
@@ -217,30 +211,37 @@ struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
rix = &pack_revindex[num];
if (!rix->revindex)
create_pack_revindex(rix);
- revindex = rix->revindex;
- lo = 0;
- hi = p->num_objects + 1;
+ return rix;
+}
+
+int find_revindex_position(struct pack_revindex *pridx, off_t ofs)
+{
+ int lo = 0;
+ int hi = pridx->p->num_objects + 1;
+ struct revindex_entry *revindex = pridx->revindex;
+
do {
unsigned mi = lo + (hi - lo) / 2;
if (revindex[mi].offset == ofs) {
- return revindex + mi;
+ return mi;
} else if (ofs < revindex[mi].offset)
hi = mi;
else
lo = mi + 1;
} while (lo < hi);
+
error("bad offset for revindex");
- return NULL;
+ return -1;
}
-void discard_revindex(void)
+struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
{
- if (pack_revindex_hashsz) {
- int i;
- for (i = 0; i < pack_revindex_hashsz; i++)
- free(pack_revindex[i].revindex);
- free(pack_revindex);
- pack_revindex_hashsz = 0;
- }
+ struct pack_revindex *pridx = revindex_for_pack(p);
+ int pos = find_revindex_position(pridx, ofs);
+
+ if (pos < 0)
+ return NULL;
+
+ return pridx->revindex + pos;
}
diff --git a/pack-revindex.h b/pack-revindex.h
index 8d5027ad91..d737f98965 100644
--- a/pack-revindex.h
+++ b/pack-revindex.h
@@ -6,7 +6,14 @@ struct revindex_entry {
unsigned int nr;
};
+struct pack_revindex {
+ struct packed_git *p;
+ struct revindex_entry *revindex;
+};
+
+struct pack_revindex *revindex_for_pack(struct packed_git *p);
+int find_revindex_position(struct pack_revindex *pridx, off_t ofs);
+
struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs);
-void discard_revindex(void);
#endif
diff --git a/pack-write.c b/pack-write.c
index 605d01b25c..9b8308b759 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -364,5 +364,7 @@ void finish_tmp_packfile(char *name_buffer,
if (rename(idx_tmp_name, name_buffer))
die_errno("unable to rename temporary index file");
+ *end_of_name_prefix = '\0';
+
free((void *)idx_tmp_name);
}
diff --git a/path.c b/path.c
index 24594c4112..f9c5062427 100644
--- a/path.c
+++ b/path.c
@@ -265,12 +265,12 @@ static struct passwd *getpw_str(const char *username, size_t len)
char *expand_user_path(const char *path)
{
struct strbuf user_path = STRBUF_INIT;
- const char *first_slash = strchrnul(path, '/');
const char *to_copy = path;
if (path == NULL)
goto return_null;
if (path[0] == '~') {
+ const char *first_slash = strchrnul(path, '/');
const char *username = path + 1;
size_t username_len = first_slash - username;
if (username_len == 0) {
diff --git a/pathspec.c b/pathspec.c
index 6cb9fd3014..8043099955 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -33,7 +33,7 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,
return;
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
- match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen);
+ ce_path_match(ce, pathspec, seen);
}
}
diff --git a/po/de.po b/po/de.po
index c0bbb65bf6..b777ef4803 100644
--- a/po/de.po
+++ b/po/de.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: git 1.8.5\n"
+"Project-Id-Version: git 1.9\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2013-11-02 08:06+0800\n"
+"POT-Creation-Date: 2014-02-01 08:06+0800\n"
"PO-Revision-Date: 2013-07-28 18:42+0200\n"
"Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
"Language-Team: German <>\n"
@@ -57,7 +57,7 @@ msgstr ""
msgid "git archive --remote <repo> [--exec <cmd>] --list"
msgstr "git archive --remote <Repository> [--exec <Programm>] --list"
-#: archive.c:242 builtin/add.c:240 builtin/add.c:556 builtin/rm.c:328
+#: archive.c:242 builtin/add.c:240 builtin/add.c:559 builtin/rm.c:328
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein"
@@ -78,8 +78,8 @@ msgstr "Präfix"
msgid "prepend prefix to each pathname in the archive"
msgstr "stellt einen Präfix vor jeden Pfadnamen in dem Archiv"
-#: archive.c:330 builtin/archive.c:88 builtin/blame.c:2264
-#: builtin/blame.c:2265 builtin/config.c:58 builtin/fast-export.c:680
+#: archive.c:330 builtin/archive.c:88 builtin/blame.c:2265
+#: builtin/blame.c:2266 builtin/config.c:58 builtin/fast-export.c:680
#: builtin/fast-export.c:682 builtin/grep.c:716 builtin/hash-object.c:77
#: builtin/ls-files.c:486 builtin/ls-files.c:489 builtin/notes.c:408
#: builtin/notes.c:565 builtin/read-tree.c:108 parse-options.h:154
@@ -268,64 +268,64 @@ msgstr "Fehler beim Sperren der Referenz zur Aktualisierung."
msgid "Failed to write ref"
msgstr "Fehler beim Schreiben der Referenz."
-#: bundle.c:36
+#: bundle.c:37
#, c-format
msgid "'%s' does not look like a v2 bundle file"
msgstr "'%s' sieht nicht wie eine v2 Paketdatei aus"
-#: bundle.c:63
+#: bundle.c:64
#, c-format
msgid "unrecognized header: %s%s (%d)"
msgstr "nicht erkannter Kopfbereich: %s%s (%d)"
-#: bundle.c:89 builtin/commit.c:706
+#: bundle.c:90 builtin/commit.c:706
#, c-format
msgid "could not open '%s'"
msgstr "Konnte '%s' nicht öffnen"
-#: bundle.c:140
+#: bundle.c:141
msgid "Repository lacks these prerequisite commits:"
msgstr "Dem Repository fehlen folgende vorausgesetzte Commits:"
-#: bundle.c:164 sequencer.c:662 sequencer.c:1112 builtin/log.c:332
-#: builtin/log.c:821 builtin/log.c:1418 builtin/log.c:1644 builtin/merge.c:364
+#: bundle.c:165 sequencer.c:662 sequencer.c:1112 builtin/log.c:332
+#: builtin/log.c:821 builtin/log.c:1418 builtin/log.c:1644 builtin/merge.c:357
#: builtin/shortlog.c:158
msgid "revision walk setup failed"
msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
-#: bundle.c:186
+#: bundle.c:187
#, c-format
msgid "The bundle contains this ref:"
msgid_plural "The bundle contains these %d refs:"
msgstr[0] "Das Paket enthält diese Referenz:"
msgstr[1] "Das Paket enthält diese %d Referenzen:"
-#: bundle.c:193
+#: bundle.c:194
msgid "The bundle records a complete history."
msgstr "Das Paket speichert eine komplette Historie."
-#: bundle.c:195
+#: bundle.c:196
#, c-format
msgid "The bundle requires this ref:"
msgid_plural "The bundle requires these %d refs:"
msgstr[0] "Das Paket benötigt diese Referenz:"
msgstr[1] "Das Paket benötigt diese %d Referenzen:"
-#: bundle.c:294
+#: bundle.c:296
msgid "rev-list died"
msgstr "\"rev-list\" abgebrochen"
-#: bundle.c:300 builtin/log.c:1329 builtin/shortlog.c:261
+#: bundle.c:302 builtin/log.c:1329 builtin/shortlog.c:261
#, c-format
msgid "unrecognized argument: %s"
msgstr "nicht erkanntes Argument: %s"
-#: bundle.c:335
+#: bundle.c:337
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr "Referenz '%s' wird durch \"rev-list\" Optionen ausgeschlossen"
-#: bundle.c:380
+#: bundle.c:382
msgid "Refusing to create empty bundle."
msgstr "Erstellung eines leeren Pakets zurückgewiesen."
@@ -360,16 +360,16 @@ msgstr "%s %s ist kein Commit!"
msgid "memory exhausted"
msgstr "Speicher verbraucht"
-#: connected.c:60
+#: connected.c:70
msgid "Could not run 'git rev-list'"
msgstr "Konnte 'git rev-list' nicht ausführen"
-#: connected.c:80
+#: connected.c:90
#, c-format
msgid "failed write to rev-list: %s"
msgstr "Fehler beim Schreiben nach rev-list: %s"
-#: connected.c:88
+#: connected.c:98
#, c-format
msgid "failed to close rev-list's stdin: %s"
msgstr "Fehler beim Schließen von rev-list's Standard-Eingabe: %s"
@@ -441,23 +441,28 @@ msgid_plural "%lu years ago"
msgstr[0] "vor %lu Jahr"
msgstr[1] "vor %lu Jahren"
-#: diff.c:112
+#: diffcore-order.c:24
+#, c-format
+msgid "failed to read orderfile '%s'"
+msgstr "Fehler beim Lesen der Reihenfolgedatei '%s'."
+
+#: diff.c:113
#, c-format
msgid " Failed to parse dirstat cut-off percentage '%s'\n"
msgstr ""
" Fehler beim Parsen des abgeschnittenen \"dirstat\" Prozentsatzes '%s'\n"
-#: diff.c:117
+#: diff.c:118
#, c-format
msgid " Unknown dirstat parameter '%s'\n"
msgstr " Unbekannter \"dirstat\" Parameter '%s'\n"
-#: diff.c:210
+#: diff.c:213
#, c-format
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "Unbekannter Wert in Konfigurationsvariable 'diff.dirstat': '%s'"
-#: diff.c:260
+#: diff.c:263
#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
@@ -466,7 +471,7 @@ msgstr ""
"Fehler in 'diff.dirstat' Konfigurationsvariable gefunden:\n"
"%s"
-#: diff.c:3490
+#: diff.c:3509
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -475,7 +480,7 @@ msgstr ""
"Fehler beim Parsen des --dirstat/-X Optionsparameters:\n"
"%s"
-#: diff.c:3504
+#: diff.c:3523
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr "Fehler beim Parsen des --submodule Optionsparameters: '%s'"
@@ -586,7 +591,7 @@ msgid "failed to read the cache"
msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
#: merge.c:110 builtin/checkout.c:358 builtin/checkout.c:559
-#: builtin/clone.c:655
+#: builtin/clone.c:661
msgid "unable to write new index file"
msgstr "Konnte neue Staging-Area-Datei nicht schreiben."
@@ -635,7 +640,7 @@ msgstr "kann Objekt %s '%s' nicht lesen"
msgid "blob expected for %s '%s'"
msgstr "Blob erwartet für %s '%s'"
-#: merge-recursive.c:774 builtin/clone.c:311
+#: merge-recursive.c:774 builtin/clone.c:317
#, c-format
msgid "failed to open '%s'"
msgstr "Fehler beim Öffnen von '%s'"
@@ -685,7 +690,7 @@ msgstr ""
msgid "rename"
msgstr "umbenennen"
-#: merge-recursive.c:1082
+#: merge-recursive.c:1082 wt-status.c:283
msgid "renamed"
msgstr "umbenannt"
@@ -750,7 +755,7 @@ msgstr "Objekt %s ist kein Blob"
msgid "modify"
msgstr "ändern"
-#: merge-recursive.c:1565
+#: merge-recursive.c:1565 wt-status.c:281
msgid "modified"
msgstr "geändert"
@@ -772,7 +777,7 @@ msgstr "%s ausgelassen (Ergebnis des Merges existiert bereits)"
msgid "Auto-merging %s"
msgstr "automatischer Merge von %s"
-#: merge-recursive.c:1634 git-submodule.sh:1125
+#: merge-recursive.c:1634 git-submodule.sh:1148
msgid "submodule"
msgstr "Submodul"
@@ -844,7 +849,7 @@ msgstr "Merge hat keinen Commit zurückgegeben"
msgid "Could not parse object '%s'"
msgstr "Konnte Objekt '%s' nicht parsen."
-#: merge-recursive.c:2010 builtin/merge.c:672
+#: merge-recursive.c:2010 builtin/merge.c:665
msgid "Unable to write index."
msgstr "Konnte Staging-Area nicht schreiben."
@@ -901,47 +906,50 @@ msgstr " %s"
msgid "-NUM"
msgstr "-NUM"
-#: pathspec.c:118
+#: pathspec.c:133
msgid "global 'glob' and 'noglob' pathspec settings are incompatible"
-msgstr "Globale Einstellungen zur Pfadspezifikation 'glob' und 'noglob' sind inkompatibel."
+msgstr ""
+"Globale Einstellungen zur Pfadspezifikation 'glob' und 'noglob' sind "
+"inkompatibel."
-#: pathspec.c:128
+#: pathspec.c:143
msgid ""
"global 'literal' pathspec setting is incompatible with all other global "
"pathspec settings"
-msgstr "Globale Einstellung zur Pfadspezifikation 'literal' ist inkompatibel\n"
+msgstr ""
+"Globale Einstellung zur Pfadspezifikation 'literal' ist inkompatibel\n"
"mit allen anderen Optionen."
-#: pathspec.c:158
+#: pathspec.c:177
msgid "invalid parameter for pathspec magic 'prefix'"
msgstr "ungültiger Parameter für Pfadspezifikationsangabe 'prefix'"
-#: pathspec.c:164
+#: pathspec.c:183
#, c-format
msgid "Invalid pathspec magic '%.*s' in '%s'"
msgstr "ungültige Pfadspezifikationsangabe '%.*s' in '%s'"
-#: pathspec.c:168
+#: pathspec.c:187
#, c-format
msgid "Missing ')' at the end of pathspec magic in '%s'"
msgstr "Fehlendes ')' am Ende der Pfadspezifikationsangabe in '%s'"
-#: pathspec.c:186
+#: pathspec.c:205
#, c-format
msgid "Unimplemented pathspec magic '%c' in '%s'"
msgstr "nicht unterstützte Pfadspezifikationsangabe '%c' in '%s'"
-#: pathspec.c:211
+#: pathspec.c:230
#, c-format
msgid "%s: 'literal' and 'glob' are incompatible"
msgstr "%s: 'literal' und 'glob' sind inkompatibel"
-#: pathspec.c:222
+#: pathspec.c:241
#, c-format
msgid "%s: '%s' is outside repository"
msgstr "%s: '%s' liegt außerhalb des Repositories"
-#: pathspec.c:278
+#: pathspec.c:291
#, c-format
msgid "Pathspec '%s' is in submodule '%.*s'"
msgstr "Pfadspezifikation '%s' befindet sich in Submodul '%.*s'"
@@ -951,42 +959,75 @@ msgstr "Pfadspezifikation '%s' befindet sich in Submodul '%.*s'"
#. * name. E.g. when add--interactive dies when running
#. * "checkout -p"
#.
-#: pathspec.c:340
+#: pathspec.c:353
#, c-format
msgid "%s: pathspec magic not supported by this command: %s"
-msgstr "%s: Pfadspezifikationsangabe wird von diesem Kommando nicht unterstützt: %s"
+msgstr ""
+"%s: Pfadspezifikationsangabe wird von diesem Kommando nicht unterstützt: %s"
-#: pathspec.c:415
+#: pathspec.c:433
#, c-format
msgid "pathspec '%s' is beyond a symbolic link"
msgstr "Pfadspezifikation '%s' ist hinter einem symbolischen Verweis"
-#: remote.c:1833
+#: pathspec.c:442
+msgid ""
+"There is nothing to exclude from by :(exclude) patterns.\n"
+"Perhaps you forgot to add either ':/' or '.' ?"
+msgstr ""
+":(exclude) Muster, aber keine anderen Pfadspezifikationen angegeben.\n"
+"Vielleicht haben Sie vergessen entweder ':/' oder '.' hinzuzufügen?"
+
+#: remote.c:753
+#, c-format
+msgid "Cannot fetch both %s and %s to %s"
+msgstr "Kann 'fetch' nicht für sowohl %s als auch %s nach %s ausführen."
+
+#: remote.c:757
+#, c-format
+msgid "%s usually tracks %s, not %s"
+msgstr "%s folgt üblicherweise %s, nicht %s"
+
+#: remote.c:761
+#, c-format
+msgid "%s tracks both %s and %s"
+msgstr "%s folgt sowohl %s als auch %s"
+
+#.
+#. * This last possibility doesn't occur because
+#. * FETCH_HEAD_IGNORE entries always appear at
+#. * the end of the list.
+#.
+#: remote.c:769
+msgid "Internal error"
+msgstr "Interner Fehler"
+
+#: remote.c:1871
#, c-format
msgid "Your branch is based on '%s', but the upstream is gone.\n"
msgstr "Ihr Branch basiert auf '%s', aber Upstream-Branch wurde entfernt.\n"
-#: remote.c:1837
+#: remote.c:1875
msgid " (use \"git branch --unset-upstream\" to fixup)\n"
msgstr " (benutzen Sie \"git branch --unset-upstream\" zum Beheben)\n"
-#: remote.c:1840
+#: remote.c:1878
#, c-format
msgid "Your branch is up-to-date with '%s'.\n"
msgstr "Ihr Branch ist auf dem selben Stand wie '%s'.\n"
-#: remote.c:1844
+#: remote.c:1882
#, c-format
msgid "Your branch is ahead of '%s' by %d commit.\n"
msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
msgstr[0] "Ihr Branch ist vor '%s' um %d Commit.\n"
msgstr[1] "Ihr Branch ist vor '%s' um %d Commits.\n"
-#: remote.c:1850
+#: remote.c:1888
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (benutzen Sie \"git push\" um lokale Commits zu publizieren)\n"
-#: remote.c:1853
+#: remote.c:1891
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -996,12 +1037,12 @@ msgstr[0] ""
msgstr[1] ""
"Ihr Branch ist zu '%s' um %d Commits hinterher, und kann vorgespult werden.\n"
-#: remote.c:1861
+#: remote.c:1899
msgid " (use \"git pull\" to update your local branch)\n"
msgstr ""
" (benutzen Sie \"git pull\" um Ihren lokalen Branch zu aktualisieren)\n"
-#: remote.c:1864
+#: remote.c:1902
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -1016,7 +1057,7 @@ msgstr[1] ""
"Ihr Branch und '%s' sind divergiert,\n"
"und haben jeweils %d und %d unterschiedliche Commits.\n"
-#: remote.c:1874
+#: remote.c:1912
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr ""
" (benutzen Sie \"git pull\" um Ihren Branch mit dem Remote-Branch "
@@ -1031,14 +1072,14 @@ msgstr "Öffnen von /dev/null fehlgeschlagen"
msgid "dup2(%d,%d) failed"
msgstr "dup2(%d,%d) fehlgeschlagen"
-#: sequencer.c:206 builtin/merge.c:790 builtin/merge.c:903
-#: builtin/merge.c:1013 builtin/merge.c:1023
+#: sequencer.c:206 builtin/merge.c:783 builtin/merge.c:896
+#: builtin/merge.c:1006 builtin/merge.c:1016
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Konnte '%s' nicht zum Schreiben öffnen."
-#: sequencer.c:208 builtin/merge.c:350 builtin/merge.c:793
-#: builtin/merge.c:1015 builtin/merge.c:1028
+#: sequencer.c:208 builtin/merge.c:343 builtin/merge.c:786
+#: builtin/merge.c:1008 builtin/merge.c:1021
#, c-format
msgid "Could not write to '%s'"
msgstr "Konnte nicht nach '%s' schreiben."
@@ -1280,7 +1321,7 @@ msgstr "Kann nicht als allerersten Commit einen Revert ausführen."
msgid "Can't cherry-pick into empty head"
msgstr "Kann nicht als allerersten Commit einen Cherry-Pick ausführen."
-#: sha1_name.c:440
+#: sha1_name.c:439
msgid ""
"Git normally never creates a ref that ends with 40 hex characters\n"
"because it will be ignored when you just specify 40-hex. These refs\n"
@@ -1305,28 +1346,29 @@ msgstr ""
"indem Sie \"git config advice.objectNameWarning false\"\n"
"ausführen."
-#: sha1_name.c:1112
+#: sha1_name.c:1070
msgid "HEAD does not point to a branch"
msgstr "HEAD zeigt auf keinen Branch"
-#: sha1_name.c:1115
+#: sha1_name.c:1073
#, c-format
msgid "No such branch: '%s'"
msgstr "Kein solcher Branch '%s'"
-#: sha1_name.c:1117
+#: sha1_name.c:1075
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Kein Upstream-Branch für Branch '%s' konfiguriert."
-#: sha1_name.c:1121
+#: sha1_name.c:1079
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "Upstream-Branch '%s' ist nicht als Remote-Tracking-Branch gespeichert"
#: submodule.c:64 submodule.c:98
msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
-msgstr "Kann nicht zusammengeführte .gitmodules-Datei nicht ändern, lösen\n"
+msgstr ""
+"Kann nicht zusammengeführte .gitmodules-Datei nicht ändern, lösen\n"
"Sie zuerst die Konflikte auf"
#: submodule.c:68 submodule.c:102
@@ -1428,245 +1470,237 @@ msgstr "konnte aktuellen Benutzer nicht in Passwort-Datei finden: %s"
msgid "no such user"
msgstr "kein solcher Benutzer"
-#: wt-status.c:146
+#: wt-status.c:150
msgid "Unmerged paths:"
msgstr "Nicht zusammengeführte Pfade:"
-#: wt-status.c:173 wt-status.c:200
+#: wt-status.c:177 wt-status.c:204
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr ""
" (benutzen Sie \"git reset %s <Datei>...\" zum Entfernen aus der Staging-"
"Area)"
-#: wt-status.c:175 wt-status.c:202
+#: wt-status.c:179 wt-status.c:206
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr ""
" (benutzen Sie \"git rm --cached <Datei>...\" zum Entfernen aus der Staging-"
"Area)"
-#: wt-status.c:179
+#: wt-status.c:183
msgid " (use \"git add <file>...\" to mark resolution)"
msgstr ""
" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
-#: wt-status.c:181 wt-status.c:185
+#: wt-status.c:185 wt-status.c:189
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr ""
" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung entsprechend zu "
"markieren)"
-#: wt-status.c:183
+#: wt-status.c:187
msgid " (use \"git rm <file>...\" to mark resolution)"
msgstr ""
" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
-#: wt-status.c:194
+#: wt-status.c:198
msgid "Changes to be committed:"
msgstr "zum Commit vorgemerkte Änderungen:"
-#: wt-status.c:212
+#: wt-status.c:216
msgid "Changes not staged for commit:"
msgstr "Änderungen, die nicht zum Commit vorgemerkt sind:"
-#: wt-status.c:216
+#: wt-status.c:220
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr ""
" (benutzen Sie \"git add <Datei>...\" um die Änderungen zum Commit "
"vorzumerken)"
-#: wt-status.c:218
+#: wt-status.c:222
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr ""
" (benutzen Sie \"git add/rm <Datei>...\" um die Änderungen zum Commit "
"vorzumerken)"
-#: wt-status.c:219
+#: wt-status.c:223
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr ""
" (benutzen Sie \"git checkout -- <Datei>...\" um die Änderungen im "
"Arbeitsverzeichnis zu verwerfen)"
-#: wt-status.c:221
+#: wt-status.c:225
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
" (committen oder verwerfen Sie den unbeobachteten oder geänderten Inhalt in "
"den Submodulen)"
-#: wt-status.c:233
+#: wt-status.c:237
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr ""
" (benutzen Sie \"git %s <Datei>...\" um die Änderungen zum Commit "
"vorzumerken)"
-#: wt-status.c:250
+#: wt-status.c:254
msgid "bug"
msgstr "Fehler"
-#: wt-status.c:255
+#: wt-status.c:259
msgid "both deleted:"
msgstr "beide gelöscht:"
-#: wt-status.c:256
+#: wt-status.c:260
msgid "added by us:"
msgstr "von uns hinzugefügt:"
-#: wt-status.c:257
+#: wt-status.c:261
msgid "deleted by them:"
msgstr "von denen gelöscht:"
-#: wt-status.c:258
+#: wt-status.c:262
msgid "added by them:"
msgstr "von denen hinzugefügt:"
-#: wt-status.c:259
+#: wt-status.c:263
msgid "deleted by us:"
msgstr "von uns gelöscht:"
-#: wt-status.c:260
+#: wt-status.c:264
msgid "both added:"
msgstr "von beiden hinzugefügt:"
-#: wt-status.c:261
+#: wt-status.c:265
msgid "both modified:"
msgstr "von beiden geändert:"
-#: wt-status.c:291
-msgid "new commits, "
-msgstr "neue Commits, "
-
-#: wt-status.c:293
-msgid "modified content, "
-msgstr "geänderter Inhalt, "
-
-#: wt-status.c:295
-msgid "untracked content, "
-msgstr "unbeobachteter Inhalt, "
+#: wt-status.c:275
+msgid "new file"
+msgstr "neue Datei"
-#: wt-status.c:312
-#, c-format
-msgid "new file: %s"
-msgstr "neue Datei: %s"
+#: wt-status.c:277
+msgid "copied"
+msgstr "kopiert"
-#: wt-status.c:315
-#, c-format
-msgid "copied: %s -> %s"
-msgstr "kopiert: %s -> %s"
+#: wt-status.c:279
+msgid "deleted"
+msgstr "gelöscht"
-#: wt-status.c:318
-#, c-format
-msgid "deleted: %s"
-msgstr "gelöscht: %s"
+#: wt-status.c:285
+msgid "typechange"
+msgstr "Typänderung"
-#: wt-status.c:321
-#, c-format
-msgid "modified: %s"
-msgstr "geändert: %s"
+#: wt-status.c:287
+msgid "unknown"
+msgstr "unbekannt"
-#: wt-status.c:324
-#, c-format
-msgid "renamed: %s -> %s"
-msgstr "umbenannt: %s -> %s"
+#: wt-status.c:289
+msgid "unmerged"
+msgstr "nicht zusammengeführt"
-#: wt-status.c:327
-#, c-format
-msgid "typechange: %s"
-msgstr "Typänderung: %s"
+#: wt-status.c:336
+msgid "new commits, "
+msgstr "neue Commits, "
-#: wt-status.c:330
-#, c-format
-msgid "unknown: %s"
-msgstr "unbekannt: %s"
+#: wt-status.c:338
+msgid "modified content, "
+msgstr "geänderter Inhalt, "
-#: wt-status.c:333
-#, c-format
-msgid "unmerged: %s"
-msgstr "nicht zusammengeführt: %s"
+#: wt-status.c:340
+msgid "untracked content, "
+msgstr "unbeobachteter Inhalt, "
-#: wt-status.c:336
+#: wt-status.c:357
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "Fehler: unbehandelter Differenz-Status %c"
-#: wt-status.c:703
+#: wt-status.c:732
msgid "Submodules changed but not updated:"
msgstr "Submodule geändert, aber nicht aktualisiert:"
-#: wt-status.c:705
+#: wt-status.c:734
msgid "Submodule changes to be committed:"
msgstr "Änderungen in Submodul zum Committen:"
-#: wt-status.c:848
+#: wt-status.c:836
+msgid ""
+"Do not touch the line above.\n"
+"Everything below will be removed."
+msgstr ""
+"Ändern Sie nicht die obige Zeile.\n"
+"Alles unterhalb von ihr wird entfernt."
+
+#: wt-status.c:899
msgid "You have unmerged paths."
msgstr "Sie haben nicht zusammengeführte Pfade."
-#: wt-status.c:851
+#: wt-status.c:902
msgid " (fix conflicts and run \"git commit\")"
msgstr " (beheben Sie die Konflikte und führen Sie \"git commit\" aus)"
-#: wt-status.c:854
+#: wt-status.c:905
msgid "All conflicts fixed but you are still merging."
msgstr "Alle Konflikte sind behoben, aber Sie sind immer noch beim Merge."
-#: wt-status.c:857
+#: wt-status.c:908
msgid " (use \"git commit\" to conclude merge)"
msgstr " (benutzen Sie \"git commit\" um den Merge abzuschließen)"
-#: wt-status.c:867
+#: wt-status.c:918
msgid "You are in the middle of an am session."
msgstr "Eine \"am\"-Sitzung ist im Gange."
-#: wt-status.c:870
+#: wt-status.c:921
msgid "The current patch is empty."
msgstr "Der aktuelle Patch ist leer."
-#: wt-status.c:874
+#: wt-status.c:925
msgid " (fix conflicts and then run \"git am --continue\")"
msgstr ""
" (beheben Sie die Konflikte und führen Sie dann \"git am --continue\" aus)"
-#: wt-status.c:876
+#: wt-status.c:927
msgid " (use \"git am --skip\" to skip this patch)"
msgstr " (benutzen Sie \"git am --skip\" um diesen Patch auszulassen)"
-#: wt-status.c:878
+#: wt-status.c:929
msgid " (use \"git am --abort\" to restore the original branch)"
msgstr ""
" (benutzen Sie \"git am --abort\" um den ursprünglichen Branch "
"wiederherzustellen)"
-#: wt-status.c:938 wt-status.c:955
+#: wt-status.c:989 wt-status.c:1006
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
msgstr "Sie sind gerade beim Rebase von Branch '%s' auf '%s'."
-#: wt-status.c:943 wt-status.c:960
+#: wt-status.c:994 wt-status.c:1011
msgid "You are currently rebasing."
msgstr "Sie sind gerade beim Rebase."
-#: wt-status.c:946
+#: wt-status.c:997
msgid " (fix conflicts and then run \"git rebase --continue\")"
msgstr ""
" (beheben Sie die Konflikte und führen Sie dann \"git rebase --continue\" "
"aus)"
-#: wt-status.c:948
+#: wt-status.c:999
msgid " (use \"git rebase --skip\" to skip this patch)"
msgstr " (benutzen Sie \"git rebase --skip\" um diesen Patch auszulassen)"
-#: wt-status.c:950
+#: wt-status.c:1001
msgid " (use \"git rebase --abort\" to check out the original branch)"
msgstr ""
" (benutzen Sie \"git rebase --abort\" um den ursprünglichen Branch "
"auszuchecken)"
-#: wt-status.c:963
+#: wt-status.c:1014
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr " (alle Konflikte behoben: führen Sie \"git rebase --continue\" aus)"
-#: wt-status.c:967
+#: wt-status.c:1018
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
@@ -1674,129 +1708,129 @@ msgstr ""
"Sie teilen gerade einen Commit auf, während ein Rebase von Branch '%s' auf "
"'%s' im Gange ist."
-#: wt-status.c:972
+#: wt-status.c:1023
msgid "You are currently splitting a commit during a rebase."
msgstr "Sie teilen gerade einen Commit während eines Rebase auf."
-#: wt-status.c:975
+#: wt-status.c:1026
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
msgstr ""
" (Sobald Ihr Arbeitsverzeichnis unverändert ist, führen Sie \"git rebase --"
"continue\" aus)"
-#: wt-status.c:979
+#: wt-status.c:1030
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
"Sie editieren gerade einen Commit während eines Rebase von Branch '%s' auf "
"'%s'."
-#: wt-status.c:984
+#: wt-status.c:1035
msgid "You are currently editing a commit during a rebase."
msgstr "Sie editieren gerade einen Commit während eines Rebase."
-#: wt-status.c:987
+#: wt-status.c:1038
msgid " (use \"git commit --amend\" to amend the current commit)"
msgstr ""
" (benutzen Sie \"git commit --amend\" um den aktuellen Commit nachzubessern)"
-#: wt-status.c:989
+#: wt-status.c:1040
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr ""
" (benutzen Sie \"git rebase --continue\" sobald Ihre Änderungen "
"abgeschlossen sind)"
-#: wt-status.c:999
+#: wt-status.c:1050
#, c-format
msgid "You are currently cherry-picking commit %s."
msgstr "Sie führen gerade \"cherry-pick\" von Commit %s aus."
-#: wt-status.c:1004
+#: wt-status.c:1055
msgid " (fix conflicts and run \"git cherry-pick --continue\")"
msgstr ""
" (beheben Sie die Konflikte und führen Sie dann \"git cherry-pick --continue"
"\" aus)"
-#: wt-status.c:1007
+#: wt-status.c:1058
msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
msgstr ""
" (alle Konflikte behoben: führen Sie \"git cherry-pick --continue\" aus)"
-#: wt-status.c:1009
+#: wt-status.c:1060
msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
msgstr ""
" (benutzen Sie \"git cherry-pick --abort\" um die Cherry-Pick-Operation "
"abzubrechen)"
-#: wt-status.c:1018
+#: wt-status.c:1069
#, c-format
msgid "You are currently reverting commit %s."
msgstr "Sie sind gerade an einem Revert von Commit '%s'."
-#: wt-status.c:1023
+#: wt-status.c:1074
msgid " (fix conflicts and run \"git revert --continue\")"
msgstr ""
" (beheben Sie die Konflikte und führen Sie dann \"git revert --continue\" "
"aus)"
-#: wt-status.c:1026
+#: wt-status.c:1077
msgid " (all conflicts fixed: run \"git revert --continue\")"
msgstr " (alle Konflikte behoben: führen Sie \"git revert --continue\" aus)"
-#: wt-status.c:1028
+#: wt-status.c:1079
msgid " (use \"git revert --abort\" to cancel the revert operation)"
msgstr ""
" (benutzen Sie \"git revert --abort\" um die Revert-Operation abzubrechen)"
-#: wt-status.c:1039
+#: wt-status.c:1090
#, c-format
msgid "You are currently bisecting, started from branch '%s'."
msgstr "Sie sind gerade bei einer binären Suche, gestartet von Branch '%s'."
-#: wt-status.c:1043
+#: wt-status.c:1094
msgid "You are currently bisecting."
msgstr "Sie sind gerade bei einer binären Suche."
-#: wt-status.c:1046
+#: wt-status.c:1097
msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr ""
" (benutzen Sie \"git bisect reset\" um zum ursprünglichen Branch "
"zurückzukehren)"
-#: wt-status.c:1221
+#: wt-status.c:1272
msgid "On branch "
msgstr "Auf Branch "
-#: wt-status.c:1228
+#: wt-status.c:1279
msgid "rebase in progress; onto "
msgstr "Rebase im Gange; auf "
-#: wt-status.c:1235
+#: wt-status.c:1286
msgid "HEAD detached at "
msgstr "HEAD losgelöst bei "
-#: wt-status.c:1237
+#: wt-status.c:1288
msgid "HEAD detached from "
msgstr "HEAD losgelöst von "
-#: wt-status.c:1240
+#: wt-status.c:1291
msgid "Not currently on any branch."
msgstr "Im Moment auf keinem Branch."
-#: wt-status.c:1257
+#: wt-status.c:1308
msgid "Initial commit"
msgstr "Initialer Commit"
-#: wt-status.c:1271
+#: wt-status.c:1322
msgid "Untracked files"
msgstr "Unbeobachtete Dateien"
-#: wt-status.c:1273
+#: wt-status.c:1324
msgid "Ignored files"
msgstr "Ignorierte Dateien"
-#: wt-status.c:1277
+#: wt-status.c:1328
#, c-format
msgid ""
"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
@@ -1807,32 +1841,32 @@ msgstr ""
"'status -uno' könnte das beschleunigen, aber Sie müssen darauf achten,\n"
"neue Dateien selbstständig hinzuzufügen (siehe 'git help status')."
-#: wt-status.c:1283
+#: wt-status.c:1334
#, c-format
msgid "Untracked files not listed%s"
msgstr "Unbeobachtete Dateien nicht aufgelistet%s"
-#: wt-status.c:1285
+#: wt-status.c:1336
msgid " (use -u option to show untracked files)"
msgstr " (benutzen Sie die Option -u um unbeobachteten Dateien anzuzeigen)"
-#: wt-status.c:1291
+#: wt-status.c:1342
msgid "No changes"
msgstr "Keine Änderungen"
-#: wt-status.c:1296
+#: wt-status.c:1347
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
"keine Änderungen zum Commit vorgemerkt (benutzen Sie \"git add\" und/oder "
"\"git commit -a\")\n"
-#: wt-status.c:1299
+#: wt-status.c:1350
#, c-format
msgid "no changes added to commit\n"
msgstr "keine Änderungen zum Commit vorgemerkt\n"
-#: wt-status.c:1302
+#: wt-status.c:1353
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
@@ -1841,60 +1875,60 @@ msgstr ""
"nichts zum Commit vorgemerkt, aber es gibt unbeobachtete Dateien (benutzen "
"Sie \"git add\" zum Beobachten)\n"
-#: wt-status.c:1305
+#: wt-status.c:1356
#, c-format
msgid "nothing added to commit but untracked files present\n"
msgstr "nichts zum Commit vorgemerkt, aber es gibt unbeobachtete Dateien\n"
-#: wt-status.c:1308
+#: wt-status.c:1359
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr ""
"nichts zu committen (Erstellen/Kopieren Sie Dateien und benutzen Sie \"git "
"add\" zum Beobachten)\n"
-#: wt-status.c:1311 wt-status.c:1316
+#: wt-status.c:1362 wt-status.c:1367
#, c-format
msgid "nothing to commit\n"
msgstr "nichts zu committen\n"
-#: wt-status.c:1314
+#: wt-status.c:1365
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
"nichts zu committen (benutzen Sie die Option -u, um unbeobachtete Dateien "
"anzuzeigen)\n"
-#: wt-status.c:1318
+#: wt-status.c:1369
#, c-format
msgid "nothing to commit, working directory clean\n"
msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
-#: wt-status.c:1427
+#: wt-status.c:1478
msgid "HEAD (no branch)"
msgstr "HEAD (kein Branch)"
-#: wt-status.c:1433
+#: wt-status.c:1484
msgid "Initial commit on "
msgstr "Initialer Commit auf "
-#: wt-status.c:1463
+#: wt-status.c:1514
msgid "gone"
msgstr "entfernt"
-#: wt-status.c:1465
+#: wt-status.c:1516
msgid "behind "
msgstr "hinterher "
-#: wt-status.c:1468 wt-status.c:1471
+#: wt-status.c:1519 wt-status.c:1522
msgid "ahead "
msgstr "voraus "
-#: wt-status.c:1473
+#: wt-status.c:1524
msgid ", behind "
msgstr ", hinterher "
-#: compat/precompose_utf8.c:55 builtin/clone.c:350
+#: compat/precompose_utf8.c:55 builtin/clone.c:356
#, c-format
msgid "failed to unlink '%s'"
msgstr "Konnte '%s' nicht entfernen."
@@ -2027,15 +2061,15 @@ msgstr ""
"Die folgenden Pfade werden durch eine Ihrer \".gitignore\" Dateien "
"ignoriert:\n"
-#: builtin/add.c:354 builtin/clean.c:875 builtin/fetch.c:92 builtin/mv.c:66
-#: builtin/prune-packed.c:73 builtin/push.c:459 builtin/remote.c:1253
+#: builtin/add.c:354 builtin/clean.c:875 builtin/fetch.c:93 builtin/mv.c:70
+#: builtin/prune-packed.c:77 builtin/push.c:506 builtin/remote.c:1344
#: builtin/rm.c:269
msgid "dry run"
msgstr "Probelauf"
#: builtin/add.c:355 builtin/apply.c:4410 builtin/check-ignore.c:19
#: builtin/commit.c:1249 builtin/count-objects.c:95 builtin/fsck.c:612
-#: builtin/log.c:1592 builtin/mv.c:65 builtin/read-tree.c:113
+#: builtin/log.c:1592 builtin/mv.c:69 builtin/read-tree.c:113
msgid "be verbose"
msgstr "erweiterte Ausgaben"
@@ -2120,11 +2154,11 @@ msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Wollten Sie vielleicht 'git add .' sagen?\n"
#: builtin/add.c:492 builtin/check-ignore.c:172 builtin/clean.c:919
-#: builtin/commit.c:320 builtin/mv.c:86 builtin/reset.c:224 builtin/rm.c:299
+#: builtin/commit.c:320 builtin/mv.c:90 builtin/reset.c:224 builtin/rm.c:299
msgid "index file corrupt"
msgstr "Staging-Area-Datei beschädigt"
-#: builtin/add.c:589 builtin/apply.c:4506 builtin/mv.c:259 builtin/rm.c:432
+#: builtin/add.c:592 builtin/apply.c:4506 builtin/mv.c:270 builtin/rm.c:432
msgid "Unable to write new index file"
msgstr "Konnte neue Staging-Area-Datei nicht schreiben."
@@ -2463,7 +2497,7 @@ msgid "unable to read index file"
msgstr "Konnte Staging-Area-Datei nicht lesen"
#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:90
-#: builtin/fetch.c:77
+#: builtin/fetch.c:78
msgid "path"
msgstr "Pfad"
@@ -2678,96 +2712,96 @@ msgstr "git blame [Optionen] [rev-opts] [rev] [--] Datei"
msgid "[rev-opts] are documented in git-rev-list(1)"
msgstr "[rev-opts] sind dokumentiert in git-rev-list(1)"
-#: builtin/blame.c:2248
+#: builtin/blame.c:2249
msgid "Show blame entries as we find them, incrementally"
msgstr "Zeigt \"blame\"-Einträge schrittweise, während wir sie generieren"
-#: builtin/blame.c:2249
+#: builtin/blame.c:2250
msgid "Show blank SHA-1 for boundary commits (Default: off)"
msgstr "Zeigt leere SHA-1 für Grenz-Commits (Standard: aus)"
-#: builtin/blame.c:2250
+#: builtin/blame.c:2251
msgid "Do not treat root commits as boundaries (Default: off)"
msgstr "Behandelt Ursprungs-Commit nicht als Grenzen (Standard: aus)"
-#: builtin/blame.c:2251
+#: builtin/blame.c:2252
msgid "Show work cost statistics"
msgstr "Zeigt Statistiken zum Arbeitsaufwand"
-#: builtin/blame.c:2252
+#: builtin/blame.c:2253
msgid "Show output score for blame entries"
msgstr "Zeigt Ausgabebewertung für \"blame\"-Einträge"
-#: builtin/blame.c:2253
+#: builtin/blame.c:2254
msgid "Show original filename (Default: auto)"
msgstr "Zeigt ursprünglichen Dateinamen (Standard: auto)"
-#: builtin/blame.c:2254
+#: builtin/blame.c:2255
msgid "Show original linenumber (Default: off)"
msgstr "Zeigt ursprüngliche Zeilennummer (Standard: aus)"
-#: builtin/blame.c:2255
+#: builtin/blame.c:2256
msgid "Show in a format designed for machine consumption"
msgstr "Anzeige in einem Format für maschinelle Auswertung"
-#: builtin/blame.c:2256
+#: builtin/blame.c:2257
msgid "Show porcelain format with per-line commit information"
msgstr ""
"Anzeige in Format für Fremdprogramme mit Commit-Informationen pro Zeile"
-#: builtin/blame.c:2257
+#: builtin/blame.c:2258
msgid "Use the same output mode as git-annotate (Default: off)"
msgstr "Benutzt den gleichen Ausgabemodus wie \"git-annotate\" (Standard: aus)"
-#: builtin/blame.c:2258
+#: builtin/blame.c:2259
msgid "Show raw timestamp (Default: off)"
msgstr "Zeigt unbearbeiteten Zeitstempel (Standard: aus)"
-#: builtin/blame.c:2259
+#: builtin/blame.c:2260
msgid "Show long commit SHA1 (Default: off)"
msgstr "Zeigt langen Commit-SHA1 (Standard: aus)"
-#: builtin/blame.c:2260
+#: builtin/blame.c:2261
msgid "Suppress author name and timestamp (Default: off)"
msgstr "Unterdrückt den Namen des Autors und den Zeitstempel (Standard: aus)"
-#: builtin/blame.c:2261
+#: builtin/blame.c:2262
msgid "Show author email instead of name (Default: off)"
msgstr "Zeigt anstatt des Namens die Email-Adresse des Autors (Standard: aus)"
-#: builtin/blame.c:2262
+#: builtin/blame.c:2263
msgid "Ignore whitespace differences"
msgstr "Ignoriert Unterschiede im Whitespace"
-#: builtin/blame.c:2263
+#: builtin/blame.c:2264
msgid "Spend extra cycles to find better match"
msgstr "arbeite länger, um bessere Übereinstimmungen zu finden"
-#: builtin/blame.c:2264
+#: builtin/blame.c:2265
msgid "Use revisions from <file> instead of calling git-rev-list"
msgstr "Benutzt Commits von <Datei> anstatt \"git-rev-list\" aufzurufen"
-#: builtin/blame.c:2265
+#: builtin/blame.c:2266
msgid "Use <file>'s contents as the final image"
msgstr "Benutzt Inhalte der <Datei>en als entgültiges Abbild"
-#: builtin/blame.c:2266 builtin/blame.c:2267
+#: builtin/blame.c:2267 builtin/blame.c:2268
msgid "score"
msgstr "Bewertung"
-#: builtin/blame.c:2266
+#: builtin/blame.c:2267
msgid "Find line copies within and across files"
msgstr "Findet kopierte Zeilen innerhalb oder zwischen Dateien"
-#: builtin/blame.c:2267
+#: builtin/blame.c:2268
msgid "Find line movements within and across files"
msgstr "Findet verschobene Zeilen innerhalb oder zwischen Dateien"
-#: builtin/blame.c:2268
+#: builtin/blame.c:2269
msgid "n,m"
msgstr "n,m"
-#: builtin/blame.c:2268
+#: builtin/blame.c:2269
msgid "Process only line range n,m, counting from 1"
msgstr "Verarbeitet nur Zeilen im Bereich n,m, gezählt von 1"
@@ -2873,252 +2907,252 @@ msgstr "Branch %s entfernt (war %s).\n"
msgid "branch '%s' does not point at a commit"
msgstr "Branch '%s' zeigt auf keinen Commit"
-#: builtin/branch.c:453
+#: builtin/branch.c:454
#, c-format
msgid "[%s: gone]"
msgstr "[%s: entfernt]"
-#: builtin/branch.c:456
+#: builtin/branch.c:459
#, c-format
msgid "[%s]"
msgstr "[%s]"
-#: builtin/branch.c:459
+#: builtin/branch.c:464
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s: %d hinterher]"
-#: builtin/branch.c:461
+#: builtin/branch.c:466
#, c-format
msgid "[behind %d]"
msgstr "[%d hinterher]"
-#: builtin/branch.c:465
+#: builtin/branch.c:470
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s: %d voraus]"
-#: builtin/branch.c:467
+#: builtin/branch.c:472
#, c-format
msgid "[ahead %d]"
msgstr "[%d voraus]"
-#: builtin/branch.c:470
+#: builtin/branch.c:475
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s: %d voraus, %d hinterher]"
-#: builtin/branch.c:473
+#: builtin/branch.c:478
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[%d voraus, %d hinterher]"
-#: builtin/branch.c:496
+#: builtin/branch.c:502
msgid " **** invalid ref ****"
msgstr " **** ungültige Referenz ****"
-#: builtin/branch.c:588
+#: builtin/branch.c:594
#, c-format
msgid "(no branch, rebasing %s)"
msgstr "(kein Branch, Rebase von Branch %s im Gange)"
-#: builtin/branch.c:591
+#: builtin/branch.c:597
#, c-format
msgid "(no branch, bisect started on %s)"
msgstr "(kein Branch, binäre Suche begonnen bei %s)"
-#: builtin/branch.c:594
+#: builtin/branch.c:600
#, c-format
msgid "(detached from %s)"
msgstr "(losgelöst von %s)"
-#: builtin/branch.c:597
+#: builtin/branch.c:603
msgid "(no branch)"
msgstr "(kein Branch)"
-#: builtin/branch.c:643
+#: builtin/branch.c:649
#, c-format
msgid "object '%s' does not point to a commit"
msgstr "Objekt '%s' zeigt auf keinen Commit"
-#: builtin/branch.c:675
+#: builtin/branch.c:681
msgid "some refs could not be read"
msgstr "Konnte einige Referenzen nicht lesen"
-#: builtin/branch.c:688
+#: builtin/branch.c:694
msgid "cannot rename the current branch while not on any."
msgstr ""
"Kann aktuellen Branch nicht umbenennen, solange Sie sich auf keinem befinden."
-#: builtin/branch.c:698
+#: builtin/branch.c:704
#, c-format
msgid "Invalid branch name: '%s'"
msgstr "Ungültiger Branchname: '%s'"
-#: builtin/branch.c:713
+#: builtin/branch.c:719
msgid "Branch rename failed"
msgstr "Umbenennung des Branches fehlgeschlagen"
-#: builtin/branch.c:717
+#: builtin/branch.c:723
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr "falsch benannten Branch '%s' umbenannt"
-#: builtin/branch.c:721
+#: builtin/branch.c:727
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr "Branch umbenannt zu %s, aber HEAD ist nicht aktualisiert!"
-#: builtin/branch.c:728
+#: builtin/branch.c:734
msgid "Branch is renamed, but update of config-file failed"
msgstr ""
"Branch ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
"fehlgeschlagen."
-#: builtin/branch.c:743
+#: builtin/branch.c:749
#, c-format
msgid "malformed object name %s"
msgstr "Missgebildeter Objektname %s"
-#: builtin/branch.c:767
+#: builtin/branch.c:773
#, c-format
msgid "could not write branch description template: %s"
msgstr "Konnte Beschreibungsvorlage für Branch nicht schreiben: %s"
-#: builtin/branch.c:797
+#: builtin/branch.c:803
msgid "Generic options"
msgstr "Allgemeine Optionen"
-#: builtin/branch.c:799
+#: builtin/branch.c:805
msgid "show hash and subject, give twice for upstream branch"
msgstr "Zeigt Hash und Betreff; -vv: zusätzlich Upstream-Branch"
-#: builtin/branch.c:800
+#: builtin/branch.c:806
msgid "suppress informational messages"
msgstr "unterdrückt Informationsmeldungen"
-#: builtin/branch.c:801
+#: builtin/branch.c:807
msgid "set up tracking mode (see git-pull(1))"
msgstr "stellt den Ãœbernahmemodus ein (siehe git-pull(1))"
-#: builtin/branch.c:803
+#: builtin/branch.c:809
msgid "change upstream info"
msgstr "ändert Informationen zum Upstream-Branch"
-#: builtin/branch.c:807
+#: builtin/branch.c:813
msgid "use colored output"
msgstr "verwendet farbliche Ausgaben"
-#: builtin/branch.c:808
+#: builtin/branch.c:814
msgid "act on remote-tracking branches"
msgstr "wirkt auf Remote-Tracking-Branches"
-#: builtin/branch.c:811 builtin/branch.c:817 builtin/branch.c:838
-#: builtin/branch.c:844 builtin/commit.c:1460 builtin/commit.c:1461
+#: builtin/branch.c:817 builtin/branch.c:823 builtin/branch.c:844
+#: builtin/branch.c:850 builtin/commit.c:1460 builtin/commit.c:1461
#: builtin/commit.c:1462 builtin/commit.c:1463 builtin/tag.c:468
msgid "commit"
msgstr "Commit"
-#: builtin/branch.c:812 builtin/branch.c:818
+#: builtin/branch.c:818 builtin/branch.c:824
msgid "print only branches that contain the commit"
msgstr "gibt nur Branches aus, welche diesen Commit beinhalten"
-#: builtin/branch.c:824
+#: builtin/branch.c:830
msgid "Specific git-branch actions:"
msgstr "spezifische Aktionen für \"git-branch\":"
-#: builtin/branch.c:825
+#: builtin/branch.c:831
msgid "list both remote-tracking and local branches"
msgstr "listet Remote-Tracking und lokale Branches auf"
-#: builtin/branch.c:827
+#: builtin/branch.c:833
msgid "delete fully merged branch"
msgstr "entfernt vollständig zusammengeführten Branch"
-#: builtin/branch.c:828
+#: builtin/branch.c:834
msgid "delete branch (even if not merged)"
msgstr "löscht Branch (auch wenn nicht zusammengeführt)"
-#: builtin/branch.c:829
+#: builtin/branch.c:835
msgid "move/rename a branch and its reflog"
msgstr "verschiebt/benennt einen Branch und dessen Reflog um"
-#: builtin/branch.c:830
+#: builtin/branch.c:836
msgid "move/rename a branch, even if target exists"
msgstr ""
"verschiebt/benennt einen Branch um, auch wenn das Ziel bereits existiert"
-#: builtin/branch.c:831
+#: builtin/branch.c:837
msgid "list branch names"
msgstr "listet Branchnamen auf"
-#: builtin/branch.c:832
+#: builtin/branch.c:838
msgid "create the branch's reflog"
msgstr "erzeugt das Reflog des Branches"
-#: builtin/branch.c:834
+#: builtin/branch.c:840
msgid "edit the description for the branch"
msgstr "bearbeitet die Beschreibung für den Branch"
-#: builtin/branch.c:835
+#: builtin/branch.c:841
msgid "force creation (when already exists)"
msgstr "erzeuge auch, wenn der Branch bereits existiert"
-#: builtin/branch.c:838
+#: builtin/branch.c:844
msgid "print only not merged branches"
msgstr "gibt nur Branches aus, die nicht zusammengeführt sind"
-#: builtin/branch.c:844
+#: builtin/branch.c:850
msgid "print only merged branches"
msgstr "gibt nur Branches aus, die zusammengeführt sind"
-#: builtin/branch.c:848
+#: builtin/branch.c:854
msgid "list branches in columns"
msgstr "listet Branches in Spalten auf"
-#: builtin/branch.c:861
+#: builtin/branch.c:867
msgid "Failed to resolve HEAD as a valid ref."
msgstr "Konnte HEAD nicht als gültige Referenz auflösen."
-#: builtin/branch.c:866 builtin/clone.c:629
+#: builtin/branch.c:872 builtin/clone.c:635
msgid "HEAD not found below refs/heads!"
msgstr "HEAD wurde nicht unter \"refs/heads\" gefunden!"
-#: builtin/branch.c:890
+#: builtin/branch.c:896
msgid "--column and --verbose are incompatible"
msgstr "Die Optionen --column und --verbose sind inkompatibel."
-#: builtin/branch.c:896 builtin/branch.c:935
+#: builtin/branch.c:902 builtin/branch.c:941
msgid "branch name required"
msgstr "Branchname erforderlich"
-#: builtin/branch.c:911
+#: builtin/branch.c:917
msgid "Cannot give description to detached HEAD"
msgstr "zu losgelöstem HEAD kann keine Beschreibung hinterlegt werden"
-#: builtin/branch.c:916
+#: builtin/branch.c:922
msgid "cannot edit description of more than one branch"
msgstr "Beschreibung von mehr als einem Branch kann nicht bearbeitet werden"
-#: builtin/branch.c:923
+#: builtin/branch.c:929
#, c-format
msgid "No commit on branch '%s' yet."
msgstr "Noch kein Commit in Branch '%s'."
-#: builtin/branch.c:926
+#: builtin/branch.c:932
#, c-format
msgid "No branch named '%s'."
msgstr "Branch '%s' nicht vorhanden."
-#: builtin/branch.c:941
+#: builtin/branch.c:947
msgid "too many branches for a rename operation"
msgstr "zu viele Branches für eine Umbenennen-Operation angegeben"
-#: builtin/branch.c:946
+#: builtin/branch.c:952
msgid "too many branches to set new upstream"
msgstr "zu viele Branches angegeben um Upstream-Branch zu setzen"
-#: builtin/branch.c:950
+#: builtin/branch.c:956
#, c-format
msgid ""
"could not set upstream of HEAD to %s when it does not point to any branch."
@@ -3126,43 +3160,43 @@ msgstr ""
"Konnte keinen neuen Upstream-Branch von HEAD zu %s setzen, da dieser auf\n"
"keinen Branch zeigt."
-#: builtin/branch.c:953 builtin/branch.c:975 builtin/branch.c:997
+#: builtin/branch.c:959 builtin/branch.c:981 builtin/branch.c:1002
#, c-format
msgid "no such branch '%s'"
msgstr "Kein solcher Branch '%s'"
-#: builtin/branch.c:957
+#: builtin/branch.c:963
#, c-format
msgid "branch '%s' does not exist"
msgstr "Branch '%s' existiert nicht"
-#: builtin/branch.c:969
+#: builtin/branch.c:975
msgid "too many branches to unset upstream"
msgstr ""
"zu viele Branches angegeben um Konfiguration zu Upstream-Branch zu entfernen"
-#: builtin/branch.c:973
+#: builtin/branch.c:979
msgid "could not unset upstream of HEAD when it does not point to any branch."
msgstr ""
"Konnte Konfiguration zu Upstream-Branch von HEAD nicht entfernen, da dieser\n"
"auf keinen Branch zeigt."
-#: builtin/branch.c:979
+#: builtin/branch.c:985
#, c-format
msgid "Branch '%s' has no upstream information"
msgstr "Branch '%s' hat keinen Upstream-Branch gesetzt"
-#: builtin/branch.c:994
+#: builtin/branch.c:999
msgid "it does not make sense to create 'HEAD' manually"
msgstr "'HEAD' darf nicht manuell erstellt werden"
-#: builtin/branch.c:1000
+#: builtin/branch.c:1005
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr ""
"Die Optionen -a und -r bei 'git branch' können nicht gemeimsam mit einem "
"Branchnamen verwendet werden."
-#: builtin/branch.c:1003
+#: builtin/branch.c:1008
#, c-format
msgid ""
"The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -3171,7 +3205,7 @@ msgstr ""
"Die --set-upstream Option ist veraltet und wird entfernt. Benutzen Sie --"
"track oder --set-upstream-to\n"
-#: builtin/branch.c:1020
+#: builtin/branch.c:1025
#, c-format
msgid ""
"\n"
@@ -3182,12 +3216,12 @@ msgstr ""
"Wenn Sie wollten, dass '%s' den Branch '%s' als Upstream-Branch hat, führen "
"Sie aus:\n"
-#: builtin/branch.c:1021
+#: builtin/branch.c:1026
#, c-format
msgid " git branch -d %s\n"
msgstr " git branch -d %s\n"
-#: builtin/branch.c:1022
+#: builtin/branch.c:1027
#, c-format
msgid " git branch --set-upstream-to %s\n"
msgstr " git branch --set-upstream-to %s\n"
@@ -3205,45 +3239,45 @@ msgstr "Um ein Paket zu erstellen wird ein Repository benötigt."
msgid "Need a repository to unbundle."
msgstr "Zum Entpacken wird ein Repository benötigt."
-#: builtin/cat-file.c:312
+#: builtin/cat-file.c:328
msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
msgstr "git cat-file (-t|-s|-e|-p|<Art>|--textconv) <Objekt>"
-#: builtin/cat-file.c:313
+#: builtin/cat-file.c:329
msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
msgstr "git cat-file (--batch|--batch-check) < <Liste_von_Objekten>"
-#: builtin/cat-file.c:350
+#: builtin/cat-file.c:366
msgid "<type> can be one of: blob, tree, commit, tag"
msgstr "<Art> kann sein: blob, tree, commit, tag"
-#: builtin/cat-file.c:351
+#: builtin/cat-file.c:367
msgid "show object type"
msgstr "zeigt Objektart"
-#: builtin/cat-file.c:352
+#: builtin/cat-file.c:368
msgid "show object size"
msgstr "zeigt Objektgröße"
-#: builtin/cat-file.c:354
+#: builtin/cat-file.c:370
msgid "exit with zero when there's no error"
msgstr "beendet mit Rückgabewert 0, wenn kein Fehler aufgetreten ist"
-#: builtin/cat-file.c:355
+#: builtin/cat-file.c:371
msgid "pretty-print object's content"
msgstr "ansprechende Anzeige des Objektinhaltes"
-#: builtin/cat-file.c:357
+#: builtin/cat-file.c:373
msgid "for blob objects, run textconv on object's content"
msgstr "führt eine Textkonvertierung auf den Inhalt von Blob-Objekten aus"
-#: builtin/cat-file.c:359
+#: builtin/cat-file.c:375
msgid "show info and content of objects fed from the standard input"
msgstr ""
"Anzeige von Informationen und Inhalt von Objekten, gelesen von der Standard-"
"Eingabe"
-#: builtin/cat-file.c:362
+#: builtin/cat-file.c:378
msgid "show info about objects fed from the standard input"
msgstr ""
"Anzeige von Informationen über Objekte, gelesen von der Standard-Eingabe"
@@ -3273,7 +3307,7 @@ msgstr "liest Dateinamen von der Standard-Eingabe"
msgid "terminate input and output records by a NUL character"
msgstr "schließt Einträge von Ein- und Ausgabe mit NUL-Zeichen ab"
-#: builtin/check-ignore.c:18 builtin/checkout.c:1090 builtin/gc.c:259
+#: builtin/check-ignore.c:18 builtin/checkout.c:1090 builtin/gc.c:260
msgid "suppress progress reporting"
msgstr "unterdrückt Fortschrittsanzeige"
@@ -3569,7 +3603,7 @@ msgid "Cannot switch branch to a non-commit '%s'"
msgstr "Kann Branch nicht zu Nicht-Commit '%s' wechseln"
#: builtin/checkout.c:1091 builtin/checkout.c:1093 builtin/clone.c:88
-#: builtin/remote.c:169 builtin/remote.c:171
+#: builtin/remote.c:159 builtin/remote.c:161
msgid "branch"
msgstr "Branch"
@@ -3617,11 +3651,11 @@ msgstr "erzwingt Auschecken (verwirft lokale Änderungen)"
msgid "perform a 3-way merge with the new branch"
msgstr "führt einen 3-Wege-Merge mit dem neuen Branch aus"
-#: builtin/checkout.c:1106 builtin/merge.c:232
+#: builtin/checkout.c:1106 builtin/merge.c:225
msgid "update ignored files (default)"
msgstr "aktualisiert ignorierte Dateien (Standard)"
-#: builtin/checkout.c:1107 builtin/log.c:1228 parse-options.h:251
+#: builtin/checkout.c:1107 builtin/log.c:1228 parse-options.h:248
msgid "style"
msgstr "Stil"
@@ -3820,7 +3854,7 @@ msgid "remove whole directories"
msgstr "löscht ganze Verzeichnisse"
#: builtin/clean.c:880 builtin/describe.c:420 builtin/grep.c:718
-#: builtin/ls-files.c:483 builtin/name-rev.c:315 builtin/show-ref.c:185
+#: builtin/ls-files.c:483 builtin/name-rev.c:314 builtin/show-ref.c:185
msgid "pattern"
msgstr "Muster"
@@ -3860,8 +3894,8 @@ msgstr ""
msgid "git clone [options] [--] <repo> [<dir>]"
msgstr "git clone [Optionen] [--] <Repository> [<Verzeichnis>]"
-#: builtin/clone.c:64 builtin/fetch.c:96 builtin/merge.c:229
-#: builtin/push.c:474
+#: builtin/clone.c:64 builtin/fetch.c:97 builtin/merge.c:222
+#: builtin/push.c:521
msgid "force progress reporting"
msgstr "erzwingt Fortschrittsanzeige"
@@ -3921,13 +3955,13 @@ msgstr "checkt <Branch> aus, anstatt HEAD des Remote-Repositories"
msgid "path to git-upload-pack on the remote"
msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite"
-#: builtin/clone.c:92 builtin/fetch.c:97 builtin/grep.c:663
+#: builtin/clone.c:92 builtin/fetch.c:98 builtin/grep.c:663
msgid "depth"
msgstr "Tiefe"
#: builtin/clone.c:93
msgid "create a shallow clone of that depth"
-msgstr "erstellt einen flachen Klon mit dieser Tiefe"
+msgstr "erstellt einen Klon mit unvollständiger Historie (shallow) in dieser Tiefe"
#: builtin/clone.c:95
msgid "clone only one branch, HEAD or --branch"
@@ -3954,42 +3988,52 @@ msgstr "setzt Konfiguration innerhalb des neuen Repositories"
msgid "reference repository '%s' is not a local repository."
msgstr "Referenziertes Repository '%s' ist kein lokales Repository."
-#: builtin/clone.c:315
+#: builtin/clone.c:256
+#, c-format
+msgid "reference repository '%s' is shallow"
+msgstr "Referenziertes Repository '%s' hat eine unvollständige Historie (shallow)."
+
+#: builtin/clone.c:259
+#, c-format
+msgid "reference repository '%s' is grafted"
+msgstr "Referenziertes Repository '%s' ist mit künstlichen Vorgängern (\"grafts\") eingehängt."
+
+#: builtin/clone.c:321
#, c-format
msgid "failed to create directory '%s'"
msgstr "Fehler beim Erstellen von Verzeichnis '%s'"
-#: builtin/clone.c:317 builtin/diff.c:77
+#: builtin/clone.c:323 builtin/diff.c:83
#, c-format
msgid "failed to stat '%s'"
msgstr "Konnte '%s' nicht lesen"
-#: builtin/clone.c:319
+#: builtin/clone.c:325
#, c-format
msgid "%s exists and is not a directory"
msgstr "%s existiert und ist kein Verzeichnis"
-#: builtin/clone.c:333
+#: builtin/clone.c:339
#, c-format
msgid "failed to stat %s\n"
msgstr "Konnte %s nicht lesen\n"
-#: builtin/clone.c:355
+#: builtin/clone.c:361
#, c-format
msgid "failed to create link '%s'"
msgstr "Konnte Verweis '%s' nicht erstellen"
-#: builtin/clone.c:359
+#: builtin/clone.c:365
#, c-format
msgid "failed to copy file to '%s'"
msgstr "Konnte Datei nicht nach '%s' kopieren"
-#: builtin/clone.c:382 builtin/clone.c:559
+#: builtin/clone.c:388 builtin/clone.c:565
#, c-format
msgid "done.\n"
msgstr "Fertig.\n"
-#: builtin/clone.c:395
+#: builtin/clone.c:401
msgid ""
"Clone succeeded, but checkout failed.\n"
"You can inspect what was checked out with 'git status'\n"
@@ -3999,103 +4043,113 @@ msgstr ""
"Sie können mit 'git status' prüfen, was ausgecheckt worden ist\n"
"und das Auschecken mit 'git checkout -f HEAD' erneut versuchen.\n"
-#: builtin/clone.c:474
+#: builtin/clone.c:480
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "Konnte zu klonenden Remote-Branch %s nicht finden."
-#: builtin/clone.c:554
+#: builtin/clone.c:560
#, c-format
msgid "Checking connectivity... "
msgstr "Prüfe Konnektivität... "
-#: builtin/clone.c:557
+#: builtin/clone.c:563
msgid "remote did not send all necessary objects"
msgstr "Remote-Repository hat nicht alle erforderlichen Objekte gesendet."
-#: builtin/clone.c:620
+#: builtin/clone.c:626
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr ""
"Externer HEAD bezieht sich auf eine nicht existierende Referenz und kann "
"nicht ausgecheckt werden.\n"
-#: builtin/clone.c:651
+#: builtin/clone.c:657
msgid "unable to checkout working tree"
msgstr "Arbeitsverzeichnis konnte nicht ausgecheckt werden"
-#: builtin/clone.c:759
+#: builtin/clone.c:765
msgid "Too many arguments."
msgstr "Zu viele Argumente."
-#: builtin/clone.c:763
+#: builtin/clone.c:769
msgid "You must specify a repository to clone."
msgstr "Sie müssen ein Repository zum Klonen angeben."
-#: builtin/clone.c:774
+#: builtin/clone.c:780
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "Die Optionen --bare und --origin %s sind inkompatibel."
-#: builtin/clone.c:777
+#: builtin/clone.c:783
msgid "--bare and --separate-git-dir are incompatible."
msgstr "Die Optionen --bare und --separate-git-dir sind inkompatibel."
-#: builtin/clone.c:790
+#: builtin/clone.c:796
#, c-format
msgid "repository '%s' does not exist"
msgstr "Repository '%s' existiert nicht."
-#: builtin/clone.c:795
+#: builtin/clone.c:802
msgid "--depth is ignored in local clones; use file:// instead."
msgstr ""
"Die Option --depth wird in lokalen Klonen ignoriert; benutzen Sie "
"stattdessen file://"
-#: builtin/clone.c:797
+#: builtin/clone.c:805
+msgid "source repository is shallow, ignoring --local"
+msgstr "Quelle ist ein Repository mit unvollständiger Historie (shallow),"
+"ignoriere --local"
+
+#: builtin/clone.c:810
msgid "--local is ignored"
msgstr "--local wird ignoriert"
-#: builtin/clone.c:807
+#: builtin/clone.c:814 builtin/fetch.c:1119
+#, c-format
+msgid "depth %s is not a positive number"
+msgstr "Tiefe %s ist keine positive Zahl"
+
+#: builtin/clone.c:824
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "Zielpfad '%s' existiert bereits und ist kein leeres Verzeichnis."
-#: builtin/clone.c:817
+#: builtin/clone.c:834
#, c-format
msgid "working tree '%s' already exists."
msgstr "Arbeitsverzeichnis '%s' existiert bereits."
-#: builtin/clone.c:830 builtin/clone.c:842
+#: builtin/clone.c:847 builtin/clone.c:859
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen."
-#: builtin/clone.c:833
+#: builtin/clone.c:850
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen."
-#: builtin/clone.c:852
+#: builtin/clone.c:869
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "Klone in Bare-Repository '%s'...\n"
-#: builtin/clone.c:854
+#: builtin/clone.c:871
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Klone nach '%s'...\n"
-#: builtin/clone.c:888
+#: builtin/clone.c:906
#, c-format
msgid "Don't know how to clone %s"
msgstr "Weiß nicht wie %s zu klonen ist."
-#: builtin/clone.c:939 builtin/clone.c:947
+#: builtin/clone.c:957 builtin/clone.c:965
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "Remote-Branch %s nicht im Upstream-Repository %s gefunden"
-#: builtin/clone.c:950
+#: builtin/clone.c:968
msgid "You appear to have cloned an empty repository."
msgstr "Sie scheinen ein leeres Repository geklont zu haben."
@@ -4464,7 +4518,7 @@ msgstr "zeigt Status im Kurzformat"
msgid "show branch information"
msgstr "zeigt Branchinformationen"
-#: builtin/commit.c:1255 builtin/commit.c:1486 builtin/push.c:460
+#: builtin/commit.c:1255 builtin/commit.c:1486 builtin/push.c:507
msgid "machine-readable output"
msgstr "maschinenlesbare Ausgabe"
@@ -4547,7 +4601,7 @@ msgstr "Autor"
msgid "override author for commit"
msgstr "überschreibt Autor eines Commits"
-#: builtin/commit.c:1458 builtin/gc.c:260
+#: builtin/commit.c:1458 builtin/gc.c:261
msgid "date"
msgstr "Datum"
@@ -4555,7 +4609,7 @@ msgstr "Datum"
msgid "override date for commit"
msgstr "überschreibt Datum eines Commits"
-#: builtin/commit.c:1459 builtin/merge.c:223 builtin/notes.c:405
+#: builtin/commit.c:1459 builtin/merge.c:216 builtin/notes.c:405
#: builtin/notes.c:562 builtin/tag.c:455
msgid "message"
msgstr "Beschreibung"
@@ -4613,11 +4667,11 @@ msgstr ""
msgid "include status in commit message template"
msgstr "fügt Status in die Commit-Beschreibungsvorlage ein"
-#: builtin/commit.c:1470 builtin/merge.c:230 builtin/tag.c:461
+#: builtin/commit.c:1470 builtin/merge.c:223 builtin/tag.c:461
msgid "key id"
msgstr "Schlüssel-ID"
-#: builtin/commit.c:1471 builtin/merge.c:231
+#: builtin/commit.c:1471 builtin/merge.c:224
msgid "GPG sign commit"
msgstr "signiert Commit mit GPG"
@@ -4674,7 +4728,7 @@ msgstr "erlaubt Aufzeichnung einer Änderung mit einer leeren Beschreibung"
msgid "could not parse HEAD commit"
msgstr "Konnte Commit von HEAD nicht analysieren."
-#: builtin/commit.c:1567 builtin/merge.c:525
+#: builtin/commit.c:1567 builtin/merge.c:518
#, c-format
msgid "could not open '%s' for reading"
msgstr "Konnte '%s' nicht zum Lesen öffnen."
@@ -4693,29 +4747,29 @@ msgstr "Konnte MERGE_MODE nicht lesen"
msgid "could not read commit message: %s"
msgstr "Konnte Commit-Beschreibung nicht lesen: %s"
-#: builtin/commit.c:1614
+#: builtin/commit.c:1611
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "Commit abgebrochen; Sie haben die Beschreibung nicht editiert.\n"
-#: builtin/commit.c:1619
+#: builtin/commit.c:1616
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "Commit aufgrund leerer Beschreibung abgebrochen.\n"
-#: builtin/commit.c:1634 builtin/merge.c:861 builtin/merge.c:886
+#: builtin/commit.c:1631 builtin/merge.c:854 builtin/merge.c:879
msgid "failed to write commit object"
msgstr "Fehler beim Schreiben des Commit-Objektes."
-#: builtin/commit.c:1655
+#: builtin/commit.c:1652
msgid "cannot lock HEAD ref"
msgstr "Kann Referenz von HEAD nicht sperren."
-#: builtin/commit.c:1659
+#: builtin/commit.c:1656
msgid "cannot update HEAD ref"
msgstr "Kann Referenz von HEAD nicht aktualisieren."
-#: builtin/commit.c:1670
+#: builtin/commit.c:1667
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -4978,7 +5032,7 @@ msgstr "betrachtet die jüngsten <n> Tags (Standard: 10)"
msgid "only consider tags matching <pattern>"
msgstr "betrachtet nur Tags die <Muster> entsprechen"
-#: builtin/describe.c:423 builtin/name-rev.c:322
+#: builtin/describe.c:423 builtin/name-rev.c:321
msgid "show abbreviated commit object as fallback"
msgstr "zeigt gekürztes Commit-Objekt, wenn sonst nichts zutrifft"
@@ -5004,31 +5058,31 @@ msgstr "Keine Namen gefunden, kann nichts beschreiben."
msgid "--dirty is incompatible with commit-ishes"
msgstr "Die Option --dirty kann nicht mit Commits verwendet werden."
-#: builtin/diff.c:79
+#: builtin/diff.c:85
#, c-format
msgid "'%s': not a regular file or symlink"
msgstr "'%s': keine reguläre Datei oder symbolischer Verweis"
-#: builtin/diff.c:230
+#: builtin/diff.c:236
#, c-format
msgid "invalid option: %s"
msgstr "Ungültige Option: %s"
-#: builtin/diff.c:307
+#: builtin/diff.c:357
msgid "Not a git repository"
msgstr "Kein Git-Repository"
-#: builtin/diff.c:350
+#: builtin/diff.c:400
#, c-format
msgid "invalid object '%s' given."
msgstr "Objekt '%s' ist ungültig."
-#: builtin/diff.c:359
+#: builtin/diff.c:409
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "Mehr als zwei Blobs angegeben: '%s'"
-#: builtin/diff.c:366
+#: builtin/diff.c:416
#, c-format
msgid "unhandled object '%s' given."
msgstr "unbehandeltes Objekt '%s' angegeben"
@@ -5089,147 +5143,157 @@ msgstr "git fetch --multiple [<Optionen>] [(<Repository> | <Gruppe>)...]"
msgid "git fetch --all [<options>]"
msgstr "git fetch --all [<Optionen>]"
-#: builtin/fetch.c:74
+#: builtin/fetch.c:75
msgid "fetch from all remotes"
msgstr "fordert von allen Remote-Repositories an"
-#: builtin/fetch.c:76
+#: builtin/fetch.c:77
msgid "append to .git/FETCH_HEAD instead of overwriting"
msgstr "hängt an .git/FETCH_HEAD an, anstatt zu überschreiben"
-#: builtin/fetch.c:78
+#: builtin/fetch.c:79
msgid "path to upload pack on remote end"
msgstr "Pfad des Programms zum Hochladen von Paketen auf der Gegenseite"
-#: builtin/fetch.c:79
+#: builtin/fetch.c:80
msgid "force overwrite of local branch"
msgstr "erzwingt das Ãœberschreiben von lokalen Branches"
-#: builtin/fetch.c:81
+#: builtin/fetch.c:82
msgid "fetch from multiple remotes"
msgstr "fordert von mehreren Remote-Repositories an"
-#: builtin/fetch.c:83
+#: builtin/fetch.c:84
msgid "fetch all tags and associated objects"
msgstr "fordert alle Tags und verbundene Objekte an"
-#: builtin/fetch.c:85
+#: builtin/fetch.c:86
msgid "do not fetch all tags (--no-tags)"
msgstr "fordert nicht alle Tags an (--no-tags)"
-#: builtin/fetch.c:87
+#: builtin/fetch.c:88
msgid "prune remote-tracking branches no longer on remote"
msgstr ""
"entfernt Remote-Tracking-Branches, die sich nicht mehr im Remote-Repository "
"befinden"
-#: builtin/fetch.c:88
+#: builtin/fetch.c:89
msgid "on-demand"
msgstr "bei-Bedarf"
-#: builtin/fetch.c:89
+#: builtin/fetch.c:90
msgid "control recursive fetching of submodules"
msgstr "kontrolliert rekursive Anforderungen von Submodulen"
-#: builtin/fetch.c:93
+#: builtin/fetch.c:94
msgid "keep downloaded pack"
msgstr "behält heruntergeladenes Paket"
-#: builtin/fetch.c:95
+#: builtin/fetch.c:96
msgid "allow updating of HEAD ref"
msgstr "erlaubt Aktualisierung der \"HEAD\"-Referenz"
-#: builtin/fetch.c:98
+#: builtin/fetch.c:99
msgid "deepen history of shallow clone"
-msgstr "vertieft die Historie eines flachen Klons"
+msgstr "vertieft die Historie eines Klons mit unvollständiger Historie (shallow)"
-#: builtin/fetch.c:100
+#: builtin/fetch.c:101
msgid "convert to a complete repository"
msgstr "konvertiert zu einem vollständigen Repository"
-#: builtin/fetch.c:102 builtin/log.c:1197
+#: builtin/fetch.c:103 builtin/log.c:1197
msgid "dir"
msgstr "Verzeichnis"
-#: builtin/fetch.c:103
+#: builtin/fetch.c:104
msgid "prepend this to submodule path output"
msgstr "stellt dies an die Ausgabe der Submodul-Pfade voran"
-#: builtin/fetch.c:106
+#: builtin/fetch.c:107
msgid "default mode for recursion"
msgstr "Standard-Modus für Rekursion"
-#: builtin/fetch.c:236
+#: builtin/fetch.c:109
+msgid "accept refs that update .git/shallow"
+msgstr "akzeptiert Referenzen die .git/shallow aktualisieren"
+
+#: builtin/fetch.c:347
msgid "Couldn't find remote ref HEAD"
msgstr "Konnte Remote-Referenz von HEAD nicht finden."
-#: builtin/fetch.c:290
+#: builtin/fetch.c:411
#, c-format
msgid "object %s not found"
msgstr "Objekt %s nicht gefunden"
-#: builtin/fetch.c:295
+#: builtin/fetch.c:416
msgid "[up to date]"
msgstr "[aktuell]"
-#: builtin/fetch.c:309
+#: builtin/fetch.c:430
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
msgstr ""
"! %-*s %-*s -> %s (kann \"fetch\" im aktuellen Branch nicht ausführen)"
-#: builtin/fetch.c:310 builtin/fetch.c:396
+#: builtin/fetch.c:431 builtin/fetch.c:517
msgid "[rejected]"
msgstr "[zurückgewiesen]"
-#: builtin/fetch.c:321
+#: builtin/fetch.c:442
msgid "[tag update]"
msgstr "[Tag Aktualisierung]"
-#: builtin/fetch.c:323 builtin/fetch.c:358 builtin/fetch.c:376
+#: builtin/fetch.c:444 builtin/fetch.c:479 builtin/fetch.c:497
msgid " (unable to update local ref)"
msgstr " (kann lokale Referenz nicht aktualisieren)"
-#: builtin/fetch.c:341
+#: builtin/fetch.c:462
msgid "[new tag]"
msgstr "[neues Tag]"
-#: builtin/fetch.c:344
+#: builtin/fetch.c:465
msgid "[new branch]"
msgstr "[neuer Branch]"
-#: builtin/fetch.c:347
+#: builtin/fetch.c:468
msgid "[new ref]"
msgstr "[neue Referenz]"
-#: builtin/fetch.c:392
+#: builtin/fetch.c:513
msgid "unable to update local ref"
msgstr "kann lokale Referenz nicht aktualisieren"
-#: builtin/fetch.c:392
+#: builtin/fetch.c:513
msgid "forced update"
msgstr "Aktualisierung erzwungen"
-#: builtin/fetch.c:398
+#: builtin/fetch.c:519
msgid "(non-fast-forward)"
msgstr "(kein Vorspulen)"
-#: builtin/fetch.c:429 builtin/fetch.c:735
+#: builtin/fetch.c:552 builtin/fetch.c:785
#, c-format
msgid "cannot open %s: %s\n"
msgstr "kann %s nicht öffnen: %s\n"
-#: builtin/fetch.c:438
+#: builtin/fetch.c:561
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
-#: builtin/fetch.c:537
+#: builtin/fetch.c:579
+#, c-format
+msgid "reject %s because shallow roots are not allowed to be updated"
+msgstr "%s wurde zurückgewiesen, da Ursprungs-Commits von Repositories"
+"mit unvollständiger Historie (shallow) nicht aktualisiert werden dürfen."
+
+#: builtin/fetch.c:667 builtin/fetch.c:750
#, c-format
msgid "From %.*s\n"
msgstr "Von %.*s\n"
-#: builtin/fetch.c:548
+#: builtin/fetch.c:678
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -5238,57 +5302,57 @@ msgstr ""
"Einige lokale Referenzen konnten nicht aktualisiert werden; versuchen Sie\n"
"'git remote prune %s' um jeden älteren, widersprüchlichen Branch zu löschen."
-#: builtin/fetch.c:598
+#: builtin/fetch.c:730
#, c-format
msgid " (%s will become dangling)"
msgstr " (%s wird unreferenziert)"
-#: builtin/fetch.c:599
+#: builtin/fetch.c:731
#, c-format
msgid " (%s has become dangling)"
msgstr " (%s wurde unreferenziert)"
-#: builtin/fetch.c:606
+#: builtin/fetch.c:755
msgid "[deleted]"
msgstr "[gelöscht]"
-#: builtin/fetch.c:607 builtin/remote.c:1055
+#: builtin/fetch.c:756 builtin/remote.c:1050
msgid "(none)"
msgstr "(nichts)"
-#: builtin/fetch.c:725
+#: builtin/fetch.c:775
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr ""
"Der \"fetch\" in den aktuellen Branch %s von einem nicht-Bare-Repository "
"wurde verweigert."
-#: builtin/fetch.c:744
+#: builtin/fetch.c:794
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr "Option \"%s\" Wert \"%s\" ist nicht gültig für %s"
-#: builtin/fetch.c:747
+#: builtin/fetch.c:797
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "Option \"%s\" wird ignoriert für %s\n"
-#: builtin/fetch.c:801
+#: builtin/fetch.c:853
#, c-format
msgid "Don't know how to fetch from %s"
msgstr "Weiß nicht wie von %s angefordert wird."
-#: builtin/fetch.c:976
+#: builtin/fetch.c:1015
#, c-format
msgid "Fetching %s\n"
msgstr "Fordere an von %s\n"
-#: builtin/fetch.c:978 builtin/remote.c:100
+#: builtin/fetch.c:1017 builtin/remote.c:90
#, c-format
msgid "Could not fetch %s"
msgstr "Konnte nicht von %s anfordern"
-#: builtin/fetch.c:997
+#: builtin/fetch.c:1036
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
@@ -5297,35 +5361,35 @@ msgstr ""
"oder den Namen des Remote-Repositories an, von welchem neue\n"
"Commits angefordert werden sollen."
-#: builtin/fetch.c:1020
+#: builtin/fetch.c:1059
msgid "You need to specify a tag name."
msgstr "Sie müssen den Namen des Tags angeben."
-#: builtin/fetch.c:1068
+#: builtin/fetch.c:1107
msgid "--depth and --unshallow cannot be used together"
msgstr ""
"Die Optionen --depth und --unshallow können nicht gemeinsam verwendet werden."
-#: builtin/fetch.c:1070
+#: builtin/fetch.c:1109
msgid "--unshallow on a complete repository does not make sense"
msgstr ""
-"Die Option --unshallow kann nicht in einem vollständigen Repository "
+"Die Option --unshallow kann nicht in einem Repository mit unvollständiger Historie "
"verwendet werden."
-#: builtin/fetch.c:1089
+#: builtin/fetch.c:1132
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all akzeptiert kein Repository als Argument"
-#: builtin/fetch.c:1091
+#: builtin/fetch.c:1134
msgid "fetch --all does not make sense with refspecs"
msgstr "fetch --all kann nicht mit Refspecs verwendet werden."
-#: builtin/fetch.c:1102
+#: builtin/fetch.c:1145
#, c-format
msgid "No such remote or remote group: %s"
msgstr "Kein Remote-Repository (einzeln oder Gruppe): %s"
-#: builtin/fetch.c:1110
+#: builtin/fetch.c:1153
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr ""
"Das Abholen einer Gruppe von Remote-Repositories kann nicht mit der Angabe\n"
@@ -5337,8 +5401,9 @@ msgstr ""
"git fmt-merge-msg [-m <Beschreibung>] [--log[=<n>]|--no-log] [--file <Datei>]"
#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:702
-#: builtin/merge.c:203 builtin/show-branch.c:655 builtin/show-ref.c:178
-#: builtin/tag.c:446 parse-options.h:135 parse-options.h:245
+#: builtin/merge.c:196 builtin/repack.c:160 builtin/repack.c:164
+#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:446
+#: parse-options.h:135 parse-options.h:242
msgid "n"
msgstr "Anzahl"
@@ -5362,43 +5427,43 @@ msgstr "verwendet <Text> als Beschreibungsanfang"
msgid "file to read from"
msgstr "Datei zum Einlesen"
-#: builtin/for-each-ref.c:995
+#: builtin/for-each-ref.c:1063
msgid "git for-each-ref [options] [<pattern>]"
msgstr "git for-each-ref [Optionen] [<Muster>]"
-#: builtin/for-each-ref.c:1010
+#: builtin/for-each-ref.c:1078
msgid "quote placeholders suitably for shells"
msgstr "formatiert Platzhalter als Shell-String"
-#: builtin/for-each-ref.c:1012
+#: builtin/for-each-ref.c:1080
msgid "quote placeholders suitably for perl"
msgstr "formatiert Platzhalter als Perl-String"
-#: builtin/for-each-ref.c:1014
+#: builtin/for-each-ref.c:1082
msgid "quote placeholders suitably for python"
msgstr "formatiert Platzhalter als Python-String"
-#: builtin/for-each-ref.c:1016
+#: builtin/for-each-ref.c:1084
msgid "quote placeholders suitably for tcl"
msgstr "formatiert Platzhalter als TCL-String"
-#: builtin/for-each-ref.c:1019
+#: builtin/for-each-ref.c:1087
msgid "show only <n> matched refs"
msgstr "zeigt nur <n> passende Referenzen"
-#: builtin/for-each-ref.c:1020
+#: builtin/for-each-ref.c:1088 builtin/replace.c:177
msgid "format"
msgstr "Format"
-#: builtin/for-each-ref.c:1020
+#: builtin/for-each-ref.c:1088
msgid "format to use for the output"
msgstr "für die Ausgabe zu verwendendes Format"
-#: builtin/for-each-ref.c:1021
+#: builtin/for-each-ref.c:1089
msgid "key"
msgstr "Schüssel"
-#: builtin/for-each-ref.c:1022
+#: builtin/for-each-ref.c:1090
msgid "field name to sort on"
msgstr "sortiere nach diesem Feld"
@@ -5442,42 +5507,43 @@ msgstr "aktiviert genauere Prüfung"
msgid "write dangling objects in .git/lost-found"
msgstr "schreibt unreferenzierte Objekte nach .git/lost-found"
-#: builtin/fsck.c:623 builtin/prune.c:134
+#: builtin/fsck.c:623 builtin/prune.c:144
msgid "show progress"
msgstr "zeigt Fortschrittsanzeige"
-#: builtin/gc.c:23
+#: builtin/gc.c:24
msgid "git gc [options]"
msgstr "git gc [Optionen]"
-#: builtin/gc.c:79
+#: builtin/gc.c:80
#, c-format
msgid "Invalid %s: '%s'"
msgstr "Ungültiger %s: '%s'"
-#: builtin/gc.c:106
+#: builtin/gc.c:107
#, c-format
msgid "insanely long object directory %.*s"
msgstr "zu langes Objekt-Verzeichnis %.*s"
-#: builtin/gc.c:261
+#: builtin/gc.c:262
msgid "prune unreferenced objects"
msgstr "entfernt unreferenzierte Objekte"
-#: builtin/gc.c:263
+#: builtin/gc.c:264
msgid "be more thorough (increased runtime)"
msgstr "mehr Gründlichkeit (erhöht Laufzeit)"
-#: builtin/gc.c:264
+#: builtin/gc.c:265
msgid "enable auto-gc mode"
msgstr "aktiviert \"auto-gc\" Modus"
-#: builtin/gc.c:265
+#: builtin/gc.c:266
msgid "force running gc even if there may be another gc running"
-msgstr "erzwingt Ausführung von \"git gc\" selbst wenn ein anderes\n"
+msgstr ""
+"erzwingt Ausführung von \"git gc\" selbst wenn ein anderes\n"
"\"git gc\" bereits ausgeführt wird"
-#: builtin/gc.c:305
+#: builtin/gc.c:306
#, c-format
msgid ""
"Auto packing the repository for optimum performance. You may also\n"
@@ -5488,7 +5554,7 @@ msgstr ""
"Siehe \"git help gc\" für weitere Informationen.\n"
#. be quiet on --auto
-#: builtin/gc.c:315
+#: builtin/gc.c:316
#, c-format
msgid ""
"gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)"
@@ -5496,7 +5562,7 @@ msgstr ""
"\"git gc\" wird bereits auf Maschine '%s' pid %<PRIuMAX> ausgeführt\n"
"(benutzen Sie --force falls nicht)"
-#: builtin/gc.c:340
+#: builtin/gc.c:341
msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr ""
@@ -5845,57 +5911,57 @@ msgstr ""
"'%s': Kommando für unterstützten Handbuchbetrachter.\n"
"Sie könnten stattdessen 'man.<Werkzeug>.path' benutzen."
-#: builtin/help.c:349
+#: builtin/help.c:353
#, c-format
msgid "'%s': unknown man viewer."
msgstr "'%s': unbekannter Handbuch-Betrachter."
-#: builtin/help.c:366
+#: builtin/help.c:370
msgid "no man viewer handled the request"
msgstr "kein Handbuch-Betrachter konnte mit dieser Anfrage umgehen"
-#: builtin/help.c:374
+#: builtin/help.c:378
msgid "no info viewer handled the request"
msgstr "kein Informations-Betrachter konnte mit dieser Anfrage umgehen"
-#: builtin/help.c:420
+#: builtin/help.c:424
msgid "Defining attributes per path"
msgstr "Definition von Attributen pro Pfad"
-#: builtin/help.c:421
+#: builtin/help.c:425
msgid "A Git glossary"
msgstr "Ein Git-Glossar"
-#: builtin/help.c:422
+#: builtin/help.c:426
msgid "Specifies intentionally untracked files to ignore"
msgstr "Spezifikation von bewusst ignorierten, unbeobachteten Dateien"
-#: builtin/help.c:423
+#: builtin/help.c:427
msgid "Defining submodule properties"
msgstr "Definition von Submodul-Eigenschaften"
-#: builtin/help.c:424
+#: builtin/help.c:428
msgid "Specifying revisions and ranges for Git"
msgstr "Spezifikation von Commits und Bereichen für Git"
-#: builtin/help.c:425
+#: builtin/help.c:429
msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
msgstr "Eine einführende Anleitung zu Git (für Version 1.5.1 oder neuer)"
-#: builtin/help.c:426
+#: builtin/help.c:430
msgid "An overview of recommended workflows with Git"
msgstr "Eine Übersicht über empfohlene Arbeitsabläufe mit Git"
-#: builtin/help.c:438
+#: builtin/help.c:442
msgid "The common Git guides are:\n"
msgstr "Die allgemein verwendeten Git-Anleitungen sind:\n"
-#: builtin/help.c:460 builtin/help.c:476
+#: builtin/help.c:463 builtin/help.c:480
#, c-format
msgid "usage: %s%s"
msgstr "Verwendung: %s%s"
-#: builtin/help.c:492
+#: builtin/help.c:496
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "für `git %s' wurde der Alias `%s' angelegt"
@@ -6305,21 +6371,21 @@ msgstr "Berechtigungen"
msgid "specify that the git repository is to be shared amongst several users"
msgstr "gibt an, dass das Git-Repository mit mehreren Benutzern geteilt wird"
-#: builtin/init-db.c:493 builtin/prune-packed.c:75 builtin/repack.c:155
+#: builtin/init-db.c:493 builtin/prune-packed.c:79 builtin/repack.c:155
msgid "be quiet"
msgstr "weniger Ausgaben"
-#: builtin/init-db.c:522 builtin/init-db.c:529
+#: builtin/init-db.c:525 builtin/init-db.c:530
#, c-format
msgid "cannot mkdir %s"
msgstr "kann Verzeichnis %s nicht erstellen"
-#: builtin/init-db.c:533
+#: builtin/init-db.c:534
#, c-format
msgid "cannot chdir to %s"
msgstr "kann nicht in Verzeichnis %s wechseln"
-#: builtin/init-db.c:555
+#: builtin/init-db.c:556
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -6328,11 +6394,11 @@ msgstr ""
"%s (oder --work-tree=<Verzeichnis>) nicht erlaubt ohne Spezifizierung von %s "
"(oder --git-dir=<Verzeichnis>)"
-#: builtin/init-db.c:579
+#: builtin/init-db.c:580
msgid "Cannot access current working directory"
msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen."
-#: builtin/init-db.c:586
+#: builtin/init-db.c:587
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "Kann nicht auf Arbeitsverzeichnis '%s' zugreifen."
@@ -6768,153 +6834,153 @@ msgstr "Verfügbare Strategien sind:"
msgid "Available custom strategies are:"
msgstr "Verfügbare benutzerdefinierte Strategien sind:"
-#: builtin/merge.c:198
+#: builtin/merge.c:191
msgid "do not show a diffstat at the end of the merge"
msgstr "zeigt keine Zusammenfassung der Unterschiede am Schluss des Merges an"
-#: builtin/merge.c:201
+#: builtin/merge.c:194
msgid "show a diffstat at the end of the merge"
msgstr "zeigt eine Zusammenfassung der Unterschiede am Schluss des Merges an"
-#: builtin/merge.c:202
+#: builtin/merge.c:195
msgid "(synonym to --stat)"
msgstr "(Synonym für --stat)"
-#: builtin/merge.c:204
+#: builtin/merge.c:197
msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr ""
"fügt (höchstens <n>) Einträge von \"shortlog\" zur Beschreibung des Merge-"
"Commits hinzu"
-#: builtin/merge.c:207
+#: builtin/merge.c:200
msgid "create a single commit instead of doing a merge"
msgstr "erzeugt einen einzelnen Commit anstatt eines Merges"
-#: builtin/merge.c:209
+#: builtin/merge.c:202
msgid "perform a commit if the merge succeeds (default)"
msgstr "führt einen Commit durch, wenn der Merge erfolgreich war (Standard)"
-#: builtin/merge.c:211
+#: builtin/merge.c:204
msgid "edit message before committing"
msgstr "Bearbeitung der Beschreibung vor dem Commit"
-#: builtin/merge.c:212
+#: builtin/merge.c:205
msgid "allow fast-forward (default)"
msgstr "erlaubt Vorspulen (Standard)"
-#: builtin/merge.c:214
+#: builtin/merge.c:207
msgid "abort if fast-forward is not possible"
msgstr "bricht ab, wenn kein Vorspulen möglich ist"
-#: builtin/merge.c:218
+#: builtin/merge.c:211
msgid "Verify that the named commit has a valid GPG signature"
msgstr "überprüft den genannten Commit auf eine gültige GPG-Signatur"
-#: builtin/merge.c:219 builtin/notes.c:738 builtin/revert.c:89
+#: builtin/merge.c:212 builtin/notes.c:738 builtin/revert.c:89
msgid "strategy"
msgstr "Strategie"
-#: builtin/merge.c:220
+#: builtin/merge.c:213
msgid "merge strategy to use"
msgstr "zu verwendende Merge-Strategie"
-#: builtin/merge.c:221
+#: builtin/merge.c:214
msgid "option=value"
msgstr "Option=Wert"
-#: builtin/merge.c:222
+#: builtin/merge.c:215
msgid "option for selected merge strategy"
msgstr "Option für ausgewählte Merge-Strategie"
-#: builtin/merge.c:224
+#: builtin/merge.c:217
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
"führt Commit-Beschreibung zusammen (für einen Merge, der kein Vorspulen war)"
-#: builtin/merge.c:228
+#: builtin/merge.c:221
msgid "abort the current in-progress merge"
msgstr "bricht den sich im Gange befindlichen Merge ab"
-#: builtin/merge.c:257
+#: builtin/merge.c:250
msgid "could not run stash."
msgstr "Konnte \"stash\" nicht ausführen."
-#: builtin/merge.c:262
+#: builtin/merge.c:255
msgid "stash failed"
msgstr "\"stash\" fehlgeschlagen"
-#: builtin/merge.c:267
+#: builtin/merge.c:260
#, c-format
msgid "not a valid object: %s"
msgstr "kein gültiges Objekt: %s"
-#: builtin/merge.c:286 builtin/merge.c:303
+#: builtin/merge.c:279 builtin/merge.c:296
msgid "read-tree failed"
msgstr "read-tree fehlgeschlagen"
-#: builtin/merge.c:333
+#: builtin/merge.c:326
msgid " (nothing to squash)"
msgstr " (nichts zu quetschen)"
-#: builtin/merge.c:346
+#: builtin/merge.c:339
#, c-format
msgid "Squash commit -- not updating HEAD\n"
msgstr "Quetsche Commit -- HEAD wird nicht aktualisiert\n"
-#: builtin/merge.c:378
+#: builtin/merge.c:371
msgid "Writing SQUASH_MSG"
msgstr "Schreibe SQUASH_MSG"
-#: builtin/merge.c:380
+#: builtin/merge.c:373
msgid "Finishing SQUASH_MSG"
msgstr "Schließe SQUASH_MSG ab"
-#: builtin/merge.c:403
+#: builtin/merge.c:396
#, c-format
msgid "No merge message -- not updating HEAD\n"
msgstr "Keine Merge-Commit-Beschreibung -- HEAD wird nicht aktualisiert\n"
-#: builtin/merge.c:453
+#: builtin/merge.c:446
#, c-format
msgid "'%s' does not point to a commit"
msgstr "'%s' zeigt auf keinen Commit"
-#: builtin/merge.c:565
+#: builtin/merge.c:558
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Ungültiger branch.%s.mergeoptions String: %s"
-#: builtin/merge.c:657
+#: builtin/merge.c:650
msgid "git write-tree failed to write a tree"
msgstr "\"git write-tree\" schlug beim Schreiben eines \"Tree\"-Objektes fehl"
-#: builtin/merge.c:685
+#: builtin/merge.c:678
msgid "Not handling anything other than two heads merge."
msgstr "Es wird nur der Merge von zwei Branches behandelt."
-#: builtin/merge.c:699
+#: builtin/merge.c:692
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "Unbekannte Option für merge-recursive: -X%s"
-#: builtin/merge.c:713
+#: builtin/merge.c:706
#, c-format
msgid "unable to write %s"
msgstr "konnte %s nicht schreiben"
-#: builtin/merge.c:802
+#: builtin/merge.c:795
#, c-format
msgid "Could not read from '%s'"
msgstr "konnte nicht von '%s' lesen"
-#: builtin/merge.c:811
+#: builtin/merge.c:804
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
"Merge wurde nicht committet; benutzen Sie 'git commit' um den Merge "
"abzuschließen.\n"
-#: builtin/merge.c:817
+#: builtin/merge.c:810
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -6930,50 +6996,50 @@ msgstr ""
"Zeilen beginnend mit '%c' werden ignoriert, und eine leere Beschreibung\n"
"bricht den Commit ab.\n"
-#: builtin/merge.c:841
+#: builtin/merge.c:834
msgid "Empty commit message."
msgstr "Leere Commit-Beschreibung"
-#: builtin/merge.c:853
+#: builtin/merge.c:846
#, c-format
msgid "Wonderful.\n"
msgstr "Wunderbar.\n"
-#: builtin/merge.c:918
+#: builtin/merge.c:911
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
"Automatischer Merge fehlgeschlagen; beheben Sie die Konflikte und committen "
"Sie dann das Ergebnis.\n"
-#: builtin/merge.c:934
+#: builtin/merge.c:927
#, c-format
msgid "'%s' is not a commit"
msgstr "'%s' ist kein Commit"
-#: builtin/merge.c:975
+#: builtin/merge.c:968
msgid "No current branch."
msgstr "Sie befinden sich auf keinem Branch."
-#: builtin/merge.c:977
+#: builtin/merge.c:970
msgid "No remote for the current branch."
msgstr "Kein Remote-Repository für den aktuellen Branch."
-#: builtin/merge.c:979
+#: builtin/merge.c:972
msgid "No default upstream defined for the current branch."
msgstr ""
"Es ist kein Standard-Upstream-Branch für den aktuellen Branch definiert."
-#: builtin/merge.c:984
+#: builtin/merge.c:977
#, c-format
msgid "No remote-tracking branch for %s from %s"
msgstr "Kein Remote-Tracking-Branch für %s von %s"
-#: builtin/merge.c:1140
+#: builtin/merge.c:1133
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "Es gibt keinen Merge zum Abbrechen (vermisse MERGE_HEAD)"
-#: builtin/merge.c:1156 git-pull.sh:31
+#: builtin/merge.c:1149 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6981,11 +7047,11 @@ msgstr ""
"Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert).\n"
"Bitte committen Sie Ihre Änderungen, bevor Sie \"merge\" ausführen können."
-#: builtin/merge.c:1159 git-pull.sh:34
+#: builtin/merge.c:1152 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert)."
-#: builtin/merge.c:1163
+#: builtin/merge.c:1156
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6993,143 +7059,151 @@ msgstr ""
"Sie haben \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert).\n"
"Bitte committen Sie Ihre Änderungen, bevor Sie \"merge\" ausführen können."
-#: builtin/merge.c:1166
+#: builtin/merge.c:1159
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr ""
"Sie haben \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert)."
-#: builtin/merge.c:1175
+#: builtin/merge.c:1168
msgid "You cannot combine --squash with --no-ff."
msgstr "Sie können --squash nicht mit --no-ff kombinieren."
-#: builtin/merge.c:1184
+#: builtin/merge.c:1177
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr "Kein Commit angegeben und merge.defaultToUpstream ist nicht gesetzt."
-#: builtin/merge.c:1216
+#: builtin/merge.c:1209
msgid "Can merge only exactly one commit into empty head"
msgstr "Kann nur exakt einen Commit in einem leeren Branch zusammenführen."
-#: builtin/merge.c:1219
+#: builtin/merge.c:1212
msgid "Squash commit into empty head not supported yet"
msgstr ""
"Bin auf einem Commit, der noch geboren wird; kann \"squash\" nicht ausführen."
-#: builtin/merge.c:1221
+#: builtin/merge.c:1214
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr ""
"Nicht vorzuspulender Commit kann nicht in einem leeren Branch verwendet "
"werden."
-#: builtin/merge.c:1226
+#: builtin/merge.c:1219
#, c-format
msgid "%s - not something we can merge"
msgstr "%s - nichts was wir zusammenführen können"
-#: builtin/merge.c:1277
+#: builtin/merge.c:1270
#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr ""
"Commit %s hat eine nicht vertrauenswürdige GPG-Signatur, angeblich von %s."
-#: builtin/merge.c:1280
+#: builtin/merge.c:1273
#, c-format
msgid "Commit %s has a bad GPG signature allegedly by %s."
msgstr "Commit %s hat eine ungültige GPG-Signatur, angeblich von %s."
#. 'N'
-#: builtin/merge.c:1283
+#: builtin/merge.c:1276
#, c-format
msgid "Commit %s does not have a GPG signature."
msgstr "Commit %s hat keine GPG-Signatur."
-#: builtin/merge.c:1286
+#: builtin/merge.c:1279
#, c-format
msgid "Commit %s has a good GPG signature by %s\n"
msgstr "Commit %s hat eine gültige GPG-Signatur von %s\n"
-#: builtin/merge.c:1370
+#: builtin/merge.c:1363
#, c-format
msgid "Updating %s..%s\n"
msgstr "Aktualisiere %s..%s\n"
-#: builtin/merge.c:1409
+#: builtin/merge.c:1402
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "Probiere wirklich trivialen \"in-index\"-Merge...\n"
-#: builtin/merge.c:1416
+#: builtin/merge.c:1409
#, c-format
msgid "Nope.\n"
msgstr "Nein.\n"
-#: builtin/merge.c:1448
+#: builtin/merge.c:1441
msgid "Not possible to fast-forward, aborting."
msgstr "Vorspulen nicht möglich, breche ab."
-#: builtin/merge.c:1471 builtin/merge.c:1550
+#: builtin/merge.c:1464 builtin/merge.c:1543
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "Rücklauf des Verzeichnisses bis zum Ursprung...\n"
-#: builtin/merge.c:1475
+#: builtin/merge.c:1468
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "Probiere Merge-Strategie %s...\n"
-#: builtin/merge.c:1541
+#: builtin/merge.c:1534
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "Keine Merge-Strategie behandelt diesen Merge.\n"
-#: builtin/merge.c:1543
+#: builtin/merge.c:1536
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "Merge mit Strategie %s fehlgeschlagen.\n"
-#: builtin/merge.c:1552
+#: builtin/merge.c:1545
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr "Benutzen Sie \"%s\" um die Auflösung per Hand vorzubereiten.\n"
-#: builtin/merge.c:1564
+#: builtin/merge.c:1557
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
"Automatischer Merge abgeschlossen; halte, wie gewünscht, vor dem Commit an\n"
-#: builtin/merge-base.c:26
+#: builtin/merge-base.c:29
msgid "git merge-base [-a|--all] <commit> <commit>..."
msgstr "git merge-base [-a|--all] <Commit> <Commit>..."
-#: builtin/merge-base.c:27
+#: builtin/merge-base.c:30
msgid "git merge-base [-a|--all] --octopus <commit>..."
msgstr "git merge-base [-a|--all] --octopus <Commit>..."
-#: builtin/merge-base.c:28
+#: builtin/merge-base.c:31
msgid "git merge-base --independent <commit>..."
msgstr "git merge-base --independent <Commit>..."
-#: builtin/merge-base.c:29
+#: builtin/merge-base.c:32
msgid "git merge-base --is-ancestor <commit> <commit>"
msgstr "git merge-base --is-ancestor <Commit> <Commit>"
-#: builtin/merge-base.c:98
+#: builtin/merge-base.c:33
+msgid "git merge-base --fork-point <ref> [<commit>]"
+msgstr "git merge-base --fork-point <Referenz> [<Commit>]"
+
+#: builtin/merge-base.c:214
msgid "output all common ancestors"
msgstr "Ausgabe aller gemeinsamen Vorgänger-Commits"
-#: builtin/merge-base.c:99
+#: builtin/merge-base.c:216
msgid "find ancestors for a single n-way merge"
msgstr "findet Vorgänger-Commits für einen einzelnen n-Wege-Merge"
-#: builtin/merge-base.c:100
+#: builtin/merge-base.c:218
msgid "list revs not reachable from others"
msgstr "listet Commits auf, die nicht durch Andere erreichbar sind"
-#: builtin/merge-base.c:102
+#: builtin/merge-base.c:220
msgid "is the first one ancestor of the other?"
msgstr "ist der Erste ein Vorgänger-Commit von dem Anderen?"
+#: builtin/merge-base.c:222
+msgid "find where <commit> forked from reflog of <ref>"
+msgstr "findet wo <Commit> von Reflog von <Referenz> abgespalten wurde"
+
#: builtin/merge-file.c:8
msgid ""
"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
@@ -7190,124 +7264,129 @@ msgstr "erlaubt die Erstellung von mehr als einem \"Tree\"-Objekt"
msgid "git mv [options] <source>... <destination>"
msgstr "git mv [Optionen] <Quelle>... <Ziel>"
-#: builtin/mv.c:67
+#: builtin/mv.c:71
msgid "force move/rename even if target exists"
msgstr "erzwingt Verschieben/Umbenennen, auch wenn das Ziel existiert"
-#: builtin/mv.c:68
+#: builtin/mv.c:72
msgid "skip move/rename errors"
msgstr "überspringt Fehler beim Verschieben oder Umbenennen"
-#: builtin/mv.c:113
+#: builtin/mv.c:122
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
msgstr "Prüfe Umbenennung von '%s' nach '%s'\n"
-#: builtin/mv.c:117
+#: builtin/mv.c:126
msgid "bad source"
msgstr "ungültige Quelle"
-#: builtin/mv.c:120
+#: builtin/mv.c:129
msgid "can not move directory into itself"
msgstr "kann Verzeichnis nicht in sich selbst verschieben"
-#: builtin/mv.c:123
+#: builtin/mv.c:132
msgid "cannot move directory over file"
msgstr "kann Verzeichnis nicht über Datei verschieben"
-#: builtin/mv.c:129
+#: builtin/mv.c:138
#, c-format
msgid "Huh? Directory %s is in index and no submodule?"
msgstr "Huh? Verzeichnis %s ist zum Commit vorgemerkt und kein Submodul?"
-#: builtin/mv.c:131 builtin/rm.c:318
+#: builtin/mv.c:140 builtin/rm.c:318
msgid "Please, stage your changes to .gitmodules or stash them to proceed"
msgstr ""
-"Bitte merken Sie Ihre Änderungen in .gitmodules zum Commit vor oder benutzen\n"
+"Bitte merken Sie Ihre Änderungen in .gitmodules zum Commit vor oder "
+"benutzen\n"
"Sie \"stash\" um fortzufahren."
-#: builtin/mv.c:147
+#: builtin/mv.c:156
#, c-format
msgid "Huh? %.*s is in index?"
msgstr "Huh? %.*s ist zum Commit vorgemerkt?"
-#: builtin/mv.c:159
+#: builtin/mv.c:168
msgid "source directory is empty"
msgstr "Quellverzeichnis ist leer"
-#: builtin/mv.c:191
+#: builtin/mv.c:200
msgid "not under version control"
msgstr "nicht unter Versionskontrolle"
-#: builtin/mv.c:193
+#: builtin/mv.c:202
msgid "destination exists"
msgstr "Ziel existiert bereits"
-#: builtin/mv.c:201
+#: builtin/mv.c:210
#, c-format
msgid "overwriting '%s'"
msgstr "überschreibe '%s'"
-#: builtin/mv.c:204
+#: builtin/mv.c:213
msgid "Cannot overwrite"
msgstr "Kann nicht überschreiben"
-#: builtin/mv.c:207
+#: builtin/mv.c:216
msgid "multiple sources for the same target"
msgstr "mehrere Quellen für das selbe Ziel"
-#: builtin/mv.c:222
+#: builtin/mv.c:218
+msgid "destination directory does not exist"
+msgstr "Zielverzeichnis existiert nicht"
+
+#: builtin/mv.c:233
#, c-format
msgid "%s, source=%s, destination=%s"
msgstr "%s, Quelle=%s, Ziel=%s"
-#: builtin/mv.c:232
+#: builtin/mv.c:243
#, c-format
msgid "Renaming %s to %s\n"
msgstr "Benenne %s nach %s um\n"
-#: builtin/mv.c:235 builtin/remote.c:731 builtin/repack.c:330
+#: builtin/mv.c:246 builtin/remote.c:726 builtin/repack.c:328
#, c-format
msgid "renaming '%s' failed"
msgstr "Umbenennung von '%s' fehlgeschlagen"
-#: builtin/name-rev.c:259
+#: builtin/name-rev.c:258
msgid "git name-rev [options] <commit>..."
msgstr "git name-rev [Optionen] <Commit>..."
-#: builtin/name-rev.c:260
+#: builtin/name-rev.c:259
msgid "git name-rev [options] --all"
msgstr "git name-rev [Optionen] --all"
-#: builtin/name-rev.c:261
+#: builtin/name-rev.c:260
msgid "git name-rev [options] --stdin"
msgstr "git name-rev [Optionen] --stdin"
-#: builtin/name-rev.c:313
+#: builtin/name-rev.c:312
msgid "print only names (no SHA-1)"
msgstr "zeigt nur Namen an (keine SHA-1)"
-#: builtin/name-rev.c:314
+#: builtin/name-rev.c:313
msgid "only use tags to name the commits"
msgstr "verwendet nur Tags um die Commits zu benennen"
-#: builtin/name-rev.c:316
+#: builtin/name-rev.c:315
msgid "only use refs matching <pattern>"
msgstr "verwendet nur Referenzen die <Muster> entsprechen"
-#: builtin/name-rev.c:318
+#: builtin/name-rev.c:317
msgid "list all commits reachable from all refs"
msgstr "listet alle Commits auf, die von allen Referenzen erreichbar sind"
-#: builtin/name-rev.c:319
+#: builtin/name-rev.c:318
msgid "read from stdin"
msgstr "liest von der Standard-Eingabe"
-#: builtin/name-rev.c:320
+#: builtin/name-rev.c:319
msgid "allow to print `undefined` names (default)"
msgstr "erlaubt Ausgabe von `undefinierten` Namen (Standard)"
-#: builtin/name-rev.c:326
+#: builtin/name-rev.c:325
msgid "dereference tags in the input (internal use)"
msgstr "dereferenziert Tags in der Eingabe (interne Verwendung)"
@@ -7636,7 +7715,7 @@ msgstr "Notiz-Referenz"
msgid "use notes from <notes_ref>"
msgstr "verwendet Notizen von <Notiz-Referenz>"
-#: builtin/notes.c:974 builtin/remote.c:1598
+#: builtin/notes.c:974 builtin/remote.c:1593
#, c-format
msgid "Unknown subcommand: %s"
msgstr "Unbekanntes Unterkommando: %s"
@@ -7656,150 +7735,150 @@ msgstr ""
msgid "deflate error (%d)"
msgstr "Fehler beim Komprimieren (%d)"
-#: builtin/pack-objects.c:2398
+#: builtin/pack-objects.c:2396
#, c-format
msgid "unsupported index version %s"
msgstr "Nicht unterstützte Staging-Area-Version %s"
-#: builtin/pack-objects.c:2402
+#: builtin/pack-objects.c:2400
#, c-format
msgid "bad index version '%s'"
msgstr "Ungültige Staging-Area-Version '%s'"
-#: builtin/pack-objects.c:2425
+#: builtin/pack-objects.c:2423
#, c-format
msgid "option %s does not accept negative form"
msgstr "Option %s akzeptiert keine negative Form"
-#: builtin/pack-objects.c:2429
+#: builtin/pack-objects.c:2427
#, c-format
msgid "unable to parse value '%s' for option %s"
msgstr "konnte Wert '%s' für Option %s nicht parsen"
-#: builtin/pack-objects.c:2448
+#: builtin/pack-objects.c:2446
msgid "do not show progress meter"
msgstr "zeigt keine Fortschrittsanzeige"
-#: builtin/pack-objects.c:2450
+#: builtin/pack-objects.c:2448
msgid "show progress meter"
msgstr "zeigt Fortschrittsanzeige"
-#: builtin/pack-objects.c:2452
+#: builtin/pack-objects.c:2450
msgid "show progress meter during object writing phase"
msgstr "zeigt Forschrittsanzeige während der Phase des Schreibens der Objekte"
-#: builtin/pack-objects.c:2455
+#: builtin/pack-objects.c:2453
msgid "similar to --all-progress when progress meter is shown"
msgstr "ähnlich zu --all-progress wenn Fortschrittsanzeige darstellt wird"
-#: builtin/pack-objects.c:2456
+#: builtin/pack-objects.c:2454
msgid "version[,offset]"
msgstr "version[,offset]"
-#: builtin/pack-objects.c:2457
+#: builtin/pack-objects.c:2455
msgid "write the pack index file in the specified idx format version"
msgstr ""
"schreibt die Index-Datei des Paketes in der angegebenen Indexformat-Version"
-#: builtin/pack-objects.c:2460
+#: builtin/pack-objects.c:2458
msgid "maximum size of each output pack file"
msgstr "maximale Größe für jede ausgegebene Paketdatei"
-#: builtin/pack-objects.c:2462
+#: builtin/pack-objects.c:2460
msgid "ignore borrowed objects from alternate object store"
msgstr "ignoriert geliehene Objekte von alternativem Objektspeicher"
-#: builtin/pack-objects.c:2464
+#: builtin/pack-objects.c:2462
msgid "ignore packed objects"
msgstr "ignoriert gepackte Objekte"
-#: builtin/pack-objects.c:2466
+#: builtin/pack-objects.c:2464
msgid "limit pack window by objects"
msgstr "begrenzt Paketfenster durch Objekte"
-#: builtin/pack-objects.c:2468
+#: builtin/pack-objects.c:2466
msgid "limit pack window by memory in addition to object limit"
msgstr "begrenzt Paketfenster, zusätzlich zur Objektbegrenzung, durch Speicher"
-#: builtin/pack-objects.c:2470
+#: builtin/pack-objects.c:2468
msgid "maximum length of delta chain allowed in the resulting pack"
msgstr ""
"maximale Länge der erlaubten Differenzverkettung im resultierenden Paket"
-#: builtin/pack-objects.c:2472
+#: builtin/pack-objects.c:2470
msgid "reuse existing deltas"
msgstr "verwendet existierende Unterschiede wieder"
-#: builtin/pack-objects.c:2474
+#: builtin/pack-objects.c:2472
msgid "reuse existing objects"
msgstr "verwendet existierende Objekte wieder"
-#: builtin/pack-objects.c:2476
+#: builtin/pack-objects.c:2474
msgid "use OFS_DELTA objects"
msgstr "verwendet OFS_DELTA Objekte"
-#: builtin/pack-objects.c:2478
+#: builtin/pack-objects.c:2476
msgid "use threads when searching for best delta matches"
msgstr ""
"verwendet Threads bei der Suche nach den besten Ãœbereinstimmungen bei "
"Unterschieden"
-#: builtin/pack-objects.c:2480
+#: builtin/pack-objects.c:2478
msgid "do not create an empty pack output"
msgstr "erzeugt keine leeren Pakete"
-#: builtin/pack-objects.c:2482
+#: builtin/pack-objects.c:2480
msgid "read revision arguments from standard input"
msgstr "liest Argumente bezüglich Commits von der Standard-Eingabe"
-#: builtin/pack-objects.c:2484
+#: builtin/pack-objects.c:2482
msgid "limit the objects to those that are not yet packed"
msgstr "begrenzt die Objekte zu solchen, die noch nicht gepackt wurden"
-#: builtin/pack-objects.c:2487
+#: builtin/pack-objects.c:2485
msgid "include objects reachable from any reference"
msgstr "schließt Objekte ein, die von jeder Referenz erreichbar sind"
-#: builtin/pack-objects.c:2490
+#: builtin/pack-objects.c:2488
msgid "include objects referred by reflog entries"
msgstr ""
"schließt Objekte ein, die von Einträgen des Reflogs referenziert werden"
-#: builtin/pack-objects.c:2493
+#: builtin/pack-objects.c:2491
msgid "output pack to stdout"
msgstr "schreibt Paket in die Standard-Ausgabe"
-#: builtin/pack-objects.c:2495
+#: builtin/pack-objects.c:2493
msgid "include tag objects that refer to objects to be packed"
msgstr "schließt Tag-Objekte ein, die auf gepackte Objekte referenzieren"
-#: builtin/pack-objects.c:2497
+#: builtin/pack-objects.c:2495
msgid "keep unreachable objects"
msgstr "behält nicht erreichbare Objekte"
-#: builtin/pack-objects.c:2498 parse-options.h:143
+#: builtin/pack-objects.c:2496 parse-options.h:143
msgid "time"
msgstr "Zeit"
-#: builtin/pack-objects.c:2499
+#: builtin/pack-objects.c:2497
msgid "unpack unreachable objects newer than <time>"
msgstr "entpackt nicht erreichbare Objekte, die neuer als <Zeit> sind"
-#: builtin/pack-objects.c:2502
+#: builtin/pack-objects.c:2500
msgid "create thin packs"
msgstr "erzeugt dünnere Pakete"
-#: builtin/pack-objects.c:2504
+#: builtin/pack-objects.c:2502
msgid "ignore packs that have companion .keep file"
msgstr "ignoriert Pakete die .keep Dateien haben"
-#: builtin/pack-objects.c:2506
+#: builtin/pack-objects.c:2504
msgid "pack compression level"
msgstr "Komprimierungsgrad für Paketierung"
-#: builtin/pack-objects.c:2508
+#: builtin/pack-objects.c:2506
msgid "do not hide commits by grafts"
-msgstr "verbirgt keine Commits mit künstlichen Vorgängern (\"grafts\")"
+msgstr "verbirgt keine künstlichen Vorgänger-Commits (\"grafts\")"
#: builtin/pack-refs.c:6
msgid "git pack-refs [options]"
@@ -7821,15 +7900,15 @@ msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]"
msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
msgstr "git prune [-n] [-v] [--expire <Zeit>] [--] [<head>...]"
-#: builtin/prune.c:132
+#: builtin/prune.c:142
msgid "do not remove, show only"
msgstr "nicht löschen, nur anzeigen"
-#: builtin/prune.c:133
+#: builtin/prune.c:143
msgid "report pruned objects"
msgstr "meldet gelöschte Objekte"
-#: builtin/prune.c:136
+#: builtin/prune.c:146
msgid "expire objects older than <time>"
msgstr "lässt Objekte älter als <Zeit> verfallen"
@@ -7837,15 +7916,15 @@ msgstr "lässt Objekte älter als <Zeit> verfallen"
msgid "git push [<options>] [<repository> [<refspec>...]]"
msgstr "git push [<Optionen>] [<Repository> [<Refspec>...]]"
-#: builtin/push.c:47
+#: builtin/push.c:86
msgid "tag shorthand without <tag>"
msgstr "Kurzschrift für Tag ohne <Tag>"
-#: builtin/push.c:66
+#: builtin/push.c:96
msgid "--delete only accepts plain target ref names"
msgstr "Die Option --delete akzeptiert nur reine Referenznamen als Ziel."
-#: builtin/push.c:101
+#: builtin/push.c:141
msgid ""
"\n"
"To choose either option permanently, see push.default in 'git help config'."
@@ -7854,7 +7933,7 @@ msgstr ""
"Um eine Variante permanent zu verwenden, siehe push.default in 'git help "
"config'."
-#: builtin/push.c:104
+#: builtin/push.c:144
#, c-format
msgid ""
"The upstream branch of your current branch does not match\n"
@@ -7880,7 +7959,7 @@ msgstr ""
" git push %s %s\n"
"%s"
-#: builtin/push.c:119
+#: builtin/push.c:159
#, c-format
msgid ""
"You are not currently on a branch.\n"
@@ -7895,7 +7974,7 @@ msgstr ""
"\n"
" git push %s HEAD:<Name-des-Remote-Branches>\n"
-#: builtin/push.c:133
+#: builtin/push.c:173
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
@@ -7909,13 +7988,13 @@ msgstr ""
"\n"
" git push --set-upstream %s %s\n"
-#: builtin/push.c:141
+#: builtin/push.c:181
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
msgstr ""
"Der aktuelle Branch %s hat mehrere Upstream-Branches, \"push\" verweigert."
-#: builtin/push.c:144
+#: builtin/push.c:184
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
@@ -7926,7 +8005,7 @@ msgstr ""
"Branches '%s' ist, ohne anzugeben, was versendet werden soll, um welchen\n"
"Remote-Branch zu aktualisieren."
-#: builtin/push.c:167
+#: builtin/push.c:207
msgid ""
"push.default is unset; its implicit value is changing in\n"
"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
@@ -7938,6 +8017,13 @@ msgid ""
"\n"
" git config --global push.default simple\n"
"\n"
+"When push.default is set to 'matching', git will push local branches\n"
+"to the remote branches that already exist with the same name.\n"
+"\n"
+"In Git 2.0, Git will default to the more conservative 'simple'\n"
+"behavior, which only pushes the current branch to the corresponding\n"
+"remote branch that 'git pull' uses to update the current branch.\n"
+"\n"
"See 'git help config' and search for 'push.default' for further "
"information.\n"
"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
@@ -7955,20 +8041,27 @@ msgstr ""
"\n"
" git config --global push.default simple\n"
"\n"
-"Führen Sie 'git help config' aus und suchen Sie nach 'push.default' für "
+"Wenn 'push.default' auf den Wert 'matching' gesetzt ist, werden lokale\n"
+"Branches zu den Remote-Branches mit den selben Namen versendet.\n"
+"\n"
+"In Git 2.0 wird das Standardverhalten zu 'simple' geändert. Hierbei wird\n"
+"der aktuelle Branch zu dem entsprechenden Remote-Branch versendet, den\n"
+"'git pull' zur Aktualisierung des aktuellen Branches verwendet.\n"
+"\n"
+"Führen Sie 'git help config' aus und suchen Sie nach 'push.default' für\n"
"weitere Informationen.\n"
-"(Der Modus 'simple' wurde in Git 1.7.11 eingeführt. Benutze den ähnlichen "
-"Modus 'current' anstatt 'simple', falls Sie gelegentlich ältere Versionen "
-"von Git benutzen.)"
+"(Der Modus 'simple' wurde in Git 1.7.11 eingeführt. Benutzen Sie den ähnlichen\n"
+"Modus 'current' anstatt 'simple', falls Sie gelegentlich ältere Versionen von\n"
+"Git benutzen.)"
-#: builtin/push.c:227
+#: builtin/push.c:274
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
"Sie haben keine Refspec für \"push\" angegeben, und push.default ist "
"\"nothing\"."
-#: builtin/push.c:234
+#: builtin/push.c:281
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
"its remote counterpart. Integrate the remote changes (e.g.\n"
@@ -7982,7 +8075,7 @@ msgstr ""
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:240
+#: builtin/push.c:287
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
@@ -7998,7 +8091,7 @@ msgstr ""
"'simple', 'current'\n"
"oder 'upstream' setzen, um nur den aktuellen Branch zu versenden."
-#: builtin/push.c:246
+#: builtin/push.c:293
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. Check out this branch and integrate the remote changes\n"
@@ -8012,7 +8105,7 @@ msgstr ""
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:252
+#: builtin/push.c:299
msgid ""
"Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
@@ -8031,13 +8124,13 @@ msgstr ""
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:259
+#: builtin/push.c:306
msgid "Updates were rejected because the tag already exists in the remote."
msgstr ""
"Aktualisierungen wurden zurückgewiesen, weil das Tag bereits\n"
"im Remote-Repository existiert."
-#: builtin/push.c:262
+#: builtin/push.c:309
msgid ""
"You cannot update a remote ref that points at a non-commit object,\n"
"or update a remote ref to make it point at a non-commit object,\n"
@@ -8047,22 +8140,22 @@ msgstr ""
"das kein Commit ist, oder es auf ein solches Objekt zeigen lassen, ohne\n"
"die Option '--force' zu verwenden.\n"
-#: builtin/push.c:328
+#: builtin/push.c:375
#, c-format
msgid "Pushing to %s\n"
msgstr "Versende nach %s\n"
-#: builtin/push.c:332
+#: builtin/push.c:379
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "Fehler beim Versenden einiger Referenzen nach '%s'"
-#: builtin/push.c:365
+#: builtin/push.c:412
#, c-format
msgid "bad repository '%s'"
msgstr "ungültiges Repository '%s'"
-#: builtin/push.c:366
+#: builtin/push.c:413
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -8084,95 +8177,95 @@ msgstr ""
"\n"
" git push <Name>\n"
-#: builtin/push.c:381
+#: builtin/push.c:428
msgid "--all and --tags are incompatible"
msgstr "Die Optionen --all und --tags sind inkompatibel."
-#: builtin/push.c:382
+#: builtin/push.c:429
msgid "--all can't be combined with refspecs"
msgstr "Die Option --all kann nicht mit Refspecs kombiniert werden."
-#: builtin/push.c:387
+#: builtin/push.c:434
msgid "--mirror and --tags are incompatible"
msgstr "Die Optionen --mirror und --tags sind inkompatibel."
-#: builtin/push.c:388
+#: builtin/push.c:435
msgid "--mirror can't be combined with refspecs"
msgstr "Die Option --mirror kann nicht mit Refspecs kombiniert werden."
-#: builtin/push.c:393
+#: builtin/push.c:440
msgid "--all and --mirror are incompatible"
msgstr "Die Optionen --all und --mirror sind inkompatibel."
-#: builtin/push.c:453
+#: builtin/push.c:500
msgid "repository"
msgstr "Repository"
-#: builtin/push.c:454
+#: builtin/push.c:501
msgid "push all refs"
msgstr "versendet alle Referenzen"
-#: builtin/push.c:455
+#: builtin/push.c:502
msgid "mirror all refs"
msgstr "spiegelt alle Referenzen"
-#: builtin/push.c:457
+#: builtin/push.c:504
msgid "delete refs"
msgstr "löscht Referenzen"
-#: builtin/push.c:458
+#: builtin/push.c:505
msgid "push tags (can't be used with --all or --mirror)"
msgstr "versendet Tags (kann nicht mit --all oder --mirror verwendet werden)"
-#: builtin/push.c:461
+#: builtin/push.c:508
msgid "force updates"
msgstr "erzwingt Aktualisierung"
-#: builtin/push.c:463
+#: builtin/push.c:510
msgid "refname>:<expect"
msgstr "Referenzname>:<Erwartungswert"
-#: builtin/push.c:464
+#: builtin/push.c:511
msgid "require old value of ref to be at this value"
msgstr "Referenz muss sich auf dem angegebenen Wert befinden"
-#: builtin/push.c:466
+#: builtin/push.c:513
msgid "check"
msgstr ""
-#: builtin/push.c:467
+#: builtin/push.c:514
msgid "control recursive pushing of submodules"
msgstr "steuert rekursiven \"push\" von Submodulen"
-#: builtin/push.c:469
+#: builtin/push.c:516
msgid "use thin pack"
msgstr "verwendet kleinere Pakete"
-#: builtin/push.c:470 builtin/push.c:471
+#: builtin/push.c:517 builtin/push.c:518
msgid "receive pack program"
msgstr "'receive pack' Programm"
-#: builtin/push.c:472
+#: builtin/push.c:519
msgid "set upstream for git pull/status"
msgstr "setzt Upstream für \"git pull/status\""
-#: builtin/push.c:475
+#: builtin/push.c:522
msgid "prune locally removed refs"
msgstr "entfernt lokal gelöschte Referenzen"
-#: builtin/push.c:477
+#: builtin/push.c:524
msgid "bypass pre-push hook"
msgstr "umgeht \"pre-push hook\""
-#: builtin/push.c:478
+#: builtin/push.c:525
msgid "push missing but relevant tags"
msgstr "versendet fehlende, aber relevante Tags"
-#: builtin/push.c:488
+#: builtin/push.c:535
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "Die Option --delete ist inkompatibel mit --all, --mirror und --tags."
-#: builtin/push.c:490
+#: builtin/push.c:537
msgid "--delete doesn't make sense without any refs"
msgstr "Die Option --delete kann nur mit Referenzen verwendet werden."
@@ -8261,11 +8354,11 @@ msgstr "'%s' für '%s' ist kein gültiger Zeitstempel"
msgid "'%s' is not a valid timestamp"
msgstr "'%s' ist kein gültiger Zeitstempel"
-#: builtin/remote.c:11
+#: builtin/remote.c:12
msgid "git remote [-v | --verbose]"
msgstr "git remote [-v | --verbose]"
-#: builtin/remote.c:12
+#: builtin/remote.c:13
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -8273,82 +8366,82 @@ msgstr ""
"git remote add [-t <Branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
"mirror=<fetch|push>] <Name> <URL>"
-#: builtin/remote.c:13 builtin/remote.c:32
+#: builtin/remote.c:14 builtin/remote.c:33
msgid "git remote rename <old> <new>"
msgstr "git remote rename <alt> <neu>"
-#: builtin/remote.c:14 builtin/remote.c:37
+#: builtin/remote.c:15 builtin/remote.c:38
msgid "git remote remove <name>"
msgstr "git remote remove <Name>"
-#: builtin/remote.c:15
+#: builtin/remote.c:16
msgid "git remote set-head <name> (-a | --auto | -d | --delete |<branch>)"
msgstr "git remote set-head <Name> (-a | --auto | -d | --delete | <Branch>)"
-#: builtin/remote.c:16
+#: builtin/remote.c:17
msgid "git remote [-v | --verbose] show [-n] <name>"
msgstr "git remote [-v | --verbose] show [-n] <Name>"
-#: builtin/remote.c:17
+#: builtin/remote.c:18
msgid "git remote prune [-n | --dry-run] <name>"
msgstr "git remote prune [-n | --dry-run] <Name>"
-#: builtin/remote.c:18
+#: builtin/remote.c:19
msgid ""
"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
msgstr ""
"git remote [-v | --verbose] update [-p | --prune] [(<Gruppe> | <Remote>)...]"
-#: builtin/remote.c:19
+#: builtin/remote.c:20
msgid "git remote set-branches [--add] <name> <branch>..."
msgstr "git remote set-branches [--add] <Name> <Branch>..."
-#: builtin/remote.c:20 builtin/remote.c:68
+#: builtin/remote.c:21 builtin/remote.c:69
msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
msgstr "git remote set-url [--push] <Name> <neueURL> [<alteURL>]"
-#: builtin/remote.c:21 builtin/remote.c:69
+#: builtin/remote.c:22 builtin/remote.c:70
msgid "git remote set-url --add <name> <newurl>"
msgstr "git remote set-url --add <Name> <neueURL>"
-#: builtin/remote.c:22 builtin/remote.c:70
+#: builtin/remote.c:23 builtin/remote.c:71
msgid "git remote set-url --delete <name> <url>"
msgstr "git remote set-url --delete <Name> <URL>"
-#: builtin/remote.c:27
+#: builtin/remote.c:28
msgid "git remote add [<options>] <name> <url>"
msgstr "git remote add [<Optionen>] <Name> <URL>"
-#: builtin/remote.c:42
+#: builtin/remote.c:43
msgid "git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"
msgstr "git remote set-head <Name> (-a | --auto | -d | --delete | <Branch>)"
-#: builtin/remote.c:47
+#: builtin/remote.c:48
msgid "git remote set-branches <name> <branch>..."
msgstr "git remote set-branches <Name> <Branch>..."
-#: builtin/remote.c:48
+#: builtin/remote.c:49
msgid "git remote set-branches --add <name> <branch>..."
msgstr "git remote set-branches --add <Name> <Branch>..."
-#: builtin/remote.c:53
+#: builtin/remote.c:54
msgid "git remote show [<options>] <name>"
msgstr "git remote show [<Optionen>] <Name>"
-#: builtin/remote.c:58
+#: builtin/remote.c:59
msgid "git remote prune [<options>] <name>"
msgstr "git remote prune [<Optionen>] <Name>"
-#: builtin/remote.c:63
+#: builtin/remote.c:64
msgid "git remote update [<options>] [<group> | <remote>]..."
msgstr "git remote update [<Optionen>] [<Gruppe> | <externesRepository>]..."
-#: builtin/remote.c:98
+#: builtin/remote.c:88
#, c-format
msgid "Updating %s"
msgstr "Aktualisiere %s"
-#: builtin/remote.c:130
+#: builtin/remote.c:120
msgid ""
"--mirror is dangerous and deprecated; please\n"
"\t use --mirror=fetch or --mirror=push instead"
@@ -8356,107 +8449,107 @@ msgstr ""
"--mirror ist gefährlich und veraltet; bitte\n"
"\t benutzen Sie stattdessen --mirror=fetch oder --mirror=push"
-#: builtin/remote.c:147
+#: builtin/remote.c:137
#, c-format
msgid "unknown mirror argument: %s"
msgstr "unbekanntes Argument für Option --mirror: %s"
-#: builtin/remote.c:163
+#: builtin/remote.c:153
msgid "fetch the remote branches"
msgstr "fordert die Remote-Branches an"
-#: builtin/remote.c:165
+#: builtin/remote.c:155
msgid "import all tags and associated objects when fetching"
msgstr "importiert alle Tags und verbundene Objekte beim Anfordern"
-#: builtin/remote.c:168
+#: builtin/remote.c:158
msgid "or do not fetch any tag at all (--no-tags)"
msgstr "oder fordere gar keine Zweige an (--no-tags)"
-#: builtin/remote.c:170
+#: builtin/remote.c:160
msgid "branch(es) to track"
msgstr "Branch(es) zur Ãœbernahme"
-#: builtin/remote.c:171
+#: builtin/remote.c:161
msgid "master branch"
msgstr "Hauptbranch"
-#: builtin/remote.c:172
+#: builtin/remote.c:162
msgid "push|fetch"
msgstr "push|fetch"
-#: builtin/remote.c:173
+#: builtin/remote.c:163
msgid "set up remote as a mirror to push to or fetch from"
msgstr ""
"Aufsetzen des Remote-Repositories als Spiegel-Repository für \"push\" und "
"\"fetch\""
-#: builtin/remote.c:185
+#: builtin/remote.c:175
msgid "specifying a master branch makes no sense with --mirror"
msgstr ""
"Die Option --mirror kann nicht mit der Angabe eines Hauptbranches verwendet "
"werden."
-#: builtin/remote.c:187
+#: builtin/remote.c:177
msgid "specifying branches to track makes sense only with fetch mirrors"
msgstr ""
"Die Angabe von zu folgenden Branches kann nur mit dem Anfordern von "
"Spiegelarchiven verwendet werden."
-#: builtin/remote.c:195 builtin/remote.c:646
+#: builtin/remote.c:185 builtin/remote.c:641
#, c-format
msgid "remote %s already exists."
msgstr "externes Repository %s existiert bereits"
-#: builtin/remote.c:199 builtin/remote.c:650
+#: builtin/remote.c:189 builtin/remote.c:645
#, c-format
msgid "'%s' is not a valid remote name"
msgstr "'%s' ist kein gültiger Name für ein Remote-Repository"
-#: builtin/remote.c:243
+#: builtin/remote.c:233
#, c-format
msgid "Could not setup master '%s'"
msgstr "Konnte symbolische Referenz für Hauptbranch von '%s' nicht einrichten"
-#: builtin/remote.c:299
+#: builtin/remote.c:289
#, c-format
msgid "more than one %s"
msgstr "mehr als ein %s"
-#: builtin/remote.c:339
+#: builtin/remote.c:334
#, c-format
msgid "Could not get fetch map for refspec %s"
msgstr "Konnte Fetch-Map für Refspec %s nicht bekommen"
-#: builtin/remote.c:440 builtin/remote.c:448
+#: builtin/remote.c:435 builtin/remote.c:443
msgid "(matching)"
msgstr "(übereinstimmend)"
-#: builtin/remote.c:452
+#: builtin/remote.c:447
msgid "(delete)"
msgstr "(lösche)"
-#: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607
+#: builtin/remote.c:590 builtin/remote.c:596 builtin/remote.c:602
#, c-format
msgid "Could not append '%s' to '%s'"
msgstr "Konnte '%s' nicht an '%s' anhängen."
-#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
+#: builtin/remote.c:634 builtin/remote.c:787 builtin/remote.c:885
#, c-format
msgid "No such remote: %s"
msgstr "Kein solches Remote-Repository: %s"
-#: builtin/remote.c:656
+#: builtin/remote.c:651
#, c-format
msgid "Could not rename config section '%s' to '%s'"
msgstr "Konnte Sektion '%s' in Konfiguration nicht nach '%s' umbenennen"
-#: builtin/remote.c:662 builtin/remote.c:799
+#: builtin/remote.c:657 builtin/remote.c:794
#, c-format
msgid "Could not remove config section '%s'"
msgstr "Konnte Sektion '%s' nicht aus Konfiguration entfernen"
-#: builtin/remote.c:677
+#: builtin/remote.c:672
#, c-format
msgid ""
"Not updating non-default fetch refspec\n"
@@ -8467,32 +8560,32 @@ msgstr ""
"\t%s\n"
"\tBitte aktualisieren Sie, falls notwendig, die Konfiguration manuell."
-#: builtin/remote.c:683
+#: builtin/remote.c:678
#, c-format
msgid "Could not append '%s'"
msgstr "Konnte '%s' nicht anhängen."
-#: builtin/remote.c:694
+#: builtin/remote.c:689
#, c-format
msgid "Could not set '%s'"
msgstr "Konnte '%s' nicht setzen"
-#: builtin/remote.c:716
+#: builtin/remote.c:711
#, c-format
msgid "deleting '%s' failed"
msgstr "Konnte '%s' nicht löschen"
-#: builtin/remote.c:750
+#: builtin/remote.c:745
#, c-format
msgid "creating '%s' failed"
msgstr "Konnte '%s' nicht erstellen"
-#: builtin/remote.c:764
+#: builtin/remote.c:759
#, c-format
msgid "Could not remove branch %s"
msgstr "Konnte Branch %s nicht löschen"
-#: builtin/remote.c:834
+#: builtin/remote.c:829
msgid ""
"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
"to delete it, use:"
@@ -8508,120 +8601,120 @@ msgstr[1] ""
"entfernt;\n"
"um diese zu entfernen, benutzen Sie:"
-#: builtin/remote.c:943
+#: builtin/remote.c:938
#, c-format
msgid " new (next fetch will store in remotes/%s)"
msgstr " neu (wird bei nächstem \"fetch\" in remotes/%s gespeichert)"
-#: builtin/remote.c:946
+#: builtin/remote.c:941
msgid " tracked"
msgstr " gefolgt"
-#: builtin/remote.c:948
+#: builtin/remote.c:943
msgid " stale (use 'git remote prune' to remove)"
msgstr " veraltet (benutzen Sie 'git remote prune' zum Löschen)"
-#: builtin/remote.c:950
+#: builtin/remote.c:945
msgid " ???"
msgstr " ???"
-#: builtin/remote.c:991
+#: builtin/remote.c:986
#, c-format
msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
msgstr "ungültiges branch.%s.merge; kann Rebase nicht auf > 1 Branch ausführen"
-#: builtin/remote.c:998
+#: builtin/remote.c:993
#, c-format
msgid "rebases onto remote %s"
msgstr "Rebase auf Remote-Branch %s"
-#: builtin/remote.c:1001
+#: builtin/remote.c:996
#, c-format
msgid " merges with remote %s"
msgstr " führt mit Remote-Branch %s zusammen"
-#: builtin/remote.c:1002
+#: builtin/remote.c:997
msgid " and with remote"
msgstr " und mit Remote-Branch"
-#: builtin/remote.c:1004
+#: builtin/remote.c:999
#, c-format
msgid "merges with remote %s"
msgstr "führt mit Remote-Branch %s zusammen"
-#: builtin/remote.c:1005
+#: builtin/remote.c:1000
msgid " and with remote"
msgstr " und mit Remote-Branch"
-#: builtin/remote.c:1051
+#: builtin/remote.c:1046
msgid "create"
msgstr "erstellt"
-#: builtin/remote.c:1054
+#: builtin/remote.c:1049
msgid "delete"
msgstr "gelöscht"
-#: builtin/remote.c:1058
+#: builtin/remote.c:1053
msgid "up to date"
msgstr "aktuell"
-#: builtin/remote.c:1061
+#: builtin/remote.c:1056
msgid "fast-forwardable"
msgstr "vorspulbar"
-#: builtin/remote.c:1064
+#: builtin/remote.c:1059
msgid "local out of date"
msgstr "lokal nicht aktuell"
-#: builtin/remote.c:1071
+#: builtin/remote.c:1066
#, c-format
msgid " %-*s forces to %-*s (%s)"
msgstr " %-*s erzwingt Versandt nach %-*s (%s)"
-#: builtin/remote.c:1074
+#: builtin/remote.c:1069
#, c-format
msgid " %-*s pushes to %-*s (%s)"
msgstr " %-*s versendet nach %-*s (%s)"
-#: builtin/remote.c:1078
+#: builtin/remote.c:1073
#, c-format
msgid " %-*s forces to %s"
msgstr " %-*s erzwingt Versand nach %s"
-#: builtin/remote.c:1081
+#: builtin/remote.c:1076
#, c-format
msgid " %-*s pushes to %s"
msgstr " %-*s versendet nach %s"
-#: builtin/remote.c:1091
+#: builtin/remote.c:1144
msgid "do not query remotes"
msgstr "keine Abfrage von Remote-Repositories"
-#: builtin/remote.c:1118
+#: builtin/remote.c:1171
#, c-format
msgid "* remote %s"
msgstr "* Remote-Repository %s"
-#: builtin/remote.c:1119
+#: builtin/remote.c:1172
#, c-format
msgid " Fetch URL: %s"
msgstr " URL zum Abholen: %s"
-#: builtin/remote.c:1120 builtin/remote.c:1285
+#: builtin/remote.c:1173 builtin/remote.c:1318
msgid "(no URL)"
msgstr "(keine URL)"
-#: builtin/remote.c:1129 builtin/remote.c:1131
+#: builtin/remote.c:1182 builtin/remote.c:1184
#, c-format
msgid " Push URL: %s"
msgstr " URL zum Versenden: %s"
-#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
+#: builtin/remote.c:1186 builtin/remote.c:1188 builtin/remote.c:1190
#, c-format
msgid " HEAD branch: %s"
msgstr " Hauptbranch: %s"
-#: builtin/remote.c:1139
+#: builtin/remote.c:1192
#, c-format
msgid ""
" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
@@ -8629,146 +8722,146 @@ msgstr ""
" Hauptbranch (externer HEAD ist mehrdeutig, könnte einer der folgenden "
"sein):\n"
-#: builtin/remote.c:1151
+#: builtin/remote.c:1204
#, c-format
msgid " Remote branch:%s"
msgid_plural " Remote branches:%s"
msgstr[0] " Remote-Branch:%s"
msgstr[1] " Remote-Branches:%s"
-#: builtin/remote.c:1154 builtin/remote.c:1181
+#: builtin/remote.c:1207 builtin/remote.c:1234
msgid " (status not queried)"
msgstr " (Zustand nicht abgefragt)"
-#: builtin/remote.c:1163
+#: builtin/remote.c:1216
msgid " Local branch configured for 'git pull':"
msgid_plural " Local branches configured for 'git pull':"
msgstr[0] " Lokaler Branch konfiguriert für 'git pull':"
msgstr[1] " Lokale Branches konfiguriert für 'git pull':"
-#: builtin/remote.c:1171
+#: builtin/remote.c:1224
msgid " Local refs will be mirrored by 'git push'"
msgstr " Lokale Referenzen werden von 'git push' gespiegelt"
-#: builtin/remote.c:1178
+#: builtin/remote.c:1231
#, c-format
msgid " Local ref configured for 'git push'%s:"
msgid_plural " Local refs configured for 'git push'%s:"
msgstr[0] " Lokale Referenz konfiguriert für 'git push'%s:"
msgstr[1] " Lokale Referenzen konfiguriert für 'git push'%s:"
-#: builtin/remote.c:1199
+#: builtin/remote.c:1252
msgid "set refs/remotes/<name>/HEAD according to remote"
msgstr "setzt refs/remotes/<Name>/HEAD gemäß dem Remote-Repository"
-#: builtin/remote.c:1201
+#: builtin/remote.c:1254
msgid "delete refs/remotes/<name>/HEAD"
msgstr "entfernt refs/remotes/<Name>/HEAD"
-#: builtin/remote.c:1216
+#: builtin/remote.c:1269
msgid "Cannot determine remote HEAD"
msgstr "Kann HEAD des Remote-Repositories nicht bestimmen"
-#: builtin/remote.c:1218
+#: builtin/remote.c:1271
msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
msgstr ""
"Mehrere Hauptbranches im Remote-Repository. Bitte wählen Sie explizit einen "
"aus mit:"
-#: builtin/remote.c:1228
+#: builtin/remote.c:1281
#, c-format
msgid "Could not delete %s"
msgstr "Konnte %s nicht entfernen"
-#: builtin/remote.c:1236
+#: builtin/remote.c:1289
#, c-format
msgid "Not a valid ref: %s"
msgstr "keine gültige Referenz: %s"
-#: builtin/remote.c:1238
+#: builtin/remote.c:1291
#, c-format
msgid "Could not setup %s"
msgstr "Konnte %s nicht einrichten"
-#: builtin/remote.c:1274
+#: builtin/remote.c:1307
#, c-format
msgid " %s will become dangling!"
msgstr " %s wird unreferenziert!"
-#: builtin/remote.c:1275
+#: builtin/remote.c:1308
#, c-format
msgid " %s has become dangling!"
msgstr " %s wurde unreferenziert!"
-#: builtin/remote.c:1281
+#: builtin/remote.c:1314
#, c-format
msgid "Pruning %s"
msgstr "entferne veraltete Branches von %s"
-#: builtin/remote.c:1282
+#: builtin/remote.c:1315
#, c-format
msgid "URL: %s"
msgstr "URL: %s"
-#: builtin/remote.c:1295
+#: builtin/remote.c:1328
#, c-format
msgid " * [would prune] %s"
msgstr " * [würde veralteten Branch entfernen] %s"
-#: builtin/remote.c:1298
+#: builtin/remote.c:1331
#, c-format
msgid " * [pruned] %s"
msgstr "* [veralteten Branch entfernt] %s"
-#: builtin/remote.c:1321
+#: builtin/remote.c:1374
msgid "prune remotes after fetching"
msgstr "entfernt veraltete Branches im Remote-Repository nach \"fetch\""
-#: builtin/remote.c:1387 builtin/remote.c:1461
+#: builtin/remote.c:1440 builtin/remote.c:1514
#, c-format
msgid "No such remote '%s'"
msgstr "Kein solches Remote-Repository '%s'"
-#: builtin/remote.c:1407
+#: builtin/remote.c:1460
msgid "add branch"
msgstr "fügt Branch hinzu"
-#: builtin/remote.c:1414
+#: builtin/remote.c:1467
msgid "no remote specified"
msgstr "kein Remote-Repository angegeben"
-#: builtin/remote.c:1436
+#: builtin/remote.c:1489
msgid "manipulate push URLs"
msgstr "manipuliert URLs für \"push\""
-#: builtin/remote.c:1438
+#: builtin/remote.c:1491
msgid "add URL"
msgstr "fügt URL hinzu"
-#: builtin/remote.c:1440
+#: builtin/remote.c:1493
msgid "delete URLs"
msgstr "löscht URLs"
-#: builtin/remote.c:1447
+#: builtin/remote.c:1500
msgid "--add --delete doesn't make sense"
msgstr ""
"Die Optionen --add und --delete können nicht gemeinsam verwendet werden."
-#: builtin/remote.c:1487
+#: builtin/remote.c:1540
#, c-format
msgid "Invalid old URL pattern: %s"
msgstr "ungültiges altes URL Format: %s"
-#: builtin/remote.c:1495
+#: builtin/remote.c:1548
#, c-format
msgid "No such URL found: %s"
msgstr "Keine solche URL gefunden: %s"
-#: builtin/remote.c:1497
+#: builtin/remote.c:1550
msgid "Will not delete all non-push URLs"
msgstr "Werde keine URLs entfernen, die nicht für \"push\" bestimmt sind"
-#: builtin/remote.c:1569
+#: builtin/remote.c:1564
msgid "be verbose; must be placed before a subcommand"
msgstr "erweiterte Ausgaben; muss vor einem Unterkommando angegeben werden"
@@ -8816,9 +8909,14 @@ msgstr "mit -A, löscht keine Objekte älter als dieses Datum"
msgid "size of the window used for delta compression"
msgstr "Größe des Fensters für die Delta-Kompression"
+#: builtin/repack.c:162 builtin/repack.c:166
+msgid "bytes"
+msgstr "Bytes"
+
#: builtin/repack.c:163
msgid "same as the above, but limit memory size instead of entries count"
-msgstr "gleiches wie oben, limitiert aber die Speichergröße anstatt der\n"
+msgstr ""
+"gleiches wie oben, limitiert aber die Speichergröße anstatt der\n"
"Anzahl der Einträge"
#: builtin/repack.c:165
@@ -8829,7 +8927,7 @@ msgstr "limitiert die maximale Delta-Tiefe"
msgid "maximum size of each packfile"
msgstr "maximale Größe für jede Paketdatei"
-#: builtin/repack.c:345
+#: builtin/repack.c:343
#, c-format
msgid "removing '%s' failed"
msgstr "Löschen von '%s' fehlgeschlagen"
@@ -8843,21 +8941,25 @@ msgid "git replace -d <object>..."
msgstr "git replace -d <Objekt>..."
#: builtin/replace.c:19
-msgid "git replace -l [<pattern>]"
-msgstr "git replace -l [<Muster>]"
+msgid "git replace [--format=<format>] [-l [<pattern>]]"
+msgstr "git replace [--format=<Format>] [-l [<Muster>]]"
-#: builtin/replace.c:131
+#: builtin/replace.c:174
msgid "list replace refs"
msgstr "listet ersetzende Referenzen auf"
-#: builtin/replace.c:132
+#: builtin/replace.c:175
msgid "delete replace refs"
msgstr "löscht ersetzende Referenzen"
-#: builtin/replace.c:133
+#: builtin/replace.c:176
msgid "replace the ref if it exists"
msgstr "ersetzt die Referenz, wenn sie existiert"
+#: builtin/replace.c:177
+msgid "use this format"
+msgstr "benutzt das angegebene Format"
+
#: builtin/rerere.c:12
msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
msgstr "git rerere [clean | forget path... | status | remaining | diff | gc]"
@@ -8991,19 +9093,23 @@ msgstr "Konnte Staging-Area-Datei nicht zu Commit '%s' setzen."
msgid "Could not write new index file."
msgstr "Konnte neue Staging-Area-Datei nicht schreiben."
-#: builtin/rev-parse.c:345
+#: builtin/rev-parse.c:359
msgid "git rev-parse --parseopt [options] -- [<args>...]"
msgstr "git rev-parse --parseopt [Optionen] -- [<Argumente>...]"
-#: builtin/rev-parse.c:350
+#: builtin/rev-parse.c:364
msgid "keep the `--` passed as an arg"
msgstr "lässt `--` als Argument"
-#: builtin/rev-parse.c:352
+#: builtin/rev-parse.c:366
msgid "stop parsing after the first non-option argument"
msgstr "stoppt das Parsen nach dem ersten Argument was keine Option ist"
-#: builtin/rev-parse.c:470
+#: builtin/rev-parse.c:369
+msgid "output in stuck long form"
+msgstr "Ausgabe in Langform mit Argumenten an den Optionen (getrennt durch '=')"
+
+#: builtin/rev-parse.c:486
msgid ""
"git rev-parse --parseopt [options] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
@@ -9253,67 +9359,67 @@ msgstr ""
msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
msgstr "git show-branch (-g|--reflog)[=<n>[,<Basis>]] [--list] [<Referenz>]"
-#: builtin/show-branch.c:650
+#: builtin/show-branch.c:649
msgid "show remote-tracking and local branches"
msgstr "zeigt Remote-Tracking und lokale Branches an"
-#: builtin/show-branch.c:652
+#: builtin/show-branch.c:651
msgid "show remote-tracking branches"
msgstr "zeigt Remote-Tracking-Branches an"
-#: builtin/show-branch.c:654
+#: builtin/show-branch.c:653
msgid "color '*!+-' corresponding to the branch"
msgstr "färbt '*!+-' entsprechend des Branches ein"
-#: builtin/show-branch.c:656
+#: builtin/show-branch.c:655
msgid "show <n> more commits after the common ancestor"
msgstr "zeigt <n> weitere Commits nach dem gemeinsamen Vorgänger-Commit"
-#: builtin/show-branch.c:658
+#: builtin/show-branch.c:657
msgid "synonym to more=-1"
msgstr "Synonym für more=-1"
-#: builtin/show-branch.c:659
+#: builtin/show-branch.c:658
msgid "suppress naming strings"
msgstr "unterdrückt Namen"
-#: builtin/show-branch.c:661
+#: builtin/show-branch.c:660
msgid "include the current branch"
msgstr "bezieht den aktuellen Branch ein"
-#: builtin/show-branch.c:663
+#: builtin/show-branch.c:662
msgid "name commits with their object names"
msgstr "benennt Commits nach ihren Objektnamen"
-#: builtin/show-branch.c:665
+#: builtin/show-branch.c:664
msgid "show possible merge bases"
msgstr "zeigt mögliche Merge-Basen an"
-#: builtin/show-branch.c:667
+#: builtin/show-branch.c:666
msgid "show refs unreachable from any other ref"
msgstr "zeigt Referenzen die unerreichbar von allen anderen Referenzen sind"
-#: builtin/show-branch.c:669
+#: builtin/show-branch.c:668
msgid "show commits in topological order"
msgstr "zeigt Commits in topologischer Ordnung"
-#: builtin/show-branch.c:672
+#: builtin/show-branch.c:671
msgid "show only commits not on the first branch"
msgstr "zeigt nur Commits, die sich nicht im ersten Branch befinden"
-#: builtin/show-branch.c:674
+#: builtin/show-branch.c:673
msgid "show merges reachable from only one tip"
msgstr "zeigt Merges, die nur von einem Branch aus erreichbar sind"
-#: builtin/show-branch.c:676
+#: builtin/show-branch.c:675
msgid "topologically sort, maintaining date order where possible"
msgstr "topologische Sortierung, Beibehaltung Datumsordnung wo möglich"
-#: builtin/show-branch.c:679
+#: builtin/show-branch.c:678
msgid "<n>[,<base>]"
msgstr "<n>[,<Basis>]"
-#: builtin/show-branch.c:680
+#: builtin/show-branch.c:679
msgid "show <n> most recent ref-log entries starting at base"
msgstr "zeigt die <n> jüngsten Einträge im Reflog beginnend an der Basis"
@@ -9815,15 +9921,15 @@ msgstr "Verfallsdatum"
msgid "no-op (backward compatibility)"
msgstr "Kein Effekt (Rückwärtskompatibilität)"
-#: parse-options.h:238
+#: parse-options.h:235
msgid "be more verbose"
msgstr "erweiterte Ausgaben"
-#: parse-options.h:240
+#: parse-options.h:237
msgid "be more quiet"
msgstr "weniger Ausgaben"
-#: parse-options.h:246
+#: parse-options.h:243
msgid "use <n> digits to display SHA-1s"
msgstr "benutze <n> Ziffern zur Anzeige von SHA-1s"
@@ -10141,8 +10247,9 @@ msgstr ""
"<gueltigerbranch>'."
#: git-bisect.sh:140
-msgid "won't bisect on seeked tree"
-msgstr "binäre Suche auf gesuchtem Branch nicht möglich"
+msgid "won't bisect on cg-seek'ed tree"
+msgstr ""
+"binäre Suche auf einem durch 'cg-seek' geändertem Verzeichnis nicht möglich"
#: git-bisect.sh:144
msgid "Bad HEAD - strange symbolic ref"
@@ -10292,7 +10399,7 @@ msgstr ""
#. The working tree and the index file is still based on the
#. $orig_head commit, but we are merging into $curr_head.
#. First update the working tree to match $curr_head.
-#: git-pull.sh:255
+#: git-pull.sh:247
#, sh-format
msgid ""
"Warning: fetch updated the current branch head.\n"
@@ -10302,15 +10409,15 @@ msgstr ""
"Warnung: \"fetch\" aktualisierte die Spitze des aktuellen Branches.\n"
"Warnung: Spule Ihr Arbeitsverzeichnis von Commit $orig_head vor."
-#: git-pull.sh:280
+#: git-pull.sh:272
msgid "Cannot merge multiple branches into empty head"
msgstr "Kann nicht mehrere Branches in einen ungeborenen Branch zusammenführen"
-#: git-pull.sh:284
+#: git-pull.sh:276
msgid "Cannot rebase onto multiple branches"
msgstr "kann Rebase nicht auf mehrere Branches ausführen"
-#: git-rebase.sh:54
+#: git-rebase.sh:55
msgid ""
"When you have resolved this problem, run \"git rebase --continue\".\n"
"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
@@ -10324,16 +10431,16 @@ msgstr ""
"Um den ursprünglichen Branch wiederherzustellen und den Rebase abzubrechen,\n"
"führen Sie \"git rebase --abort\" aus."
-#: git-rebase.sh:156
+#: git-rebase.sh:158
msgid "Applied autostash."
msgstr "\"autostash\" angewendet."
-#: git-rebase.sh:159
+#: git-rebase.sh:161
#, sh-format
msgid "Cannot store $stash_sha1"
msgstr "Kann $stash_sha1 nicht speichern."
-#: git-rebase.sh:160
+#: git-rebase.sh:162
msgid ""
"Applying autostash resulted in conflicts.\n"
"Your changes are safe in the stash.\n"
@@ -10343,33 +10450,33 @@ msgstr ""
"Ihre Änderungen sind im Stash sicher.\n"
"Sie können jederzeit \"git stash pop\" oder \"git stash drop\" ausführen.\n"
-#: git-rebase.sh:199
+#: git-rebase.sh:201
msgid "The pre-rebase hook refused to rebase."
msgstr "Der \"pre-rebase hook\" hat den Rebase zurückgewiesen."
-#: git-rebase.sh:204
+#: git-rebase.sh:206
msgid "It looks like git-am is in progress. Cannot rebase."
msgstr "\"git-am\" scheint im Gange zu sein. Kann Rebase nicht durchführen."
-#: git-rebase.sh:338
+#: git-rebase.sh:346
msgid "The --exec option must be used with the --interactive option"
msgstr "Die Option --exec muss mit --interactive verwendet werden."
-#: git-rebase.sh:343
+#: git-rebase.sh:351
msgid "No rebase in progress?"
msgstr "Kein Rebase im Gange?"
-#: git-rebase.sh:354
+#: git-rebase.sh:362
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
"Die --edit-todo Aktion kann nur während eines interaktiven Rebase verwendet "
"werden."
-#: git-rebase.sh:361
+#: git-rebase.sh:369
msgid "Cannot read HEAD"
msgstr "Kann HEAD nicht lesen"
-#: git-rebase.sh:364
+#: git-rebase.sh:372
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
@@ -10377,12 +10484,12 @@ msgstr ""
"Sie müssen alle Merge-Konflikte editieren und diese dann\n"
"mittels \"git add\" als aufgelöst markieren"
-#: git-rebase.sh:382
+#: git-rebase.sh:390
#, sh-format
msgid "Could not move back to $head_name"
msgstr "Konnte nicht zu $head_name zurückgehen"
-#: git-rebase.sh:401
+#: git-rebase.sh:409
#, sh-format
msgid ""
"It seems that there is already a $state_dir_base directory, and\n"
@@ -10403,68 +10510,68 @@ msgstr ""
"und führen Sie dieses Kommando nochmal aus. Es wird angehalten, falls noch\n"
"etwas Schützenswertes vorhanden ist."
-#: git-rebase.sh:446
+#: git-rebase.sh:456
#, sh-format
msgid "invalid upstream $upstream_name"
msgstr "ungültiger Upstream-Branch $upstream_name"
-#: git-rebase.sh:470
+#: git-rebase.sh:480
#, sh-format
msgid "$onto_name: there are more than one merge bases"
msgstr "$onto_name: es gibt mehr als eine Merge-Basis"
-#: git-rebase.sh:473 git-rebase.sh:477
+#: git-rebase.sh:483 git-rebase.sh:487
#, sh-format
msgid "$onto_name: there is no merge base"
msgstr "$onto_name: es gibt keine Merge-Basis"
-#: git-rebase.sh:482
+#: git-rebase.sh:492
#, sh-format
msgid "Does not point to a valid commit: $onto_name"
msgstr "$onto_name zeigt auf keinen gültigen Commit"
-#: git-rebase.sh:505
+#: git-rebase.sh:515
#, sh-format
msgid "fatal: no such branch: $branch_name"
msgstr "fatal: Branch $branch_name nicht gefunden"
-#: git-rebase.sh:528
+#: git-rebase.sh:548
msgid "Cannot autostash"
msgstr "Kann \"autostash\" nicht ausführen."
-#: git-rebase.sh:533
+#: git-rebase.sh:553
#, sh-format
msgid "Created autostash: $stash_abbrev"
msgstr "\"autostash\" erzeugt: $stash_abbrev"
-#: git-rebase.sh:537
+#: git-rebase.sh:557
msgid "Please commit or stash them."
msgstr "Bitte committen Sie die Änderungen oder benutzen Sie \"stash\"."
-#: git-rebase.sh:557
+#: git-rebase.sh:577
#, sh-format
msgid "Current branch $branch_name is up to date."
msgstr "Aktueller Branch $branch_name ist auf dem neusten Stand."
-#: git-rebase.sh:561
+#: git-rebase.sh:581
#, sh-format
msgid "Current branch $branch_name is up to date, rebase forced."
msgstr ""
"Aktueller Branch $branch_name ist auf dem neusten Stand, Rebase erzwungen."
-#: git-rebase.sh:572
+#: git-rebase.sh:592
#, sh-format
msgid "Changes from $mb to $onto:"
msgstr "Änderungen von $mb zu $onto:"
#. Detach HEAD and reset the tree
-#: git-rebase.sh:581
+#: git-rebase.sh:601
msgid "First, rewinding head to replay your work on top of it..."
msgstr ""
"Zunächst wird der Branch zurückgespult, um Ihre Änderungen\n"
"darauf neu anzuwenden..."
-#: git-rebase.sh:591
+#: git-rebase.sh:611
#, sh-format
msgid "Fast-forwarded $branch_name to $onto_name."
msgstr "$branch_name zu $onto_name vorgespult."
@@ -10718,52 +10825,52 @@ msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
msgid "Entering '$prefix$displaypath'"
msgstr "Betrete '$prefix$displaypath'"
-#: git-submodule.sh:554
+#: git-submodule.sh:559
#, sh-format
msgid "Stopping at '$prefix$displaypath'; script returned non-zero status."
msgstr "Stoppe bei '$prefix$displaypath'; Skript gab nicht-Null Status zurück."
-#: git-submodule.sh:600
+#: git-submodule.sh:605
#, sh-format
msgid "No url found for submodule path '$displaypath' in .gitmodules"
msgstr "Keine URL für Submodul-Pfad '$displaypath' in .gitmodules gefunden"
-#: git-submodule.sh:609
+#: git-submodule.sh:614
#, sh-format
msgid "Failed to register url for submodule path '$displaypath'"
msgstr ""
"Fehler beim Eintragen der URL für Submodul-Pfad '$displaypath' in die "
"Konfiguration."
-#: git-submodule.sh:611
+#: git-submodule.sh:616
#, sh-format
msgid "Submodule '$name' ($url) registered for path '$displaypath'"
msgstr ""
"Submodul '$name' ($url) für Pfad '$displaypath' in die Konfiguration "
"eingetragen."
-#: git-submodule.sh:619
+#: git-submodule.sh:633
#, sh-format
msgid "Failed to register update mode for submodule path '$displaypath'"
msgstr ""
"Fehler bei Änderung des Aktualisierungsmodus für Submodul-Pfad "
"'$displaypath' in der Konfiguration."
-#: git-submodule.sh:656
+#: git-submodule.sh:671
#, sh-format
msgid "Use '.' if you really want to deinitialize all submodules"
msgstr ""
"Verwenden Sie '.' wenn Sie wirklich alle Submodule\n"
"deinitialisieren möchten."
-#: git-submodule.sh:673
+#: git-submodule.sh:688
#, sh-format
msgid "Submodule work tree '$displaypath' contains a .git directory"
msgstr ""
"Arbeitsverzeichnis des Submoduls in '$displaypath' enthält ein .git-"
"Verzeichnis"
-#: git-submodule.sh:674
+#: git-submodule.sh:689
#, sh-format
msgid ""
"(use 'rm -rf' if you really want to remove it including all of its history)"
@@ -10771,7 +10878,7 @@ msgstr ""
"(benutzen Sie 'rm -rf' wenn Sie dieses Submodul wirklich mitsamt\n"
"seiner Historie löschen möchten)"
-#: git-submodule.sh:680
+#: git-submodule.sh:695
#, sh-format
msgid ""
"Submodule work tree '$displaypath' contains local modifications; use '-f' to "
@@ -10780,31 +10887,31 @@ msgstr ""
"Arbeitsverzeichnis von Submodul in '$displaypath' enthält lokale Änderungen; "
"verwenden Sie '-f' um diese zu verwerfen"
-#: git-submodule.sh:683
+#: git-submodule.sh:698
#, sh-format
msgid "Cleared directory '$displaypath'"
msgstr "Verzeichnis '$displaypath' bereinigt."
-#: git-submodule.sh:684
+#: git-submodule.sh:699
#, sh-format
msgid "Could not remove submodule work tree '$displaypath'"
msgstr ""
"Konnte Arbeitsverzeichnis des Submoduls in '$displaypath' nicht löschen."
-#: git-submodule.sh:687
+#: git-submodule.sh:702
#, sh-format
msgid "Could not create empty submodule directory '$displaypath'"
msgstr ""
"Konnte kein leeres Verzeichnis für Submodul in '$displaypath' erstellen."
-#: git-submodule.sh:696
+#: git-submodule.sh:711
#, sh-format
msgid "Submodule '$name' ($url) unregistered for path '$displaypath'"
msgstr ""
"Submodul '$name' ($url) für Pfad '$displaypath' wurde aus der Konfiguration "
"entfernt."
-#: git-submodule.sh:811
+#: git-submodule.sh:834
#, sh-format
msgid ""
"Submodule path '$displaypath' not initialized\n"
@@ -10813,42 +10920,42 @@ msgstr ""
"Submodul-Pfad '$displaypath' ist nicht initialisiert.\n"
"Vielleicht möchten Sie 'update --init' benutzen?"
-#: git-submodule.sh:824
+#: git-submodule.sh:847
#, sh-format
msgid "Unable to find current revision in submodule path '$displaypath'"
msgstr "Konnte aktuellen Commit in Submodul-Pfad '$displaypath' nicht finden."
-#: git-submodule.sh:833
+#: git-submodule.sh:856
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr "Konnte \"fetch\" in Submodul-Pfad '$sm_path' nicht ausführen"
-#: git-submodule.sh:857
+#: git-submodule.sh:880
#, sh-format
msgid "Unable to fetch in submodule path '$displaypath'"
msgstr "Konnte \"fetch\" in Submodul-Pfad '$displaypath' nicht ausführen"
-#: git-submodule.sh:871
+#: git-submodule.sh:894
#, sh-format
msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
msgstr "Rebase auf '$sha1' in Submodul-Pfad '$displaypath' nicht möglich"
-#: git-submodule.sh:872
+#: git-submodule.sh:895
#, sh-format
msgid "Submodule path '$displaypath': rebased into '$sha1'"
msgstr "Submodul-Pfad '$displaypath': Rebase auf '$sha1'"
-#: git-submodule.sh:877
+#: git-submodule.sh:900
#, sh-format
msgid "Unable to merge '$sha1' in submodule path '$displaypath'"
msgstr "Merge von '$sha1' in Submodul-Pfad '$displaypath' fehlgeschlagen"
-#: git-submodule.sh:878
+#: git-submodule.sh:901
#, sh-format
msgid "Submodule path '$displaypath': merged in '$sha1'"
msgstr "Submodul-Pfad '$displaypath': zusammengeführt in '$sha1'"
-#: git-submodule.sh:883
+#: git-submodule.sh:906
#, sh-format
msgid ""
"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'"
@@ -10856,67 +10963,82 @@ msgstr ""
"Ausführung von '$command $sha1' in Submodul-Pfad '$prefix$sm_path' "
"fehlgeschlagen"
-#: git-submodule.sh:884
+#: git-submodule.sh:907
#, sh-format
msgid "Submodule path '$prefix$sm_path': '$command $sha1'"
msgstr "Submodul-Pfad '$prefix$sm_path': '$command $sha1'"
-#: git-submodule.sh:889
+#: git-submodule.sh:912
#, sh-format
msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
msgstr "Konnte '$sha1' in Submodul-Pfad '$displaypath' nicht auschecken."
-#: git-submodule.sh:890
+#: git-submodule.sh:913
#, sh-format
msgid "Submodule path '$displaypath': checked out '$sha1'"
msgstr "Submodul-Pfad: '$displaypath': '$sha1' ausgecheckt"
-#: git-submodule.sh:917
+#: git-submodule.sh:940
#, sh-format
msgid "Failed to recurse into submodule path '$displaypath'"
msgstr "Fehler bei Rekursion in Submodul-Pfad '$displaypath'"
-#: git-submodule.sh:1025
+#: git-submodule.sh:1048
msgid "The --cached option cannot be used with the --files option"
msgstr ""
"Die Optionen --cached und --files können nicht gemeinsam verwendet werden."
#. unexpected type
-#: git-submodule.sh:1073
+#: git-submodule.sh:1096
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "unerwarteter Modus $mod_dst"
-#: git-submodule.sh:1093
+#: git-submodule.sh:1116
#, sh-format
msgid " Warn: $display_name doesn't contain commit $sha1_src"
msgstr " Warnung: $display_name beinhaltet nicht Commit $sha1_src"
-#: git-submodule.sh:1096
+#: git-submodule.sh:1119
#, sh-format
msgid " Warn: $display_name doesn't contain commit $sha1_dst"
msgstr " Warnung: $display_name beinhaltet nicht Commit $sha1_dst"
-#: git-submodule.sh:1099
+#: git-submodule.sh:1122
#, sh-format
msgid " Warn: $display_name doesn't contain commits $sha1_src and $sha1_dst"
msgstr ""
" Warnung: $display_name beinhaltet nicht die Commits $sha1_src und $sha1_dst"
-#: git-submodule.sh:1124
+#: git-submodule.sh:1147
msgid "blob"
msgstr "Blob"
-#: git-submodule.sh:1238
+#: git-submodule.sh:1261
#, sh-format
msgid "Failed to recurse into submodule path '$sm_path'"
msgstr "Fehler bei Rekursion in Submodul-Pfad '$sm_path'"
-#: git-submodule.sh:1302
+#: git-submodule.sh:1325
#, sh-format
msgid "Synchronizing submodule url for '$displaypath'"
msgstr "Synchronisiere Submodul-URL für '$displaypath'"
+#~ msgid "copied: %s -> %s"
+#~ msgstr "kopiert: %s -> %s"
+
+#~ msgid "deleted: %s"
+#~ msgstr "gelöscht: %s"
+
+#~ msgid "modified: %s"
+#~ msgstr "geändert: %s"
+
+#~ msgid "renamed: %s -> %s"
+#~ msgstr "umbenannt: %s -> %s"
+
+#~ msgid "unmerged: %s"
+#~ msgstr "nicht zusammengeführt: %s"
+
#~ msgid "input paths are terminated by a null character"
#~ msgstr "Eingabepfade sind durch ein NUL Zeichen abgeschlossen"
diff --git a/po/fr.po b/po/fr.po
index 2acd5c4342..e10263f2b2 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -73,10 +73,10 @@ msgid ""
msgstr ""
"Project-Id-Version: git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2013-11-02 08:06+0800\n"
-"PO-Revision-Date: 2013-11-07 21:41+0100\n"
-"Last-Translator: Sébastien Helleu <flashcode@flashtux.org>\n"
-"Language-Team: Jean-Noël Avila <jn.avila@free.fr>\n"
+"POT-Creation-Date: 2014-02-01 08:06+0800\n"
+"PO-Revision-Date: 2014-02-02 14:35+0100\n"
+"Last-Translator: Jean-Noël Avila <jn.avila@free.fr>\n"
+"Language-Team: Jean-Noël Avila <jn.avila@free.fr>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -1412,21 +1412,21 @@ msgstr ""
"message\n"
"en lançant \"git config advice.objectNameWarning false\""
-#: sha1_name.c:1109
+#: sha1_name.c:1070
msgid "HEAD does not point to a branch"
msgstr "HEAD ne pointe pas sur une branche"
-#: sha1_name.c:1112
+#: sha1_name.c:1073
#, c-format
msgid "No such branch: '%s'"
msgstr "Branche inconnue : '%s'"
-#: sha1_name.c:1114
+#: sha1_name.c:1075
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Aucune branche amont configurée pour la branche '%s'"
-#: sha1_name.c:1118
+#: sha1_name.c:1079
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "La branche amont '%s' n'est pas stockée comme branche de suivi"
@@ -5311,7 +5311,8 @@ msgstr "%s n'a pas envoyé tous les objets nécessaires\n"
#: builtin/fetch.c:579
#, c-format
msgid "reject %s because shallow roots are not allowed to be updated"
-msgstr "%s rejeté parce que les racines superficielles ne sont pas mises à jour"
+msgstr ""
+"%s rejeté parce que les racines superficielles ne sont pas mises à jour"
#: builtin/fetch.c:667 builtin/fetch.c:750
#, c-format
@@ -5420,8 +5421,9 @@ msgstr ""
"git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <fichier>]"
#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:702
-#: builtin/merge.c:196 builtin/show-branch.c:654 builtin/show-ref.c:178
-#: builtin/tag.c:446 parse-options.h:135 parse-options.h:242
+#: builtin/merge.c:196 builtin/repack.c:160 builtin/repack.c:164
+#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:446
+#: parse-options.h:135 parse-options.h:242
msgid "n"
msgstr "n"
@@ -6395,17 +6397,17 @@ msgstr "spécifier que le dépôt git sera partagé entre plusieurs utilisateurs
msgid "be quiet"
msgstr "être silencieux"
-#: builtin/init-db.c:522 builtin/init-db.c:529
+#: builtin/init-db.c:525 builtin/init-db.c:530
#, c-format
msgid "cannot mkdir %s"
msgstr "impossible de créer le répertoire (mkdir) %s"
-#: builtin/init-db.c:533
+#: builtin/init-db.c:534
#, c-format
msgid "cannot chdir to %s"
msgstr "impossible de se déplacer vers le répertoire (chdir) %s"
-#: builtin/init-db.c:555
+#: builtin/init-db.c:556
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -6414,11 +6416,11 @@ msgstr ""
"%s (ou --work-tree=<répertoire>) n'est pas autorisé sans spécifier %s (ou --"
"git-dir=<répertoire>)"
-#: builtin/init-db.c:579
+#: builtin/init-db.c:580
msgid "Cannot access current working directory"
msgstr "Impossible d'accéder au répertoire de travail courant"
-#: builtin/init-db.c:586
+#: builtin/init-db.c:587
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "Impossible d'accéder à l'arbre de travail '%s'"
@@ -8042,24 +8044,30 @@ msgid ""
msgstr ""
"push.default n'est pas défini ; sa valeur implicite change dans Git 2.0\n"
"de 'matching' vers 'simple'. Pour supprimer ce message et maintenir\n"
-"le comportement actuel après la modification de la valeur de défaut, utilisez :\n"
+"le comportement actuel après la modification de la valeur de défaut, "
+"utilisez :\n"
"\n"
" git config --global push.default matching\n"
"\n"
-"Pour supprimer ce message et adopter le nouveau comportement maintenant, utilisez :\n"
+"Pour supprimer ce message et adopter le nouveau comportement maintenant, "
+"utilisez :\n"
"\n"
" git config --global push.default simple\n"
"\n"
"Quand push.default vaudra 'matching', git poussera les branches locales\n"
"sur les branches distantes qui existent déjà avec le même nom.\n"
"\n"
-"Dans Git 2.0 Git utilisera par défaut le comportement plus conservatif 'simple'\n"
-"qui ne pousse la branche courante vers la branche distante que 'git pull' utilise\n"
+"Dans Git 2.0 Git utilisera par défaut le comportement plus conservatif "
+"'simple'\n"
+"qui ne pousse la branche courante vers la branche distante que 'git pull' "
+"utilise\n"
"pour mettre à jour la branche courante.\n"
" \n"
"Voir 'git help config' et chercher 'push.default' pour plus d'information.\n"
-"(le mode 'simple' a été introduit dans Git 1.7.11. Utilisez le mode similaire\n"
-"'current' au lieu de 'simple' si vous utilisez de temps en temps d'anciennes versions de Git)"
+"(le mode 'simple' a été introduit dans Git 1.7.11. Utilisez le mode "
+"similaire\n"
+"'current' au lieu de 'simple' si vous utilisez de temps en temps d'anciennes "
+"versions de Git)"
#: builtin/push.c:274
msgid ""
@@ -8919,6 +8927,10 @@ msgstr "avec -A, ne pas suspendre les objets plus vieux que celui-ci"
msgid "size of the window used for delta compression"
msgstr "taille de la fenêtre utilisée pour la compression des deltas"
+#: builtin/repack.c:162 builtin/repack.c:166
+msgid "bytes"
+msgstr "octets"
+
#: builtin/repack.c:163
msgid "same as the above, but limit memory size instead of entries count"
msgstr ""
@@ -11021,7 +11033,7 @@ msgid "Synchronizing submodule url for '$displaypath'"
msgstr "Synchronisation de l'URL sous-module pour '$displaypath'"
#~ msgid "copied: %s -> %s"
-#~ msgstr "copié : %s -> %s"
+#~ msgstr ""
#~ msgid "deleted: %s"
#~ msgstr "supprimé : %s"
diff --git a/po/git.pot b/po/git.pot
index 13dfa8695b..33cc31d51b 100644
--- a/po/git.pot
+++ b/po/git.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2014-01-18 07:42+0800\n"
+"POT-Creation-Date: 2014-02-01 08:06+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1261,21 +1261,21 @@ msgid ""
"running \"git config advice.objectNameWarning false\""
msgstr ""
-#: sha1_name.c:1109
+#: sha1_name.c:1070
msgid "HEAD does not point to a branch"
msgstr ""
-#: sha1_name.c:1112
+#: sha1_name.c:1073
#, c-format
msgid "No such branch: '%s'"
msgstr ""
-#: sha1_name.c:1114
+#: sha1_name.c:1075
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr ""
-#: sha1_name.c:1118
+#: sha1_name.c:1079
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr ""
@@ -5015,8 +5015,9 @@ msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
msgstr ""
#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:702
-#: builtin/merge.c:196 builtin/show-branch.c:654 builtin/show-ref.c:178
-#: builtin/tag.c:446 parse-options.h:135 parse-options.h:242
+#: builtin/merge.c:196 builtin/repack.c:160 builtin/repack.c:164
+#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:446
+#: parse-options.h:135 parse-options.h:242
msgid "n"
msgstr ""
@@ -5959,28 +5960,28 @@ msgstr ""
msgid "be quiet"
msgstr ""
-#: builtin/init-db.c:522 builtin/init-db.c:529
+#: builtin/init-db.c:525 builtin/init-db.c:530
#, c-format
msgid "cannot mkdir %s"
msgstr ""
-#: builtin/init-db.c:533
+#: builtin/init-db.c:534
#, c-format
msgid "cannot chdir to %s"
msgstr ""
-#: builtin/init-db.c:555
+#: builtin/init-db.c:556
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
"dir=<directory>)"
msgstr ""
-#: builtin/init-db.c:579
+#: builtin/init-db.c:580
msgid "Cannot access current working directory"
msgstr ""
-#: builtin/init-db.c:586
+#: builtin/init-db.c:587
#, c-format
msgid "Cannot access work tree '%s'"
msgstr ""
@@ -8294,6 +8295,10 @@ msgstr ""
msgid "size of the window used for delta compression"
msgstr ""
+#: builtin/repack.c:162 builtin/repack.c:166
+msgid "bytes"
+msgstr ""
+
#: builtin/repack.c:163
msgid "same as the above, but limit memory size instead of entries count"
msgstr ""
diff --git a/po/sv.po b/po/sv.po
index 154755fcc5..8c3c59aa3b 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git 1.8.4\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2014-01-18 07:42+0800\n"
-"PO-Revision-Date: 2014-01-21 09:24+0100\n"
+"POT-Creation-Date: 2014-02-01 08:06+0800\n"
+"PO-Revision-Date: 2014-02-02 17:21+0100\n"
"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -1323,21 +1323,21 @@ msgstr ""
"Undersök referenserna och ta kanske bort dem. Stäng av meddelandet\n"
"genom att köra \"git config advice.objectNameWarning false\""
-#: sha1_name.c:1109
+#: sha1_name.c:1070
msgid "HEAD does not point to a branch"
msgstr "HEAD pekar inte på en gren"
-#: sha1_name.c:1112
+#: sha1_name.c:1073
#, c-format
msgid "No such branch: '%s'"
msgstr "Okänd gren: \"%s\""
-#: sha1_name.c:1114
+#: sha1_name.c:1075
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Ingen standarduppström angiven för grenen \"%s\""
-#: sha1_name.c:1118
+#: sha1_name.c:1079
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "Uppströmsgrenen \"%s\" är inte lagrad som en fjärrspårande gren"
@@ -5260,8 +5260,9 @@ msgstr ""
"git fmt-merge-msg [-m <meddelande>] [--log[=<n>]|--no-log] [--file <fil>]"
#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:702
-#: builtin/merge.c:196 builtin/show-branch.c:654 builtin/show-ref.c:178
-#: builtin/tag.c:446 parse-options.h:135 parse-options.h:242
+#: builtin/merge.c:196 builtin/repack.c:160 builtin/repack.c:164
+#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:446
+#: parse-options.h:135 parse-options.h:242
msgid "n"
msgstr "n"
@@ -6218,17 +6219,17 @@ msgstr "ange att git-arkivet skall delas bland flera användare"
msgid "be quiet"
msgstr "var tyst"
-#: builtin/init-db.c:522 builtin/init-db.c:529
+#: builtin/init-db.c:525 builtin/init-db.c:530
#, c-format
msgid "cannot mkdir %s"
msgstr "kan inte skapa katalogen (mkdir) %s"
-#: builtin/init-db.c:533
+#: builtin/init-db.c:534
#, c-format
msgid "cannot chdir to %s"
msgstr "kan inte byta katalog (chdir) till %s"
-#: builtin/init-db.c:555
+#: builtin/init-db.c:556
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -6237,11 +6238,11 @@ msgstr ""
"%s (eller --work-tree=<katalog>) inte tillåtet utan att ange %s (eller --git-"
"dir=<katalog>)"
-#: builtin/init-db.c:579
+#: builtin/init-db.c:580
msgid "Cannot access current working directory"
msgstr "Kan inte komma åt aktuell arbetskatalog"
-#: builtin/init-db.c:586
+#: builtin/init-db.c:587
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "Kan inte komma åt arbetskatalogen \"%s\""
@@ -8688,6 +8689,10 @@ msgstr "med -A, lös inte upp objekt äldre än detta"
msgid "size of the window used for delta compression"
msgstr "storlek på fönster använt för deltakomprimering"
+#: builtin/repack.c:162 builtin/repack.c:166
+msgid "bytes"
+msgstr "byte"
+
#: builtin/repack.c:163
msgid "same as the above, but limit memory size instead of entries count"
msgstr "samma som ovan, men begränsa minnesstorleken istället för postantal"
diff --git a/po/vi.po b/po/vi.po
index f087c05154..b9676a88e4 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git v1.9-pu\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2014-01-18 07:42+0800\n"
-"PO-Revision-Date: 2014-01-18 09:05+0700\n"
+"POT-Creation-Date: 2014-02-01 08:06+0800\n"
+"PO-Revision-Date: 2014-02-03 07:30+0700\n"
"Last-Translator: Trần Ngá»c Quân <vnwildman@gmail.com>\n"
"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
"Language: vi\n"
@@ -146,7 +146,7 @@ msgstr ""
#: branch.c:60
#, c-format
msgid "Not setting branch %s as its own upstream."
-msgstr "Chưa cài đặt nhánh %s như là thượng nguồn (upstream) của nó."
+msgstr "Chưa cài đặt nhánh %s như là thượng nguồn của nó."
#: branch.c:82
#, c-format
@@ -1177,7 +1177,7 @@ msgstr "%s: không thể phân tích lần chuyển giao mẹ của %s"
#: sequencer.c:542
#, c-format
msgid "Cannot get commit message for %s"
-msgstr "Không thể lấy thông điệp lần chuyển giao cho %s"
+msgstr "Không thể lấy ghi chú lần chuyển giao cho %s"
#: sequencer.c:628
#, c-format
@@ -1343,26 +1343,25 @@ msgstr ""
"này\n"
"bằng cách chạy lệnh \"git config advice.objectNameWarning false\""
-#: sha1_name.c:1109
+#: sha1_name.c:1070
msgid "HEAD does not point to a branch"
msgstr "HEAD không chỉ đến một nhánh nào cả"
-#: sha1_name.c:1112
+#: sha1_name.c:1073
#, c-format
msgid "No such branch: '%s'"
msgstr "Không có nhánh nào nhÆ° thế: “%sâ€"
-#: sha1_name.c:1114
+#: sha1_name.c:1075
#, c-format
msgid "No upstream configured for branch '%s'"
-msgstr "Không có thượng nguồn (upstream) được cấu hình cho nhánh “%sâ€"
+msgstr "Không có thượng nguồn được cấu hình cho nhánh “%sâ€"
-#: sha1_name.c:1118
+#: sha1_name.c:1079
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr ""
-"Nhánh thượng nguồn (upstream) “%s†không được lưu lại như là một nhánh "
-"“remote-trackingâ€"
+"Nhánh thượng nguồn “%s†không được lÆ°u lại nhÆ° là má»™t nhánh “remote-trackingâ€"
#: submodule.c:64 submodule.c:98
msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
@@ -3008,7 +3007,7 @@ msgstr "cài đặt chế độ theo dõi (xem git-pull(1))"
#: builtin/branch.c:809
msgid "change upstream info"
-msgstr "thay đổi thông tin thượng nguồn (upstream)"
+msgstr "thay đổi thông tin thượng nguồn"
#: builtin/branch.c:813
msgid "use colored output"
@@ -3066,7 +3065,7 @@ msgstr "sửa mô tả cho nhánh"
#: builtin/branch.c:841
msgid "force creation (when already exists)"
-msgstr "ép buộc tạo (khi đã sẵn tồn tại rồi)"
+msgstr "ép buộc tạo (khi đã có nhánh cùng tên)"
#: builtin/branch.c:844
msgid "print only not merged branches"
@@ -3120,15 +3119,15 @@ msgstr "quá nhiá»u nhánh dành cho thao tác đổi tên"
#: builtin/branch.c:952
msgid "too many branches to set new upstream"
-msgstr "quá nhiá»u nhánh được đặt cho thượng nguồn (upstream) má»›i"
+msgstr "quá nhiá»u nhánh được đặt cho thượng nguồn má»›i"
#: builtin/branch.c:956
#, c-format
msgid ""
"could not set upstream of HEAD to %s when it does not point to any branch."
msgstr ""
-"không thể đặt thượng nguồn (upstream) của HEAD thành %s khi mà nó chẳng chỉ "
-"đến nhánh nào cả."
+"không thể đặt thượng nguồn của HEAD thành %s khi mà nó chẳng chỉ đến nhánh "
+"nào cả."
#: builtin/branch.c:959 builtin/branch.c:981 builtin/branch.c:1002
#, c-format
@@ -3142,22 +3141,20 @@ msgstr "chÆ°a có nhánh “%sâ€"
#: builtin/branch.c:975
msgid "too many branches to unset upstream"
-msgstr "quá nhiá»u nhánh để bỠđặt thượng nguồn (upstream)"
+msgstr "quá nhiá»u nhánh để bỠđặt thượng nguồn"
#: builtin/branch.c:979
msgid "could not unset upstream of HEAD when it does not point to any branch."
-msgstr ""
-"không thể bỠđặt thượng nguồn (upstream) của HEAD không chỉ đến một nhánh "
-"nào cả."
+msgstr "không thể bỠđặt thượng nguồn của HEAD không chỉ đến một nhánh nào cả."
#: builtin/branch.c:985
#, c-format
msgid "Branch '%s' has no upstream information"
-msgstr "Nhánh “%s†không có thông tin thượng nguồn (upstream)"
+msgstr "Nhánh “%s†không có thông tin thượng nguồn"
#: builtin/branch.c:999
msgid "it does not make sense to create 'HEAD' manually"
-msgstr "không hợp lý khi tạo “HEAD†thủ công "
+msgstr "không hợp lý khi tạo “HEAD†thủ công"
#: builtin/branch.c:1005
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
@@ -3202,11 +3199,11 @@ msgstr "“%s†tốt\n"
#: builtin/bundle.c:56
msgid "Need a repository to create a bundle."
-msgstr "Cần một kho chứa để mà tạo một bundle."
+msgstr "Cần một kho chứa để có thể tạo một bundle."
#: builtin/bundle.c:60
msgid "Need a repository to unbundle."
-msgstr "Cần một kho chứa để mà bung một bundle."
+msgstr "Cần một kho chứa để có thể giải nén một bundle."
#: builtin/cat-file.c:328
msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
@@ -3264,7 +3261,7 @@ msgstr "báo cáo tất cả các thuộc tính đặt trên tập tin"
#: builtin/check-attr.c:20
msgid "use .gitattributes only from the index"
-msgstr "chỉ sử dụng .gitattributes từ bảng mục lục"
+msgstr "chỉ dùng .gitattributes từ bảng mục lục"
#: builtin/check-attr.c:21 builtin/check-ignore.c:22 builtin/hash-object.c:75
msgid "read file names from stdin"
@@ -3414,12 +3411,12 @@ msgstr "Không thể thêm kết quả hòa trá»™n cho “%sâ€"
#: builtin/checkout.c:241
#, c-format
msgid "'%s' cannot be used with updating paths"
-msgstr "“%s†không thể được sá»­ dụng vá»›i các Ä‘Æ°á»ng dẫn cập nhật"
+msgstr "không được dùng “%s†vá»›i các Ä‘Æ°á»ng dẫn cập nhật"
#: builtin/checkout.c:244 builtin/checkout.c:247
#, c-format
msgid "'%s' cannot be used with %s"
-msgstr "“%s†không thể được dùng cùng với %s"
+msgstr "không được dùng “%s†với %s"
#: builtin/checkout.c:250
#, c-format
@@ -3527,7 +3524,7 @@ msgstr "lỗi nội bộ trong khi di chuyển qua các điểm xét duyệt"
#: builtin/checkout.c:764
msgid "Previous HEAD position was"
-msgstr "Vị trí kế trước của HEAD là"
+msgstr "Vị trí trước kia của HEAD là"
#: builtin/checkout.c:791 builtin/checkout.c:1028
msgid "You are on a branch yet to be born"
@@ -3547,7 +3544,7 @@ msgstr "tham chiếu không hợp lệ: %s"
#: builtin/checkout.c:1003
#, c-format
msgid "reference is not a tree: %s"
-msgstr "tham chiếu không phải là một cây (tree):%s"
+msgstr "tham chiếu không phải là một cây:%s"
#: builtin/checkout.c:1042
msgid "paths cannot be used with switching branches"
@@ -3592,7 +3589,7 @@ msgstr "rá»i bá» HEAD tại lần chuyển giao danh nghÄ©a"
#: builtin/checkout.c:1097
msgid "set upstream info for new branch"
-msgstr "đặt thông tin thượng nguồn (upstream) cho nhánh mới"
+msgstr "đặt thông tin thượng nguồn cho nhánh mới"
#: builtin/checkout.c:1099
msgid "new branch"
@@ -3630,7 +3627,7 @@ msgstr "kiểu"
#: builtin/checkout.c:1108
msgid "conflict style (merge or diff3)"
-msgstr "xung đột kiểu (hòa trộn hay diff3)"
+msgstr "xung đột kiểu (hòa trộn hoặc diff3)"
#: builtin/checkout.c:1111
msgid "do not limit pathspecs to sparse entries only"
@@ -3642,7 +3639,7 @@ msgstr "gợi ý thứ hai “git checkout không-nhánh-nào-nhÆ°-vậyâ€"
#: builtin/checkout.c:1136
msgid "-b, -B and --orphan are mutually exclusive"
-msgstr "Tùy chá»n -b, -B và --orphan loại từ lẫn nhau"
+msgstr "Các tùy chá»n -b, -B và --orphan loại từ lẫn nhau"
#: builtin/checkout.c:1153
msgid "--track needs a branch name"
@@ -4111,7 +4108,7 @@ msgstr "Không biết làm cách nào để nhân bản (clone) %s"
#: builtin/clone.c:957 builtin/clone.c:965
#, c-format
msgid "Remote branch %s not found in upstream %s"
-msgstr "Nhánh máy chủ %s không tìm thấy trong thượng nguồn (upstream) %s"
+msgstr "Nhánh máy chủ %s không tìm thấy trong thượng nguồn %s"
#: builtin/clone.c:968
msgid "You appear to have cloned an empty repository."
@@ -5289,8 +5286,8 @@ msgstr "(không)"
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr ""
-"Từ chối việc lấy (fetch) vào trong nhánh hiện tại %s của một kho chứa không "
-"phải kho trần (bare)"
+"Từ chối việc lấy vào trong nhánh hiện tại %s của một kho chứa không phải kho "
+"trần (bare)"
#: builtin/fetch.c:794
#, c-format
@@ -5357,11 +5354,12 @@ msgstr "Việc lấy vá» cả má»™t nhóm và chỉ định refspecs không há»
#: builtin/fmt-merge-msg.c:13
msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
msgstr ""
-"git fmt-merge-msg [-m <thông điệp>] [--log[=<n>]|--no-log] [--file <tập-tin>]"
+"git fmt-merge-msg [-m <chú_thích>] [--log[=<n>]|--no-log] [--file <tập-tin>]"
#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:702
-#: builtin/merge.c:196 builtin/show-branch.c:654 builtin/show-ref.c:178
-#: builtin/tag.c:446 parse-options.h:135 parse-options.h:242
+#: builtin/merge.c:196 builtin/repack.c:160 builtin/repack.c:164
+#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:446
+#: parse-options.h:135 parse-options.h:242
msgid "n"
msgstr "n"
@@ -6322,17 +6320,17 @@ msgstr "chỉ ra cái mà kho git được chia sẻ giữa nhiá»u ngÆ°á»i dù
msgid "be quiet"
msgstr "im lặng"
-#: builtin/init-db.c:522 builtin/init-db.c:529
+#: builtin/init-db.c:525 builtin/init-db.c:530
#, c-format
msgid "cannot mkdir %s"
msgstr "không thể mkdir (tạo thư mục): %s"
-#: builtin/init-db.c:533
+#: builtin/init-db.c:534
#, c-format
msgid "cannot chdir to %s"
msgstr "không thể chdir (chuyển đổi thư mục) sang %s"
-#: builtin/init-db.c:555
+#: builtin/init-db.c:556
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -6341,11 +6339,11 @@ msgstr ""
"%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-"
"dir=<thư-mục>)"
-#: builtin/init-db.c:579
+#: builtin/init-db.c:580
msgid "Cannot access current working directory"
msgstr "Không thể truy cập thư mục làm việc hiện hành"
-#: builtin/init-db.c:586
+#: builtin/init-db.c:587
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "không thể truy cập cây (tree) làm việc “%sâ€"
@@ -6875,7 +6873,7 @@ msgstr "Hoàn thành SQUASH_MSG"
#: builtin/merge.c:396
#, c-format
msgid "No merge message -- not updating HEAD\n"
-msgstr "Không thông điệp hòa trộn -- không cập nhật HEAD\n"
+msgstr "Không có lá»i chú thích hòa trá»™n -- nên không cập nhật HEAD\n"
#: builtin/merge.c:446
#, c-format
@@ -7879,7 +7877,7 @@ msgid ""
" git push %s %s\n"
"%s"
msgstr ""
-"Nhánh thượng nguồn (upstream) của nhánh hiện tại của bạn không khớp\n"
+"Nhánh thượng nguồn của nhánh hiện tại của bạn không khớp\n"
"vá»›i tên của nhánh hiện tại của bạn. Äể push đến nhánh thượng nguồn\n"
"trên máy chủ, sử dụng\n"
"\n"
@@ -7913,7 +7911,7 @@ msgid ""
"\n"
" git push --set-upstream %s %s\n"
msgstr ""
-"Nhánh hiện tại %s không có nhánh thượng nguồn (upstream) nào.\n"
+"Nhánh hiện tại %s không có nhánh thượng nguồn nào.\n"
"Äể push (đẩy lên) nhánh hiện tại và đặt máy chủ này làm thượng nguồn "
"(upstream), sử dụng\n"
"\n"
@@ -7922,8 +7920,7 @@ msgstr ""
#: builtin/push.c:181
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
-msgstr ""
-"Nhánh hiện tại %s có nhiá»u nhánh thượng nguồn (upstream), từ chối push."
+msgstr "Nhánh hiện tại %s có nhiá»u nhánh thượng nguồn, từ chối push."
#: builtin/push.c:184
#, c-format
@@ -8382,16 +8379,15 @@ msgstr "không hiểu tham số máy bản sao (mirror): %s"
#: builtin/remote.c:153
msgid "fetch the remote branches"
-msgstr "lấy vỠ(fetch) các nhánh từ máy chủ"
+msgstr "lấy vỠcác nhánh từ máy chủ"
#: builtin/remote.c:155
msgid "import all tags and associated objects when fetching"
-msgstr ""
-"nhập vào tất cả các đối tượng thẻ và thành phần liên quan khi lấy vỠ(fetch)"
+msgstr "nhập vào tất cả các đối tượng thẻ và thành phần liên quan khi lấy vá»"
#: builtin/remote.c:158
msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "hoặc không lấy vỠ(fetch) bất kỳ thẻ nào (--no-tags)"
+msgstr "hoặc không lấy vỠbất kỳ thẻ nào (--no-tags)"
#: builtin/remote.c:160
msgid "branch(es) to track"
@@ -8618,7 +8614,7 @@ msgstr "* máy chủ %s"
#: builtin/remote.c:1172
#, c-format
msgid " Fetch URL: %s"
-msgstr " URL để lấy vỠ(fetch): %s"
+msgstr " URL để lấy vá»: %s"
#: builtin/remote.c:1173 builtin/remote.c:1318
msgid "(no URL)"
@@ -8824,6 +8820,10 @@ msgstr "vá»›i -A, các đối tượng cÅ© hÆ¡n khoảng thá»i gian này thì k
msgid "size of the window used for delta compression"
msgstr "kích thÆ°á»›c cá»­a sổ được dùng cho nén “deltaâ€"
+#: builtin/repack.c:162 builtin/repack.c:166
+msgid "bytes"
+msgstr "byte"
+
#: builtin/repack.c:163
msgid "same as the above, but limit memory size instead of entries count"
msgstr "giống như trên, nhưng giới hạn kích thước bộ nhớ hay vì số lượng"
@@ -9496,7 +9496,7 @@ msgstr "đầu thẻ (tag) quá lớn."
#: builtin/tag.c:368
msgid "no tag message?"
-msgstr "không có thông điệp (message) cho thẻ (tag)?"
+msgstr "không có chú thích gì cho cho thẻ à?"
#: builtin/tag.c:374
#, c-format
@@ -10521,8 +10521,8 @@ msgid ""
" To provide a message, use git stash save -- '$option'"
msgstr ""
"lá»—i: không hiểu tùy chá»n cho “stash saveâ€: $option\n"
-" Äể dùng thông Ä‘iệp có chứa -- ở đầu, sá»­ dụng git stash save -- \"$option"
-"\""
+" Äể có thể dùng lá»i chú thích có chứa -- ở đầu,\n"
+" dùng git stash save -- \"$option\""
#: git-stash.sh:258
msgid "No local changes to save"
@@ -10542,7 +10542,7 @@ msgstr "Không thể gỡ bỠcác thay đổi cây-làm-việc"
#: git-stash.sh:383
msgid "No stash found."
-msgstr "Không tìm thấy stash nào."
+msgstr "Không tìm thấy lần chuyển giao cất đi (stash) nào."
#: git-stash.sh:390
#, sh-format
@@ -10557,7 +10557,7 @@ msgstr "$reference không phải là tham chiếu hợp lệ"
#: git-stash.sh:424
#, sh-format
msgid "'$args' is not a stash-like commit"
-msgstr "â€$args†không phải là lần chuyển giao kiểu-stash"
+msgstr "“$args†không phải là lần chuyển giao kiểu-stash (cất đi)"
#: git-stash.sh:435
#, sh-format
@@ -10816,12 +10816,12 @@ msgstr ""
#: git-submodule.sh:856
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
-msgstr "Không thể lấy vá» (fetch) trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€"
+msgstr "Không thể lấy vá» trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€"
#: git-submodule.sh:880
#, sh-format
msgid "Unable to fetch in submodule path '$displaypath'"
-msgstr "Không thể lấy vá» (fetch) trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
+msgstr "Không thể lấy vá» trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
#: git-submodule.sh:894
#, sh-format
@@ -10982,8 +10982,7 @@ msgstr "Url Mô-Ä‘un-con đồng bá»™ hóa cho “$displaypathâ€"
#~ msgstr "hiển thị tham chiếu của HEAD"
#~ msgid "Unable to fetch in submodule path '$prefix$sm_path'"
-#~ msgstr ""
-#~ "Không thể lấy vá» (fetch) trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$prefix$sm_pathâ€"
+#~ msgstr "Không thể lấy vá» trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$prefix$sm_pathâ€"
#~ msgid "Failed to recurse into submodule path '$prefix$sm_path'"
#~ msgstr "Gặp lá»—i khi đệ quy vào trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$prefix$sm_pathâ€"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index dcbe13d10c..0942835711 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -12,8 +12,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2014-01-18 07:42+0800\n"
-"PO-Revision-Date: 2014-01-18 10:54+0800\n"
+"POT-Creation-Date: 2014-02-01 08:06+0800\n"
+"PO-Revision-Date: 2014-02-03 10:53+0800\n"
"Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n"
"Language-Team: GitHub <https://github.com/gotgit/git/>\n"
"Language: zh_CN\n"
@@ -1320,21 +1320,21 @@ msgstr ""
"å¯èƒ½éœ€è¦åˆ é™¤å®ƒä»¬ã€‚用 \"git config advice.objectNameWarning false\"\n"
"命令关闭本消æ¯é€šçŸ¥ã€‚"
-#: sha1_name.c:1109
+#: sha1_name.c:1070
msgid "HEAD does not point to a branch"
msgstr "HEAD 没有指å‘一个分支"
-#: sha1_name.c:1112
+#: sha1_name.c:1073
#, c-format
msgid "No such branch: '%s'"
msgstr "没有此分支:'%s'"
-#: sha1_name.c:1114
+#: sha1_name.c:1075
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "尚未给分支 '%s' 设置上游"
-#: sha1_name.c:1118
+#: sha1_name.c:1079
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "上游分支 '%s' 没有存储为一个远程跟踪分支"
@@ -1622,7 +1622,7 @@ msgstr " (使用 \"git commit\" 结æŸåˆå¹¶ï¼‰"
#: wt-status.c:918
msgid "You are in the middle of an am session."
-msgstr "您正处于一个 am 过程中。"
+msgstr "您正处于 am æ“作过程中。"
#: wt-status.c:921
msgid "The current patch is empty."
@@ -1646,11 +1646,11 @@ msgstr " (使用 \"git am --abort\" æ¢å¤åŽŸæœ‰åˆ†æ”¯ï¼‰"
#: wt-status.c:989 wt-status.c:1006
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
-msgstr "您正在将分支 '%s' å˜åŸºåˆ° '%s'。"
+msgstr "您在执行将分支 '%s' å˜åŸºåˆ° '%s' çš„æ“作。"
#: wt-status.c:994 wt-status.c:1011
msgid "You are currently rebasing."
-msgstr "您正在å˜åŸºã€‚"
+msgstr "您在执行å˜åŸºæ“作。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
#: wt-status.c:997
@@ -1676,11 +1676,11 @@ msgstr " (所有冲çªå·²è§£å†³ï¼šè¿è¡Œ \"git rebase --continue\")"
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
-msgstr "您正在将分支 '%s' å˜åŸºåˆ° '%s' 过程中拆分一个æ交。"
+msgstr "您在执行将分支 '%s' å˜åŸºåˆ° '%s' çš„æ“作时拆分æ交。"
#: wt-status.c:1023
msgid "You are currently splitting a commit during a rebase."
-msgstr "您正在å˜åŸºè¿‡ç¨‹ä¸­æ‹†åˆ†ä¸€ä¸ªæ交。"
+msgstr "您在执行å˜åŸºæ“作时拆分æ交。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
#: wt-status.c:1026
@@ -1690,11 +1690,11 @@ msgstr " (一旦您工作目录æ交干净åŽï¼Œè¿è¡Œ \"git rebase --contin
#: wt-status.c:1030
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
-msgstr "您正在将分支 '%s' å˜åŸºåˆ° '%s' 过程中编辑一个æ交。"
+msgstr "您在执行将分支 '%s' å˜åŸºåˆ° '%s' çš„æ“作时编辑æ交。"
#: wt-status.c:1035
msgid "You are currently editing a commit during a rebase."
-msgstr "您正在å˜åŸºè¿‡ç¨‹ä¸­ç¼–辑一个æ交。"
+msgstr "您在执行å˜åŸºæ“作时编辑æ交。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
#: wt-status.c:1038
@@ -1710,7 +1710,7 @@ msgstr " (当您对您的修改满æ„åŽæ‰§è¡Œ \"git rebase --continue\")"
#: wt-status.c:1050
#, c-format
msgid "You are currently cherry-picking commit %s."
-msgstr "您正在åšæ‹£é€‰æ交 %s。"
+msgstr "您在执行拣选æ交 %s çš„æ“作。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
#: wt-status.c:1055
@@ -1730,7 +1730,7 @@ msgstr " (使用 \"git cherry-pick --abort\" 以å–消拣选æ“作)"
#: wt-status.c:1069
#, c-format
msgid "You are currently reverting commit %s."
-msgstr "您正在å转æ交 %s 。"
+msgstr "您在执行å转æ交 %s çš„æ“作。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
#: wt-status.c:1074
@@ -1750,11 +1750,11 @@ msgstr " (使用 \"git revert --abort\" 以å–消å转æ交æ“作)"
#: wt-status.c:1090
#, c-format
msgid "You are currently bisecting, started from branch '%s'."
-msgstr "您正在从分支 '%s' 开始åšäºŒåˆ†æŸ¥æ‰¾ã€‚"
+msgstr "您在执行从分支 '%s' 开始的二分查找æ“作。"
#: wt-status.c:1094
msgid "You are currently bisecting."
-msgstr "您正在åšäºŒåˆ†æŸ¥æ‰¾ã€‚"
+msgstr "您在执行二分查找æ“作。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
#: wt-status.c:1097
@@ -1767,7 +1767,7 @@ msgstr "ä½äºŽåˆ†æ”¯ "
#: wt-status.c:1279
msgid "rebase in progress; onto "
-msgstr "å˜åŸºæ­£åœ¨è¿›è¡Œä¸­ï¼›è‡³ "
+msgstr "å˜åŸºæ“作正在进行中;至 "
#: wt-status.c:1286
msgid "HEAD detached at "
@@ -5254,8 +5254,9 @@ msgstr ""
"git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:702
-#: builtin/merge.c:196 builtin/show-branch.c:654 builtin/show-ref.c:178
-#: builtin/tag.c:446 parse-options.h:135 parse-options.h:242
+#: builtin/merge.c:196 builtin/repack.c:160 builtin/repack.c:164
+#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:446
+#: parse-options.h:135 parse-options.h:242
msgid "n"
msgstr "n"
@@ -6211,17 +6212,17 @@ msgstr "指定 git 版本库是多个用户之间共享的"
msgid "be quiet"
msgstr "ä¿æŒå®‰é™"
-#: builtin/init-db.c:522 builtin/init-db.c:529
+#: builtin/init-db.c:525 builtin/init-db.c:530
#, c-format
msgid "cannot mkdir %s"
msgstr "ä¸èƒ½åˆ›å»ºç›®å½• %s"
-#: builtin/init-db.c:533
+#: builtin/init-db.c:534
#, c-format
msgid "cannot chdir to %s"
msgstr "ä¸èƒ½åˆ‡æ¢ç›®å½•åˆ° %s"
-#: builtin/init-db.c:555
+#: builtin/init-db.c:556
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -6230,11 +6231,11 @@ msgstr ""
"ä¸å…许 %s(或 --work-tree=<directory>)而没有指定 %s(或 --git-"
"dir=<directory>)"
-#: builtin/init-db.c:579
+#: builtin/init-db.c:580
msgid "Cannot access current working directory"
msgstr "ä¸èƒ½è®¿é—®å½“å‰å·¥ä½œç›®å½•"
-#: builtin/init-db.c:586
+#: builtin/init-db.c:587
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "ä¸èƒ½è®¿é—®å·¥ä½œåŒº '%s'"
@@ -8641,6 +8642,10 @@ msgstr "使用 -A,ä¸è¦å°†æ—©äºŽç»™å®šæ—¶é—´çš„对象过期"
msgid "size of the window used for delta compression"
msgstr "用于增é‡åŽ‹ç¼©çš„窗å£å€¼"
+#: builtin/repack.c:162 builtin/repack.c:166
+msgid "bytes"
+msgstr "字节"
+
#: builtin/repack.c:163
msgid "same as the above, but limit memory size instead of entries count"
msgstr "和上é¢çš„相似,但é™åˆ¶å†…存大å°è€Œéžæ¡ç›®æ•°"
@@ -10114,7 +10119,7 @@ msgstr ""
#: git-rebase.sh:201
msgid "The pre-rebase hook refused to rebase."
-msgstr "é’©å­ pre-rebase æ‹’ç»å˜åŸºã€‚"
+msgstr "é’©å­ pre-rebase æ‹’ç»å˜åŸºæ“作。"
#: git-rebase.sh:206
msgid "It looks like git-am is in progress. Cannot rebase."
@@ -10161,12 +10166,12 @@ msgid ""
"and run me again. I am stopping in case you still have something\n"
"valuable there."
msgstr ""
-"好åƒå·²æœ‰ä¸€ä¸ª $state_dir_base 目录,我怀疑您正处于å¦å¤–一个å˜åŸºè¿‡ç¨‹ä¸­ã€‚\n"
-"如果是这样,请å°è¯•æ‰§è¡Œ\n"
+"好åƒå·²æœ‰ $state_dir_base 目录,我怀疑您正处于å¦å¤–一个å˜åŸºæ“作\n"
+"过程中。 如果是这样,请执行\n"
"\t$cmd_live_rebase\n"
"如果ä¸æ˜¯è¿™æ ·ï¼Œè¯·æ‰§è¡Œ\n"
"\t$cmd_clear_stale_rebase\n"
-"然åŽå†é‡æ–°æ‰§è¡Œå˜åŸºã€‚为é¿å…您丢失é‡è¦æ•°æ®ï¼Œæˆ‘å·²ç»åœæ­¢å½“å‰æ“作。"
+"然åŽå†é‡æ–°æ‰§è¡Œå˜åŸºæ“作。 为é¿å…丢失é‡è¦æ•°æ®ï¼Œæˆ‘å·²ç»åœæ­¢å½“å‰æ“作。"
#: git-rebase.sh:456
#, sh-format
diff --git a/preload-index.c b/preload-index.c
index 8c44ceb2c7..968ee25eae 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -3,6 +3,7 @@
*/
#include "cache.h"
#include "pathspec.h"
+#include "dir.h"
#ifdef NO_PTHREADS
static void preload_index(struct index_state *index,
@@ -53,7 +54,7 @@ static void *preload_thread(void *_data)
continue;
if (ce_uptodate(ce))
continue;
- if (!ce_path_match(ce, &p->pathspec))
+ if (!ce_path_match(ce, &p->pathspec, NULL))
continue;
if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
continue;
diff --git a/read-cache.c b/read-cache.c
index 33dd676ccb..fb440b4d9d 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -15,7 +15,8 @@
#include "strbuf.h"
#include "varint.h"
-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
+ unsigned int options);
/* Mask for the name length in ce_flags in the on-disk index */
@@ -47,6 +48,7 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
struct cache_entry *old = istate->cache[nr];
remove_name_hash(istate, old);
+ free(old);
set_index_entry(istate, nr, ce);
istate->cache_changed = 1;
}
@@ -58,7 +60,7 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
new = xmalloc(cache_entry_size(namelen));
copy_cache_entry(new, old);
- new->ce_flags &= ~CE_STATE_MASK;
+ new->ce_flags &= ~CE_HASHED;
new->ce_namelen = namelen;
memcpy(new->name, new_name, namelen + 1);
@@ -478,6 +480,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
record_resolve_undo(istate, ce);
remove_name_hash(istate, ce);
+ free(ce);
istate->cache_changed = 1;
istate->cache_nr--;
if (pos >= istate->cache_nr)
@@ -499,8 +502,10 @@ void remove_marked_cache_entries(struct index_state *istate)
unsigned int i, j;
for (i = j = 0; i < istate->cache_nr; i++) {
- if (ce_array[i]->ce_flags & CE_REMOVE)
+ if (ce_array[i]->ce_flags & CE_REMOVE) {
remove_name_hash(istate, ce_array[i]);
+ free(ce_array[i]);
+ }
else
ce_array[j++] = ce_array[i];
}
@@ -579,7 +584,7 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
return new;
}
-static void record_intent_to_add(struct cache_entry *ce)
+void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
{
unsigned char sha1[20];
if (write_sha1_file("", 0, blob_type, sha1))
@@ -665,7 +670,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
return error("unable to index file %s", path);
} else
- record_intent_to_add(ce);
+ set_object_name_for_intent_to_add_entry(ce);
if (ignore_case && alias && different_name(ce, alias))
ce = create_alias_ce(ce, alias);
@@ -696,7 +701,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)
struct cache_entry *make_cache_entry(unsigned int mode,
const unsigned char *sha1, const char *path, int stage,
- int refresh)
+ unsigned int refresh_options)
{
int size, len;
struct cache_entry *ce;
@@ -716,10 +721,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,
ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
- if (refresh)
- return refresh_cache_entry(ce, 0);
-
- return ce;
+ return refresh_cache_entry(ce, refresh_options);
}
int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
@@ -728,11 +730,6 @@ int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
}
-int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)
-{
- return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL);
-}
-
/*
* We fundamentally don't like some paths: we don't want
* dot or dot-dot anywhere, and for obvious reasons don't
@@ -1029,10 +1026,12 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
struct stat st;
struct cache_entry *updated;
int changed, size;
+ int refresh = options & CE_MATCH_REFRESH;
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
+ int ignore_missing = options & CE_MATCH_IGNORE_MISSING;
- if (ce_uptodate(ce))
+ if (!refresh || ce_uptodate(ce))
return ce;
/*
@@ -1050,6 +1049,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
}
if (lstat(ce->name, &st) < 0) {
+ if (ignore_missing && errno == ENOENT)
+ return ce;
if (err)
*err = errno;
return NULL;
@@ -1127,7 +1128,9 @@ int refresh_index(struct index_state *istate, unsigned int flags,
int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
int first = 1;
int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
- unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
+ unsigned int options = (CE_MATCH_REFRESH |
+ (really ? CE_MATCH_IGNORE_VALID : 0) |
+ (not_new ? CE_MATCH_IGNORE_MISSING : 0));
const char *modified_fmt;
const char *deleted_fmt;
const char *typechange_fmt;
@@ -1149,8 +1152,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
continue;
- if (pathspec &&
- !match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen))
+ if (pathspec && !ce_path_match(ce, pathspec, seen))
filtered = 1;
if (ce_stage(ce)) {
@@ -1176,8 +1178,6 @@ int refresh_index(struct index_state *istate, unsigned int flags,
if (!new) {
const char *fmt;
- if (not_new && cache_errno == ENOENT)
- continue;
if (really && cache_errno == EINVAL) {
/* If we are doing --really-refresh that
* means the index is not valid anymore.
@@ -1207,9 +1207,10 @@ int refresh_index(struct index_state *istate, unsigned int flags,
return has_errors;
}
-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
+ unsigned int options)
{
- return refresh_cache_ent(&the_index, ce, really, NULL, NULL);
+ return refresh_cache_ent(&the_index, ce, options, NULL, NULL);
}
@@ -1313,26 +1314,6 @@ int read_index(struct index_state *istate)
return read_index_from(istate, get_index_file());
}
-#ifndef NEEDS_ALIGNED_ACCESS
-#define ntoh_s(var) ntohs(var)
-#define ntoh_l(var) ntohl(var)
-#else
-static inline uint16_t ntoh_s_force_align(void *p)
-{
- uint16_t x;
- memcpy(&x, p, sizeof(x));
- return ntohs(x);
-}
-static inline uint32_t ntoh_l_force_align(void *p)
-{
- uint32_t x;
- memcpy(&x, p, sizeof(x));
- return ntohl(x);
-}
-#define ntoh_s(var) ntoh_s_force_align(&(var))
-#define ntoh_l(var) ntoh_l_force_align(&(var))
-#endif
-
static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
unsigned int flags,
const char *name,
@@ -1340,16 +1321,16 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on
{
struct cache_entry *ce = xmalloc(cache_entry_size(len));
- ce->ce_stat_data.sd_ctime.sec = ntoh_l(ondisk->ctime.sec);
- ce->ce_stat_data.sd_mtime.sec = ntoh_l(ondisk->mtime.sec);
- ce->ce_stat_data.sd_ctime.nsec = ntoh_l(ondisk->ctime.nsec);
- ce->ce_stat_data.sd_mtime.nsec = ntoh_l(ondisk->mtime.nsec);
- ce->ce_stat_data.sd_dev = ntoh_l(ondisk->dev);
- ce->ce_stat_data.sd_ino = ntoh_l(ondisk->ino);
- ce->ce_mode = ntoh_l(ondisk->mode);
- ce->ce_stat_data.sd_uid = ntoh_l(ondisk->uid);
- ce->ce_stat_data.sd_gid = ntoh_l(ondisk->gid);
- ce->ce_stat_data.sd_size = ntoh_l(ondisk->size);
+ ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
+ ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
+ ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
+ ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
+ ce->ce_stat_data.sd_dev = get_be32(&ondisk->dev);
+ ce->ce_stat_data.sd_ino = get_be32(&ondisk->ino);
+ ce->ce_mode = get_be32(&ondisk->mode);
+ ce->ce_stat_data.sd_uid = get_be32(&ondisk->uid);
+ ce->ce_stat_data.sd_gid = get_be32(&ondisk->gid);
+ ce->ce_stat_data.sd_size = get_be32(&ondisk->size);
ce->ce_flags = flags & ~CE_NAMEMASK;
ce->ce_namelen = len;
hashcpy(ce->sha1, ondisk->sha1);
@@ -1389,14 +1370,14 @@ static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
unsigned int flags;
/* On-disk flags are just 16 bits */
- flags = ntoh_s(ondisk->flags);
+ flags = get_be16(&ondisk->flags);
len = flags & CE_NAMEMASK;
if (flags & CE_EXTENDED) {
struct ondisk_cache_entry_extended *ondisk2;
int extended_flags;
ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
- extended_flags = ntoh_s(ondisk2->flags2) << 16;
+ extended_flags = get_be16(&ondisk2->flags2) << 16;
/* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
if (extended_flags & ~CE_EXTENDED_FLAGS)
die("Unknown index entry format %08x", extended_flags);
@@ -1894,7 +1875,7 @@ int read_index_unmerged(struct index_state *istate)
new_ce->ce_mode = ce->ce_mode;
if (add_index_entry(istate, new_ce, 0))
return error("%s: cannot drop to stage #0",
- ce->name);
+ new_ce->name);
i = index_name_pos(istate, new_ce->name, len);
}
return unmerged;
diff --git a/rerere.c b/rerere.c
index 1f2d21a72f..d55aa8a01b 100644
--- a/rerere.c
+++ b/rerere.c
@@ -672,8 +672,8 @@ int rerere_forget(struct pathspec *pathspec)
find_conflict(&conflict);
for (i = 0; i < conflict.nr; i++) {
struct string_list_item *it = &conflict.items[i];
- if (!match_pathspec_depth(pathspec, it->string, strlen(it->string),
- 0, NULL))
+ if (!match_pathspec(pathspec, it->string,
+ strlen(it->string), 0, NULL, 0))
continue;
rerere_forget_one_path(it->string, &merge_rr);
}
diff --git a/resolve-undo.c b/resolve-undo.c
index c09b00664e..44c697c36d 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -119,6 +119,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
struct string_list_item *item;
struct resolve_undo_info *ru;
int i, err = 0, matched;
+ char *name;
if (!istate->resolve_undo)
return pos;
@@ -138,20 +139,22 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
if (!ru)
return pos;
matched = ce->ce_flags & CE_MATCHED;
+ name = xstrdup(ce->name);
remove_index_entry_at(istate, pos);
for (i = 0; i < 3; i++) {
struct cache_entry *nce;
if (!ru->mode[i])
continue;
nce = make_cache_entry(ru->mode[i], ru->sha1[i],
- ce->name, i + 1, 0);
+ name, i + 1, 0);
if (matched)
nce->ce_flags |= CE_MATCHED;
if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
err = 1;
- error("cannot unmerge '%s'", ce->name);
+ error("cannot unmerge '%s'", name);
}
}
+ free(name);
if (err)
return pos;
free(ru);
@@ -182,7 +185,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
for (i = 0; i < istate->cache_nr; i++) {
const struct cache_entry *ce = istate->cache[i];
- if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
+ if (!ce_path_match(ce, pathspec, NULL))
continue;
i = unmerge_index_entry_at(istate, i);
}
diff --git a/revision.c b/revision.c
index 7f61ecde8c..bd027bc015 100644
--- a/revision.c
+++ b/revision.c
@@ -16,6 +16,7 @@
#include "line-log.h"
#include "mailmap.h"
#include "commit-slab.h"
+#include "dir.h"
volatile show_early_output_fn_t show_early_output;
@@ -773,6 +774,10 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
return 0;
commit->object.flags |= ADDED;
+ if (revs->include_check &&
+ !revs->include_check(commit, revs->include_check_data))
+ return 0;
+
/*
* If the commit is uninteresting, don't try to
* prune parents - we want the maximal uninteresting
@@ -1390,7 +1395,7 @@ static void prepare_show_merge(struct rev_info *revs)
const struct cache_entry *ce = active_cache[i];
if (!ce_stage(ce))
continue;
- if (ce_path_match(ce, &revs->prune_data)) {
+ if (ce_path_match(ce, &revs->prune_data, NULL)) {
prune_num++;
prune = xrealloc(prune, sizeof(*prune) * prune_num);
prune[prune_num-2] = ce->name;
diff --git a/revision.h b/revision.h
index 88967d6a24..1eb94c1548 100644
--- a/revision.h
+++ b/revision.h
@@ -172,6 +172,8 @@ struct rev_info {
unsigned long min_age;
int min_parents;
int max_parents;
+ int (*include_check)(struct commit *, void *);
+ void *include_check_data;
/* diff info for patches and for paths limiting */
struct diff_options diffopt;
diff --git a/sequencer.c b/sequencer.c
index 90cac7b02e..bde5f047b0 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -392,11 +392,18 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
{
struct argv_array array;
int rc;
+ char *gpg_sign;
argv_array_init(&array);
argv_array_push(&array, "commit");
argv_array_push(&array, "-n");
+ if (opts->gpg_sign) {
+ gpg_sign = xmalloc(3 + strlen(opts->gpg_sign));
+ sprintf(gpg_sign, "-S%s", opts->gpg_sign);
+ argv_array_push(&array, gpg_sign);
+ free(gpg_sign);
+ }
if (opts->signoff)
argv_array_push(&array, "-s");
if (!opts->edit) {
@@ -808,6 +815,8 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
opts->mainline = git_config_int(key, value);
else if (!strcmp(key, "options.strategy"))
git_config_string(&opts->strategy, key, value);
+ else if (!strcmp(key, "options.gpg-sign"))
+ git_config_string(&opts->gpg_sign, key, value);
else if (!strcmp(key, "options.strategy-option")) {
ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
opts->xopts[opts->xopts_nr++] = xstrdup(value);
@@ -981,6 +990,8 @@ static void save_opts(struct replay_opts *opts)
}
if (opts->strategy)
git_config_set_in_file(opts_file, "options.strategy", opts->strategy);
+ if (opts->gpg_sign)
+ git_config_set_in_file(opts_file, "options.gpg-sign", opts->gpg_sign);
if (opts->xopts) {
int i;
for (i = 0; i < opts->xopts_nr; i++)
diff --git a/sequencer.h b/sequencer.h
index 1fc22dcabe..db43e9cf86 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -37,6 +37,8 @@ struct replay_opts {
int mainline;
+ const char *gpg_sign;
+
/* Merge strategy */
const char *strategy;
const char **xopts;
diff --git a/setup.c b/setup.c
index 6c3f85ff7a..cffb6d605e 100644
--- a/setup.c
+++ b/setup.c
@@ -6,6 +6,70 @@ static int inside_git_dir = -1;
static int inside_work_tree = -1;
/*
+ * The input parameter must contain an absolute path, and it must already be
+ * normalized.
+ *
+ * Find the part of an absolute path that lies inside the work tree by
+ * dereferencing symlinks outside the work tree, for example:
+ * /dir1/repo/dir2/file (work tree is /dir1/repo) -> dir2/file
+ * /dir/file (work tree is /) -> dir/file
+ * /dir/symlink1/symlink2 (symlink1 points to work tree) -> symlink2
+ * /dir/repolink/file (repolink points to /dir/repo) -> file
+ * /dir/repo (exactly equal to work tree) -> (empty string)
+ */
+static int abspath_part_inside_repo(char *path)
+{
+ size_t len;
+ size_t wtlen;
+ char *path0;
+ int off;
+ const char *work_tree = get_git_work_tree();
+
+ if (!work_tree)
+ return -1;
+ wtlen = strlen(work_tree);
+ len = strlen(path);
+ off = 0;
+
+ /* check if work tree is already the prefix */
+ if (wtlen <= len && !strncmp(path, work_tree, wtlen)) {
+ if (path[wtlen] == '/') {
+ memmove(path, path + wtlen + 1, len - wtlen);
+ return 0;
+ } else if (path[wtlen - 1] == '/' || path[wtlen] == '\0') {
+ /* work tree is the root, or the whole path */
+ memmove(path, path + wtlen, len - wtlen + 1);
+ return 0;
+ }
+ /* work tree might match beginning of a symlink to work tree */
+ off = wtlen;
+ }
+ path0 = path;
+ path += offset_1st_component(path) + off;
+
+ /* check each '/'-terminated level */
+ while (*path) {
+ path++;
+ if (*path == '/') {
+ *path = '\0';
+ if (strcmp(real_path(path0), work_tree) == 0) {
+ memmove(path0, path + 1, len - (path - path0));
+ return 0;
+ }
+ *path = '/';
+ }
+ }
+
+ /* check whole path */
+ if (strcmp(real_path(path0), work_tree) == 0) {
+ *path0 = '\0';
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
* Normalize "path", prepending the "prefix" for relative paths. If
* remaining_prefix is not NULL, return the actual prefix still
* remains in the path. For example, prefix = sub1/sub2/ and path is
@@ -22,11 +86,17 @@ char *prefix_path_gently(const char *prefix, int len,
const char *orig = path;
char *sanitized;
if (is_absolute_path(orig)) {
- const char *temp = real_path(path);
- sanitized = xmalloc(len + strlen(temp) + 1);
- strcpy(sanitized, temp);
+ sanitized = xmalloc(strlen(path) + 1);
if (remaining_prefix)
*remaining_prefix = 0;
+ if (normalize_path_copy_len(sanitized, path, remaining_prefix)) {
+ free(sanitized);
+ return NULL;
+ }
+ if (abspath_part_inside_repo(sanitized)) {
+ free(sanitized);
+ return NULL;
+ }
} else {
sanitized = xmalloc(len + strlen(path) + 1);
if (len)
@@ -34,26 +104,10 @@ char *prefix_path_gently(const char *prefix, int len,
strcpy(sanitized + len, path);
if (remaining_prefix)
*remaining_prefix = len;
- }
- if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))
- goto error_out;
- if (is_absolute_path(orig)) {
- size_t root_len, len, total;
- const char *work_tree = get_git_work_tree();
- if (!work_tree)
- goto error_out;
- len = strlen(work_tree);
- root_len = offset_1st_component(work_tree);
- total = strlen(sanitized) + 1;
- if (strncmp(sanitized, work_tree, len) ||
- (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
- error_out:
+ if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix)) {
free(sanitized);
return NULL;
}
- if (sanitized[len] == '/')
- len++;
- memmove(sanitized, sanitized + len, total - len);
}
return sanitized;
}
diff --git a/sha1_file.c b/sha1_file.c
index 6e8c05d108..019628add5 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -252,8 +252,6 @@ char *sha1_pack_index_name(const unsigned char *sha1)
struct alternate_object_database *alt_odb_list;
static struct alternate_object_database **alt_odb_tail;
-static int git_open_noatime(const char *name);
-
/*
* Prepare alternate object database registry.
*
@@ -1232,6 +1230,7 @@ static void prepare_packed_git_one(char *objdir, int local)
if (has_extension(de->d_name, ".idx") ||
has_extension(de->d_name, ".pack") ||
+ has_extension(de->d_name, ".bitmap") ||
has_extension(de->d_name, ".keep"))
string_list_append(&garbage, path);
else
@@ -1316,7 +1315,6 @@ void prepare_packed_git(void)
void reprepare_packed_git(void)
{
- discard_revindex();
prepare_packed_git_run_once = 0;
prepare_packed_git();
}
@@ -1393,7 +1391,7 @@ int check_sha1_signature(const unsigned char *sha1, void *map,
return hashcmp(sha1, real_sha1) ? -1 : 0;
}
-static int git_open_noatime(const char *name)
+int git_open_noatime(const char *name)
{
static int sha1_file_open_flag = O_NOATIME;
diff --git a/submodule.c b/submodule.c
index 613857e400..b80ecacf60 100644
--- a/submodule.c
+++ b/submodule.c
@@ -116,30 +116,7 @@ int remove_path_from_gitmodules(const char *path)
void stage_updated_gitmodules(void)
{
- struct strbuf buf = STRBUF_INIT;
- struct stat st;
- int pos;
- struct cache_entry *ce;
- int namelen = strlen(".gitmodules");
-
- pos = cache_name_pos(".gitmodules", namelen);
- if (pos < 0) {
- warning(_("could not find .gitmodules in index"));
- return;
- }
- ce = active_cache[pos];
- ce->ce_flags = namelen;
- if (strbuf_read_file(&buf, ".gitmodules", 0) < 0)
- die(_("reading updated .gitmodules failed"));
- if (lstat(".gitmodules", &st) < 0)
- die_errno(_("unable to stat updated .gitmodules"));
- fill_stat_cache_info(ce, &st);
- ce->ce_mode = ce_mode_from_stat(ce, st.st_mode);
- if (remove_cache_entry_at(pos) < 0)
- die(_("unable to remove .gitmodules from index"));
- if (write_sha1_file(buf.buf, buf.len, blob_type, ce->sha1))
- die(_("adding updated .gitmodules failed"));
- if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
+ if (add_file_to_cache(".gitmodules", 0))
die(_("staging updated .gitmodules failed"));
}
diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh
index 394b06b32f..1f22de260a 100644
--- a/t/lib-git-daemon.sh
+++ b/t/lib-git-daemon.sh
@@ -22,7 +22,7 @@ then
test_done
fi
-LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-'8121'}
+LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-${this_test#t}}
GIT_DAEMON_PID=
GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index bfdff2a8c9..b43162ea2a 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -64,7 +64,7 @@ case $(uname) in
esac
LIB_HTTPD_PATH=${LIB_HTTPD_PATH-"$DEFAULT_HTTPD_PATH"}
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'8111'}
+LIB_HTTPD_PORT=${LIB_HTTPD_PORT-${this_test#t}}
TEST_PATH="$TEST_DIRECTORY"/lib-httpd
HTTPD_ROOT_PATH="$PWD"/httpd
diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh
new file mode 100755
index 0000000000..685d46f8b7
--- /dev/null
+++ b/t/perf/p5310-pack-bitmaps.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='Tests pack performance using bitmaps'
+. ./perf-lib.sh
+
+test_perf_large_repo
+
+# note that we do everything through config,
+# since we want to be able to compare bitmap-aware
+# git versus non-bitmap git
+test_expect_success 'setup bitmap config' '
+ git config pack.writebitmaps true &&
+ git config pack.writebitmaphashcache true
+'
+
+test_perf 'repack to disk' '
+ git repack -ad
+'
+
+test_perf 'simulated clone' '
+ git pack-objects --stdout --all </dev/null >/dev/null
+'
+
+test_perf 'simulated fetch' '
+ have=$(git rev-list HEAD~100 -1) &&
+ {
+ echo HEAD &&
+ echo ^$have
+ } | git pack-objects --revs --stdout >/dev/null
+'
+
+test_expect_success 'create partial bitmap state' '
+ # pick a commit to represent the repo tip in the past
+ cutoff=$(git rev-list HEAD~100 -1) &&
+ orig_tip=$(git rev-parse HEAD) &&
+
+ # now kill off all of the refs and pretend we had
+ # just the one tip
+ rm -rf .git/logs .git/refs/* .git/packed-refs
+ git update-ref HEAD $cutoff
+
+ # and then repack, which will leave us with a nice
+ # big bitmap pack of the "old" history, and all of
+ # the new history will be loose, as if it had been pushed
+ # up incrementally and exploded via unpack-objects
+ git repack -Ad
+
+ # and now restore our original tip, as if the pushes
+ # had happened
+ git update-ref HEAD $orig_tip
+'
+
+test_perf 'partial bitmap' '
+ git pack-objects --stdout --all </dev/null >/dev/null
+'
+
+test_done
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
new file mode 100755
index 0000000000..391e2b6492
--- /dev/null
+++ b/t/t0011-hashmap.sh
@@ -0,0 +1,240 @@
+#!/bin/sh
+
+test_description='test hashmap and string hash functions'
+. ./test-lib.sh
+
+test_hashmap() {
+ echo "$1" | test-hashmap $3 > actual &&
+ echo "$2" > expect &&
+ test_cmp expect actual
+}
+
+test_expect_success 'hash functions' '
+
+test_hashmap "hash key1" "2215982743 2215982743 116372151 116372151" &&
+test_hashmap "hash key2" "2215982740 2215982740 116372148 116372148" &&
+test_hashmap "hash fooBarFrotz" "1383912807 1383912807 3189766727 3189766727" &&
+test_hashmap "hash foobarfrotz" "2862305959 2862305959 3189766727 3189766727"
+
+'
+
+test_expect_success 'put' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+put foobarfrotz value4
+size" "NULL
+NULL
+NULL
+NULL
+64 4"
+
+'
+
+test_expect_success 'put (case insensitive)' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+size" "NULL
+NULL
+NULL
+64 3" ignorecase
+
+'
+
+test_expect_success 'replace' '
+
+test_hashmap "put key1 value1
+put key1 value2
+put fooBarFrotz value3
+put fooBarFrotz value4
+size" "NULL
+value1
+NULL
+value3
+64 2"
+
+'
+
+test_expect_success 'replace (case insensitive)' '
+
+test_hashmap "put key1 value1
+put Key1 value2
+put fooBarFrotz value3
+put foobarfrotz value4
+size" "NULL
+value1
+NULL
+value3
+64 2" ignorecase
+
+'
+
+test_expect_success 'get' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+put foobarfrotz value4
+get key1
+get key2
+get fooBarFrotz
+get notInMap" "NULL
+NULL
+NULL
+NULL
+value1
+value2
+value3
+NULL"
+
+'
+
+test_expect_success 'get (case insensitive)' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+get Key1
+get keY2
+get foobarfrotz
+get notInMap" "NULL
+NULL
+NULL
+value1
+value2
+value3
+NULL" ignorecase
+
+'
+
+test_expect_success 'add' '
+
+test_hashmap "add key1 value1
+add key1 value2
+add fooBarFrotz value3
+add fooBarFrotz value4
+get key1
+get fooBarFrotz
+get notInMap" "value2
+value1
+value4
+value3
+NULL"
+
+'
+
+test_expect_success 'add (case insensitive)' '
+
+test_hashmap "add key1 value1
+add Key1 value2
+add fooBarFrotz value3
+add foobarfrotz value4
+get key1
+get Foobarfrotz
+get notInMap" "value2
+value1
+value4
+value3
+NULL" ignorecase
+
+'
+
+test_expect_success 'remove' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+remove key1
+remove key2
+remove notInMap
+size" "NULL
+NULL
+NULL
+value1
+value2
+NULL
+64 1"
+
+'
+
+test_expect_success 'remove (case insensitive)' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+remove Key1
+remove keY2
+remove notInMap
+size" "NULL
+NULL
+NULL
+value1
+value2
+NULL
+64 1" ignorecase
+
+'
+
+test_expect_success 'iterate' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+iterate" "NULL
+NULL
+NULL
+key2 value2
+key1 value1
+fooBarFrotz value3"
+
+'
+
+test_expect_success 'iterate (case insensitive)' '
+
+test_hashmap "put key1 value1
+put key2 value2
+put fooBarFrotz value3
+iterate" "NULL
+NULL
+NULL
+fooBarFrotz value3
+key2 value2
+key1 value1" ignorecase
+
+'
+
+test_expect_success 'grow / shrink' '
+
+ rm -f in &&
+ rm -f expect &&
+ for n in $(test_seq 51)
+ do
+ echo put key$n value$n >> in &&
+ echo NULL >> expect
+ done &&
+ echo size >> in &&
+ echo 64 51 >> expect &&
+ echo put key52 value52 >> in &&
+ echo NULL >> expect
+ echo size >> in &&
+ echo 256 52 >> expect &&
+ for n in $(test_seq 12)
+ do
+ echo remove key$n >> in &&
+ echo value$n >> expect
+ done &&
+ echo size >> in &&
+ echo 256 40 >> expect &&
+ echo remove key40 >> in &&
+ echo value40 >> expect &&
+ echo size >> in &&
+ echo 64 39 >> expect &&
+ cat in | test-hashmap > out &&
+ test_cmp expect out
+
+'
+
+test_done
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 07c10c8dca..c0143a0a70 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -190,6 +190,27 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
'
+test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '
+ ln -s target symlink &&
+ test "$(test-path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink"
+'
+
+test_expect_success 'prefix_path works with only absolute path to work tree' '
+ echo "" >expected &&
+ test-path-utils prefix_path prefix "$(pwd)" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'prefix_path rejects absolute path to dir with same beginning as work tree' '
+ test_must_fail test-path-utils prefix_path prefix "$(pwd)a"
+'
+
+test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having same beginning as work tree' '
+ git init repo &&
+ ln -s repo repolink &&
+ test "a" = "$(cd repo && test-path-utils prefix_path prefix "$(pwd)/../repolink/a")"
+'
+
relative_path /foo/a/b/c/ /foo/a/b/ c/
relative_path /foo/a/b/c/ /foo/a/b c/
relative_path /foo/a//b//c/ ///foo/a/b// c/ POSIX
diff --git a/t/t3004-ls-files-basic.sh b/t/t3004-ls-files-basic.sh
index 8d9bc3c2af..9c7adbdbe1 100755
--- a/t/t3004-ls-files-basic.sh
+++ b/t/t3004-ls-files-basic.sh
@@ -36,4 +36,21 @@ test_expect_success 'ls-files -h in corrupt repository' '
test_i18ngrep "[Uu]sage: git ls-files " broken/usage
'
+test_expect_success SYMLINKS 'ls-files with absolute paths to symlinks' '
+ mkdir subs &&
+ ln -s nosuch link &&
+ ln -s ../nosuch subs/link &&
+ git add link subs/link &&
+ git ls-files -s link subs/link >expect &&
+ git ls-files -s "$(pwd)/link" "$(pwd)/subs/link" >actual &&
+ test_cmp expect actual &&
+
+ (
+ cd subs &&
+ git ls-files -s link >../expect &&
+ git ls-files -s "$(pwd)/link" >../actual
+ ) &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index 2f96100a5f..82e18548c3 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -257,6 +257,7 @@ test_expect_success 'setup 8' '
git add e &&
test_tick &&
git commit -m "rename a->e" &&
+ c7=$(git rev-parse --verify HEAD) &&
git checkout rename-ln &&
git mv a e &&
test_ln_s_add e a &&
@@ -517,6 +518,52 @@ test_expect_success 'reset and bind merge' '
'
+test_expect_success 'merge-recursive w/ empty work tree - ours has rename' '
+ (
+ GIT_WORK_TREE="$PWD/ours-has-rename-work" &&
+ export GIT_WORK_TREE &&
+ GIT_INDEX_FILE="$PWD/ours-has-rename-index" &&
+ export GIT_INDEX_FILE &&
+ mkdir "$GIT_WORK_TREE" &&
+ git read-tree -i -m $c7 &&
+ git update-index --ignore-missing --refresh &&
+ git merge-recursive $c0 -- $c7 $c3 &&
+ git ls-files -s >actual-files
+ ) 2>actual-err &&
+ >expected-err &&
+ cat >expected-files <<-EOF &&
+ 100644 $o3 0 b/c
+ 100644 $o0 0 c
+ 100644 $o0 0 d/e
+ 100644 $o0 0 e
+ EOF
+ test_cmp expected-files actual-files &&
+ test_cmp expected-err actual-err
+'
+
+test_expect_success 'merge-recursive w/ empty work tree - theirs has rename' '
+ (
+ GIT_WORK_TREE="$PWD/theirs-has-rename-work" &&
+ export GIT_WORK_TREE &&
+ GIT_INDEX_FILE="$PWD/theirs-has-rename-index" &&
+ export GIT_INDEX_FILE &&
+ mkdir "$GIT_WORK_TREE" &&
+ git read-tree -i -m $c3 &&
+ git update-index --ignore-missing --refresh &&
+ git merge-recursive $c0 -- $c3 $c7 &&
+ git ls-files -s >actual-files
+ ) 2>actual-err &&
+ >expected-err &&
+ cat >expected-files <<-EOF &&
+ 100644 $o3 0 b/c
+ 100644 $o0 0 c
+ 100644 $o0 0 d/e
+ 100644 $o0 0 e
+ EOF
+ test_cmp expected-files actual-files &&
+ test_cmp expected-err actual-err
+'
+
test_expect_success 'merge removes empty directories' '
git reset --hard master &&
diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh
index 9f5659f7fe..2bb973655b 100755
--- a/t/t4010-diff-pathspec.sh
+++ b/t/t4010-diff-pathspec.sh
@@ -140,4 +140,10 @@ test_expect_success 'diff multiple wildcard pathspecs' '
test_cmp expect actual
'
+test_expect_success 'diff-cache ignores trailing slash on submodule path' '
+ git diff --name-only HEAD^ submod >expect &&
+ git diff --name-only HEAD^ submod/ >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4034/ada/expect b/t/t4034/ada/expect
index be2376e904..a682d288b2 100644
--- a/t/t4034/ada/expect
+++ b/t/t4034/ada/expect
@@ -4,7 +4,7 @@
<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,13 +1,13 @@<RESET>
Ada.Text_IO.Put_Line("Hello World<RED>!<RESET><GREEN>?<RESET>");
-1 1e<RED>-<RESET>10 16#FE12#E2 3.141_592 '<RED>x<RESET><GREEN>y<RESET>'
+1 <RED>1e-10<RESET><GREEN>1e10<RESET> 16#FE12#E2 3.141_592 '<RED>x<RESET><GREEN>y<RESET>'
<RED>a<RESET><GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
<RED>a<RESET><GREEN>y<RESET>
<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b<RESET>
diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh
index 231412d100..e8ae2a03fd 100755
--- a/t/t4035-diff-quiet.sh
+++ b/t/t4035-diff-quiet.sh
@@ -148,4 +148,10 @@ test_expect_success 'git diff --ignore-all-space, both files outside repo' '
)
'
+test_expect_success 'git diff --quiet ignores stat-change only entries' '
+ test-chmtime +10 a &&
+ echo modified >>b &&
+ test_expect_code 1 git diff --quiet
+'
+
test_done
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
new file mode 100755
index 0000000000..d3a3afaba8
--- /dev/null
+++ b/t/t5310-pack-bitmaps.sh
@@ -0,0 +1,139 @@
+#!/bin/sh
+
+test_description='exercise basic bitmap functionality'
+. ./test-lib.sh
+
+test_expect_success 'setup repo with moderate-sized history' '
+ for i in $(test_seq 1 10); do
+ test_commit $i
+ done &&
+ git checkout -b other HEAD~5 &&
+ for i in $(test_seq 1 10); do
+ test_commit side-$i
+ done &&
+ git checkout master &&
+ blob=$(echo tagged-blob | git hash-object -w --stdin) &&
+ git tag tagged-blob $blob &&
+ git config pack.writebitmaps true &&
+ git config pack.writebitmaphashcache true
+'
+
+test_expect_success 'full repack creates bitmaps' '
+ git repack -ad &&
+ ls .git/objects/pack/ | grep bitmap >output &&
+ test_line_count = 1 output
+'
+
+test_expect_success 'rev-list --test-bitmap verifies bitmaps' '
+ git rev-list --test-bitmap HEAD
+'
+
+rev_list_tests() {
+ state=$1
+
+ test_expect_success "counting commits via bitmap ($state)" '
+ git rev-list --count HEAD >expect &&
+ git rev-list --use-bitmap-index --count HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "counting partial commits via bitmap ($state)" '
+ git rev-list --count HEAD~5..HEAD >expect &&
+ git rev-list --use-bitmap-index --count HEAD~5..HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "counting non-linear history ($state)" '
+ git rev-list --count other...master >expect &&
+ git rev-list --use-bitmap-index --count other...master >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "enumerate --objects ($state)" '
+ git rev-list --objects --use-bitmap-index HEAD >tmp &&
+ cut -d" " -f1 <tmp >tmp2 &&
+ sort <tmp2 >actual &&
+ git rev-list --objects HEAD >tmp &&
+ cut -d" " -f1 <tmp >tmp2 &&
+ sort <tmp2 >expect &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "bitmap --objects handles non-commit objects ($state)" '
+ git rev-list --objects --use-bitmap-index HEAD tagged-blob >actual &&
+ grep $blob actual
+ '
+}
+
+rev_list_tests 'full bitmap'
+
+test_expect_success 'clone from bitmapped repository' '
+ git clone --no-local --bare . clone.git &&
+ git rev-parse HEAD >expect &&
+ git --git-dir=clone.git rev-parse HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'setup further non-bitmapped commits' '
+ for i in $(test_seq 1 10); do
+ test_commit further-$i
+ done
+'
+
+rev_list_tests 'partial bitmap'
+
+test_expect_success 'fetch (partial bitmap)' '
+ git --git-dir=clone.git fetch origin master:master &&
+ git rev-parse HEAD >expect &&
+ git --git-dir=clone.git rev-parse HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'incremental repack cannot create bitmaps' '
+ test_commit more-1 &&
+ test_must_fail git repack -d
+'
+
+test_expect_success 'incremental repack can disable bitmaps' '
+ test_commit more-2 &&
+ git repack -d --no-write-bitmap-index
+'
+
+test_expect_success 'full repack, reusing previous bitmaps' '
+ git repack -ad &&
+ ls .git/objects/pack/ | grep bitmap >output &&
+ test_line_count = 1 output
+'
+
+test_expect_success 'fetch (full bitmap)' '
+ git --git-dir=clone.git fetch origin master:master &&
+ git rev-parse HEAD >expect &&
+ git --git-dir=clone.git rev-parse HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_lazy_prereq JGIT '
+ type jgit
+'
+
+test_expect_success JGIT 'we can read jgit bitmaps' '
+ git clone . compat-jgit &&
+ (
+ cd compat-jgit &&
+ rm -f .git/objects/pack/*.bitmap &&
+ jgit gc &&
+ git rev-list --test-bitmap HEAD
+ )
+'
+
+test_expect_success JGIT 'jgit can read our bitmaps' '
+ git clone . compat-us &&
+ (
+ cd compat-us &&
+ git repack -adb &&
+ # jgit gc will barf if it does not like our bitmaps
+ jgit gc
+ )
+'
+
+test_done
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index b0fa7387cb..3ae9092f5c 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -173,32 +173,4 @@ EOF
)
'
-if test -n "$NO_CURL" -o -z "$GIT_TEST_HTTPD"; then
- say 'skipping remaining tests, git built without http support'
- test_done
-fi
-
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5537'}
-. "$TEST_DIRECTORY"/lib-httpd.sh
-start_httpd
-
-test_expect_success 'clone http repository' '
- git clone --bare --no-local shallow "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
- git clone $HTTPD_URL/smart/repo.git clone &&
- (
- cd clone &&
- git fsck &&
- git log --format=%s origin/master >actual &&
- cat <<EOF >expect &&
-7
-6
-5
-4
-3
-EOF
- test_cmp expect actual
- )
-'
-
-stop_httpd
test_done
diff --git a/t/t5538-push-shallow.sh b/t/t5538-push-shallow.sh
index 0a6e40f144..8e54ac5746 100755
--- a/t/t5538-push-shallow.sh
+++ b/t/t5538-push-shallow.sh
@@ -126,7 +126,6 @@ if test -n "$NO_CURL" -o -z "$GIT_TEST_HTTPD"; then
test_done
fi
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5537'}
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh
new file mode 100755
index 0000000000..94553e1039
--- /dev/null
+++ b/t/t5539-fetch-http-shallow.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+test_description='fetch/clone from a shallow clone over http'
+
+. ./test-lib.sh
+
+if test -n "$NO_CURL"; then
+ skip_all='skipping test, git built without http support'
+ test_done
+fi
+
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+commit() {
+ echo "$1" >tracked &&
+ git add tracked &&
+ git commit -m "$1"
+}
+
+test_expect_success 'setup shallow clone' '
+ commit 1 &&
+ commit 2 &&
+ commit 3 &&
+ commit 4 &&
+ commit 5 &&
+ commit 6 &&
+ commit 7 &&
+ git clone --no-local --depth=5 .git shallow &&
+ git config --global transfer.fsckObjects true
+'
+
+test_expect_success 'clone http repository' '
+ git clone --bare --no-local shallow "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ git clone $HTTPD_URL/smart/repo.git clone &&
+ (
+ cd clone &&
+ git fsck &&
+ git log --format=%s origin/master >actual &&
+ cat <<EOF >expect &&
+7
+6
+5
+4
+3
+EOF
+ test_cmp expect actual
+ )
+'
+
+# This test is tricky. We need large enough "have"s that fetch-pack
+# will put pkt-flush in between. Then we need a "have" the server
+# does not have, it'll send "ACK %s ready"
+test_expect_success 'no shallow lines after receiving ACK ready' '
+ (
+ cd shallow &&
+ for i in $(test_seq 15)
+ do
+ git checkout --orphan unrelated$i &&
+ test_commit unrelated$i &&
+ git push -q "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+ refs/heads/unrelated$i:refs/heads/unrelated$i &&
+ git push -q ../clone/.git \
+ refs/heads/unrelated$i:refs/heads/unrelated$i ||
+ exit 1
+ done &&
+ git checkout master &&
+ test_commit new &&
+ git push "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" master
+ ) &&
+ (
+ cd clone &&
+ git checkout --orphan newnew &&
+ test_commit new-too &&
+ GIT_TRACE_PACKET="$TRASH_DIRECTORY/trace" git fetch --depth=2 &&
+ grep "fetch-pack< ACK .* ready" ../trace &&
+ ! grep "fetch-pack> done" ../trace
+ )
+'
+
+stop_httpd
+test_done
diff --git a/t/t5540-http-push.sh b/t/t5540-http-push-webdav.sh
index 5b0198cbc8..8d7b3c57e3 100755
--- a/t/t5540-http-push.sh
+++ b/t/t5540-http-push-webdav.sh
@@ -16,7 +16,6 @@ then
fi
LIB_HTTPD_DAV=t
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5540'}
. "$TEST_DIRECTORY"/lib-httpd.sh
ROOT_PATH="$PWD"
start_httpd
diff --git a/t/t5541-http-push.sh b/t/t5541-http-push-smart.sh
index bfd241ea8a..73af16f481 100755
--- a/t/t5541-http-push.sh
+++ b/t/t5541-http-push-smart.sh
@@ -12,7 +12,6 @@ if test -n "$NO_CURL"; then
fi
ROOT_PATH="$PWD"
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5541'}
. "$TEST_DIRECTORY"/lib-httpd.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
start_httpd
diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch-dumb.sh
index 8392624714..1a3a2b6c1a 100755
--- a/t/t5550-http-fetch.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -8,7 +8,6 @@ if test -n "$NO_CURL"; then
test_done
fi
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch-smart.sh
index a124efe114..e07eaf35f1 100755
--- a/t/t5551-http-fetch.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -8,7 +8,6 @@ if test -n "$NO_CURL"; then
test_done
fi
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5551'}
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh
index b5d7fbc381..d23fb02384 100755
--- a/t/t5561-http-backend.sh
+++ b/t/t5561-http-backend.sh
@@ -8,7 +8,6 @@ if test -n "$NO_CURL"; then
test_done
fi
-LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5561'}
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index e06146835c..6b16379951 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -3,7 +3,6 @@
test_description='test fetching over git protocol'
. ./test-lib.sh
-LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570}
. "$TEST_DIRECTORY"/lib-git-daemon.sh
start_git_daemon
diff --git a/t/t6131-pathspec-icase.sh b/t/t6131-pathspec-icase.sh
index a7c7ff5f49..39fc3f6769 100755
--- a/t/t6131-pathspec-icase.sh
+++ b/t/t6131-pathspec-icase.sh
@@ -69,7 +69,7 @@ test_expect_success 'tree_entry_interesting matches :(icase)bar with empty prefi
test_cmp expect actual
'
-test_expect_success 'match_pathspec_depth matches :(icase)bar' '
+test_expect_success 'match_pathspec matches :(icase)bar' '
cat <<-EOF >expect &&
BAR
bAr
@@ -79,7 +79,7 @@ test_expect_success 'match_pathspec_depth matches :(icase)bar' '
test_cmp expect actual
'
-test_expect_success 'match_pathspec_depth matches :(icase)bar with prefix' '
+test_expect_success 'match_pathspec matches :(icase)bar with prefix' '
cat <<-EOF >expect &&
fOo/BAR
fOo/bAr
@@ -89,7 +89,7 @@ test_expect_success 'match_pathspec_depth matches :(icase)bar with prefix' '
test_cmp expect actual
'
-test_expect_success 'match_pathspec_depth matches :(icase)bar with empty prefix' '
+test_expect_success 'match_pathspec matches :(icase)bar with empty prefix' '
cat <<-EOF >expect &&
bar
fOo/BAR
diff --git a/t/t7101-reset.sh b/t/t7101-reset-empty-subdirs.sh
index 96e163f084..96e163f084 100755
--- a/t/t7101-reset.sh
+++ b/t/t7101-reset-empty-subdirs.sh
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index 8d4b50d1b5..bc0846f435 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -535,4 +535,19 @@ test_expect_success 'reset with paths accepts tree' '
git diff HEAD --exit-code
'
+test_expect_success 'reset -N keeps removed files as intent-to-add' '
+ echo new-file >new-file &&
+ git add new-file &&
+ git reset -N HEAD &&
+
+ tree=$(git write-tree) &&
+ git ls-tree $tree new-file >actual &&
+ >expect &&
+ test_cmp expect actual &&
+
+ git diff --name-only >actual &&
+ echo new-file >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7104-reset.sh b/t/t7104-reset-hard.sh
index f136ee7bb5..f136ee7bb5 100755
--- a/t/t7104-reset.sh
+++ b/t/t7104-reset-hard.sh
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 0246e80b1a..28ca76384f 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -63,6 +63,9 @@ test_expect_success 'setup a submodule tree' '
git submodule add ../none none &&
test_tick &&
git commit -m "none"
+ ) &&
+ (cd super &&
+ git tag initial-setup
)
'
@@ -703,7 +706,7 @@ test_expect_success 'submodule update places git-dir in superprojects git-dir re
git clone super_update_r super_update_r2 &&
(cd super_update_r2 &&
git submodule update --init --recursive >actual &&
- test_i18ngrep "Submodule path .submodule/subsubmodule.: checked out" actual &&
+ test_i18ngrep "Submodule path .submodule/subsubmodule.: .git reset --hard -q" actual &&
(cd submodule/subsubmodule &&
git log > ../../expected
) &&
@@ -775,4 +778,37 @@ test_expect_success 'submodule update --recursive drops module name before recur
)
'
+test_expect_success 'submodule update --checkout clones detached HEAD' '
+ git clone super super4 &&
+ echo "detached HEAD" >expected &&
+ (cd super4 &&
+ git reset --hard initial-setup &&
+ git submodule init submodule &&
+ git submodule update >> /tmp/log 2>&1 &&
+ (cd submodule &&
+ git symbolic-ref HEAD > ../../actual ||
+ echo "detached HEAD" > ../../actual
+ )
+ ) &&
+ test_cmp actual expected &&
+ rm -rf super4
+'
+
+test_expect_success 'submodule update --merge clones attached HEAD' '
+ git clone super super4 &&
+ echo "refs/heads/master" >expected &&
+ (cd super4 &&
+ git reset --hard initial-setup &&
+ git submodule init submodule &&
+ git config submodule.submodule.update merge &&
+ git submodule update --merge &&
+ (cd submodule &&
+ git symbolic-ref HEAD > ../../actual ||
+ echo "detached HEAD" > ../../actual
+ )
+ ) &&
+ test_cmp actual expected &&
+ rm -rf super4
+'
+
test_done
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 1d3c56fe61..5ddac1a9f7 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -5,6 +5,8 @@ test_description='signed commit tests'
. "$TEST_DIRECTORY/lib-gpg.sh"
test_expect_success GPG 'create signed commits' '
+ test_when_finished "test_unconfig commit.gpgsign" &&
+
echo 1 >file && git add file &&
test_tick && git commit -S -m initial &&
git tag initial &&
@@ -25,12 +27,27 @@ test_expect_success GPG 'create signed commits' '
git tag fourth-unsigned &&
test_tick && git commit --amend -S -m "fourth signed" &&
- git tag fourth-signed
+ git tag fourth-signed &&
+
+ git config commit.gpgsign true &&
+ echo 5 >file && test_tick && git commit -a -m "fifth signed" &&
+ git tag fifth-signed &&
+
+ git config commit.gpgsign false &&
+ echo 6 >file && test_tick && git commit -a -m "sixth" &&
+ git tag sixth-unsigned &&
+
+ git config commit.gpgsign true &&
+ echo 7 >file && test_tick && git commit -a -m "seventh" --no-gpg-sign &&
+ git tag seventh-unsigned &&
+
+ test_tick && git rebase -f HEAD^^ && git tag sixth-signed HEAD^ &&
+ git tag seventh-signed
'
test_expect_success GPG 'show signatures' '
(
- for commit in initial second merge master
+ for commit in initial second merge fourth-signed fifth-signed sixth-signed master
do
git show --pretty=short --show-signature $commit >actual &&
grep "Good signature from" actual || exit 1
@@ -39,7 +56,7 @@ test_expect_success GPG 'show signatures' '
done
) &&
(
- for commit in merge^2 fourth-unsigned
+ for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned
do
git show --pretty=short --show-signature $commit >actual &&
grep "Good signature from" actual && exit 1
@@ -52,7 +69,7 @@ test_expect_success GPG 'show signatures' '
test_expect_success GPG 'detect fudged signature' '
git cat-file commit master >raw &&
- sed -e "s/fourth signed/4th forged/" raw >forged1 &&
+ sed -e "s/seventh/7th forged/" raw >forged1 &&
git hash-object -w -t commit forged1 >forged1.commit &&
git show --pretty=short --show-signature $(cat forged1.commit) >actual1 &&
grep "BAD signature from" actual1 &&
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 830a4c3e9d..f768c900ab 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -38,6 +38,27 @@ test_expect_success 'merge c1 with c2' '
test -f c2.c
'
+test_expect_success 'fast-forward pull succeeds with "true" in pull.ff' '
+ git reset --hard c0 &&
+ test_config pull.ff true &&
+ git pull . c1 &&
+ test "$(git rev-parse HEAD)" = "$(git rev-parse c1)"
+'
+
+test_expect_success 'fast-forward pull creates merge with "false" in pull.ff' '
+ git reset --hard c0 &&
+ test_config pull.ff false &&
+ git pull . c1 &&
+ test "$(git rev-parse HEAD^1)" = "$(git rev-parse c0)" &&
+ test "$(git rev-parse HEAD^2)" = "$(git rev-parse c1)"
+'
+
+test_expect_success 'pull prevents non-fast-forward with "only" in pull.ff' '
+ git reset --hard c1 &&
+ test_config pull.ff only &&
+ test_must_fail git pull . c3
+'
+
test_expect_success 'merge c1 with c2 (ours in pull.twohead)' '
git reset --hard c1 &&
git config pull.twohead ours &&
diff --git a/test-hashmap.c b/test-hashmap.c
new file mode 100644
index 0000000000..f5183fb9e8
--- /dev/null
+++ b/test-hashmap.c
@@ -0,0 +1,255 @@
+#include "git-compat-util.h"
+#include "hashmap.h"
+
+struct test_entry
+{
+ struct hashmap_entry ent;
+ /* key and value as two \0-terminated strings */
+ char key[FLEX_ARRAY];
+};
+
+static const char *get_value(const struct test_entry *e)
+{
+ return e->key + strlen(e->key) + 1;
+}
+
+static int test_entry_cmp(const struct test_entry *e1,
+ const struct test_entry *e2, const char* key)
+{
+ return strcmp(e1->key, key ? key : e2->key);
+}
+
+static int test_entry_cmp_icase(const struct test_entry *e1,
+ const struct test_entry *e2, const char* key)
+{
+ return strcasecmp(e1->key, key ? key : e2->key);
+}
+
+static struct test_entry *alloc_test_entry(int hash, char *key, int klen,
+ char *value, int vlen)
+{
+ struct test_entry *entry = malloc(sizeof(struct test_entry) + klen
+ + vlen + 2);
+ hashmap_entry_init(entry, hash);
+ memcpy(entry->key, key, klen + 1);
+ memcpy(entry->key + klen + 1, value, vlen + 1);
+ return entry;
+}
+
+#define HASH_METHOD_FNV 0
+#define HASH_METHOD_I 1
+#define HASH_METHOD_IDIV10 2
+#define HASH_METHOD_0 3
+#define HASH_METHOD_X2 4
+#define TEST_SPARSE 8
+#define TEST_ADD 16
+#define TEST_SIZE 100000
+
+static unsigned int hash(unsigned int method, unsigned int i, const char *key)
+{
+ unsigned int hash;
+ switch (method & 3)
+ {
+ case HASH_METHOD_FNV:
+ hash = strhash(key);
+ break;
+ case HASH_METHOD_I:
+ hash = i;
+ break;
+ case HASH_METHOD_IDIV10:
+ hash = i / 10;
+ break;
+ case HASH_METHOD_0:
+ hash = 0;
+ break;
+ }
+
+ if (method & HASH_METHOD_X2)
+ hash = 2 * hash;
+ return hash;
+}
+
+/*
+ * Test performance of hashmap.[ch]
+ * Usage: time echo "perfhashmap method rounds" | test-hashmap
+ */
+static void perf_hashmap(unsigned int method, unsigned int rounds)
+{
+ struct hashmap map;
+ char buf[16];
+ struct test_entry **entries;
+ unsigned int *hashes;
+ unsigned int i, j;
+
+ entries = malloc(TEST_SIZE * sizeof(struct test_entry *));
+ hashes = malloc(TEST_SIZE * sizeof(int));
+ for (i = 0; i < TEST_SIZE; i++) {
+ snprintf(buf, sizeof(buf), "%i", i);
+ entries[i] = alloc_test_entry(0, buf, strlen(buf), "", 0);
+ hashes[i] = hash(method, i, entries[i]->key);
+ }
+
+ if (method & TEST_ADD) {
+ /* test adding to the map */
+ for (j = 0; j < rounds; j++) {
+ hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0);
+
+ /* add entries */
+ for (i = 0; i < TEST_SIZE; i++) {
+ hashmap_entry_init(entries[i], hashes[i]);
+ hashmap_add(&map, entries[i]);
+ }
+
+ hashmap_free(&map, 0);
+ }
+ } else {
+ /* test map lookups */
+ hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0);
+
+ /* fill the map (sparsely if specified) */
+ j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;
+ for (i = 0; i < j; i++) {
+ hashmap_entry_init(entries[i], hashes[i]);
+ hashmap_add(&map, entries[i]);
+ }
+
+ for (j = 0; j < rounds; j++) {
+ for (i = 0; i < TEST_SIZE; i++) {
+ struct hashmap_entry key;
+ hashmap_entry_init(&key, hashes[i]);
+ hashmap_get(&map, &key, entries[i]->key);
+ }
+ }
+
+ hashmap_free(&map, 0);
+ }
+}
+
+#define DELIM " \t\r\n"
+
+/*
+ * Read stdin line by line and print result of commands to stdout:
+ *
+ * hash key -> strhash(key) memhash(key) strihash(key) memihash(key)
+ * put key value -> NULL / old value
+ * get key -> NULL / value
+ * remove key -> NULL / old value
+ * iterate -> key1 value1\nkey2 value2\n...
+ * size -> tablesize numentries
+ *
+ * perfhashmap method rounds -> test hashmap.[ch] performance
+ */
+int main(int argc, char *argv[])
+{
+ char line[1024];
+ struct hashmap map;
+ int icase;
+
+ /* init hash map */
+ icase = argc > 1 && !strcmp("ignorecase", argv[1]);
+ hashmap_init(&map, (hashmap_cmp_fn) (icase ? test_entry_cmp_icase
+ : test_entry_cmp), 0);
+
+ /* process commands from stdin */
+ while (fgets(line, sizeof(line), stdin)) {
+ char *cmd, *p1 = NULL, *p2 = NULL;
+ int l1 = 0, l2 = 0, hash = 0;
+ struct test_entry *entry;
+
+ /* break line into command and up to two parameters */
+ cmd = strtok(line, DELIM);
+ /* ignore empty lines */
+ if (!cmd || *cmd == '#')
+ continue;
+
+ p1 = strtok(NULL, DELIM);
+ if (p1) {
+ l1 = strlen(p1);
+ hash = icase ? strihash(p1) : strhash(p1);
+ p2 = strtok(NULL, DELIM);
+ if (p2)
+ l2 = strlen(p2);
+ }
+
+ if (!strcmp("hash", cmd) && l1) {
+
+ /* print results of different hash functions */
+ printf("%u %u %u %u\n", strhash(p1), memhash(p1, l1),
+ strihash(p1), memihash(p1, l1));
+
+ } else if (!strcmp("add", cmd) && l1 && l2) {
+
+ /* create entry with key = p1, value = p2 */
+ entry = alloc_test_entry(hash, p1, l1, p2, l2);
+
+ /* add to hashmap */
+ hashmap_add(&map, entry);
+
+ } else if (!strcmp("put", cmd) && l1 && l2) {
+
+ /* create entry with key = p1, value = p2 */
+ entry = alloc_test_entry(hash, p1, l1, p2, l2);
+
+ /* add / replace entry */
+ entry = hashmap_put(&map, entry);
+
+ /* print and free replaced entry, if any */
+ puts(entry ? get_value(entry) : "NULL");
+ free(entry);
+
+ } else if (!strcmp("get", cmd) && l1) {
+
+ /* setup static key */
+ struct hashmap_entry key;
+ hashmap_entry_init(&key, hash);
+
+ /* lookup entry in hashmap */
+ entry = hashmap_get(&map, &key, p1);
+
+ /* print result */
+ if (!entry)
+ puts("NULL");
+ while (entry) {
+ puts(get_value(entry));
+ entry = hashmap_get_next(&map, entry);
+ }
+
+ } else if (!strcmp("remove", cmd) && l1) {
+
+ /* setup static key */
+ struct hashmap_entry key;
+ hashmap_entry_init(&key, hash);
+
+ /* remove entry from hashmap */
+ entry = hashmap_remove(&map, &key, p1);
+
+ /* print result and free entry*/
+ puts(entry ? get_value(entry) : "NULL");
+ free(entry);
+
+ } else if (!strcmp("iterate", cmd)) {
+
+ struct hashmap_iter iter;
+ hashmap_iter_init(&map, &iter);
+ while ((entry = hashmap_iter_next(&iter)))
+ printf("%s %s\n", entry->key, get_value(entry));
+
+ } else if (!strcmp("size", cmd)) {
+
+ /* print table sizes */
+ printf("%u %u\n", map.tablesize, map.size);
+
+ } else if (!strcmp("perfhashmap", cmd) && l1 && l2) {
+
+ perf_hashmap(atoi(p1), atoi(p2));
+
+ } else {
+
+ printf("Unknown command %s\n", cmd);
+
+ }
+ }
+
+ hashmap_free(&map, 1);
+ return 0;
+}
diff --git a/unpack-trees.c b/unpack-trees.c
index 164354dad7..0692ebe16e 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -105,12 +105,11 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear)
{
- clear |= CE_HASHED | CE_UNHASHED;
+ clear |= CE_HASHED;
if (set & CE_REMOVE)
set |= CE_WT_REMOVE;
- ce->next = NULL;
ce->ce_flags = (ce->ce_flags & ~clear) | set;
add_index_entry(&o->result, ce,
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
diff --git a/userdiff.c b/userdiff.c
index ea43a0306f..10b61ec37d 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -15,13 +15,13 @@ static int drivers_alloc;
word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" }
static struct userdiff_driver builtin_drivers[] = {
IPATTERN("ada",
- "!^(.*[ \t])?(is new|renames|is separate)([ \t].*)?$\n"
+ "!^(.*[ \t])?(is[ \t]+new|renames|is[ \t]+separate)([ \t].*)?$\n"
"!^[ \t]*with[ \t].*$\n"
"^[ \t]*((procedure|function)[ \t]+.*)$\n"
"^[ \t]*((package|protected|task)[ \t]+.*)$",
/* -- */
"[a-zA-Z][a-zA-Z0-9_]*"
- "|[0-9][-+0-9#_.eE]"
+ "|[-+]?[0-9][0-9#_.aAbBcCdDeEfF]*([eE][+-]?[0-9_]+)?"
"|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"),
IPATTERN("fortran",
"!^([C*]|[ \t]*!)\n"
diff --git a/wt-status.c b/wt-status.c
index 4e55810059..a452407dad 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -510,7 +510,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
struct wt_status_change_data *d;
const struct cache_entry *ce = active_cache[i];
- if (!ce_path_match(ce, &s->pathspec))
+ if (!ce_path_match(ce, &s->pathspec, NULL))
continue;
it = string_list_insert(&s->change, ce->name);
d = it->util;
@@ -552,7 +552,7 @@ static void wt_status_collect_untracked(struct wt_status *s)
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
if (cache_name_is_other(ent->name, ent->len) &&
- match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
+ dir_path_match(ent, &s->pathspec, 0, NULL))
string_list_insert(&s->untracked, ent->name);
free(ent);
}
@@ -560,7 +560,7 @@ static void wt_status_collect_untracked(struct wt_status *s)
for (i = 0; i < dir.ignored_nr; i++) {
struct dir_entry *ent = dir.ignored[i];
if (cache_name_is_other(ent->name, ent->len) &&
- match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
+ dir_path_match(ent, &s->pathspec, 0, NULL))
string_list_insert(&s->ignored, ent->name);
free(ent);
}