summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml7
-rw-r--r--Documentation/CodingGuidelines5
-rw-r--r--Documentation/RelNotes/2.16.2.txt30
-rw-r--r--Documentation/RelNotes/2.16.3.txt49
-rw-r--r--Documentation/RelNotes/2.17.0.txt275
-rw-r--r--Documentation/RelNotes/2.18.0.txt67
-rw-r--r--Documentation/config.txt25
-rw-r--r--Documentation/diff-options.txt8
-rw-r--r--Documentation/fetch-options.txt17
-rw-r--r--Documentation/git-am.txt10
-rw-r--r--Documentation/git-config.txt6
-rw-r--r--Documentation/git-daemon.txt28
-rw-r--r--Documentation/git-fetch.txt87
-rw-r--r--Documentation/git-filter-branch.txt8
-rw-r--r--Documentation/git-gc.txt28
-rw-r--r--Documentation/git-index-pack.txt3
-rw-r--r--Documentation/git-interpret-trailers.txt2
-rw-r--r--Documentation/git-rebase.txt12
-rw-r--r--Documentation/git-remote.txt14
-rw-r--r--Documentation/git-send-email.txt5
-rw-r--r--Documentation/git-shortlog.txt2
-rw-r--r--Documentation/git-stash.txt2
-rw-r--r--Documentation/git-status.txt9
-rw-r--r--Documentation/git-tag.txt8
-rw-r--r--Documentation/git-update-index.txt30
-rw-r--r--Documentation/git-worktree.txt39
-rw-r--r--Documentation/git.txt3
-rw-r--r--Documentation/gitattributes.txt15
-rw-r--r--Documentation/gitignore.txt11
-rw-r--r--Documentation/gitrepository-layout.txt5
-rw-r--r--Documentation/gitsubmodules.txt14
-rw-r--r--Documentation/merge-options.txt3
-rw-r--r--Documentation/merge-strategies.txt2
-rw-r--r--Documentation/pretty-formats.txt2
-rw-r--r--Documentation/technical/api-object-access.txt2
-rw-r--r--Documentation/technical/api-submodule-config.txt2
-rw-r--r--Documentation/technical/http-protocol.txt3
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL14
-rw-r--r--Makefile127
l---------RelNotes2
-rw-r--r--apply.c145
-rw-r--r--archive-tar.c28
-rw-r--r--archive-zip.c18
-rw-r--r--archive.c32
-rw-r--r--archive.h10
-rw-r--r--bisect.c3
-rw-r--r--blame.c53
-rw-r--r--builtin/add.c9
-rw-r--r--builtin/am.c69
-rw-r--r--builtin/archive.c2
-rw-r--r--builtin/blame.c23
-rw-r--r--builtin/branch.c4
-rw-r--r--builtin/cat-file.c34
-rw-r--r--builtin/check-ignore.c3
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/checkout.c220
-rw-r--r--builtin/clean.c2
-rw-r--r--builtin/commit-tree.c6
-rw-r--r--builtin/commit.c24
-rw-r--r--builtin/config.c10
-rw-r--r--builtin/describe.c6
-rw-r--r--builtin/diff-tree.c2
-rw-r--r--builtin/difftool.c2
-rw-r--r--builtin/fast-export.c14
-rw-r--r--builtin/fetch.c66
-rw-r--r--builtin/fmt-merge-msg.c4
-rw-r--r--builtin/fsck.c16
-rw-r--r--builtin/gc.c7
-rw-r--r--builtin/grep.c54
-rw-r--r--builtin/hash-object.c3
-rw-r--r--builtin/help.c10
-rw-r--r--builtin/index-pack.c177
-rw-r--r--builtin/init-db.c30
-rw-r--r--builtin/log.c15
-rw-r--r--builtin/ls-files.c4
-rw-r--r--builtin/ls-remote.c5
-rw-r--r--builtin/ls-tree.c8
-rw-r--r--builtin/merge-tree.c5
-rw-r--r--builtin/merge.c76
-rw-r--r--builtin/mktag.c26
-rw-r--r--builtin/mktree.c36
-rw-r--r--builtin/mv.c10
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/notes.c26
-rw-r--r--builtin/pack-objects.c90
-rw-r--r--builtin/pack-redundant.c54
-rw-r--r--builtin/prune.c4
-rw-r--r--builtin/pull.c4
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/rebase--helper.c2
-rw-r--r--builtin/receive-pack.c19
-rw-r--r--builtin/reflog.c11
-rw-r--r--builtin/remote.c68
-rw-r--r--builtin/replace.c57
-rw-r--r--builtin/reset.c28
-rw-r--r--builtin/rev-list.c6
-rw-r--r--builtin/rev-parse.c36
-rw-r--r--builtin/rm.c11
-rw-r--r--builtin/shortlog.c9
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/show-ref.c4
-rw-r--r--builtin/submodule--helper.c4
-rw-r--r--builtin/tag.c33
-rw-r--r--builtin/unpack-file.c2
-rw-r--r--builtin/unpack-objects.c36
-rw-r--r--builtin/update-index.c3
-rw-r--r--builtin/update-server-info.c2
-rw-r--r--builtin/verify-commit.c4
-rw-r--r--builtin/worktree.c261
-rw-r--r--builtin/write-tree.c6
-rw-r--r--bulk-checkin.c46
-rw-r--r--bulk-checkin.h2
-rw-r--r--bundle.c2
-rw-r--r--cache-tree.c53
-rw-r--r--cache-tree.h4
-rw-r--r--cache.h102
-rwxr-xr-xci/lib-travisci.sh2
-rwxr-xr-xci/run-build-and-tests.sh (renamed from ci/run-tests.sh)3
-rwxr-xr-xci/run-build.sh8
-rw-r--r--color.c7
-rw-r--r--color.h34
-rw-r--r--combine-diff.c18
-rw-r--r--commit.c41
-rw-r--r--commit.h11
-rw-r--r--compat/mingw.c11
-rw-r--r--compat/mingw.h3
-rw-r--r--config.c2
-rw-r--r--config.mak.uname1
-rw-r--r--configure.ac26
-rw-r--r--contrib/coccinelle/strbuf.cocci17
-rw-r--r--contrib/completion/git-completion.bash325
-rw-r--r--contrib/examples/builtin-fetch--tool.c2
-rwxr-xr-xcontrib/examples/git-difftool.perl2
-rwxr-xr-xcontrib/examples/git-svnimport.perl2
-rwxr-xr-xcontrib/hooks/pre-auto-gc-battery2
-rwxr-xr-xcontrib/subtree/git-subtree.sh12
-rw-r--r--contrib/subtree/git-subtree.txt2
-rw-r--r--convert.c18
-rw-r--r--convert.h2
-rw-r--r--csum-file.c46
-rw-r--r--csum-file.h38
-rw-r--r--daemon.c46
-rw-r--r--diff-lib.c42
-rw-r--r--diff.c172
-rw-r--r--diff.h1
-rw-r--r--diffcore-delta.c16
-rw-r--r--diffcore-rename.c4
-rw-r--r--dir.c164
-rw-r--r--dir.h14
-rw-r--r--entry.c42
-rw-r--r--environment.c24
-rw-r--r--fast-import.c121
-rw-r--r--fetch-pack.c62
-rw-r--r--fsck.c4
-rw-r--r--fsmonitor.c2
-rw-r--r--fsmonitor.h2
-rwxr-xr-xgit-add--interactive.perl192
-rw-r--r--git-compat-util.h4
-rwxr-xr-xgit-cvsimport.perl4
-rwxr-xr-xgit-filter-branch.sh8
-rw-r--r--git-rebase--am.sh4
-rw-r--r--git-rebase--interactive.sh33
-rw-r--r--git-rebase--merge.sh8
-rwxr-xr-xgit-rebase.sh13
-rwxr-xr-xgit-send-email.perl199
-rw-r--r--git-sh-i18n.sh8
-rwxr-xr-xgit-stash.sh14
-rw-r--r--git.c40
-rw-r--r--gitweb/INSTALL3
-rwxr-xr-xgitweb/gitweb.perl17
-rw-r--r--grep.c7
-rw-r--r--hash.h40
-rw-r--r--http-push.c4
-rw-r--r--http-walker.c16
-rw-r--r--http.c14
-rw-r--r--imap-send.c14
-rw-r--r--line-log.c59
-rw-r--r--list-objects-filter.c2
-rw-r--r--log-tree.c17
-rw-r--r--mailmap.c2
-rw-r--r--match-trees.c54
-rw-r--r--merge-blobs.c4
-rw-r--r--merge-recursive.c1285
-rw-r--r--merge-recursive.h27
-rw-r--r--merge.c12
-rw-r--r--name-hash.c9
-rw-r--r--notes-cache.c10
-rw-r--r--notes-merge.c11
-rw-r--r--notes-utils.c9
-rw-r--r--notes-utils.h3
-rw-r--r--notes.c67
-rw-r--r--notes.h29
-rw-r--r--object.c16
-rw-r--r--object.h30
-rw-r--r--pack-bitmap-write.c33
-rw-r--r--pack-check.c36
-rw-r--r--pack-write.c77
-rw-r--r--pack.h4
-rw-r--r--packfile.c67
-rw-r--r--parse-options.c66
-rw-r--r--parse-options.h31
-rw-r--r--perl/FromCPAN/.gitattributes1
-rw-r--r--perl/FromCPAN/Error.pm (renamed from perl/Git/FromCPAN/Error.pm)295
-rw-r--r--perl/FromCPAN/Mail/Address.pm (renamed from perl/Git/FromCPAN/Mail/Address.pm)8
-rw-r--r--perl/Git.pm18
-rw-r--r--perl/Git/Error.pm46
-rw-r--r--perl/Git/LoadCPAN.pm104
-rw-r--r--perl/Git/LoadCPAN/Error.pm10
-rw-r--r--perl/Git/LoadCPAN/Mail/Address.pm10
-rwxr-xr-xperl/Git/Mail/Address.pm24
-rw-r--r--perl/Git/SVN.pm2
-rw-r--r--po/bg.po4598
-rw-r--r--po/ca.po7549
-rw-r--r--po/de.po4620
-rw-r--r--po/es.po5213
-rw-r--r--po/fr.po4586
-rw-r--r--po/git.pot4396
-rw-r--r--po/ko.po4583
-rw-r--r--po/sv.po4571
-rw-r--r--po/vi.po4591
-rw-r--r--po/zh_CN.po4561
-rw-r--r--preload-index.c2
-rw-r--r--pretty.c8
-rw-r--r--quote.c12
-rw-r--r--reachable.c4
-rw-r--r--read-cache.c131
-rw-r--r--ref-filter.c93
-rw-r--r--refs.c2
-rw-r--r--refs/packed-backend.c106
-rw-r--r--remote-curl.c13
-rw-r--r--remote-testsvn.c4
-rw-r--r--remote.c87
-rw-r--r--remote.h17
-rw-r--r--replace_object.c26
-rw-r--r--rerere.c12
-rw-r--r--resolve-undo.c15
-rw-r--r--resolve-undo.h2
-rw-r--r--revision.c13
-rw-r--r--revision.h1
-rw-r--r--send-pack.c14
-rw-r--r--sequencer.c136
-rw-r--r--setup.c62
-rw-r--r--sha1-lookup.c28
-rw-r--r--sha1-lookup.h22
-rw-r--r--sha1_file.c314
-rw-r--r--sha1_name.c51
-rw-r--r--sha1dc_git.h6
-rw-r--r--split-index.c16
-rw-r--r--split-index.h2
-rw-r--r--strbuf.c34
-rw-r--r--strbuf.h27
-rw-r--r--streaming.c18
-rw-r--r--streaming.h2
-rw-r--r--submodule-config.c6
-rw-r--r--submodule.c38
-rw-r--r--submodule.h2
-rw-r--r--t/README37
-rw-r--r--t/helper/test-dump-untracked-cache.c4
-rw-r--r--t/helper/test-hashmap.c53
-rw-r--r--t/helper/test-wildmatch.c2
-rw-r--r--t/lib-terminal.sh4
-rwxr-xr-xt/perf/aggregate.perl48
-rwxr-xr-xt/perf/run8
-rwxr-xr-xt/t0002-gitfile.sh53
-rwxr-xr-xt/t0008-ignores.sh22
-rwxr-xr-xt/t0040-parse-options.sh2
-rwxr-xr-xt/t0041-usage.sh107
-rwxr-xr-xt/t0050-filesystem.sh16
-rwxr-xr-xt/t0205-gettext-poison.sh4
-rwxr-xr-xt/t1300-repo-config.sh23
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh2
-rwxr-xr-xt/t1507-rev-parse-upstream.sh14
-rwxr-xr-xt/t1510-repo-setup.sh4
-rwxr-xr-xt/t2025-worktree-add.sh54
-rwxr-xr-xt/t2026-worktree-prune.sh7
-rwxr-xr-xt/t2028-worktree-move.sh85
-rwxr-xr-xt/t3030-merge-recursive.sh36
-rwxr-xr-xt/t3070-wildmatch.sh655
-rwxr-xr-xt/t3200-branch.sh2
-rwxr-xr-xt/t3400-rebase.sh34
-rwxr-xr-xt/t3404-rebase-interactive.sh14
-rwxr-xr-xt/t3405-rebase-malformed.sh23
-rwxr-xr-xt/t3408-rebase-multi-line.sh26
-rwxr-xr-xt/t3501-revert-cherry-pick.sh5
-rwxr-xr-xt/t3701-add-interactive.sh315
-rwxr-xr-xt/t3905-stash-include-untracked.sh52
-rwxr-xr-xt/t4001-diff-rename.sh11
-rwxr-xr-xt/t4013-diff-various.sh5
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--stat_--compact-summary_initial12
-rw-r--r--t/t4013/diff.diff-tree_--pretty_-R_--root_--stat_--compact-summary_initial12
-rw-r--r--t/t4013/diff.diff-tree_--stat_--compact-summary_initial_mode4
-rw-r--r--t/t4013/diff.diff-tree_-R_--stat_--compact-summary_initial_mode4
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rw-r--r--t/t4018/golang-complex-function8
-rw-r--r--t/t4018/golang-func4
-rw-r--r--t/t4018/golang-interface4
-rw-r--r--t/t4018/golang-long-func5
-rw-r--r--t/t4018/golang-struct4
-rwxr-xr-xt/t4052-stat-output.sh46
-rwxr-xr-xt/t4135-apply-weird-filenames.sh17
-rwxr-xr-xt/t4150-am.sh17
-rwxr-xr-xt/t4151-am-abort.sh5
-rwxr-xr-xt/t4201-shortlog.sh5
-rwxr-xr-xt/t5302-pack-index.sh5
-rwxr-xr-xt/t5500-fetch-pack.sh12
-rwxr-xr-xt/t5510-fetch.sh247
-rwxr-xr-xt/t5526-fetch-submodules.sh4
-rwxr-xr-xt/t5536-fetch-conflicts.sh22
-rwxr-xr-xt/t5541-http-push-smart.sh2
-rwxr-xr-xt/t5545-push-options.sh40
-rwxr-xr-xt/t5570-git-daemon.sh2
-rwxr-xr-xt/t5616-partial-clone.sh11
-rwxr-xr-xt/t5812-proto-disable-http.sh5
-rwxr-xr-xt/t6015-rev-list-show-all-parents.sh31
-rwxr-xr-xt/t6022-merge-rename.sh6
-rwxr-xr-xt/t6040-tracking-info.sh42
-rwxr-xr-xt/t6043-merge-rename-directories.sh3998
-rwxr-xr-xt/t6120-describe.sh8
-rwxr-xr-xt/t6200-fmt-merge-msg.sh2
-rwxr-xr-xt/t6300-for-each-ref.sh7
-rwxr-xr-xt/t7001-mv.sh6
-rwxr-xr-xt/t7004-tag.sh30
-rwxr-xr-xt/t7006-pager.sh49
-rwxr-xr-xt/t7063-status-untracked-cache.sh90
-rwxr-xr-xt/t7064-wtstatus-pv2.sh62
-rwxr-xr-xt/t7409-submodule-detached-work-tree.sh2
-rwxr-xr-xt/t7519-status-fsmonitor.sh39
-rwxr-xr-xt/t7600-merge.sh38
-rwxr-xr-xt/t7607-merge-overwrite.sh7
-rwxr-xr-xt/t9001-send-email.sh2
-rwxr-xr-xt/t9400-git-cvsserver-server.sh8
-rwxr-xr-xt/t9402-git-cvsserver-refs.sh8
-rwxr-xr-xt/t9902-completion.sh43
-rwxr-xr-xt/t9903-bash-prompt.sh14
-rw-r--r--t/test-lib-functions.sh106
-rw-r--r--t/test-lib.sh50
-rw-r--r--tag.c12
-rw-r--r--tempfile.c12
-rw-r--r--tempfile.h34
-rw-r--r--trailer.c44
-rw-r--r--transport.c6
-rw-r--r--tree-walk.c45
-rw-r--r--tree-walk.h2
-rw-r--r--tree.c16
-rw-r--r--tree.h2
-rw-r--r--unpack-trees.c13
-rw-r--r--unpack-trees.h4
-rw-r--r--upload-pack.c8
-rw-r--r--userdiff.c11
-rw-r--r--walker.c4
-rw-r--r--worktree.c96
-rw-r--r--worktree.h18
-rw-r--r--wrapper.c40
-rw-r--r--wt-status.c61
-rw-r--r--wt-status.h8
-rw-r--r--xdiff-interface.c2
357 files changed, 39099 insertions, 26528 deletions
diff --git a/.travis.yml b/.travis.yml
index 4684b3f..5f5ee4f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,7 +33,6 @@ matrix:
compiler:
addons:
before_install:
- before_script:
script:
- >
test "$TRAVIS_REPO_SLUG" != "git/git" ||
@@ -46,7 +45,6 @@ matrix:
services:
- docker
before_install:
- before_script:
script: ci/run-linux32-docker.sh
- env: jobname=StaticAnalysis
os: linux
@@ -56,7 +54,6 @@ matrix:
packages:
- coccinelle
before_install:
- before_script:
script: ci/run-static-analysis.sh
after_failure:
- env: jobname=Documentation
@@ -68,13 +65,11 @@ matrix:
- asciidoc
- xmlto
before_install:
- before_script:
script: ci/test-documentation.sh
after_failure:
before_install: ci/install-dependencies.sh
-before_script: ci/run-build.sh
-script: ci/run-tests.sh
+script: ci/run-build-and-tests.sh
after_failure: ci/print-test-failures.sh
notifications:
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index c4cb5ff..48aa4ed 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -386,6 +386,11 @@ For C programs:
- Use Git's gettext wrappers to make the user interface
translatable. See "Marking strings for translation" in po/README.
+ - Variables and functions local to a given source file should be marked
+ with "static". Variables that are visible to other source files
+ must be declared with "extern" in header files. However, function
+ declarations should not use "extern", as that is already the default.
+
For Perl programs:
- Most of the C guidelines above apply.
diff --git a/Documentation/RelNotes/2.16.2.txt b/Documentation/RelNotes/2.16.2.txt
new file mode 100644
index 0000000..a216466
--- /dev/null
+++ b/Documentation/RelNotes/2.16.2.txt
@@ -0,0 +1,30 @@
+Git v2.16.2 Release Notes
+=========================
+
+Fixes since v2.16.1
+-------------------
+
+ * An old regression in "git describe --all $annotated_tag^0" has been
+ fixed.
+
+ * "git svn dcommit" did not take into account the fact that a
+ svn+ssh:// URL with a username@ (typically used for pushing) refers
+ to the same SVN repository without the username@ and failed when
+ svn.pushmergeinfo option is set.
+
+ * "git merge -Xours/-Xtheirs" learned to use our/their version when
+ resolving a conflicting updates to a symbolic link.
+
+ * "git clone $there $here" is allowed even when here directory exists
+ as long as it is an empty directory, but the command incorrectly
+ removed it upon a failure of the operation.
+
+ * "git stash -- <pathspec>" incorrectly blew away untracked files in
+ the directory that matched the pathspec, which has been corrected.
+
+ * "git add -p" was taught to ignore local changes to submodules as
+ they do not interfere with the partial addition of regular changes
+ anyway.
+
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.16.3.txt b/Documentation/RelNotes/2.16.3.txt
new file mode 100644
index 0000000..64a0bcb
--- /dev/null
+++ b/Documentation/RelNotes/2.16.3.txt
@@ -0,0 +1,49 @@
+Git v2.16.3 Release Notes
+=========================
+
+Fixes since v2.16.2
+-------------------
+
+ * "git status" after moving a path in the working tree (hence making
+ it appear "removed") and then adding with the -N option (hence
+ making that appear "added") detected it as a rename, but did not
+ report the old and new pathnames correctly.
+
+ * "git commit --fixup" did not allow "-m<message>" option to be used
+ at the same time; allow it to annotate resulting commit with more
+ text.
+
+ * When resetting the working tree files recursively, the working tree
+ of submodules are now also reset to match.
+
+ * Fix for a commented-out code to adjust it to a rather old API change
+ around object ID.
+
+ * When there are too many changed paths, "git diff" showed a warning
+ message but in the middle of a line.
+
+ * The http tracing code, often used to debug connection issues,
+ learned to redact potentially sensitive information from its output
+ so that it can be more safely sharable.
+
+ * Crash fix for a corner case where an error codepath tried to unlock
+ what it did not acquire lock on.
+
+ * The split-index mode had a few corner case bugs fixed.
+
+ * Assorted fixes to "git daemon".
+
+ * Completion of "git merge -s<strategy>" (in contrib/) did not work
+ well in non-C locale.
+
+ * Workaround for segfault with more recent versions of SVN.
+
+ * Recently introduced leaks in fsck have been plugged.
+
+ * Travis CI integration now builds the executable in 'script' phase
+ to follow the established practice, rather than during
+ 'before_script' phase. This allows the CI categorize the failures
+ better ('failed' is project's fault, 'errored' is build
+ environment's).
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.17.0.txt b/Documentation/RelNotes/2.17.0.txt
index e1e509b..d6db0e1 100644
--- a/Documentation/RelNotes/2.17.0.txt
+++ b/Documentation/RelNotes/2.17.0.txt
@@ -8,20 +8,92 @@ UI, Workflows & Features
* "diff" family of commands learned "--find-object=<object-id>" option
to limit the findings to changes that involve the named object.
- (merge 4d8c51aa19 sb/diff-blobfind-pickaxe later to maint).
+
+ * "git format-patch" learned to give 72-cols to diffstat, which is
+ consistent with other line length limits the subcommand uses for
+ its output meant for e-mails.
+
+ * The log from "git daemon" can be redirected with a new option; one
+ relevant use case is to send the log to standard error (instead of
+ syslog) when running it from inetd.
+
+ * "git rebase" learned to take "--allow-empty-message" option.
+
+ * "git am" has learned the "--quit" option, in addition to the
+ existing "--abort" option; having the pair mirrors a few other
+ commands like "rebase" and "cherry-pick".
+
+ * "git worktree add" learned to run the post-checkout hook, just like
+ "git clone" runs it upon the initial checkout.
+
+ * "git tag" learned an explicit "--edit" option that allows the
+ message given via "-m" and "-F" to be further edited.
+
+ * "git fetch --prune-tags" may be used as a handy short-hand for
+ getting rid of stale tags that are locally held.
+
+ * The new "--show-current-patch" option gives an end-user facing way
+ to get the diff being applied when "git rebase" (and "git am")
+ stops with a conflict.
+
+ * "git add -p" used to offer "/" (look for a matching hunk) as a
+ choice, even there was only one hunk, which has been corrected.
+ Also the single-key help is now given only for keys that are
+ enabled (e.g. help for '/' won't be shown when there is only one
+ hunk).
+
+ * Since Git 1.7.9, "git merge" defaulted to --no-ff (i.e. even when
+ the side branch being merged is a descendant of the current commit,
+ create a merge commit instead of fast-forwarding) when merging a
+ tag object. This was appropriate default for integrators who pull
+ signed tags from their downstream contributors, but caused an
+ unnecessary merges when used by downstream contributors who
+ habitually "catch up" their topic branches with tagged releases
+ from the upstream. Update "git merge" to default to --no-ff only
+ when merging a tag object that does *not* sit at its usual place in
+ refs/tags/ hierarchy, and allow fast-forwarding otherwise, to
+ mitigate the problem.
+
+ * "git status" can spend a lot of cycles to compute the relation
+ between the current branch and its upstream, which can now be
+ disabled with "--no-ahead-behind" option.
+
+ * "git diff" and friends learned funcname patterns for Go language
+ source files.
+
+ * "git send-email" learned "--reply-to=<address>" option.
+
+ * Funcname pattern used for C# now recognizes "async" keyword.
+
+ * In a way similar to how "git tag" learned to honor the pager
+ setting only in the list mode, "git config" learned to ignore the
+ pager setting when it is used for setting values (i.e. when the
+ purpose of the operation is not to "show").
Performance, Internal Implementation, Development Support etc.
* More perf tests for threaded grep
- (merge 7b31b55db1 ab/perf-grep-threads later to maint).
* "perf" test output can be sent to codespeed server.
- (merge 19cf57a92e cc/codespeed later to maint).
* The build procedure for perl/ part has been greatly simplified by
weaning ourselves off of MakeMaker.
+ * Perl 5.8 or greater has been required since Git 1.7.4 released in
+ 2010, but we continued to assume some core modules may not exist and
+ used a conditional "eval { require <<module>> }"; we no longer do
+ this. Some platforms (Fedora/RedHat/CentOS, for example) ship Perl
+ without all core modules by default (e.g. Digest::MD5, File::Temp,
+ File::Spec, Net::Domain, Net::SMTP). Users on such platforms may
+ need to install these additional modules.
+
+ * As a convenience, we install copies of Perl modules we require which
+ are not part of the core Perl distribution (e.g. Error and
+ Mail::Address). Users and packagers whose operating system provides
+ these modules can set NO_PERL_CPAN_FALLBACKS to avoid installing the
+ bundled modules.
+
* In preparation for implementing narrow/partial clone, the machinery
for checking object connectivity used by gc and fsck has been
taught that a missing object is OK when it is referenced by a
@@ -44,13 +116,10 @@ Performance, Internal Implementation, Development Support etc.
* The tracing machinery learned to report tweaking of environment
variables as well.
- (merge 090a09272a nd/trace-with-env later to maint).
* Update Coccinelle rules to catch and optimize strbuf_addf(&buf, "%s", str)
- (merge cd9a4b6d93 rs/strbuf-cocci-workaround later to maint).
* Prevent "clang-format" from breaking line after function return type.
- (merge a3715d43e8 po/clang-format-functype-weight later to maint).
* The sequencer infrastructure is shared across "git cherry-pick",
"git rebase -i", etc., and has always spawned "git commit" when it
@@ -59,6 +128,40 @@ Performance, Internal Implementation, Development Support etc.
gives performance boost for a few tens of percents in some sample
scenarios.
+ * Push the submodule version of collision-detecting SHA-1 hash
+ implementation a bit harder on builders.
+
+ * Avoid mmapping small files while using packed refs (especially ones
+ with zero size, which would cause later munmap() to fail).
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * More tests for wildmatch functions.
+
+ * The code to binary search starting from a fan-out table (which is
+ how the packfile is indexed with object names) has been refactored
+ into a reusable helper.
+
+ * We now avoid using identifiers that clash with C++ keywords. Even
+ though it is not a goal to compile Git with C++ compilers, changes
+ like this help use of code analysis tools that targets C++ on our
+ codebase.
+
+ * The executable is now built in 'script' phase in Travis CI integration,
+ to follow the established practice, rather than during 'before_script'
+ phase. This allows the CI categorize the failures better ('failed'
+ is project's fault, 'errored' is build environment's).
+ (merge 3c93b82920 sg/travis-build-during-script-phase later to maint).
+
+ * Writing out the index file when the only thing that changed in it
+ is the untracked cache information is often wasteful, and this has
+ been optimized out.
+
+ * Various pieces of Perl code we have have been cleaned up.
+
+ * Internal API clean-up to allow write_locked_index() optionally skip
+ writing the in-core index when it is not modified.
+
Also contains various documentation updates and code clean-ups.
@@ -68,44 +171,35 @@ Fixes since v2.16
* An old regression in "git describe --all $annotated_tag^0" has been
fixed.
- (merge 1bba00130a dk/describe-all-output-fix later to maint).
* "git status" after moving a path in the working tree (hence making
it appear "removed") and then adding with the -N option (hence
making that appear "added") detected it as a rename, but did not
report the old and new pathnames correctly.
- (merge 176ea74793 nd/ita-wt-renames-in-status later to maint).
* "git svn dcommit" did not take into account the fact that a
svn+ssh:// URL with a username@ (typically used for pushing) refers
to the same SVN repository without the username@ and failed when
svn.pushmergeinfo option is set.
- (merge 8aaed892fd jm/svn-pushmergeinfo-fix later to maint).
* API clean-up around revision traversal.
- (merge 6fcec2f9ae rs/lose-leak-pending later to maint).
* "git merge -Xours/-Xtheirs" learned to use our/their version when
resolving a conflicting updates to a symbolic link.
- (merge fd48b46474 jc/merge-symlink-ours-theirs later to maint).
* "git clone $there $here" is allowed even when here directory exists
as long as it is an empty directory, but the command incorrectly
removed it upon a failure of the operation.
- (merge d45420c1c8 jk/abort-clone-with-existing-dest later to maint).
* "git commit --fixup" did not allow "-m<message>" option to be used
at the same time; allow it to annotate resulting commit with more
text.
- (merge 30884c9afc ab/commit-m-with-fixup later to maint).
* When resetting the working tree files recursively, the working tree
of submodules are now also reset to match.
- (merge 7dcc1f4df8 sb/submodule-update-reset-fix later to maint).
* "git stash -- <pathspec>" incorrectly blew away untracked files in
the directory that matched the pathspec, which has been corrected.
- (merge bba067d2fa tg/stash-with-pathspec-fix later to maint).
* Instead of maintaining home-grown email address parsing code, ship
a copy of reasonably recent Mail::Address to be used as a fallback
@@ -115,7 +209,6 @@ Fixes since v2.16
* "git add -p" was taught to ignore local changes to submodules as
they do not interfere with the partial addition of regular changes
anyway.
- (merge 12434efc1d nd/add-i-ignore-submodules later to maint).
* Avoid showing a warning message in the middle of a line of "git
diff" output.
@@ -143,11 +236,124 @@ Fixes since v2.16
* Workaround for segfault with more recent versions of SVN.
(merge 7f6f75e97a ew/svn-branch-segfault-fix later to maint).
+ * Plug recently introduced leaks in fsck.
+ (merge ba3a08ca0e jt/fsck-code-cleanup later to maint).
+
+ * "git pull --rebase" did not pass verbosity setting down when
+ recursing into a submodule.
+ (merge a56771a668 sb/pull-rebase-submodule later to maint).
+
+ * The way "git reset --hard" reports the commit the updated HEAD
+ points at is made consistent with the way how the commit title is
+ generated by the other parts of the system. This matters when the
+ title is spread across physically multiple lines.
+ (merge 1cf823fb68 tg/reset-hard-show-head-with-pretty later to maint).
+
+ * Test fixes.
+ (merge 63b1a175ee sg/test-i18ngrep later to maint).
+
+ * Some bugs around "untracked cache" feature have been fixed. This
+ will notice corrupt data in the untracked cache left by old and
+ buggy code and issue a warning---the index can be fixed by clearing
+ the untracked cache from it.
+ (merge 0cacebf099 nd/fix-untracked-cache-invalidation later to maint).
+ (merge 7bf0be7501 ab/untracked-cache-invalidation-docs later to maint).
+
+ * "git blame HEAD COPYING" in a bare repository failed to run, while
+ "git blame HEAD -- COPYING" run just fine. This has been corrected.
+
+ * "git add" files in the same directory, but spelling the directory
+ path in different cases on case insensitive filesystem, corrupted
+ the name hash data structure and led to unexpected results. This
+ has been corrected.
+ (merge c95525e90d bp/name-hash-dirname-fix later to maint).
+
+ * "git rebase -p" mangled log messages of a merge commit, which is
+ now fixed.
+ (merge ed5144d7eb js/fix-merge-arg-quoting-in-rebase-p later to maint).
+
+ * Some low level protocol codepath could crash when they get an
+ unexpected flush packet, which is now fixed.
+ (merge bb1356dc64 js/packet-read-line-check-null later to maint).
+
+ * "git check-ignore" with multiple paths got confused when one is a
+ file and the other is a directory, which has been fixed.
+ (merge d60771e930 rs/check-ignore-multi later to maint).
+
+ * "git describe $garbage" stopped giving any errors when the garbage
+ happens to be a string with 40 hexadecimal letters.
+ (merge a8e7a2bf0f sb/describe-blob later to maint).
+
+ * Code to unquote single-quoted string (used in the parser for
+ configuration files, etc.) did not diagnose bogus input correctly
+ and produced bogus results instead.
+ (merge ddbbf8eb25 jk/sq-dequote-on-bogus-input later to maint).
+
+ * Many places in "git apply" knew that "/dev/null" that signals
+ "there is no such file on this side of the diff" can be followed by
+ whitespace and garbage when parsing a patch, except for one, which
+ made an otherwise valid patch (e.g. ones from subversion) rejected.
+ (merge e454ad4bec tk/apply-dev-null-verify-name-fix later to maint).
+
+ * We no longer create any *.spec file, so "make clean" should not
+ remove it.
+ (merge 4321bdcabb tz/do-not-clean-spec-file later to maint).
+
+ * "git push" over http transport did not unquote the push-options
+ correctly.
+ (merge 90dce21eb0 jk/push-options-via-transport-fix later to maint).
+
+ * "git send-email" learned to complain when the batch-size option is
+ not defined when the relogin-delay option is, since these two are
+ mutually required.
+ (merge 9caa70697b xz/send-email-batch-size later to maint).
+
+ * Y2k20 fix ;-) for our perl scripts.
+ (merge a40e06ee33 bw/perl-timegm-timelocal-fix later to maint).
+
+ * Threaded "git grep" has been optimized to avoid allocation in code
+ section that is covered under a mutex.
+ (merge 38ef24dccf rv/grep-cleanup later to maint).
+
+ * "git subtree" script (in contrib/) scripted around "git log", whose
+ output got affected by end-user configuration like log.showsignature
+ (merge 8841b5222c sg/subtree-signed-commits later to maint).
+
+ * While finding unique object name abbreviation, the code may
+ accidentally have read beyond the end of the array of object names
+ in a pack.
+ (merge 21abed500c ds/find-unique-abbrev-optim later to maint).
+
+ * Micro optimization in revision traversal code.
+ (merge ebbed3ba04 ds/mark-parents-uninteresting-optim later to maint).
+
+ * "git commit" used to run "gc --auto" near the end, which was lost
+ when the command was reimplemented in C by mistake.
+ (merge 095c741edd ab/gc-auto-in-commit later to maint).
+
+ * Allow running a couple of tests with "sh -x".
+ (merge c20bf94abc sg/cvs-tests-with-x later to maint).
+
+ * The codepath to replace an existing entry in the index had a bug in
+ updating the name hash structure, which has been fixed.
+ (merge 0e267b7a24 bp/refresh-cache-ent-rehash-fix later to maint).
+
+ * The transfer.fsckobjects configuration tells "git fetch" to
+ validate the data and connected-ness of objects in the received
+ pack; the code to perform this check has been taught about the
+ narrow clone's convention that missing objects that are reachable
+ from objects in a pack that came from a promissor remote is OK.
+
+ * There was an unused file-scope static variable left in http.c when
+ building for versions of libCURL that is older than 7.19.4, which
+ has been fixed.
+ (merge b8fd6008ec rj/http-code-cleanup later to maint).
+
+ * Shell script portability fix.
+ (merge 206a6ae013 ml/filter-branch-portability-fix later to maint).
+
* Other minor doc, test and build updates and code cleanups.
(merge e2a5a028c7 bw/oidmap-autoinit later to maint).
- (merge f0a6068a9f ys/bisect-object-id-missing-conversion-fix later to maint).
- (merge 30221a3389 as/read-tree-prefix-doc-fix later to maint).
- (merge 9bd2ce5432 ab/doc-cat-file-e-still-shows-errors later to maint).
(merge ec3b4b06f8 cl/t9001-cleanup later to maint).
(merge e1b3f3dd38 ks/submodule-doc-updates later to maint).
(merge fbac558a9b rs/describe-unique-abbrev later to maint).
@@ -159,3 +365,34 @@ Fixes since v2.16
(merge 4e801463c7 jc/mailinfo-cleanup-fix later to maint).
(merge ef5b3a6c5e nd/shared-index-fix later to maint).
(merge 9f5258cbb8 tz/doc-show-defaults-to-head later to maint).
+ (merge b780e4407d jc/worktree-add-short-help later to maint).
+ (merge ae239fc8e5 rs/cocci-strbuf-addf-to-addstr later to maint).
+ (merge 2e22a85e5c nd/ignore-glob-doc-update later to maint).
+ (merge 3738031581 jk/gettext-poison later to maint).
+ (merge 54360a1956 rj/sparse-updates later to maint).
+ (merge 12e31a6b12 sg/doc-test-must-fail-args later to maint).
+ (merge 760f1ad101 bc/doc-interpret-trailers-grammofix later to maint).
+ (merge 4ccf461f56 bp/fsmonitor later to maint).
+ (merge a6119f82b1 jk/test-hashmap-updates later to maint).
+ (merge 5aea9fe6cc rd/typofix later to maint).
+ (merge e4e5da2796 sb/status-doc-fix later to maint).
+ (merge 7976e901c8 gs/test-unset-xdg-cache-home later to maint).
+ (merge d023df1ee6 tg/worktree-create-tracking later to maint).
+ (merge 4cbe92fd41 sm/mv-dry-run-update later to maint).
+ (merge 75e5e9c3f7 sb/color-h-cleanup later to maint).
+ (merge 2708ef4af6 sg/t6300-modernize later to maint).
+ (merge d88e92d4e0 bw/doc-submodule-recurse-config-with-clone later to maint).
+ (merge f74bbc8dd2 jk/cached-commit-buffer later to maint).
+ (merge 1316416903 ms/non-ascii-ticks later to maint).
+ (merge 878056005e rs/strbuf-read-file-or-whine later to maint).
+ (merge 79f0ba1547 jk/strbuf-read-file-close-error later to maint).
+ (merge edfb8ba068 ot/ref-filter-cleanup later to maint).
+ (merge 11395a3b4b jc/test-must-be-empty later to maint).
+ (merge 768b9d6db7 mk/doc-pretty-fill later to maint).
+ (merge 2caa7b8d27 ab/man-sec-list later to maint).
+ (merge 40c17eb184 ks/t3200-typofix later to maint).
+ (merge bd9958c358 dp/merge-strategy-doc-fix later to maint).
+ (merge 9ee0540a40 js/ming-strftime later to maint).
+ (merge 1775e990f7 tz/complete-tag-delete-tagname later to maint).
+ (merge 00a4b03501 rj/warning-uninitialized-fix later to maint).
+ (merge b635ed97a0 jk/attributes-path-doc later to maint).
diff --git a/Documentation/RelNotes/2.18.0.txt b/Documentation/RelNotes/2.18.0.txt
new file mode 100644
index 0000000..9042c3f
--- /dev/null
+++ b/Documentation/RelNotes/2.18.0.txt
@@ -0,0 +1,67 @@
+Git 2.18 Release Notes
+======================
+
+Updates since v2.17
+-------------------
+
+UI, Workflows & Features
+
+ * Rename detection logic in "diff" family that is used in "merge" has
+ learned to guess when all of x/a, x/b and x/c have moved to z/a,
+ z/b and z/c, it is likely that x/d added in the meantime would also
+ want to move to z/d by taking the hint that the entire directory
+ 'x' moved to 'z'. A bug causing dirty files involved in a rename
+ to be overwritten during merge has also been fixed as part of this
+ work.
+
+ * "git filter-branch" learned to use a different exit code to allow
+ the callers to tell the case where there was no new commits to
+ rewrite from other error cases.
+
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * A "git fetch" from a repository with insane number of refs into a
+ repository that is already up-to-date still wasted too many cycles
+ making many lstat(2) calls to see if these objects at the tips
+ exist as loose objects locally. These lstat(2) calls are optimized
+ away by enumerating all loose objects beforehand.
+ It is unknown if the new strategy negatively affects existing use
+ cases, fetching into a repository with many loose objects from a
+ repository with small number of refs.
+
+ * Git can be built to use either v1 or v2 of the PCRE library, and so
+ far, the build-time configuration USE_LIBPCRE=YesPlease instructed
+ the build procedure to use v1, but now it means v2. USE_LIBPCRE1
+ and USE_LIBPCRE2 can be used to explicitly choose which version to
+ use, as before.
+
+ * The build procedure learned to optionally use symbolic links
+ (instead of hardlinks and copies) to install "git-foo" for built-in
+ commands, whose binaries are all identical.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * The way "git worktree prune" worked internally has been simplified,
+ by assuming how "git worktree move" moves an existing worktree to a
+ different place.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.17
+-----------------
+
+ * "git shortlog cruft" aborted with a BUG message when run outside a
+ Git repository. The command has been taught to complain about
+ extra and unwanted arguments on its command line instead in such a
+ case.
+ (merge 4aa0161e83 ma/shortlog-revparse later to maint).
+
+ * "git stash push -u -- <pathspec>" gave an unnecessary and confusing
+ error message when there was no tracked files that match the
+ <pathspec>, which has been fixed.
+ (merge 353278687e tg/stash-untracked-with-pathspec-fix later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f57e9cf..4e0cff8 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1398,7 +1398,16 @@ fetch.unpackLimit::
fetch.prune::
If true, fetch will automatically behave as if the `--prune`
- option was given on the command line. See also `remote.<name>.prune`.
+ option was given on the command line. See also `remote.<name>.prune`
+ and the PRUNING section of linkgit:git-fetch[1].
+
+fetch.pruneTags::
+ If true, fetch will automatically behave as if the
+ `refs/tags/*:refs/tags/*` refspec was provided when pruning,
+ if not set already. This allows for setting both this option
+ and `fetch.prune` to maintain a 1=1 mapping to upstream
+ refs. See also `remote.<name>.pruneTags` and the PRUNING
+ section of linkgit:git-fetch[1].
fetch.output::
Control how ref update status is printed. Valid values are
@@ -2945,6 +2954,15 @@ remote.<name>.prune::
remote (as if the `--prune` option was given on the command line).
Overrides `fetch.prune` settings, if any.
+remote.<name>.pruneTags::
+ When set to true, fetching from this remote by default will also
+ remove any local tags that no longer exist on the remote if pruning
+ is activated in general via `remote.<name>.prune`, `fetch.prune` or
+ `--prune`. Overrides `fetch.pruneTags` settings, if any.
++
+See also `remote.<name>.prune` and the PRUNING section of
+linkgit:git-fetch[1].
+
remotes.<group>::
The list of remotes which are fetched by "git remote update
<group>". See linkgit:git-remote[1].
@@ -3210,7 +3228,8 @@ submodule.active::
submodule.recurse::
Specifies if commands recurse into submodules by default. This
- applies to all commands that have a `--recurse-submodules` option.
+ applies to all commands that have a `--recurse-submodules` option,
+ except `clone`.
Defaults to false.
submodule.fetchJobs::
@@ -3345,7 +3364,7 @@ uploadpack.packObjectsHook::
stdout.
uploadpack.allowFilter::
- If this option is set, `upload-pack` will advertise partial
+ If this option is set, `upload-pack` will support partial
clone and partial fetch object filtering.
+
Note that this configuration variable is ignored if it is seen in the
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index c330c01..e3a44f0 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -128,6 +128,14 @@ have to use `--diff-algorithm=default` option.
These parameters can also be set individually with `--stat-width=<width>`,
`--stat-name-width=<name-width>` and `--stat-count=<count>`.
+--compact-summary::
+ Output a condensed summary of extended header information such
+ as file creations or deletions ("new" or "gone", optionally "+l"
+ if it's a symlink) and mode changes ("+x" or "-x" for adding
+ or removing executable bit respectively) in diffstat. The
+ information is put betwen the filename part and the graph
+ part. Implies `--stat`.
+
--numstat::
Similar to `--stat`, but shows number of added and
deleted lines in decimal notation and pathname without
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index fb6bebb..8631e36 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -73,7 +73,22 @@ ifndef::git-pull[]
are fetched due to an explicit refspec (either on the command
line or in the remote configuration, for example if the remote
was cloned with the --mirror option), then they are also
- subject to pruning.
+ subject to pruning. Supplying `--prune-tags` is a shorthand for
+ providing the tag refspec.
++
+See the PRUNING section below for more details.
+
+-P::
+--prune-tags::
+ Before fetching, remove any local tags that no longer exist on
+ the remote if `--prune` is enabled. This option should be used
+ more carefully, unlike `--prune` it will remove any local
+ references (local tags) that have been created. This option is
+ a shorthand for providing the explicit tag refspec along with
+ `--prune`, see the discussion about that in its documentation.
++
+See the PRUNING section below for more details.
+
endif::git-pull[]
ifndef::git-pull[]
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 12879e4..6f6c34b 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -16,7 +16,7 @@ SYNOPSIS
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
[--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
[(<mbox> | <Maildir>)...]
-'git am' (--continue | --skip | --abort)
+'git am' (--continue | --skip | --abort | --quit | --show-current-patch)
DESCRIPTION
-----------
@@ -167,6 +167,14 @@ default. You can use `--no-utf8` to override this.
--abort::
Restore the original branch and abort the patching operation.
+--quit::
+ Abort the patching operation but keep HEAD and the index
+ untouched.
+
+--show-current-patch::
+ Show the patch being applied when "git am" is stopped because
+ of conflicts.
+
DISCUSSION
----------
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 14da5fc..e09ed5d 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -233,6 +233,12 @@ See also <<FILES>>.
using `--file`, `--global`, etc) and `on` when searching all
config files.
+CONFIGURATION
+-------------
+`pager.config` is only respected when listing configuration, i.e., when
+using `--list` or any of the `--get-*` which may return multiple results.
+The default is to use a pager.
+
[[FILES]]
FILES
-----
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index 3c91db7..56d54a4 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -20,6 +20,7 @@ SYNOPSIS
[--inetd |
[--listen=<host_or_ipaddr>] [--port=<n>]
[--user=<user> [--group=<group>]]]
+ [--log-destination=(stderr|syslog|none)]
[<directory>...]
DESCRIPTION
@@ -80,7 +81,8 @@ OPTIONS
do not have the 'git-daemon-export-ok' file.
--inetd::
- Have the server run as an inetd service. Implies --syslog.
+ Have the server run as an inetd service. Implies --syslog (may be
+ overridden with `--log-destination=`).
Incompatible with --detach, --port, --listen, --user and --group
options.
@@ -110,8 +112,28 @@ OPTIONS
zero for no limit.
--syslog::
- Log to syslog instead of stderr. Note that this option does not imply
- --verbose, thus by default only error conditions will be logged.
+ Short for `--log-destination=syslog`.
+
+--log-destination=<destination>::
+ Send log messages to the specified destination.
+ Note that this option does not imply --verbose,
+ thus by default only error conditions will be logged.
+ The <destination> must be one of:
++
+--
+stderr::
+ Write to standard error.
+ Note that if `--detach` is specified,
+ the process disconnects from the real standard error,
+ making this destination effectively equivalent to `none`.
+syslog::
+ Write to syslog, using the `git-daemon` identifier.
+none::
+ Disable all logging.
+--
++
+The default destination is `syslog` if `--inetd` or `--detach` is specified,
+otherwise `stderr`.
--user-path::
--user-path=<path>::
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index b153aef..e319935 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -99,6 +99,93 @@ The latter use of the `remote.<repository>.fetch` values can be
overridden by giving the `--refmap=<refspec>` parameter(s) on the
command line.
+PRUNING
+-------
+
+Git has a default disposition of keeping data unless it's explicitly
+thrown away; this extends to holding onto local references to branches
+on remotes that have themselves deleted those branches.
+
+If left to accumulate, these stale references might make performance
+worse on big and busy repos that have a lot of branch churn, and
+e.g. make the output of commands like `git branch -a --contains
+<commit>` needlessly verbose, as well as impacting anything else
+that'll work with the complete set of known references.
+
+These remote-tracking references can be deleted as a one-off with
+either of:
+
+------------------------------------------------
+# While fetching
+$ git fetch --prune <name>
+
+# Only prune, don't fetch
+$ git remote prune <name>
+------------------------------------------------
+
+To prune references as part of your normal workflow without needing to
+remember to run that, set `fetch.prune` globally, or
+`remote.<name>.prune` per-remote in the config. See
+linkgit:git-config[1].
+
+Here's where things get tricky and more specific. The pruning feature
+doesn't actually care about branches, instead it'll prune local <->
+remote-references as a function of the refspec of the remote (see
+`<refspec>` and <<CRTB,CONFIGURED REMOTE-TRACKING BRANCHES>> above).
+
+Therefore if the refspec for the remote includes
+e.g. `refs/tags/*:refs/tags/*`, or you manually run e.g. `git fetch
+--prune <name> "refs/tags/*:refs/tags/*"` it won't be stale remote
+tracking branches that are deleted, but any local tag that doesn't
+exist on the remote.
+
+This might not be what you expect, i.e. you want to prune remote
+`<name>`, but also explicitly fetch tags from it, so when you fetch
+from it you delete all your local tags, most of which may not have
+come from the `<name>` remote in the first place.
+
+So be careful when using this with a refspec like
+`refs/tags/*:refs/tags/*`, or any other refspec which might map
+references from multiple remotes to the same local namespace.
+
+Since keeping up-to-date with both branches and tags on the remote is
+a common use-case the `--prune-tags` option can be supplied along with
+`--prune` to prune local tags that don't exist on the remote, and
+force-update those tags that differ. Tag pruning can also be enabled
+with `fetch.pruneTags` or `remote.<name>.pruneTags` in the config. See
+linkgit:git-config[1].
+
+The `--prune-tags` option is equivalent to having
+`refs/tags/*:refs/tags/*` declared in the refspecs of the remote. This
+can lead to some seemingly strange interactions:
+
+------------------------------------------------
+# These both fetch tags
+$ git fetch --no-tags origin 'refs/tags/*:refs/tags/*'
+$ git fetch --no-tags --prune-tags origin
+------------------------------------------------
+
+The reason it doesn't error out when provided without `--prune` or its
+config versions is for flexibility of the configured versions, and to
+maintain a 1=1 mapping between what the command line flags do, and
+what the configuration versions do.
+
+It's reasonable to e.g. configure `fetch.pruneTags=true` in
+`~/.gitconfig` to have tags pruned whenever `git fetch --prune` is
+run, without making every invocation of `git fetch` without `--prune`
+an error.
+
+Pruning tags with `--prune-tags` also works when fetching a URL
+instead of a named remote. These will all prune tags not found on
+origin:
+
+------------------------------------------------
+$ git fetch origin --prune --prune-tags
+$ git fetch origin --prune 'refs/tags/*:refs/tags/*'
+$ git fetch <url of origin> --prune --prune-tags
+$ git fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
+------------------------------------------------
+
OUTPUT
------
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 3a52e4d..b634043 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -222,6 +222,14 @@ this purpose, they are instead rewritten to point at the nearest ancestor that
was not excluded.
+EXIT STATUS
+-----------
+
+On success, the exit status is `0`. If the filter can't find any commits to
+rewrite, the exit status is `2`. On any other error, the exit status may be
+any other non-zero value.
+
+
Examples
--------
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 571b5a7..3126e0d 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -15,8 +15,9 @@ DESCRIPTION
-----------
Runs a number of housekeeping tasks within the current repository,
such as compressing file revisions (to reduce disk space and increase
-performance) and removing unreachable objects which may have been
-created from prior invocations of 'git add'.
+performance), removing unreachable objects which may have been
+created from prior invocations of 'git add', packing refs, pruning
+reflog, rerere metadata or stale working trees.
Users are encouraged to run this task on a regular basis within
each repository to maintain good disk space utilization and good
@@ -45,20 +46,25 @@ OPTIONS
With this option, 'git gc' checks whether any housekeeping is
required; if not, it exits without performing any work.
Some git commands run `git gc --auto` after performing
- operations that could create many loose objects.
+ operations that could create many loose objects. Housekeeping
+ is required if there are too many loose objects or too many
+ packs in the repository.
+
-Housekeeping is required if there are too many loose objects or
-too many packs in the repository. If the number of loose objects
-exceeds the value of the `gc.auto` configuration variable, then
-all loose objects are combined into a single pack using
-`git repack -d -l`. Setting the value of `gc.auto` to 0
-disables automatic packing of loose objects.
+If the number of loose objects exceeds the value of the `gc.auto`
+configuration variable, then all loose objects are combined into a
+single pack using `git repack -d -l`. Setting the value of `gc.auto`
+to 0 disables automatic packing of loose objects.
+
If the number of packs exceeds the value of `gc.autoPackLimit`,
then existing packs (except those marked with a `.keep` file)
are consolidated into a single pack by using the `-A` option of
'git repack'. Setting `gc.autoPackLimit` to 0 disables
automatic consolidation of packs.
++
+If houskeeping is required due to many loose objects or packs, all
+other housekeeping tasks (e.g. rerere, working trees, reflog...) will
+be performed as well.
+
--prune=<date>::
Prune loose objects older than date (default is 2 weeks ago,
@@ -133,6 +139,10 @@ The optional configuration variable `gc.pruneExpire` controls how old
the unreferenced loose objects have to be before they are pruned. The
default is "2 weeks ago".
+Optional configuration variable `gc.worktreePruneExpire` controls how
+old a stale working tree should be before `git worktree prune` deletes
+it. Default is "3 months ago".
+
Notes
-----
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 1b4b65d..138edb4 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -77,6 +77,9 @@ OPTIONS
--check-self-contained-and-connected::
Die if the pack contains broken links. For internal use only.
+--fsck-objects::
+ Die if the pack contains broken objects. For internal use only.
+
--threads=<n>::
Specifies the number of threads to spawn when resolving
deltas. This requires that index-pack be compiled with
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 9dd19a1..ff446f1 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -51,7 +51,7 @@ with only spaces at the end of the commit message part, one blank line
will be added before the new trailer.
Existing trailers are extracted from the input message by looking for
-a group of one or more lines that (i) are all trailers, or (ii) contains at
+a group of one or more lines that (i) is all trailers, or (ii) contains at
least one Git-generated or user-configured trailer and consists of at
least 25% trailers.
The group must be preceded by one or more empty (or whitespace-only) lines.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 8a861c1..3277ca1 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[<upstream> [<branch>]]
'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
--root [<branch>]
-'git rebase' --continue | --skip | --abort | --quit | --edit-todo
+'git rebase' --continue | --skip | --abort | --quit | --edit-todo | --show-current-patch
DESCRIPTION
-----------
@@ -244,12 +244,22 @@ leave out at most one of A and B, in which case it defaults to HEAD.
Keep the commits that do not change anything from its
parents in the result.
+--allow-empty-message::
+ By default, rebasing commits with an empty message will fail.
+ This option overrides that behavior, allowing commits with empty
+ messages to be rebased.
+
--skip::
Restart the rebasing process by skipping the current patch.
--edit-todo::
Edit the todo list during an interactive rebase.
+--show-current-patch::
+ Show the current patch in an interactive rebase or when rebase
+ is stopped because of conflicts. This is the equivalent of
+ `git show REBASE_HEAD`.
+
-m::
--merge::
Use merging strategies to rebase. When the recursive (default) merge
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 577b969..4feddc0 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -172,10 +172,14 @@ With `-n` option, the remote heads are not queried first with
'prune'::
-Deletes all stale remote-tracking branches under <name>.
-These stale branches have already been removed from the remote repository
-referenced by <name>, but are still locally available in
-"remotes/<name>".
+Deletes stale references associated with <name>. By default, stale
+remote-tracking branches under <name> are deleted, but depending on
+global configuration and the configuration of the remote we might even
+prune local tags that haven't been pushed there. Equivalent to `git
+fetch --prune <name>`, except that no new references will be fetched.
++
+See the PRUNING section of linkgit:git-fetch[1] for what it'll prune
+depending on various configuration.
+
With `--dry-run` option, report what branches will be pruned, but do not
actually prune them.
@@ -189,7 +193,7 @@ remotes.default is not defined, all remotes which do not have the
configuration parameter remote.<name>.skipDefaultUpdate set to true will
be updated. (See linkgit:git-config[1]).
+
-With `--prune` option, prune all the remotes that are updated.
+With `--prune` option, run pruning against all the remotes that are updated.
DISCUSSION
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 8060ea3..71ef97b 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -84,6 +84,11 @@ See the CONFIGURATION section for `sendemail.multiEdit`.
the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not
set, as returned by "git var -l".
+--reply-to=<address>::
+ Specify the address where replies from recipients should go to.
+ Use this if replies to messages should go to another address than what
+ is specified with the --from parameter.
+
--in-reply-to=<identifier>::
Make the first mail (or all the mails with `--no-thread`) appear as a
reply to the given Message-Id, which avoids breaking threads to
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index ee6c547..5e35ea1 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -8,8 +8,8 @@ git-shortlog - Summarize 'git log' output
SYNOPSIS
--------
[verse]
-git log --pretty=short | 'git shortlog' [<options>]
'git shortlog' [<options>] [<revision range>] [[\--] <path>...]
+git log --pretty=short | 'git shortlog' [<options>]
DESCRIPTION
-----------
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 056dfb8..7ef8c47 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -14,7 +14,7 @@ SYNOPSIS
'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
'git stash' branch <branchname> [<stash>]
'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
- [-u|--include-untracked] [-a|--all] [-m|--message <message>]]
+ [-u|--include-untracked] [-a|--all] [-m|--message <message>]
[--] [<pathspec>...]]
'git stash' clear
'git stash' create [<message>]
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 72bfb87..6c230c0 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -130,6 +130,11 @@ ignored, then the directory is not shown, but all contents are shown.
without options are equivalent to 'always' and 'never'
respectively.
+--ahead-behind::
+--no-ahead-behind::
+ Display or do not display detailed ahead/behind counts for the
+ branch relative to its upstream branch. Defaults to true.
+
<pathspec>...::
See the 'pathspec' entry in linkgit:gitglossary[7].
@@ -184,10 +189,10 @@ in which case `XY` are `!!`.
X Y Meaning
-------------------------------------------------
- [MD] not updated
+ [AMD] not updated
M [ MD] updated in index
A [ MD] added to index
- D [ M] deleted from index
+ D deleted from index
R [ MD] renamed in index
C [ MD] copied in index
[MARC] index and work tree matches
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 956fc01..1d17101 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -9,7 +9,7 @@ git-tag - Create, list, delete or verify a tag object signed with GPG
SYNOPSIS
--------
[verse]
-'git tag' [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>]
+'git tag' [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>] [-e]
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
'git tag' [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
@@ -167,6 +167,12 @@ This option is only applicable when listing tags without annotation lines.
Implies `-a` if none of `-a`, `-s`, or `-u <keyid>`
is given.
+-e::
+--edit::
+ The message taken from file with `-F` and command line with
+ `-m` are usually used as the tag message unmodified.
+ This option lets you further edit the message taken from these sources.
+
--cleanup=<mode>::
This option sets how the tag message is cleaned up.
The '<mode>' can be one of 'verbatim', 'whitespace' and 'strip'. The
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index bdb0342..3897a59 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -464,6 +464,32 @@ command reads the index; while when `--[no-|force-]untracked-cache`
are used, the untracked cache is immediately added to or removed from
the index.
+Before 2.17, the untracked cache had a bug where replacing a directory
+with a symlink to another directory could cause it to incorrectly show
+files tracked by git as untracked. See the "status: add a failing test
+showing a core.untrackedCache bug" commit to git.git. A workaround for
+that is (and this might work for other undiscovered bugs in the
+future):
+
+----------------
+$ git -c core.untrackedCache=false status
+----------------
+
+This bug has also been shown to affect non-symlink cases of replacing
+a directory with a file when it comes to the internal structures of
+the untracked cache, but no case has been reported where this resulted in
+wrong "git status" output.
+
+There are also cases where existing indexes written by git versions
+before 2.17 will reference directories that don't exist anymore,
+potentially causing many "could not open directory" warnings to be
+printed on "git status". These are new warnings for existing issues
+that were previously silently discarded.
+
+As with the bug described above the solution is to one-off do a "git
+status" run with `core.untrackedCache=false` to flush out the leftover
+bad data.
+
File System Monitor
-------------------
@@ -484,8 +510,8 @@ the `core.fsmonitor` configuration variable (see
linkgit:git-config[1]) than using the `--fsmonitor` option to
`git update-index` in each repository, especially if you want to do so
across all repositories you use, because you can set the configuration
-variable to `true` (or `false`) in your `$HOME/.gitconfig` just once
-and have it affect all repositories you touch.
+variable in your `$HOME/.gitconfig` just once and have it affect all
+repositories you touch.
When the `core.fsmonitor` configuration variable is changed, the
file system monitor is added to or removed from the index the next time
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f5..e7eb24a 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -12,7 +12,9 @@ SYNOPSIS
'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]
'git worktree list' [--porcelain]
'git worktree lock' [--reason <string>] <worktree>
+'git worktree move' <worktree> <new-path>
'git worktree prune' [-n] [-v] [--expire <expire>]
+'git worktree remove' [--force] <worktree>
'git worktree unlock' <worktree>
DESCRIPTION
@@ -34,10 +36,6 @@ The working tree's administrative files in the repository (see
`git worktree prune` in the main or any linked working tree to
clean up any stale administrative files.
-If you move a linked working tree, you need to manually update the
-administrative files so that they do not get pruned automatically. See
-section "DETAILS" for more information.
-
If a linked working tree is stored on a portable device or network share
which is not always mounted, you can prevent its administrative files from
being pruned by issuing the `git worktree lock` command, optionally
@@ -52,10 +50,11 @@ is linked to the current repository, sharing everything except working
directory specific files such as HEAD, index, etc. `-` may also be
specified as `<commit-ish>`; it is synonymous with `@{-1}`.
+
-If <commit-ish> is a branch name (call it `<branch>` and is not found,
+If <commit-ish> is a branch name (call it `<branch>`) and is not found,
and neither `-b` nor `-B` nor `--detach` are used, but there does
exist a tracking branch in exactly one remote (call it `<remote>`)
-with a matching name, treat as equivalent to
+with a matching name, treat as equivalent to:
++
------------
$ git worktree add --track -b <branch> <path> <remote>/<branch>
------------
@@ -79,10 +78,22 @@ files from being pruned automatically. This also prevents it from
being moved or deleted. Optionally, specify a reason for the lock
with `--reason`.
+move::
+
+Move a working tree to a new location. Note that the main working tree
+or linked working trees containing submodules cannot be moved.
+
prune::
Prune working tree information in $GIT_DIR/worktrees.
+remove::
+
+Remove a working tree. Only clean working trees (no untracked files
+and no modification in tracked files) can be removed. Unclean working
+trees or ones with submodules can be removed with `--force`. The main
+working tree cannot be removed.
+
unlock::
Unlock a working tree, allowing it to be pruned, moved or deleted.
@@ -92,9 +103,10 @@ OPTIONS
-f::
--force::
- By default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and
- is already checked out by another working tree. This option overrides
- that safeguard.
+ By default, `add` refuses to create a new working tree when
+ `<commit-ish>` is a branch name and is already checked out by
+ another working tree and `remove` refuses to remove an unclean
+ working tree. This option overrides that safeguard.
-b <new-branch>::
-B <new-branch>::
@@ -196,7 +208,7 @@ thumb is do not make any assumption about whether a path belongs to
$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
-If you move a linked working tree, you need to update the 'gitdir' file
+If you manually move a linked working tree, you need to update the 'gitdir' file
in the entry's directory. For example, if a linked working tree is moved
to `/newpath/test-next` and its `.git` file points to
`/path/main/.git/worktrees/test-next`, then update
@@ -276,13 +288,6 @@ Multiple checkout in general is still experimental, and the support
for submodules is incomplete. It is NOT recommended to make multiple
checkouts of a superproject.
-git-worktree could provide more automation for tasks currently
-performed manually, such as:
-
-- `remove` to remove a linked working tree and its administrative files (and
- warn if the working tree is dirty)
-- `mv` to move or rename a working tree and update its administrative files
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 8163b57..4767860 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -849,6 +849,9 @@ Report bugs to the Git mailing list <git@vger.kernel.org> where the
development and maintenance is primarily done. You do not have to be
subscribed to the list to send a message there.
+Issues which are security relevant should be disclosed privately to
+the Git Security mailing list <git-security@googlegroups.com>.
+
SEE ALSO
--------
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index c21f5ca..1094fe2 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -56,9 +56,16 @@ Unspecified::
When more than one pattern matches the path, a later line
overrides an earlier line. This overriding is done per
-attribute. The rules how the pattern matches paths are the
-same as in `.gitignore` files; see linkgit:gitignore[5].
-Unlike `.gitignore`, negative patterns are forbidden.
+attribute.
+
+The rules by which the pattern matches paths are the same as in
+`.gitignore` files (see linkgit:gitignore[5]), with a few exceptions:
+
+ - negative patterns are forbidden
+
+ - patterns that match a directory do not recursively match paths
+ inside that directory (so using the trailing-slash `path/` syntax is
+ pointless in an attributes file; use `path/**` instead)
When deciding what attributes are assigned to a path, Git
consults `$GIT_DIR/info/attributes` file (which has the highest
@@ -714,6 +721,8 @@ patterns are available:
- `fountain` suitable for Fountain documents.
+- `golang` suitable for source code in the Go language.
+
- `html` suitable for HTML/XHTML documents.
- `java` suitable for source code in the Java language.
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 63260f0..ff5d7f9 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -102,12 +102,11 @@ PATTERN FORMAT
(relative to the toplevel of the work tree if not from a
`.gitignore` file).
- - Otherwise, Git treats the pattern as a shell glob suitable
- for consumption by fnmatch(3) with the FNM_PATHNAME flag:
- wildcards in the pattern will not match a / in the pathname.
- For example, "Documentation/{asterisk}.html" matches
- "Documentation/git.html" but not "Documentation/ppc/ppc.html"
- or "tools/perf/Documentation/perf.html".
+ - Otherwise, Git treats the pattern as a shell glob: "`*`" matches
+ anything except "`/`", "`?`" matches any one character except "`/`"
+ and "`[]`" matches one character in a selected range. See
+ fnmatch(3) and the FNM_PATHNAME flag for a more detailed
+ description.
- A leading slash matches the beginning of the pathname.
For example, "/{asterisk}.c" matches "cat-file.c" but not
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index c60bcad..e85148f 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -275,11 +275,6 @@ worktrees/<id>/locked::
or manually by `git worktree prune`. The file may contain a string
explaining why the repository is locked.
-worktrees/<id>/link::
- If this file exists, it is a hard link to the linked .git
- file. It is used to detect if the linked repository is
- manually removed.
-
SEE ALSO
--------
linkgit:git-init[1],
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index 4d6c177..3b9faab 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -24,7 +24,7 @@ On the filesystem, a submodule usually (but not always - see FORMS below)
consists of (i) a Git directory located under the `$GIT_DIR/modules/`
directory of its superproject, (ii) a working directory inside the
superproject's working directory, and a `.git` file at the root of
-the submodule’s working directory pointing to (i).
+the submodule's working directory pointing to (i).
Assuming the submodule has a Git directory at `$GIT_DIR/modules/foo/`
and a working directory at `path/to/bar/`, the superproject tracks the
@@ -33,7 +33,7 @@ in its `.gitmodules` file (see linkgit:gitmodules[5]) of the form
`submodule.foo.path = path/to/bar`.
The `gitlink` entry contains the object name of the commit that the
-superproject expects the submodule’s working directory to be at.
+superproject expects the submodule's working directory to be at.
The section `submodule.foo.*` in the `.gitmodules` file gives additional
hints to Git's porcelain layer. For example, the `submodule.foo.url`
@@ -136,27 +136,27 @@ using older versions of Git.
+
It is possible to construct these old form repositories manually.
+
-When deinitialized or deleted (see below), the submodule’s Git
+When deinitialized or deleted (see below), the submodule's Git
directory is automatically moved to `$GIT_DIR/modules/<name>/`
of the superproject.
* Deinitialized submodule: A `gitlink`, and a `.gitmodules` entry,
-but no submodule working directory. The submodule’s Git directory
+but no submodule working directory. The submodule's Git directory
may be there as after deinitializing the Git directory is kept around.
The directory which is supposed to be the working directory is empty instead.
+
A submodule can be deinitialized by running `git submodule deinit`.
Besides emptying the working directory, this command only modifies
-the superproject’s `$GIT_DIR/config` file, so the superproject’s history
+the superproject's `$GIT_DIR/config` file, so the superproject's history
is not affected. This can be undone using `git submodule init`.
* Deleted submodule: A submodule can be deleted by running
`git rm <submodule path> && git commit`. This can be undone
using `git revert`.
+
-The deletion removes the superproject’s tracking data, which are
+The deletion removes the superproject's tracking data, which are
both the `gitlink` entry and the section in the `.gitmodules` file.
-The submodule’s working directory is removed from the file
+The submodule's working directory is removed from the file
system, but the Git directory is kept around as it to make it
possible to checkout past commits without requiring fetching
from another repository.
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 3888c3f..63a3fc0 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -35,7 +35,8 @@ set to `no` at the beginning of them.
--no-ff::
Create a merge commit even when the merge resolves as a
fast-forward. This is the default behaviour when merging an
- annotated (and possibly signed) tag.
+ annotated (and possibly signed) tag that is not stored in
+ its natural place in 'refs/tags/' hierarchy.
--ff-only::
Refuse to merge and exit with a non-zero status unless the
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index fd5d748..4a58aad 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -40,7 +40,7 @@ the other tree did, declaring 'our' history contains all that happened in it.
theirs;;
This is the opposite of 'ours'; note that, unlike 'ours', there is
- no 'theirs' merge stragegy to confuse this merge option with.
+ no 'theirs' merge strategy to confuse this merge option with.
patience;;
With this option, 'merge-recursive' spends a little extra time
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index e664c08..6109ef0 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -202,7 +202,7 @@ endif::git-rev-list[]
- '%>>(<N>)', '%>>|(<N>)': similar to '%>(<N>)', '%>|(<N>)'
respectively, except that if the next placeholder takes more spaces
than given and there are spaces on its left, use those spaces
-- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
+- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
respectively, but padding both sides (i.e. the text is centered)
- %(trailers[:options]): display the trailers of the body as interpreted
by linkgit:git-interpret-trailers[1]. The `trailers` string may be
diff --git a/Documentation/technical/api-object-access.txt b/Documentation/technical/api-object-access.txt
index 03bb0e9..a1162e5 100644
--- a/Documentation/technical/api-object-access.txt
+++ b/Documentation/technical/api-object-access.txt
@@ -7,7 +7,7 @@ Talk about <sha1_file.c> and <object.h> family, things like
* read_object_with_reference()
* has_sha1_file()
* write_sha1_file()
-* pretend_sha1_file()
+* pretend_object_file()
* lookup_{object,commit,tag,blob,tree}
* parse_{object,commit,tag,blob,tree}
* Use of object flags
diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt
index 3dce003..ee907c4 100644
--- a/Documentation/technical/api-submodule-config.txt
+++ b/Documentation/technical/api-submodule-config.txt
@@ -4,7 +4,7 @@ submodule config cache API
The submodule config cache API allows to read submodule
configurations/information from specified revisions. Internally
information is lazily read into a cache that is used to avoid
-unnecessary parsing of the same .gitmodule files. Lookups can be done by
+unnecessary parsing of the same .gitmodules files. Lookups can be done by
submodule path or name.
Usage
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
index a0e45f2..64f49d0 100644
--- a/Documentation/technical/http-protocol.txt
+++ b/Documentation/technical/http-protocol.txt
@@ -214,10 +214,12 @@ smart server reply:
S: Cache-Control: no-cache
S:
S: 001e# service=git-upload-pack\n
+ S: 0000
S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
S: 0042d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
+ S: 0000
The client may send Extra Parameters (see
Documentation/technical/pack-protocol.txt) as a colon-separated string
@@ -277,6 +279,7 @@ The returned response contains "version 1" if "version=1" was sent as an
Extra Parameter.
smart_reply = PKT-LINE("# service=$servicename" LF)
+ "0000"
*1("version 1")
ref_list
"0000"
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 0c86f1c..12ff59c 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.16.GIT
+DEF_VER=v2.17.GIT
LF='
'
diff --git a/INSTALL b/INSTALL
index 808e07b..c39006e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -88,9 +88,9 @@ Issues of note:
export GIT_EXEC_PATH PATH GITPERLLIB
- By default (unless NO_PERL is provided) Git will ship various perl
- scripts & libraries it needs. However, for simplicity it doesn't
- use the ExtUtils::MakeMaker toolchain to decide where to place the
- perl libraries. Depending on the system this can result in the perl
+ scripts. However, for simplicity it doesn't use the
+ ExtUtils::MakeMaker toolchain to decide where to place the perl
+ libraries. Depending on the system this can result in the perl
libraries not being where you'd like them if they're expected to be
used by things other than Git itself.
@@ -102,6 +102,11 @@ Issues of note:
Will result in e.g. perllibdir=/usr/share/perl/5.26.1 on Debian,
perllibdir=/usr/share/perl5 (which we'd use by default) on CentOS.
+ - Unless NO_PERL is provided Git will ship various perl libraries it
+ needs. Distributors of Git will usually want to set
+ NO_PERL_CPAN_FALLBACKS if NO_PERL is not provided to use their own
+ copies of the CPAN modules Git needs.
+
- Git is reasonably self-sufficient, but does depend on a few external
programs and libraries. Git can be used without most of them by adding
the approriate "NO_<LIBRARY>=YesPlease" to the make command line or
@@ -121,7 +126,8 @@ Issues of note:
Redhat/Fedora are reported to ship Perl binary package with some
core modules stripped away (see http://lwn.net/Articles/477234/),
so you might need to install additional packages other than Perl
- itself, e.g. Time::HiRes.
+ itself, e.g. Digest::MD5, File::Spec, File::Temp, Net::Domain,
+ Net::SMTP, and Time::HiRes.
- git-imap-send needs the OpenSSL library to talk IMAP over SSL if
you are using libcurl older than 7.34.0. Otherwise you can use
diff --git a/Makefile b/Makefile
index 5bcd83d..96f6138 100644
--- a/Makefile
+++ b/Makefile
@@ -29,10 +29,10 @@ all::
# Perl-compatible regular expressions instead of standard or extended
# POSIX regular expressions.
#
-# Currently USE_LIBPCRE is a synonym for USE_LIBPCRE1, define
-# USE_LIBPCRE2 instead if you'd like to use version 2 of the PCRE
-# library. The USE_LIBPCRE flag will likely be changed to mean v2 by
-# default in future releases.
+# USE_LIBPCRE is a synonym for USE_LIBPCRE2, define USE_LIBPCRE1
+# instead if you'd like to use the legacy version 1 of the PCRE
+# library. Support for version 1 will likely be removed in some future
+# release of Git, as upstream has all but abandoned it.
#
# When using USE_LIBPCRE1, define NO_LIBPCRE1_JIT if the PCRE v1
# library is compiled without --enable-jit. We will auto-detect
@@ -296,6 +296,12 @@ all::
#
# Define NO_PERL if you do not want Perl scripts or libraries at all.
#
+# Define NO_PERL_CPAN_FALLBACKS if you do not want to install bundled
+# copies of CPAN modules that serve as a fallback in case the modules
+# are not available on the system. This option is intended for
+# distributions that want to use their packaged versions of Perl
+# modules, instead of the fallbacks shipped with Git.
+#
# Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
# but /usr/bin/python2.7 on some platforms).
#
@@ -329,6 +335,13 @@ all::
# when hardlinking a file to another name and unlinking the original file right
# away (some NTFS drivers seem to zero the contents in that scenario).
#
+# Define INSTALL_SYMLINKS if you prefer to have everything that can be
+# symlinked between bin/ and libexec/ to use relative symlinks between
+# the two. This option overrides NO_CROSS_DIRECTORY_HARDLINKS and
+# NO_INSTALL_HARDLINKS which will also use symlinking by indirection
+# within the same directory in some cases, INSTALL_SYMLINKS will
+# always symlink to the final target directly.
+#
# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
# programs as a tar, where bin/ and libexec/ might be on different file systems.
#
@@ -468,8 +481,7 @@ ARFLAGS = rcs
# This can help installing the suite in a relocatable way.
prefix = $(HOME)
-bindir_relative = bin
-bindir = $(prefix)/$(bindir_relative)
+bindir = $(prefix)/bin
mandir = $(prefix)/share/man
infodir = $(prefix)/share/info
gitexecdir = libexec/git-core
@@ -486,8 +498,10 @@ lib = lib
# DESTDIR =
pathsep = :
+bindir_relative = $(patsubst $(prefix)/%,%,$(bindir))
mandir_relative = $(patsubst $(prefix)/%,%,$(mandir))
infodir_relative = $(patsubst $(prefix)/%,%,$(infodir))
+gitexecdir_relative = $(patsubst $(prefix)/%,%,$(gitexecdir))
htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
export prefix bindir sharedir sysconfdir gitwebdir perllibdir localedir
@@ -1164,13 +1178,18 @@ ifdef NO_LIBGEN_H
COMPAT_OBJS += compat/basename.o
endif
-USE_LIBPCRE1 ?= $(USE_LIBPCRE)
+USE_LIBPCRE2 ?= $(USE_LIBPCRE)
-ifneq (,$(USE_LIBPCRE1))
- ifdef USE_LIBPCRE2
-$(error Only set USE_LIBPCRE1 (or its alias USE_LIBPCRE) or USE_LIBPCRE2, not both!)
+ifneq (,$(USE_LIBPCRE2))
+ ifdef USE_LIBPCRE1
+$(error Only set USE_LIBPCRE2 (or its alias USE_LIBPCRE) or USE_LIBPCRE1, not both!)
endif
+ BASIC_CFLAGS += -DUSE_LIBPCRE2
+ EXTLIBS += -lpcre2-8
+endif
+
+ifdef USE_LIBPCRE1
BASIC_CFLAGS += -DUSE_LIBPCRE1
EXTLIBS += -lpcre
@@ -1179,11 +1198,6 @@ ifdef NO_LIBPCRE1_JIT
endif
endif
-ifdef USE_LIBPCRE2
- BASIC_CFLAGS += -DUSE_LIBPCRE2
- EXTLIBS += -lpcre2-8
-endif
-
ifdef LIBPCREDIR
BASIC_CFLAGS += -I$(LIBPCREDIR)/include
EXTLIBS += -L$(LIBPCREDIR)/$(lib) $(CC_LD_DYNPATH)$(LIBPCREDIR)/$(lib)
@@ -1513,7 +1527,9 @@ else
LIB_OBJS += sha1dc_git.o
ifdef DC_SHA1_EXTERNAL
ifdef DC_SHA1_SUBMODULE
+ ifneq ($(DC_SHA1_SUBMODULE),auto)
$(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both)
+ endif
endif
BASIC_CFLAGS += -DDC_SHA1_EXTERNAL
EXTLIBS += -lsha1detectcoll
@@ -1733,6 +1749,7 @@ infodir_relative_SQ = $(subst ','\'',$(infodir_relative))
perllibdir_SQ = $(subst ','\'',$(perllibdir))
localedir_SQ = $(subst ','\'',$(localedir))
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
+gitexecdir_relative_SQ = $(subst ','\'',$(gitexecdir_relative))
template_dir_SQ = $(subst ','\'',$(template_dir))
htmldir_relative_SQ = $(subst ','\'',$(htmldir_relative))
prefix_SQ = $(subst ','\'',$(prefix))
@@ -2160,6 +2177,8 @@ gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SPARSE_FLAGS += \
-DCURL_DISABLE_TYPECHECK
+pack-revindex.sp: SPARSE_FLAGS += -Wno-memcpy-max-count
+
ifdef NO_EXPAT
http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
endif
@@ -2214,13 +2233,15 @@ $(VCSSVN_LIB): $(VCSSVN_OBJS)
export DEFAULT_EDITOR DEFAULT_PAGER
-.PHONY: doc man html info pdf
-doc:
+.PHONY: doc man man-perl html info pdf
+doc: man-perl
$(MAKE) -C Documentation all
-man:
+man: man-perl
$(MAKE) -C Documentation man
+man-perl: perl/build/man/man3/Git.3pm
+
html:
$(MAKE) -C Documentation html
@@ -2298,14 +2319,22 @@ po/build/locale/%/LC_MESSAGES/git.mo: po/%.po
LIB_PERL := $(wildcard perl/Git.pm perl/Git/*.pm perl/Git/*/*.pm perl/Git/*/*/*.pm)
LIB_PERL_GEN := $(patsubst perl/%.pm,perl/build/lib/%.pm,$(LIB_PERL))
+LIB_CPAN := $(wildcard perl/FromCPAN/*.pm perl/FromCPAN/*/*.pm)
+LIB_CPAN_GEN := $(patsubst perl/%.pm,perl/build/lib/%.pm,$(LIB_CPAN))
ifndef NO_PERL
all:: $(LIB_PERL_GEN)
+ifndef NO_PERL_CPAN_FALLBACKS
+all:: $(LIB_CPAN_GEN)
+endif
+NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\'',$(NO_PERL_CPAN_FALLBACKS))
endif
perl/build/lib/%.pm: perl/%.pm
$(QUIET_GEN)mkdir -p $(dir $@) && \
- sed -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' < $< > $@
+ sed -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
+ -e 's|@@NO_PERL_CPAN_FALLBACKS@@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \
+ < $< > $@
perl/build/man/man3/Git.3pm: perl/Git.pm
$(QUIET_GEN)mkdir -p $(dir $@) && \
@@ -2586,39 +2615,48 @@ endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
+ destdir_from_execdir_SQ=$$(echo '$(gitexecdir_relative_SQ)' | sed -e 's|[^/][^/]*|..|g') && \
{ test "$$bindir/" = "$$execdir/" || \
for p in git$X $(filter $(install_bindir_programs),$(ALL_PROGRAMS)); do \
$(RM) "$$execdir/$$p" && \
- test -z "$(NO_INSTALL_HARDLINKS)$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
- ln "$$bindir/$$p" "$$execdir/$$p" 2>/dev/null || \
- cp "$$bindir/$$p" "$$execdir/$$p" || exit; \
+ test -n "$(INSTALL_SYMLINKS)" && \
+ ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/$$p" "$$execdir/$$p" || \
+ { test -z "$(NO_INSTALL_HARDLINKS)$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
+ ln "$$bindir/$$p" "$$execdir/$$p" 2>/dev/null || \
+ cp "$$bindir/$$p" "$$execdir/$$p" || exit; } \
done; \
} && \
for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \
$(RM) "$$bindir/$$p" && \
- test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
- ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
- cp "$$bindir/git$X" "$$bindir/$$p" || exit; \
+ test -n "$(INSTALL_SYMLINKS)" && \
+ ln -s "git$X" "$$bindir/$$p" || \
+ { test -z "$(NO_INSTALL_HARDLINKS)" && \
+ ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
+ ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
+ cp "$$bindir/git$X" "$$bindir/$$p" || exit; } \
done && \
for p in $(BUILT_INS); do \
$(RM) "$$execdir/$$p" && \
- test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
- ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
- cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
+ test -n "$(INSTALL_SYMLINKS)" && \
+ ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
+ { test -z "$(NO_INSTALL_HARDLINKS)" && \
+ ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
+ ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
+ cp "$$execdir/git$X" "$$execdir/$$p" || exit; } \
done && \
remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
for p in $$remote_curl_aliases; do \
$(RM) "$$execdir/$$p" && \
- test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
- ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
- cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \
+ test -n "$(INSTALL_SYMLINKS)" && \
+ ln -s "git-remote-http$X" "$$execdir/$$p" || \
+ { test -z "$(NO_INSTALL_HARDLINKS)" && \
+ ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
+ ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
+ cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; } \
done && \
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
-.PHONY: install-gitweb install-doc install-man install-html install-info install-pdf
+.PHONY: install-gitweb install-doc install-man install-man-perl install-html install-info install-pdf
.PHONY: quick-install-doc quick-install-man quick-install-html
install-gitweb:
$(MAKE) -C gitweb install
@@ -2629,7 +2667,7 @@ install-doc: install-man-perl
install-man: install-man-perl
$(MAKE) -C Documentation install-man
-install-man-perl: perl/build/man/man3/Git.3pm
+install-man-perl: man-perl
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mandir_SQ)/man3'
(cd perl/build/man/man3 && $(TAR) cf - .) | \
(cd '$(DESTDIR_SQ)$(mandir_SQ)/man3' && umask 022 && $(TAR) xof -)
@@ -2668,6 +2706,21 @@ dist: git-archive$(X) configure
$(GIT_TARNAME)/configure \
$(GIT_TARNAME)/version \
$(GIT_TARNAME)/git-gui/version
+ifdef DC_SHA1_SUBMODULE
+ @mkdir -p $(GIT_TARNAME)/sha1collisiondetection/lib
+ @cp sha1collisiondetection/LICENSE.txt \
+ $(GIT_TARNAME)/sha1collisiondetection/
+ @cp sha1collisiondetection/LICENSE.txt \
+ $(GIT_TARNAME)/sha1collisiondetection/
+ @cp sha1collisiondetection/lib/sha1.[ch] \
+ $(GIT_TARNAME)/sha1collisiondetection/lib/
+ @cp sha1collisiondetection/lib/ubc_check.[ch] \
+ $(GIT_TARNAME)/sha1collisiondetection/lib/
+ $(TAR) rf $(GIT_TARNAME).tar \
+ $(GIT_TARNAME)/sha1collisiondetection/LICENSE.txt \
+ $(GIT_TARNAME)/sha1collisiondetection/lib/sha1.[ch] \
+ $(GIT_TARNAME)/sha1collisiondetection/lib/ubc_check.[ch]
+endif
@$(RM) -r $(GIT_TARNAME)
gzip -f -9 $(GIT_TARNAME).tar
@@ -2717,7 +2770,7 @@ clean: profile-clean coverage-clean
$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
$(RM) -r bin-wrappers $(dep_dirs)
$(RM) -r po/build/
- $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
+ $(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
diff --git a/RelNotes b/RelNotes
index 7a6dc06..f6c58b3 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.17.0.txt \ No newline at end of file
+Documentation/RelNotes/2.18.0.txt \ No newline at end of file
diff --git a/apply.c b/apply.c
index f8b67bf..7e5792c 100644
--- a/apply.c
+++ b/apply.c
@@ -950,7 +950,7 @@ static int gitdiff_verify_name(struct apply_state *state,
}
free(another);
} else {
- if (!starts_with(line, "/dev/null\n"))
+ if (!is_dev_null(line))
return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
}
@@ -2301,7 +2301,7 @@ static void update_pre_post_images(struct image *preimage,
size_t len, size_t postlen)
{
int i, ctx, reduced;
- char *new, *old, *fixed;
+ char *new_buf, *old_buf, *fixed;
struct image fixed_preimage;
/*
@@ -2327,25 +2327,25 @@ static void update_pre_post_images(struct image *preimage,
* We trust the caller to tell us if the update can be done
* in place (postlen==0) or not.
*/
- old = postimage->buf;
+ old_buf = postimage->buf;
if (postlen)
- new = postimage->buf = xmalloc(postlen);
+ new_buf = postimage->buf = xmalloc(postlen);
else
- new = old;
+ new_buf = old_buf;
fixed = preimage->buf;
for (i = reduced = ctx = 0; i < postimage->nr; i++) {
size_t l_len = postimage->line[i].len;
if (!(postimage->line[i].flag & LINE_COMMON)) {
/* an added line -- no counterparts in preimage */
- memmove(new, old, l_len);
- old += l_len;
- new += l_len;
+ memmove(new_buf, old_buf, l_len);
+ old_buf += l_len;
+ new_buf += l_len;
continue;
}
/* a common context -- skip it in the original postimage */
- old += l_len;
+ old_buf += l_len;
/* and find the corresponding one in the fixed preimage */
while (ctx < preimage->nr &&
@@ -2365,29 +2365,29 @@ static void update_pre_post_images(struct image *preimage,
/* and copy it in, while fixing the line length */
l_len = preimage->line[ctx].len;
- memcpy(new, fixed, l_len);
- new += l_len;
+ memcpy(new_buf, fixed, l_len);
+ new_buf += l_len;
fixed += l_len;
postimage->line[i].len = l_len;
ctx++;
}
if (postlen
- ? postlen < new - postimage->buf
- : postimage->len < new - postimage->buf)
+ ? postlen < new_buf - postimage->buf
+ : postimage->len < new_buf - postimage->buf)
die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
- (int)postlen, (int) postimage->len, (int)(new - postimage->buf));
+ (int)postlen, (int) postimage->len, (int)(new_buf - postimage->buf));
/* Fix the length of the whole thing */
- postimage->len = new - postimage->buf;
+ postimage->len = new_buf - postimage->buf;
postimage->nr -= reduced;
}
static int line_by_line_fuzzy_match(struct image *img,
struct image *preimage,
struct image *postimage,
- unsigned long try,
- int try_lno,
+ unsigned long current,
+ int current_lno,
int preimage_limit)
{
int i;
@@ -2404,9 +2404,9 @@ static int line_by_line_fuzzy_match(struct image *img,
for (i = 0; i < preimage_limit; i++) {
size_t prelen = preimage->line[i].len;
- size_t imglen = img->line[try_lno+i].len;
+ size_t imglen = img->line[current_lno+i].len;
- if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
+ if (!fuzzy_matchlines(img->buf + current + imgoff, imglen,
preimage->buf + preoff, prelen))
return 0;
if (preimage->line[i].flag & LINE_COMMON)
@@ -2443,7 +2443,7 @@ static int line_by_line_fuzzy_match(struct image *img,
*/
extra_chars = preimage_end - preimage_eof;
strbuf_init(&fixed, imgoff + extra_chars);
- strbuf_add(&fixed, img->buf + try, imgoff);
+ strbuf_add(&fixed, img->buf + current, imgoff);
strbuf_add(&fixed, preimage_eof, extra_chars);
fixed_buf = strbuf_detach(&fixed, &fixed_len);
update_pre_post_images(preimage, postimage,
@@ -2455,8 +2455,8 @@ static int match_fragment(struct apply_state *state,
struct image *img,
struct image *preimage,
struct image *postimage,
- unsigned long try,
- int try_lno,
+ unsigned long current,
+ int current_lno,
unsigned ws_rule,
int match_beginning, int match_end)
{
@@ -2466,12 +2466,12 @@ static int match_fragment(struct apply_state *state,
size_t fixed_len, postlen;
int preimage_limit;
- if (preimage->nr + try_lno <= img->nr) {
+ if (preimage->nr + current_lno <= img->nr) {
/*
* The hunk falls within the boundaries of img.
*/
preimage_limit = preimage->nr;
- if (match_end && (preimage->nr + try_lno != img->nr))
+ if (match_end && (preimage->nr + current_lno != img->nr))
return 0;
} else if (state->ws_error_action == correct_ws_error &&
(ws_rule & WS_BLANK_AT_EOF)) {
@@ -2482,7 +2482,7 @@ static int match_fragment(struct apply_state *state,
* match with img, and the remainder of the preimage
* must be blank.
*/
- preimage_limit = img->nr - try_lno;
+ preimage_limit = img->nr - current_lno;
} else {
/*
* The hunk extends beyond the end of the img and
@@ -2492,27 +2492,27 @@ static int match_fragment(struct apply_state *state,
return 0;
}
- if (match_beginning && try_lno)
+ if (match_beginning && current_lno)
return 0;
/* Quick hash check */
for (i = 0; i < preimage_limit; i++)
- if ((img->line[try_lno + i].flag & LINE_PATCHED) ||
- (preimage->line[i].hash != img->line[try_lno + i].hash))
+ if ((img->line[current_lno + i].flag & LINE_PATCHED) ||
+ (preimage->line[i].hash != img->line[current_lno + i].hash))
return 0;
if (preimage_limit == preimage->nr) {
/*
* Do we have an exact match? If we were told to match
- * at the end, size must be exactly at try+fragsize,
- * otherwise try+fragsize must be still within the preimage,
+ * at the end, size must be exactly at current+fragsize,
+ * otherwise current+fragsize must be still within the preimage,
* and either case, the old piece should match the preimage
* exactly.
*/
if ((match_end
- ? (try + preimage->len == img->len)
- : (try + preimage->len <= img->len)) &&
- !memcmp(img->buf + try, preimage->buf, preimage->len))
+ ? (current + preimage->len == img->len)
+ : (current + preimage->len <= img->len)) &&
+ !memcmp(img->buf + current, preimage->buf, preimage->len))
return 1;
} else {
/*
@@ -2543,7 +2543,7 @@ static int match_fragment(struct apply_state *state,
*/
if (state->ws_ignore_action == ignore_ws_change)
return line_by_line_fuzzy_match(img, preimage, postimage,
- try, try_lno, preimage_limit);
+ current, current_lno, preimage_limit);
if (state->ws_error_action != correct_ws_error)
return 0;
@@ -2577,10 +2577,10 @@ static int match_fragment(struct apply_state *state,
*/
strbuf_init(&fixed, preimage->len + 1);
orig = preimage->buf;
- target = img->buf + try;
+ target = img->buf + current;
for (i = 0; i < preimage_limit; i++) {
size_t oldlen = preimage->line[i].len;
- size_t tgtlen = img->line[try_lno + i].len;
+ size_t tgtlen = img->line[current_lno + i].len;
size_t fixstart = fixed.len;
struct strbuf tgtfix;
int match;
@@ -2666,8 +2666,8 @@ static int find_pos(struct apply_state *state,
int match_beginning, int match_end)
{
int i;
- unsigned long backwards, forwards, try;
- int backwards_lno, forwards_lno, try_lno;
+ unsigned long backwards, forwards, current;
+ int backwards_lno, forwards_lno, current_lno;
/*
* If match_beginning or match_end is specified, there is no
@@ -2687,25 +2687,25 @@ static int find_pos(struct apply_state *state,
if ((size_t) line > img->nr)
line = img->nr;
- try = 0;
+ current = 0;
for (i = 0; i < line; i++)
- try += img->line[i].len;
+ current += img->line[i].len;
/*
* There's probably some smart way to do this, but I'll leave
* that to the smart and beautiful people. I'm simple and stupid.
*/
- backwards = try;
+ backwards = current;
backwards_lno = line;
- forwards = try;
+ forwards = current;
forwards_lno = line;
- try_lno = line;
+ current_lno = line;
for (i = 0; ; i++) {
if (match_fragment(state, img, preimage, postimage,
- try, try_lno, ws_rule,
+ current, current_lno, ws_rule,
match_beginning, match_end))
- return try_lno;
+ return current_lno;
again:
if (backwards_lno == 0 && forwards_lno == img->nr)
@@ -2718,8 +2718,8 @@ static int find_pos(struct apply_state *state,
}
backwards_lno--;
backwards -= img->line[backwards_lno].len;
- try = backwards;
- try_lno = backwards_lno;
+ current = backwards;
+ current_lno = backwards_lno;
} else {
if (forwards_lno == img->nr) {
i++;
@@ -2727,8 +2727,8 @@ static int find_pos(struct apply_state *state,
}
forwards += img->line[forwards_lno].len;
forwards_lno++;
- try = forwards;
- try_lno = forwards_lno;
+ current = forwards;
+ current_lno = forwards_lno;
}
}
@@ -3154,7 +3154,7 @@ static int apply_binary(struct apply_state *state,
* See if the old one matches what the patch
* applies to.
*/
- hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+ hash_object_file(img->buf, img->len, blob_type, &oid);
if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
return error(_("the patch applies to '%s' (%s), "
"which does not match the "
@@ -3180,7 +3180,7 @@ static int apply_binary(struct apply_state *state,
unsigned long size;
char *result;
- result = read_sha1_file(oid.hash, &type, &size);
+ result = read_object_file(&oid, &type, &size);
if (!result)
return error(_("the necessary postimage %s for "
"'%s' cannot be read"),
@@ -3199,7 +3199,7 @@ static int apply_binary(struct apply_state *state,
name);
/* verify that the result matches */
- hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+ hash_object_file(img->buf, img->len, blob_type, &oid);
if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
name, patch->new_sha1_prefix, oid_to_hex(&oid));
@@ -3242,7 +3242,7 @@ static int read_blob_object(struct strbuf *buf, const struct object_id *oid, uns
unsigned long sz;
char *result;
- result = read_sha1_file(oid->hash, &type, &sz);
+ result = read_object_file(oid, &type, &sz);
if (!result)
return -1;
/* XXX read_sha1_file NUL-terminates */
@@ -3554,7 +3554,7 @@ static int try_threeway(struct apply_state *state,
/* Preimage the patch was prepared for */
if (patch->is_new)
- write_sha1_file("", 0, blob_type, pre_oid.hash);
+ write_object_file("", 0, blob_type, &pre_oid);
else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
read_blob_object(&buf, &pre_oid, patch->old_mode))
return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
@@ -3570,7 +3570,7 @@ static int try_threeway(struct apply_state *state,
return -1;
}
/* post_oid is theirs */
- write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash);
+ write_object_file(tmp_image.buf, tmp_image.len, blob_type, &post_oid);
clear_image(&tmp_image);
/* our_oid is ours */
@@ -3583,7 +3583,7 @@ static int try_threeway(struct apply_state *state,
return error(_("cannot read the current contents of '%s'"),
patch->old_name);
}
- write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash);
+ write_object_file(tmp_image.buf, tmp_image.len, blob_type, &our_oid);
clear_image(&tmp_image);
/* in-core three-way merge between post and our using pre as base */
@@ -4163,30 +4163,30 @@ static void show_mode_change(struct patch *p, int show_name)
static void show_rename_copy(struct patch *p)
{
const char *renamecopy = p->is_rename ? "rename" : "copy";
- const char *old, *new;
+ const char *old_name, *new_name;
/* Find common prefix */
- old = p->old_name;
- new = p->new_name;
+ old_name = p->old_name;
+ new_name = p->new_name;
while (1) {
const char *slash_old, *slash_new;
- slash_old = strchr(old, '/');
- slash_new = strchr(new, '/');
+ slash_old = strchr(old_name, '/');
+ slash_new = strchr(new_name, '/');
if (!slash_old ||
!slash_new ||
- slash_old - old != slash_new - new ||
- memcmp(old, new, slash_new - new))
+ slash_old - old_name != slash_new - new_name ||
+ memcmp(old_name, new_name, slash_new - new_name))
break;
- old = slash_old + 1;
- new = slash_new + 1;
+ old_name = slash_old + 1;
+ new_name = slash_new + 1;
}
- /* p->old_name thru old is the common prefix, and old and new
+ /* p->old_name thru old_name is the common prefix, and old_name and new_name
* through the end of names are renames
*/
- if (old != p->old_name)
+ if (old_name != p->old_name)
printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
- (int)(old - p->old_name), p->old_name,
- old, new, p->score);
+ (int)(old_name - p->old_name), p->old_name,
+ old_name, new_name, p->score);
else
printf(" %s %s => %s (%d%%)\n", renamecopy,
p->old_name, p->new_name, p->score);
@@ -4291,7 +4291,7 @@ static int add_index_file(struct apply_state *state,
}
fill_stat_cache_info(ce, &st);
}
- if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) {
+ if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
free(ce);
return error(_("unable to create backing store "
"for newly created file %s"), path);
@@ -4943,8 +4943,9 @@ int apply_parse_options(int argc, const char **argv,
N_("make sure the patch is applicable to the current index")),
OPT_BOOL(0, "cached", &state->cached,
N_("apply a patch without touching the working tree")),
- OPT_BOOL(0, "unsafe-paths", &state->unsafe_paths,
- N_("accept a patch that touches outside the working area")),
+ OPT_BOOL_F(0, "unsafe-paths", &state->unsafe_paths,
+ N_("accept a patch that touches outside the working area"),
+ PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "apply", force_apply,
N_("also apply the patch (use with --stat/--summary/--check)")),
OPT_BOOL('3', "3way", &state->threeway,
diff --git a/archive-tar.c b/archive-tar.c
index c6ed96e..3563bcb 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -111,7 +111,7 @@ static void write_trailer(void)
* queues up writes, so that all our write(2) calls write exactly one
* full block; pads writes to RECORDSIZE
*/
-static int stream_blocked(const unsigned char *sha1)
+static int stream_blocked(const struct object_id *oid)
{
struct git_istream *st;
enum object_type type;
@@ -119,9 +119,9 @@ static int stream_blocked(const unsigned char *sha1)
char buf[BLOCKSIZE];
ssize_t readlen;
- st = open_istream(sha1, &type, &sz, NULL);
+ st = open_istream(oid, &type, &sz, NULL);
if (!st)
- return error("cannot stream blob %s", sha1_to_hex(sha1));
+ return error("cannot stream blob %s", oid_to_hex(oid));
for (;;) {
readlen = read_istream(st, buf, sizeof(buf));
if (readlen <= 0)
@@ -218,7 +218,7 @@ static void prepare_header(struct archiver_args *args,
}
static void write_extended_header(struct archiver_args *args,
- const unsigned char *sha1,
+ const struct object_id *oid,
const void *buffer, unsigned long size)
{
struct ustar_header header;
@@ -226,14 +226,14 @@ static void write_extended_header(struct archiver_args *args,
memset(&header, 0, sizeof(header));
*header.typeflag = TYPEFLAG_EXT_HEADER;
mode = 0100666;
- xsnprintf(header.name, sizeof(header.name), "%s.paxheader", sha1_to_hex(sha1));
+ xsnprintf(header.name, sizeof(header.name), "%s.paxheader", oid_to_hex(oid));
prepare_header(args, &header, mode, size);
write_blocked(&header, sizeof(header));
write_blocked(buffer, size);
}
static int write_tar_entry(struct archiver_args *args,
- const unsigned char *sha1,
+ const struct object_id *oid,
const char *path, size_t pathlen,
unsigned int mode)
{
@@ -257,7 +257,7 @@ static int write_tar_entry(struct archiver_args *args,
mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
} else {
return error("unsupported file mode: 0%o (SHA1: %s)",
- mode, sha1_to_hex(sha1));
+ mode, oid_to_hex(oid));
}
if (pathlen > sizeof(header.name)) {
size_t plen = get_path_prefix(path, pathlen,
@@ -268,7 +268,7 @@ static int write_tar_entry(struct archiver_args *args,
memcpy(header.name, path + plen + 1, rest);
} else {
xsnprintf(header.name, sizeof(header.name), "%s.data",
- sha1_to_hex(sha1));
+ oid_to_hex(oid));
strbuf_append_ext_header(&ext_header, "path",
path, pathlen);
}
@@ -276,14 +276,14 @@ static int write_tar_entry(struct archiver_args *args,
memcpy(header.name, path, pathlen);
if (S_ISREG(mode) && !args->convert &&
- sha1_object_info(sha1, &size) == OBJ_BLOB &&
+ oid_object_info(oid, &size) == OBJ_BLOB &&
size > big_file_threshold)
buffer = NULL;
else if (S_ISLNK(mode) || S_ISREG(mode)) {
enum object_type type;
- buffer = sha1_file_to_archive(args, path, sha1, old_mode, &type, &size);
+ buffer = object_file_to_archive(args, path, oid, old_mode, &type, &size);
if (!buffer)
- return error("cannot read %s", sha1_to_hex(sha1));
+ return error("cannot read %s", oid_to_hex(oid));
} else {
buffer = NULL;
size = 0;
@@ -292,7 +292,7 @@ static int write_tar_entry(struct archiver_args *args,
if (S_ISLNK(mode)) {
if (size > sizeof(header.linkname)) {
xsnprintf(header.linkname, sizeof(header.linkname),
- "see %s.paxheader", sha1_to_hex(sha1));
+ "see %s.paxheader", oid_to_hex(oid));
strbuf_append_ext_header(&ext_header, "linkpath",
buffer, size);
} else
@@ -308,7 +308,7 @@ static int write_tar_entry(struct archiver_args *args,
prepare_header(args, &header, mode, size_in_header);
if (ext_header.len > 0) {
- write_extended_header(args, sha1, ext_header.buf,
+ write_extended_header(args, oid, ext_header.buf,
ext_header.len);
}
strbuf_release(&ext_header);
@@ -317,7 +317,7 @@ static int write_tar_entry(struct archiver_args *args,
if (buffer)
write_blocked(buffer, size);
else
- err = stream_blocked(sha1);
+ err = stream_blocked(oid);
}
free(buffer);
return err;
diff --git a/archive-zip.c b/archive-zip.c
index e8913e5..6b20bce 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -276,7 +276,7 @@ static int entry_is_binary(const char *path, const void *buffer, size_t size)
#define STREAM_BUFFER_SIZE (1024 * 16)
static int write_zip_entry(struct archiver_args *args,
- const unsigned char *sha1,
+ const struct object_id *oid,
const char *path, size_t pathlen,
unsigned int mode)
{
@@ -314,7 +314,7 @@ static int write_zip_entry(struct archiver_args *args,
if (pathlen > 0xffff) {
return error("path too long (%d chars, SHA1: %s): %s",
- (int)pathlen, sha1_to_hex(sha1), path);
+ (int)pathlen, oid_to_hex(oid), path);
}
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
@@ -325,7 +325,7 @@ static int write_zip_entry(struct archiver_args *args,
compressed_size = 0;
buffer = NULL;
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
- enum object_type type = sha1_object_info(sha1, &size);
+ enum object_type type = oid_object_info(oid, &size);
method = 0;
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
@@ -337,18 +337,18 @@ static int write_zip_entry(struct archiver_args *args,
if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
size > big_file_threshold) {
- stream = open_istream(sha1, &type, &size, NULL);
+ stream = open_istream(oid, &type, &size, NULL);
if (!stream)
return error("cannot stream blob %s",
- sha1_to_hex(sha1));
+ oid_to_hex(oid));
flags |= ZIP_STREAM;
out = buffer = NULL;
} else {
- buffer = sha1_file_to_archive(args, path, sha1, mode,
- &type, &size);
+ buffer = object_file_to_archive(args, path, oid, mode,
+ &type, &size);
if (!buffer)
return error("cannot read %s",
- sha1_to_hex(sha1));
+ oid_to_hex(oid));
crc = crc32(crc, buffer, size);
is_binary = entry_is_binary(path_without_prefix,
buffer, size);
@@ -357,7 +357,7 @@ static int write_zip_entry(struct archiver_args *args,
compressed_size = (method == 0) ? size : 0;
} else {
return error("unsupported file mode: 0%o (SHA1: %s)", mode,
- sha1_to_hex(sha1));
+ oid_to_hex(oid));
}
if (creator_version > max_creator_version)
diff --git a/archive.c b/archive.c
index 0b7b62a..93ab175 100644
--- a/archive.c
+++ b/archive.c
@@ -63,16 +63,16 @@ static void format_subst(const struct commit *commit,
free(to_free);
}
-void *sha1_file_to_archive(const struct archiver_args *args,
- const char *path, const unsigned char *sha1,
- unsigned int mode, enum object_type *type,
- unsigned long *sizep)
+void *object_file_to_archive(const struct archiver_args *args,
+ const char *path, const struct object_id *oid,
+ unsigned int mode, enum object_type *type,
+ unsigned long *sizep)
{
void *buffer;
const struct commit *commit = args->convert ? args->commit : NULL;
path += args->baselen;
- buffer = read_sha1_file(sha1, type, sizep);
+ buffer = read_object_file(oid, type, sizep);
if (buffer && S_ISREG(mode)) {
struct strbuf buf = STRBUF_INIT;
size_t size = 0;
@@ -121,7 +121,7 @@ static int check_attr_export_subst(const struct attr_check *check)
return check && ATTR_TRUE(check->items[1].value);
}
-static int write_archive_entry(const unsigned char *sha1, const char *base,
+static int write_archive_entry(const struct object_id *oid, const char *base,
int baselen, const char *filename, unsigned mode, int stage,
void *context)
{
@@ -153,7 +153,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
- err = write_entry(args, sha1, path.buf, path.len, mode);
+ err = write_entry(args, oid, path.buf, path.len, mode);
if (err)
return err;
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
@@ -161,7 +161,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
- return write_entry(args, sha1, path.buf, path.len, mode);
+ return write_entry(args, oid, path.buf, path.len, mode);
}
static void queue_directory(const unsigned char *sha1,
@@ -191,14 +191,14 @@ static int write_directory(struct archiver_context *c)
d->path[d->len - 1] = '\0'; /* no trailing slash */
ret =
write_directory(c) ||
- write_archive_entry(d->oid.hash, d->path, d->baselen,
+ write_archive_entry(&d->oid, d->path, d->baselen,
d->path + d->baselen, d->mode,
d->stage, c) != READ_TREE_RECURSIVE;
free(d);
return ret ? -1 : 0;
}
-static int queue_or_write_archive_entry(const unsigned char *sha1,
+static int queue_or_write_archive_entry(const struct object_id *oid,
struct strbuf *base, const char *filename,
unsigned mode, int stage, void *context)
{
@@ -224,14 +224,14 @@ static int queue_or_write_archive_entry(const unsigned char *sha1,
if (check_attr_export_ignore(check))
return 0;
- queue_directory(sha1, base, filename,
+ queue_directory(oid->hash, base, filename,
mode, stage, c);
return READ_TREE_RECURSIVE;
}
if (write_directory(c))
return -1;
- return write_archive_entry(sha1, base->buf, base->len, filename, mode,
+ return write_archive_entry(oid, base->buf, base->len, filename, mode,
stage, context);
}
@@ -250,7 +250,7 @@ int write_archive_entries(struct archiver_args *args,
len--;
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)len, args->base);
- err = write_entry(args, args->tree->object.oid.hash, args->base,
+ err = write_entry(args, &args->tree->object.oid, args->base,
len, 040777);
if (err)
return err;
@@ -303,7 +303,7 @@ static const struct archiver *lookup_archiver(const char *name)
return NULL;
}
-static int reject_entry(const unsigned char *sha1, struct strbuf *base,
+static int reject_entry(const struct object_id *oid, struct strbuf *base,
const char *filename, unsigned mode,
int stage, void *context)
{
@@ -397,8 +397,8 @@ static void parse_treeish_arg(const char **argv,
unsigned int mode;
int err;
- err = get_tree_entry(tree->object.oid.hash, prefix,
- tree_oid.hash, &mode);
+ err = get_tree_entry(&tree->object.oid, prefix, &tree_oid,
+ &mode);
if (err || !S_ISDIR(mode))
die("current working directory is untracked");
diff --git a/archive.h b/archive.h
index 62d1d82..1f9954f 100644
--- a/archive.h
+++ b/archive.h
@@ -31,7 +31,7 @@ extern void init_tar_archiver(void);
extern void init_zip_archiver(void);
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
- const unsigned char *sha1,
+ const struct object_id *oid,
const char *path, size_t pathlen,
unsigned int mode);
@@ -39,9 +39,9 @@ extern int write_archive_entries(struct archiver_args *args, write_archive_entry
extern int write_archive(int argc, const char **argv, const char *prefix, const char *name_hint, int remote);
const char *archive_format_from_filename(const char *filename);
-extern void *sha1_file_to_archive(const struct archiver_args *args,
- const char *path, const unsigned char *sha1,
- unsigned int mode, enum object_type *type,
- unsigned long *sizep);
+extern void *object_file_to_archive(const struct archiver_args *args,
+ const char *path, const struct object_id *oid,
+ unsigned int mode, enum object_type *type,
+ unsigned long *sizep);
#endif /* ARCHIVE_H */
diff --git a/bisect.c b/bisect.c
index f6d05bd..ad395bb 100644
--- a/bisect.c
+++ b/bisect.c
@@ -132,7 +132,8 @@ static void show_list(const char *debug, int counted, int nr,
unsigned flags = commit->object.flags;
enum object_type type;
unsigned long size;
- char *buf = read_sha1_file(commit->object.oid.hash, &type, &size);
+ char *buf = read_object_file(&commit->object.oid, &type,
+ &size);
const char *subject_start;
int subject_len;
diff --git a/blame.c b/blame.c
index 2893f3c..78c9808 100644
--- a/blame.c
+++ b/blame.c
@@ -80,8 +80,8 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path)
struct object_id blob_oid;
unsigned mode;
- if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) &&
- sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
+ if (!get_tree_entry(commit_oid, path, &blob_oid, &mode) &&
+ oid_object_info(&blob_oid, NULL) == OBJ_BLOB)
return;
}
@@ -232,7 +232,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
convert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0);
origin->file.ptr = buf.buf;
origin->file.size = buf.len;
- pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
+ pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid);
/*
* Read the current index, replace the path entry with
@@ -297,8 +297,8 @@ static void fill_origin_blob(struct diff_options *opt,
textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
;
else
- file->ptr = read_sha1_file(o->blob_oid.hash, &type,
- &file_size);
+ file->ptr = read_object_file(&o->blob_oid, &type,
+ &file_size);
file->size = file_size;
if (!file->ptr)
@@ -502,11 +502,9 @@ static int fill_blob_sha1_and_mode(struct blame_origin *origin)
{
if (!is_null_oid(&origin->blob_oid))
return 0;
- if (get_tree_entry(origin->commit->object.oid.hash,
- origin->path,
- origin->blob_oid.hash, &origin->mode))
+ if (get_tree_entry(&origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
goto error_out;
- if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB)
+ if (oid_object_info(&origin->blob_oid, NULL) != OBJ_BLOB)
goto error_out;
return 0;
error_out:
@@ -998,28 +996,29 @@ unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e)
}
/*
- * best_so_far[] and this[] are both a split of an existing blame_entry
- * that passes blame to the parent. Maintain best_so_far the best split
- * so far, by comparing this and best_so_far and copying this into
+ * best_so_far[] and potential[] are both a split of an existing blame_entry
+ * that passes blame to the parent. Maintain best_so_far the best split so
+ * far, by comparing potential and best_so_far and copying potential into
* bst_so_far as needed.
*/
static void copy_split_if_better(struct blame_scoreboard *sb,
struct blame_entry *best_so_far,
- struct blame_entry *this)
+ struct blame_entry *potential)
{
int i;
- if (!this[1].suspect)
+ if (!potential[1].suspect)
return;
if (best_so_far[1].suspect) {
- if (blame_entry_score(sb, &this[1]) < blame_entry_score(sb, &best_so_far[1]))
+ if (blame_entry_score(sb, &potential[1]) <
+ blame_entry_score(sb, &best_so_far[1]))
return;
}
for (i = 0; i < 3; i++)
- blame_origin_incref(this[i].suspect);
+ blame_origin_incref(potential[i].suspect);
decref_split(best_so_far);
- memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
+ memcpy(best_so_far, potential, sizeof(struct blame_entry[3]));
}
/*
@@ -1046,12 +1045,12 @@ static void handle_split(struct blame_scoreboard *sb,
if (ent->num_lines <= tlno)
return;
if (tlno < same) {
- struct blame_entry this[3];
+ struct blame_entry potential[3];
tlno += ent->s_lno;
same += ent->s_lno;
- split_overlap(this, ent, tlno, plno, same, parent);
- copy_split_if_better(sb, split, this);
- decref_split(this);
+ split_overlap(potential, ent, tlno, plno, same, parent);
+ copy_split_if_better(sb, split, potential);
+ decref_split(potential);
}
}
@@ -1273,7 +1272,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
struct diff_filepair *p = diff_queued_diff.queue[i];
struct blame_origin *norigin;
mmfile_t file_p;
- struct blame_entry this[3];
+ struct blame_entry potential[3];
if (!DIFF_FILE_VALID(p->one))
continue; /* does not exist in parent */
@@ -1292,10 +1291,10 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
for (j = 0; j < num_ents; j++) {
find_copy_in_blob(sb, blame_list[j].ent,
- norigin, this, &file_p);
+ norigin, potential, &file_p);
copy_split_if_better(sb, blame_list[j].split,
- this);
- decref_split(this);
+ potential);
+ decref_split(potential);
}
blame_origin_decref(norigin);
}
@@ -1830,8 +1829,8 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
&sb->final_buf_size))
;
else
- sb->final_buf = read_sha1_file(o->blob_oid.hash, &type,
- &sb->final_buf_size);
+ sb->final_buf = read_object_file(&o->blob_oid, &type,
+ &sb->final_buf_size);
if (!sb->final_buf)
die(_("cannot read blob %s for path %s"),
diff --git a/builtin/add.c b/builtin/add.c
index bf01d89..9ef7fb0 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -294,7 +294,7 @@ static struct option builtin_add_options[] = {
OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
- OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
+ OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0),
OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")),
OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
@@ -534,10 +534,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
unplug_bulk_checkin();
finish:
- if (active_cache_changed) {
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
- die(_("Unable to write new index file"));
- }
+ if (write_locked_index(&the_index, &lock_file,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ die(_("Unable to write new index file"));
UNLEAK(pathspec);
UNLEAK(dir);
diff --git a/builtin/am.c b/builtin/am.c
index 5bdd2d7..1bcc360 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1011,6 +1011,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
+ delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
if (split_mail(state, patch_format, paths, keep_cr) < 0) {
am_destroy(state);
@@ -1110,6 +1111,7 @@ static void am_next(struct am_state *state)
oidclr(&state->orig_commit);
unlink(am_path(state, "original-commit"));
+ delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
if (!get_oid("HEAD", &head))
write_state_text(state, "abort-safety", oid_to_hex(&head));
@@ -1441,6 +1443,8 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
oidcpy(&state->orig_commit, &commit_oid);
write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
+ update_ref("am", "REBASE_HEAD", &commit_oid,
+ NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
return 0;
}
@@ -1546,7 +1550,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
discard_cache();
read_cache_from(index_path);
- if (write_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(&orig_tree, &the_index, index_path, 0, NULL))
return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
say(state, stdout, _("Using index info to reconstruct a base tree..."));
@@ -1571,7 +1575,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
return error(_("Did you hand edit your patch?\n"
"It does not apply to blobs recorded in its index."));
- if (write_index_as_tree(their_tree.hash, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(&their_tree, &the_index, index_path, 0, NULL))
return error("could not write tree");
say(state, stdout, _("Falling back to patching base and 3-way merge..."));
@@ -1622,7 +1626,7 @@ static void do_commit(const struct am_state *state)
if (run_hook_le(NULL, "pre-applypatch", NULL))
exit(1);
- if (write_cache_as_tree(tree.hash, 0, NULL))
+ if (write_cache_as_tree(&tree, 0, NULL))
die(_("git write-tree failed to write a tree"));
if (!get_oid_commit("HEAD", &parent)) {
@@ -1641,8 +1645,8 @@ static void do_commit(const struct am_state *state)
setenv("GIT_COMMITTER_DATE",
state->ignore_date ? "" : state->author_date, 1);
- if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
- author, state->sign_commit))
+ if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
+ author, state->sign_commit))
die(_("failed to write commit object"));
reflog_msg = getenv("GIT_REFLOG_ACTION");
@@ -1831,8 +1835,7 @@ static void am_run(struct am_state *state, int resume)
git_config_get_bool("advice.amworkdir", &advice_amworkdir);
if (advice_amworkdir)
- printf_ln(_("The copy of the patch that failed is found in: %s"),
- am_path(state, "patch"));
+ printf_ln(_("Use 'git am --show-current-patch' to see the failed patch"));
die_user_resolve(state);
}
@@ -2001,7 +2004,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem
if (fast_forward_to(head_tree, head_tree, 1))
return -1;
- if (write_cache_as_tree(index.hash, 0, NULL))
+ if (write_cache_as_tree(&index, 0, NULL))
return -1;
index_tree = parse_tree_indirect(&index);
@@ -2121,6 +2124,34 @@ static void am_abort(struct am_state *state)
am_destroy(state);
}
+static int show_patch(struct am_state *state)
+{
+ struct strbuf sb = STRBUF_INIT;
+ const char *patch_path;
+ int len;
+
+ if (!is_null_oid(&state->orig_commit)) {
+ const char *av[4] = { "show", NULL, "--", NULL };
+ char *new_oid_str;
+ int ret;
+
+ av[1] = new_oid_str = xstrdup(oid_to_hex(&state->orig_commit));
+ ret = run_command_v_opt(av, RUN_GIT_CMD);
+ free(new_oid_str);
+ return ret;
+ }
+
+ patch_path = am_path(state, msgnum(state));
+ len = strbuf_read_file(&sb, patch_path, 0);
+ if (len < 0)
+ die_errno(_("failed to read '%s'"), patch_path);
+
+ setup_pager();
+ write_in_full(1, sb.buf, sb.len);
+ strbuf_release(&sb);
+ return 0;
+}
+
/**
* parse_options() callback that validates and sets opt->value to the
* PATCH_FORMAT_* enum value corresponding to `arg`.
@@ -2149,7 +2180,9 @@ enum resume_mode {
RESUME_APPLY,
RESUME_RESOLVED,
RESUME_SKIP,
- RESUME_ABORT
+ RESUME_ABORT,
+ RESUME_QUIT,
+ RESUME_SHOW_PATCH
};
static int git_am_config(const char *k, const char *v, void *cb)
@@ -2171,6 +2204,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
int patch_format = PATCH_FORMAT_UNKNOWN;
enum resume_mode resume = RESUME_FALSE;
int in_progress;
+ int ret = 0;
const char * const usage[] = {
N_("git am [<options>] [(<mbox> | <Maildir>)...]"),
@@ -2249,6 +2283,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
OPT_CMDMODE(0, "abort", &resume,
N_("restore the original branch and abort the patching operation."),
RESUME_ABORT),
+ OPT_CMDMODE(0, "quit", &resume,
+ N_("abort the patching operation but keep HEAD where it is."),
+ RESUME_QUIT),
+ OPT_CMDMODE(0, "show-current-patch", &resume,
+ N_("show the patch being applied."),
+ RESUME_SHOW_PATCH),
OPT_BOOL(0, "committer-date-is-author-date",
&state.committer_date_is_author_date,
N_("lie about committer date")),
@@ -2317,7 +2357,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
* stray directories.
*/
if (file_exists(state.dir) && !state.rebasing) {
- if (resume == RESUME_ABORT) {
+ if (resume == RESUME_ABORT || resume == RESUME_QUIT) {
am_destroy(&state);
am_state_release(&state);
return 0;
@@ -2359,11 +2399,18 @@ int cmd_am(int argc, const char **argv, const char *prefix)
case RESUME_ABORT:
am_abort(&state);
break;
+ case RESUME_QUIT:
+ am_rerere_clear();
+ am_destroy(&state);
+ break;
+ case RESUME_SHOW_PATCH:
+ ret = show_patch(&state);
+ break;
default:
die("BUG: invalid resume value");
}
am_state_release(&state);
- return 0;
+ return ret;
}
diff --git a/builtin/archive.c b/builtin/archive.c
index f863465..73971d0 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -55,7 +55,7 @@ static int run_remote_archiver(int argc, const char **argv,
buf = packet_read_line(fd[0], NULL);
if (!buf)
- die(_("git archive: expected ACK/NAK, got EOF"));
+ die(_("git archive: expected ACK/NAK, got a flush packet"));
if (strcmp(buf, "ACK")) {
if (starts_with(buf, "NACK "))
die(_("git archive: NACK %s"), buf + 5);
diff --git a/builtin/blame.c b/builtin/blame.c
index 005f55a..db38c0b 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -499,7 +499,7 @@ static int read_ancestry(const char *graft_file)
static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
{
- const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash,
+ const char *uniq = find_unique_abbrev(&suspect->commit->object.oid,
auto_abbrev);
int len = strlen(uniq);
if (auto_abbrev < len)
@@ -649,6 +649,15 @@ static int blame_move_callback(const struct option *option, const char *arg, int
return 0;
}
+static int is_a_rev(const char *name)
+{
+ struct object_id oid;
+
+ if (get_oid(name, &oid))
+ return 0;
+ return OBJ_NONE < oid_object_info(&oid, NULL);
+}
+
int cmd_blame(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@@ -720,6 +729,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
for (;;) {
switch (parse_options_step(&ctx, options, blame_opt_usage)) {
case PARSE_OPT_HELP:
+ case PARSE_OPT_ERROR:
exit(129);
case PARSE_OPT_DONE:
if (ctx.argv[0])
@@ -845,16 +855,15 @@ parse_done:
} else {
if (argc < 2)
usage_with_options(blame_opt_usage, options);
- path = add_prefix(prefix, argv[argc - 1]);
- if (argc == 3 && !file_exists(path)) { /* (2b) */
+ if (argc == 3 && is_a_rev(argv[argc - 1])) { /* (2b) */
path = add_prefix(prefix, argv[1]);
argv[1] = argv[2];
+ } else { /* (2a) */
+ if (argc == 2 && is_a_rev(argv[1]) && !get_git_work_tree())
+ die("missing <path> to blame");
+ path = add_prefix(prefix, argv[argc - 1]);
}
argv[argc - 1] = "--";
-
- setup_work_tree();
- if (!file_exists(path))
- die_errno("cannot stat path '%s'", path);
}
revs.disable_stdin = 1;
diff --git a/builtin/branch.c b/builtin/branch.c
index 8dcc2ed..5bd2a0d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -273,7 +273,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
bname.buf,
(flags & REF_ISBROKEN) ? "broken"
: (flags & REF_ISSYMREF) ? target
- : find_unique_abbrev(oid.hash, DEFAULT_ABBREV));
+ : find_unique_abbrev(&oid, DEFAULT_ABBREV));
}
delete_branch_config(bname.buf);
@@ -615,7 +615,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOL(0, "edit-description", &edit_description,
N_("edit the description for the branch")),
- OPT__FORCE(&force, N_("force creation, move/rename, deletion")),
+ OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE),
OPT_MERGED(&filter, N_("print only branches that are merged")),
OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index cf9ea5c..2c46d25 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -32,7 +32,7 @@ static int filter_object(const char *path, unsigned mode,
{
enum object_type type;
- *buf = read_sha1_file(oid->hash, &type, size);
+ *buf = read_object_file(oid, &type, size);
if (!*buf)
return error(_("cannot read object %s '%s'"),
oid_to_hex(oid), path);
@@ -76,8 +76,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
buf = NULL;
switch (opt) {
case 't':
- oi.typename = &sb;
- if (sha1_object_info_extended(oid.hash, &oi, flags) < 0)
+ oi.type_name = &sb;
+ if (oid_object_info_extended(&oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
if (sb.len) {
printf("%s\n", sb.buf);
@@ -88,7 +88,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
case 's':
oi.sizep = &size;
- if (sha1_object_info_extended(oid.hash, &oi, flags) < 0)
+ if (oid_object_info_extended(&oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
printf("%lu\n", size);
return 0;
@@ -116,7 +116,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
/* else fallthrough */
case 'p':
- type = sha1_object_info(oid.hash, NULL);
+ type = oid_object_info(&oid, NULL);
if (type < 0)
die("Not a valid object name %s", obj_name);
@@ -130,7 +130,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
if (type == OBJ_BLOB)
return stream_blob_to_fd(1, &oid, NULL, 0);
- buf = read_sha1_file(oid.hash, &type, &size);
+ buf = read_object_file(&oid, &type, &size);
if (!buf)
die("Cannot read object %s", obj_name);
@@ -140,8 +140,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
case 0:
if (type_from_string(exp_type) == OBJ_BLOB) {
struct object_id blob_oid;
- if (sha1_object_info(oid.hash, NULL) == OBJ_TAG) {
- char *buffer = read_sha1_file(oid.hash, &type, &size);
+ if (oid_object_info(&oid, NULL) == OBJ_TAG) {
+ char *buffer = read_object_file(&oid, &type,
+ &size);
const char *target;
if (!skip_prefix(buffer, "object ", &target) ||
get_oid_hex(target, &blob_oid))
@@ -150,7 +151,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
} else
oidcpy(&blob_oid, &oid);
- if (sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
+ if (oid_object_info(&blob_oid, NULL) == OBJ_BLOB)
return stream_blob_to_fd(1, &blob_oid, NULL, 0);
/*
* we attempted to dereference a tag to a blob
@@ -159,7 +160,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
* fall-back to the usual case.
*/
}
- buf = read_object_with_reference(oid.hash, exp_type, &size, NULL);
+ buf = read_object_with_reference(&oid, exp_type, &size, NULL);
break;
default:
@@ -229,7 +230,7 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
if (data->mark_query)
data->info.typep = &data->type;
else
- strbuf_addstr(sb, typename(data->type));
+ strbuf_addstr(sb, type_name(data->type));
} else if (is_atom("objectsize", atom, len)) {
if (data->mark_query)
data->info.sizep = &data->size;
@@ -304,8 +305,9 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
enum object_type type;
if (!textconv_object(data->rest, 0100644, oid,
1, &contents, &size))
- contents = read_sha1_file(oid->hash, &type,
- &size);
+ contents = read_object_file(oid,
+ &type,
+ &size);
if (!contents)
die("could not convert '%s' %s",
oid_to_hex(oid), data->rest);
@@ -321,7 +323,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
unsigned long size;
void *contents;
- contents = read_sha1_file(oid->hash, &type, &size);
+ contents = read_object_file(oid, &type, &size);
if (!contents)
die("object %s disappeared", oid_to_hex(oid));
if (type != data->type)
@@ -340,8 +342,8 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
struct strbuf buf = STRBUF_INIT;
if (!data->skip_object_info &&
- sha1_object_info_extended(data->oid.hash, &data->info,
- OBJECT_INFO_LOOKUP_REPLACE) < 0) {
+ oid_object_info_extended(&data->oid, &data->info,
+ OBJECT_INFO_LOOKUP_REPLACE) < 0) {
printf("%s missing\n",
obj_name ? obj_name : oid_to_hex(&data->oid));
fflush(stdout);
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 3e280b9..ec9a959 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -72,7 +72,7 @@ static int check_ignore(struct dir_struct *dir,
{
const char *full_path;
char *seen;
- int num_ignored = 0, dtype = DT_UNKNOWN, i;
+ int num_ignored = 0, i;
struct exclude *exclude;
struct pathspec pathspec;
@@ -104,6 +104,7 @@ static int check_ignore(struct dir_struct *dir,
full_path = pathspec.items[i].match;
exclude = NULL;
if (!seen[i]) {
+ int dtype = DT_UNKNOWN;
exclude = last_exclude_matching(dir, &the_index,
full_path, &dtype);
}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index b0e78b8..a730f6a 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -157,7 +157,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
struct option builtin_checkout_index_options[] = {
OPT_BOOL('a', "all", &all,
N_("check out all files in the index")),
- OPT__FORCE(&force, N_("force overwrite of existing files")),
+ OPT__FORCE(&force, N_("force overwrite of existing files"), 0),
OPT__QUIET(&quiet,
N_("no warning for existing files and files not in index")),
OPT_BOOL('n', "no-create", &not_new,
diff --git a/builtin/checkout.c b/builtin/checkout.c
index c54c78d..b49b582 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -54,19 +54,19 @@ struct checkout_opts {
struct tree *source_tree;
};
-static int post_checkout_hook(struct commit *old, struct commit *new,
+static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
return run_hook_le(NULL, "post-checkout",
- oid_to_hex(old ? &old->object.oid : &null_oid),
- oid_to_hex(new ? &new->object.oid : &null_oid),
+ oid_to_hex(old_commit ? &old_commit->object.oid : &null_oid),
+ oid_to_hex(new_commit ? &new_commit->object.oid : &null_oid),
changed ? "1" : "0", NULL);
- /* "new" can be NULL when checking out from the index before
+ /* "new_commit" can be NULL when checking out from the index before
a commit exists. */
}
-static int update_some(const unsigned char *sha1, struct strbuf *base,
+static int update_some(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
int len;
@@ -78,7 +78,7 @@ static int update_some(const unsigned char *sha1, struct strbuf *base,
len = base->len + strlen(pathname);
ce = xcalloc(1, cache_entry_size(len));
- hashcpy(ce->oid.hash, sha1);
+ oidcpy(&ce->oid, oid);
memcpy(ce->name, base->buf, base->len);
memcpy(ce->name + base->len, pathname, len - base->len);
ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
@@ -227,8 +227,7 @@ static int checkout_merged(int pos, const struct checkout *state)
* (it also writes the merge result to the object database even
* when it may contain conflicts).
*/
- if (write_sha1_file(result_buf.ptr, result_buf.size,
- blob_type, oid.hash))
+ if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
ce = make_cache_entry(mode, oid.hash, path, 2, 0);
@@ -406,10 +405,10 @@ static void describe_detached_head(const char *msg, struct commit *commit)
pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
if (print_sha1_ellipsis()) {
fprintf(stderr, "%s %s... %s\n", msg,
- find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+ find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
} else {
fprintf(stderr, "%s %s %s\n", msg,
- find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+ find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
}
strbuf_release(&sb);
}
@@ -472,8 +471,8 @@ static void setup_branch_path(struct branch_info *branch)
}
static int merge_working_tree(const struct checkout_opts *opts,
- struct branch_info *old,
- struct branch_info *new,
+ struct branch_info *old_branch_info,
+ struct branch_info *new_branch_info,
int *writeout_error)
{
int ret;
@@ -485,7 +484,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
resolve_undo_clear();
if (opts->force) {
- ret = reset_tree(new->commit->tree, opts, 1, writeout_error);
+ ret = reset_tree(new_branch_info->commit->tree, opts, 1, writeout_error);
if (ret)
return ret;
} else {
@@ -511,7 +510,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
topts.initial_checkout = is_cache_unborn();
topts.update = 1;
topts.merge = 1;
- topts.gently = opts->merge && old->commit;
+ topts.gently = opts->merge && old_branch_info->commit;
topts.verbose_update = opts->show_progress;
topts.fn = twoway_merge;
if (opts->overwrite_ignore) {
@@ -519,11 +518,11 @@ static int merge_working_tree(const struct checkout_opts *opts,
topts.dir->flags |= DIR_SHOW_IGNORED;
setup_standard_excludes(topts.dir);
}
- tree = parse_tree_indirect(old->commit ?
- &old->commit->object.oid :
+ tree = parse_tree_indirect(old_branch_info->commit ?
+ &old_branch_info->commit->object.oid :
the_hash_algo->empty_tree);
init_tree_desc(&trees[0], tree->buffer, tree->size);
- tree = parse_tree_indirect(&new->commit->object.oid);
+ tree = parse_tree_indirect(&new_branch_info->commit->object.oid);
init_tree_desc(&trees[1], tree->buffer, tree->size);
ret = unpack_trees(2, trees, &topts);
@@ -540,10 +539,10 @@ static int merge_working_tree(const struct checkout_opts *opts,
return 1;
/*
- * Without old->commit, the below is the same as
+ * Without old_branch_info->commit, the below is the same as
* the two-tree unpack we already tried and failed.
*/
- if (!old->commit)
+ if (!old_branch_info->commit)
return 1;
/* Do more real merge */
@@ -571,18 +570,18 @@ static int merge_working_tree(const struct checkout_opts *opts,
o.verbosity = 0;
work = write_tree_from_memory(&o);
- ret = reset_tree(new->commit->tree, opts, 1,
+ ret = reset_tree(new_branch_info->commit->tree, opts, 1,
writeout_error);
if (ret)
return ret;
- o.ancestor = old->name;
- o.branch1 = new->name;
+ o.ancestor = old_branch_info->name;
+ o.branch1 = new_branch_info->name;
o.branch2 = "local";
- ret = merge_trees(&o, new->commit->tree, work,
- old->commit->tree, &result);
+ ret = merge_trees(&o, new_branch_info->commit->tree, work,
+ old_branch_info->commit->tree, &result);
if (ret < 0)
exit(128);
- ret = reset_tree(new->commit->tree, opts, 0,
+ ret = reset_tree(new_branch_info->commit->tree, opts, 0,
writeout_error);
strbuf_release(&o.obuf);
if (ret)
@@ -600,25 +599,25 @@ static int merge_working_tree(const struct checkout_opts *opts,
die(_("unable to write new index file"));
if (!opts->force && !opts->quiet)
- show_local_changes(&new->commit->object, &opts->diff_options);
+ show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
return 0;
}
-static void report_tracking(struct branch_info *new)
+static void report_tracking(struct branch_info *new_branch_info)
{
struct strbuf sb = STRBUF_INIT;
- struct branch *branch = branch_get(new->name);
+ struct branch *branch = branch_get(new_branch_info->name);
- if (!format_tracking_info(branch, &sb))
+ if (!format_tracking_info(branch, &sb, AHEAD_BEHIND_FULL))
return;
fputs(sb.buf, stdout);
strbuf_release(&sb);
}
static void update_refs_for_switch(const struct checkout_opts *opts,
- struct branch_info *old,
- struct branch_info *new)
+ struct branch_info *old_branch_info,
+ struct branch_info *new_branch_info)
{
struct strbuf msg = STRBUF_INIT;
const char *old_desc, *reflog_msg;
@@ -645,69 +644,69 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
free(refname);
}
else
- create_branch(opts->new_branch, new->name,
+ create_branch(opts->new_branch, new_branch_info->name,
opts->new_branch_force ? 1 : 0,
opts->new_branch_force ? 1 : 0,
opts->new_branch_log,
opts->quiet,
opts->track);
- new->name = opts->new_branch;
- setup_branch_path(new);
+ new_branch_info->name = opts->new_branch;
+ setup_branch_path(new_branch_info);
}
- old_desc = old->name;
- if (!old_desc && old->commit)
- old_desc = oid_to_hex(&old->commit->object.oid);
+ old_desc = old_branch_info->name;
+ if (!old_desc && old_branch_info->commit)
+ old_desc = oid_to_hex(&old_branch_info->commit->object.oid);
reflog_msg = getenv("GIT_REFLOG_ACTION");
if (!reflog_msg)
strbuf_addf(&msg, "checkout: moving from %s to %s",
- old_desc ? old_desc : "(invalid)", new->name);
+ old_desc ? old_desc : "(invalid)", new_branch_info->name);
else
strbuf_insert(&msg, 0, reflog_msg, strlen(reflog_msg));
- if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
+ if (!strcmp(new_branch_info->name, "HEAD") && !new_branch_info->path && !opts->force_detach) {
/* Nothing to do. */
- } else if (opts->force_detach || !new->path) { /* No longer on any branch. */
- update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
+ } else if (opts->force_detach || !new_branch_info->path) { /* No longer on any branch. */
+ update_ref(msg.buf, "HEAD", &new_branch_info->commit->object.oid, NULL,
REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
if (!opts->quiet) {
- if (old->path &&
+ if (old_branch_info->path &&
advice_detached_head && !opts->force_detach)
- detach_advice(new->name);
- describe_detached_head(_("HEAD is now at"), new->commit);
+ detach_advice(new_branch_info->name);
+ describe_detached_head(_("HEAD is now at"), new_branch_info->commit);
}
- } else if (new->path) { /* Switch branches. */
- if (create_symref("HEAD", new->path, msg.buf) < 0)
+ } else if (new_branch_info->path) { /* Switch branches. */
+ if (create_symref("HEAD", new_branch_info->path, msg.buf) < 0)
die(_("unable to update HEAD"));
if (!opts->quiet) {
- if (old->path && !strcmp(new->path, old->path)) {
+ if (old_branch_info->path && !strcmp(new_branch_info->path, old_branch_info->path)) {
if (opts->new_branch_force)
fprintf(stderr, _("Reset branch '%s'\n"),
- new->name);
+ new_branch_info->name);
else
fprintf(stderr, _("Already on '%s'\n"),
- new->name);
+ new_branch_info->name);
} else if (opts->new_branch) {
if (opts->branch_exists)
- fprintf(stderr, _("Switched to and reset branch '%s'\n"), new->name);
+ fprintf(stderr, _("Switched to and reset branch '%s'\n"), new_branch_info->name);
else
- fprintf(stderr, _("Switched to a new branch '%s'\n"), new->name);
+ fprintf(stderr, _("Switched to a new branch '%s'\n"), new_branch_info->name);
} else {
fprintf(stderr, _("Switched to branch '%s'\n"),
- new->name);
+ new_branch_info->name);
}
}
- if (old->path && old->name) {
- if (!ref_exists(old->path) && reflog_exists(old->path))
- delete_reflog(old->path);
+ if (old_branch_info->path && old_branch_info->name) {
+ if (!ref_exists(old_branch_info->path) && reflog_exists(old_branch_info->path))
+ delete_reflog(old_branch_info->path);
}
}
remove_branch_state();
strbuf_release(&msg);
if (!opts->quiet &&
- (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD"))))
- report_tracking(new);
+ (new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, "HEAD"))))
+ report_tracking(new_branch_info);
}
static int add_pending_uninteresting_ref(const char *refname,
@@ -721,7 +720,7 @@ static int add_pending_uninteresting_ref(const char *refname,
static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
{
strbuf_addstr(sb, " ");
- strbuf_add_unique_abbrev(sb, commit->object.oid.hash, DEFAULT_ABBREV);
+ strbuf_add_unique_abbrev(sb, &commit->object.oid, DEFAULT_ABBREV);
strbuf_addch(sb, ' ');
if (!parse_commit(commit))
pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
@@ -779,7 +778,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
" git branch <new-branch-name> %s\n\n",
/* Give ngettext() the count */
lost),
- find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
+ find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
}
/*
@@ -787,10 +786,10 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
* HEAD. If it is not reachable from any ref, this is the last chance
* for the user to do so without resorting to reflog.
*/
-static void orphaned_commit_warning(struct commit *old, struct commit *new)
+static void orphaned_commit_warning(struct commit *old_commit, struct commit *new_commit)
{
struct rev_info revs;
- struct object *object = &old->object;
+ struct object *object = &old_commit->object;
init_revisions(&revs, NULL);
setup_revisions(0, NULL, &revs, NULL);
@@ -799,57 +798,57 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
add_pending_object(&revs, object, oid_to_hex(&object->oid));
for_each_ref(add_pending_uninteresting_ref, &revs);
- add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
+ add_pending_oid(&revs, "HEAD", &new_commit->object.oid, UNINTERESTING);
if (prepare_revision_walk(&revs))
die(_("internal error in revision walk"));
- if (!(old->object.flags & UNINTERESTING))
- suggest_reattach(old, &revs);
+ if (!(old_commit->object.flags & UNINTERESTING))
+ suggest_reattach(old_commit, &revs);
else
- describe_detached_head(_("Previous HEAD position was"), old);
+ describe_detached_head(_("Previous HEAD position was"), old_commit);
/* Clean up objects used, as they will be reused. */
clear_commit_marks_all(ALL_REV_FLAGS);
}
static int switch_branches(const struct checkout_opts *opts,
- struct branch_info *new)
+ struct branch_info *new_branch_info)
{
int ret = 0;
- struct branch_info old;
+ struct branch_info old_branch_info;
void *path_to_free;
struct object_id rev;
int flag, writeout_error = 0;
- memset(&old, 0, sizeof(old));
- old.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
- if (old.path)
- old.commit = lookup_commit_reference_gently(&rev, 1);
+ memset(&old_branch_info, 0, sizeof(old_branch_info));
+ old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
+ if (old_branch_info.path)
+ old_branch_info.commit = lookup_commit_reference_gently(&rev, 1);
if (!(flag & REF_ISSYMREF))
- old.path = NULL;
+ old_branch_info.path = NULL;
- if (old.path)
- skip_prefix(old.path, "refs/heads/", &old.name);
+ if (old_branch_info.path)
+ skip_prefix(old_branch_info.path, "refs/heads/", &old_branch_info.name);
- if (!new->name) {
- new->name = "HEAD";
- new->commit = old.commit;
- if (!new->commit)
+ if (!new_branch_info->name) {
+ new_branch_info->name = "HEAD";
+ new_branch_info->commit = old_branch_info.commit;
+ if (!new_branch_info->commit)
die(_("You are on a branch yet to be born"));
- parse_commit_or_die(new->commit);
+ parse_commit_or_die(new_branch_info->commit);
}
- ret = merge_working_tree(opts, &old, new, &writeout_error);
+ ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
if (ret) {
free(path_to_free);
return ret;
}
- if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
- orphaned_commit_warning(old.commit, new->commit);
+ if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit)
+ orphaned_commit_warning(old_branch_info.commit, new_branch_info->commit);
- update_refs_for_switch(opts, &old, new);
+ update_refs_for_switch(opts, &old_branch_info, new_branch_info);
- ret = post_checkout_hook(old.commit, new->commit, 1);
+ ret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);
free(path_to_free);
return ret || writeout_error;
}
@@ -870,7 +869,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
- struct branch_info *new,
+ struct branch_info *new_branch_info,
struct checkout_opts *opts,
struct object_id *rev)
{
@@ -988,22 +987,22 @@ static int parse_branchname_arg(int argc, const char **argv,
argv++;
argc--;
- new->name = arg;
- setup_branch_path(new);
+ new_branch_info->name = arg;
+ setup_branch_path(new_branch_info);
- if (!check_refname_format(new->path, 0) &&
- !read_ref(new->path, &branch_rev))
+ if (!check_refname_format(new_branch_info->path, 0) &&
+ !read_ref(new_branch_info->path, &branch_rev))
oidcpy(rev, &branch_rev);
else
- new->path = NULL; /* not an existing branch */
+ new_branch_info->path = NULL; /* not an existing branch */
- new->commit = lookup_commit_reference_gently(rev, 1);
- if (!new->commit) {
+ new_branch_info->commit = lookup_commit_reference_gently(rev, 1);
+ if (!new_branch_info->commit) {
/* not a commit */
*source_tree = parse_tree_indirect(rev);
} else {
- parse_commit_or_die(new->commit);
- *source_tree = new->commit->tree;
+ parse_commit_or_die(new_branch_info->commit);
+ *source_tree = new_branch_info->commit->tree;
}
if (!*source_tree) /* case (1): want a tree */
@@ -1043,7 +1042,7 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
}
static int checkout_branch(struct checkout_opts *opts,
- struct branch_info *new)
+ struct branch_info *new_branch_info)
{
if (opts->pathspec.nr)
die(_("paths cannot be used with switching branches"));
@@ -1072,21 +1071,21 @@ static int checkout_branch(struct checkout_opts *opts,
} else if (opts->track == BRANCH_TRACK_UNSPECIFIED)
opts->track = git_branch_track;
- if (new->name && !new->commit)
+ if (new_branch_info->name && !new_branch_info->commit)
die(_("Cannot switch branch to a non-commit '%s'"),
- new->name);
+ new_branch_info->name);
- if (new->path && !opts->force_detach && !opts->new_branch &&
+ if (new_branch_info->path && !opts->force_detach && !opts->new_branch &&
!opts->ignore_other_worktrees) {
int flag;
char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag);
if (head_ref &&
- (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
- die_if_checked_out(new->path, 1);
+ (!(flag & REF_ISSYMREF) || strcmp(head_ref, new_branch_info->path)))
+ die_if_checked_out(new_branch_info->path, 1);
free(head_ref);
}
- if (!new->commit && opts->new_branch) {
+ if (!new_branch_info->commit && opts->new_branch) {
struct object_id rev;
int flag;
@@ -1094,13 +1093,13 @@ static int checkout_branch(struct checkout_opts *opts,
(flag & REF_ISSYMREF) && is_null_oid(&rev))
return switch_unborn_to_new_branch(opts);
}
- return switch_branches(opts, new);
+ return switch_branches(opts, new_branch_info);
}
int cmd_checkout(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
- struct branch_info new;
+ struct branch_info new_branch_info;
char *conflict_style = NULL;
int dwim_new_local_branch = 1;
struct option options[] = {
@@ -1118,9 +1117,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
2),
OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
3),
- OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)")),
+ OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)"),
+ PARSE_OPT_NOCOMPLETE),
OPT_BOOL('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
- OPT_BOOL(0, "overwrite-ignore", &opts.overwrite_ignore, N_("update ignored files (default)")),
+ OPT_BOOL_F(0, "overwrite-ignore", &opts.overwrite_ignore,
+ N_("update ignored files (default)"),
+ PARSE_OPT_NOCOMPLETE),
OPT_STRING(0, "conflict", &conflict_style, N_("style"),
N_("conflict style (merge or diff3)")),
OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
@@ -1138,7 +1140,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
};
memset(&opts, 0, sizeof(opts));
- memset(&new, 0, sizeof(new));
+ memset(&new_branch_info, 0, sizeof(new_branch_info));
opts.overwrite_ignore = 1;
opts.prefix = prefix;
opts.show_progress = -1;
@@ -1210,7 +1212,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.track == BRANCH_TRACK_UNSPECIFIED &&
!opts.new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
- &new, &opts, &rev);
+ &new_branch_info, &opts, &rev);
argv += n;
argc -= n;
}
@@ -1253,7 +1255,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
UNLEAK(opts);
if (opts.patch_mode || opts.pathspec.nr)
- return checkout_paths(&opts, new.name);
+ return checkout_paths(&opts, new_branch_info.name);
else
- return checkout_branch(&opts, &new);
+ return checkout_branch(&opts, &new_branch_info);
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 189e206..fad533a 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -909,7 +909,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT__QUIET(&quiet, N_("do not print names of files removed")),
OPT__DRY_RUN(&dry_run, N_("dry run")),
- OPT__FORCE(&force, N_("force")),
+ OPT__FORCE(&force, N_("force"), PARSE_OPT_NOCOMPLETE),
OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
OPT_BOOL('d', NULL, &remove_directories,
N_("remove whole directories")),
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 2177251..ecf4219 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -58,7 +58,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
usage(commit_tree_usage);
if (get_oid_commit(argv[i], &oid))
die("Not a valid object name %s", argv[i]);
- assert_sha1_type(oid.hash, OBJ_COMMIT);
+ assert_oid_type(&oid, OBJ_COMMIT);
new_parent(lookup_commit(&oid), &parents);
continue;
}
@@ -117,8 +117,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
die_errno("git commit-tree: failed to read");
}
- if (commit_tree(buffer.buf, buffer.len, tree_oid.hash, parents,
- commit_oid.hash, NULL, sign_commit)) {
+ if (commit_tree(buffer.buf, buffer.len, &tree_oid, parents, &commit_oid,
+ NULL, sign_commit)) {
strbuf_release(&buffer);
return 1;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 5dd766a..37fcb55 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -389,13 +389,9 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
if (active_cache_changed
|| !cache_tree_fully_valid(active_cache_tree))
update_main_cache_tree(WRITE_TREE_SILENT);
- if (active_cache_changed) {
- if (write_locked_index(&the_index, &index_lock,
- COMMIT_LOCK))
- die(_("unable to write new_index file"));
- } else {
- rollback_lock_file(&index_lock);
- }
+ if (write_locked_index(&the_index, &index_lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ die(_("unable to write new_index file"));
commit_style = COMMIT_AS_IS;
ret = get_index_file();
goto out;
@@ -1061,6 +1057,9 @@ static void finalize_deferred_config(struct wt_status *s)
s->show_branch = status_deferred_config.show_branch;
if (s->show_branch < 0)
s->show_branch = 0;
+
+ if (s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED)
+ s->ahead_behind_flags = AHEAD_BEHIND_FULL;
}
static int parse_and_validate_options(int argc, const char *argv[],
@@ -1277,6 +1276,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
N_("show branch information")),
OPT_BOOL(0, "show-stash", &s.show_stash,
N_("show stash information")),
+ OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
+ N_("compute full ahead/behind values")),
{ OPTION_CALLBACK, 0, "porcelain", &status_format,
N_("version"), N_("machine-readable output"),
PARSE_OPT_OPTARG, opt_parse_porcelain },
@@ -1402,6 +1403,7 @@ int run_commit_hook(int editor_is_used, const char *index_file, const char *name
int cmd_commit(int argc, const char **argv, const char *prefix)
{
+ const char *argv_gc_auto[] = {"gc", "--auto", NULL};
static struct wt_status s;
static struct option builtin_commit_options[] = {
OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
@@ -1437,6 +1439,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
STATUS_FORMAT_SHORT),
OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")),
+ OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
+ N_("compute full ahead/behind values")),
OPT_SET_INT(0, "porcelain", &status_format,
N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
OPT_SET_INT(0, "long", &status_format,
@@ -1579,8 +1583,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
append_merge_tag_headers(parents, &tail);
}
- if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash,
- parents, oid.hash, author_ident.buf, sign_commit, extra)) {
+ if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
+ parents, &oid, author_ident.buf, sign_commit,
+ extra)) {
rollback_index_files();
die(_("failed to write commit object"));
}
@@ -1606,6 +1611,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
"not exceeded, and then \"git reset HEAD\" to recover."));
rerere(0);
+ run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
if (amend && !no_post_rewrite) {
commit_post_rewrite(current_head, &oid);
diff --git a/builtin/config.c b/builtin/config.c
index ab5f954..01169dd 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -48,6 +48,13 @@ static int show_origin;
#define ACTION_GET_COLORBOOL (1<<14)
#define ACTION_GET_URLMATCH (1<<15)
+/*
+ * The actions "ACTION_LIST | ACTION_GET_*" which may produce more than
+ * one line of output and which should therefore be paged.
+ */
+#define PAGING_ACTIONS (ACTION_LIST | ACTION_GET_ALL | \
+ ACTION_GET_REGEXP | ACTION_GET_URLMATCH)
+
#define TYPE_BOOL (1<<0)
#define TYPE_INT (1<<1)
#define TYPE_BOOL_OR_INT (1<<2)
@@ -594,6 +601,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
usage_with_options(builtin_config_usage, builtin_config_options);
}
+ if (actions & PAGING_ACTIONS)
+ setup_auto_pager("config", 1);
+
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
if (config_with_options(show_all_config, NULL,
diff --git a/builtin/describe.c b/builtin/describe.c
index c428984..de840f9 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -285,7 +285,7 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
{
- strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
+ strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid, abbrev));
}
static void describe_commit(struct object_id *oid, struct strbuf *dst)
@@ -383,7 +383,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
if (!match_cnt) {
struct object_id *cmit_oid = &cmit->object.oid;
if (always) {
- strbuf_add_unique_abbrev(dst, cmit_oid->hash, abbrev);
+ strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
if (suffix)
strbuf_addstr(dst, suffix);
return;
@@ -502,7 +502,7 @@ static void describe(const char *arg, int last_one)
if (cmit)
describe_commit(&oid, &sb);
- else if (lookup_blob(&oid))
+ else if (oid_object_info(&oid, NULL) == OBJ_BLOB)
describe_blob(oid, &sb);
else
die(_("%s is neither a commit nor blob"), arg);
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index b775a75..4736151 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -76,7 +76,7 @@ static int diff_tree_stdin(char *line)
if (obj->type == OBJ_TREE)
return stdin_diff_trees((struct tree *)obj, p);
error("Object %s is a %s, not a commit or tree",
- oid_to_hex(&oid), typename(obj->type));
+ oid_to_hex(&oid), type_name(obj->type));
return -1;
}
diff --git a/builtin/difftool.c b/builtin/difftool.c
index bcc79d1..ee8dce0 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -306,7 +306,7 @@ static char *get_symlink(const struct object_id *oid, const char *path)
} else {
enum object_type type;
unsigned long size;
- data = read_sha1_file(oid->hash, &type, &size);
+ data = read_object_file(oid, &type, &size);
if (!data)
die(_("could not read object %s for symlink %s"),
oid_to_hex(oid), path);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 796d0cd..a15898d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -237,10 +237,10 @@ static void export_blob(const struct object_id *oid)
object = (struct object *)lookup_blob(oid);
eaten = 0;
} else {
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf)
die ("Could not read blob %s", oid_to_hex(oid));
- if (check_sha1_signature(oid->hash, buf, size, typename(type)) < 0)
+ if (check_object_signature(oid, buf, size, type_name(type)) < 0)
die("sha1 mismatch in blob %s", oid_to_hex(oid));
object = parse_object_buffer(oid, type, size, buf, &eaten);
}
@@ -682,7 +682,7 @@ static void handle_tag(const char *name, struct tag *tag)
return;
}
- buf = read_sha1_file(tag->object.oid.hash, &type, &size);
+ buf = read_object_file(&tag->object.oid, &type, &size);
if (!buf)
die ("Could not read tag %s", oid_to_hex(&tag->object.oid));
message = memmem(buf, size, "\n\n", 2);
@@ -757,7 +757,7 @@ static void handle_tag(const char *name, struct tag *tag)
if (tagged->type != OBJ_COMMIT) {
die ("Tag %s tags unexported %s!",
oid_to_hex(&tag->object.oid),
- typename(tagged->type));
+ type_name(tagged->type));
}
p = (struct commit *)tagged;
for (;;) {
@@ -839,7 +839,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (!commit) {
warning("%s: Unexpected object of type %s, skipping.",
e->name,
- typename(e->item->type));
+ type_name(e->item->type));
continue;
}
@@ -851,7 +851,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
continue;
default: /* OBJ_TAG (nested tags) is already handled */
warning("Tag points to object of unexpected type %s, skipping.",
- typename(commit->object.type));
+ type_name(commit->object.type));
continue;
}
@@ -947,7 +947,7 @@ static void import_marks(char *input_file)
if (last_idnum < mark)
last_idnum = mark;
- type = sha1_object_info(oid.hash, NULL);
+ type = oid_object_info(&oid, NULL);
if (type < 0)
die("object not found: %s", oid_to_hex(&oid));
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 8ee998e..8295f92 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -39,6 +39,10 @@ static int fetch_prune_config = -1; /* unspecified */
static int prune = -1; /* unspecified */
#define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
+static int fetch_prune_tags_config = -1; /* unspecified */
+static int prune_tags = -1; /* unspecified */
+#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
+
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
static int progress = -1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
@@ -66,6 +70,11 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
return 0;
}
+ if (!strcmp(k, "fetch.prunetags")) {
+ fetch_prune_tags_config = git_config_bool(k, v);
+ return 0;
+ }
+
if (!strcmp(k, "submodule.recurse")) {
int r = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
@@ -117,7 +126,7 @@ static struct option builtin_fetch_options[] = {
N_("append to .git/FETCH_HEAD instead of overwriting")),
OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
N_("path to upload pack on remote end")),
- OPT__FORCE(&force, N_("force overwrite of local branch")),
+ OPT__FORCE(&force, N_("force overwrite of local branch"), 0),
OPT_BOOL('m', "multiple", &multiple,
N_("fetch from multiple remotes")),
OPT_SET_INT('t', "tags", &tags,
@@ -128,6 +137,8 @@ static struct option builtin_fetch_options[] = {
N_("number of submodules fetched in parallel")),
OPT_BOOL('p', "prune", &prune,
N_("prune remote-tracking branches no longer on remote")),
+ OPT_BOOL('P', "prune-tags", &prune_tags,
+ N_("prune local tags no longer on remote and clobber changed tags")),
{ OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, N_("on-demand"),
N_("control recursive fetching of submodules"),
PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules },
@@ -626,7 +637,7 @@ static int update_local_ref(struct ref *ref,
struct branch *current_branch = branch_get(NULL);
const char *pretty_ref = prettify_refname(ref->name);
- type = sha1_object_info(ref->new_oid.hash, NULL);
+ type = oid_object_info(&ref->new_oid, NULL);
if (type < 0)
die(_("object %s not found"), oid_to_hex(&ref->new_oid));
@@ -697,9 +708,9 @@ static int update_local_ref(struct ref *ref,
if (in_merge_bases(current, updated)) {
struct strbuf quickref = STRBUF_INIT;
int r;
- strbuf_add_unique_abbrev(&quickref, current->object.oid.hash, DEFAULT_ABBREV);
+ strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
strbuf_addstr(&quickref, "..");
- strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV);
+ strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(&ref->new_oid);
@@ -712,9 +723,9 @@ static int update_local_ref(struct ref *ref,
} else if (force || ref->force) {
struct strbuf quickref = STRBUF_INIT;
int r;
- strbuf_add_unique_abbrev(&quickref, current->object.oid.hash, DEFAULT_ABBREV);
+ strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
strbuf_addstr(&quickref, "...");
- strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV);
+ strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(&ref->new_oid);
@@ -1220,6 +1231,8 @@ static void add_options_to_argv(struct argv_array *argv)
argv_array_push(argv, "--dry-run");
if (prune != -1)
argv_array_push(argv, prune ? "--prune" : "--no-prune");
+ if (prune_tags != -1)
+ argv_array_push(argv, prune_tags ? "--prune-tags" : "--no-prune-tags");
if (update_head_ok)
argv_array_push(argv, "--update-head-ok");
if (force)
@@ -1323,12 +1336,15 @@ static inline void fetch_one_setup_partial(struct remote *remote)
return;
}
-static int fetch_one(struct remote *remote, int argc, const char **argv)
+static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
{
static const char **refs = NULL;
struct refspec *refspec;
int ref_nr = 0;
+ int j = 0;
int exit_code;
+ int maybe_prune_tags;
+ int remote_via_config = remote_is_configured(remote, 0);
if (!remote)
die(_("No remote repository specified. Please, specify either a URL or a\n"
@@ -1338,18 +1354,39 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
if (prune < 0) {
/* no command line request */
- if (0 <= gtransport->remote->prune)
- prune = gtransport->remote->prune;
+ if (0 <= remote->prune)
+ prune = remote->prune;
else if (0 <= fetch_prune_config)
prune = fetch_prune_config;
else
prune = PRUNE_BY_DEFAULT;
}
+ if (prune_tags < 0) {
+ /* no command line request */
+ if (0 <= remote->prune_tags)
+ prune_tags = remote->prune_tags;
+ else if (0 <= fetch_prune_tags_config)
+ prune_tags = fetch_prune_tags_config;
+ else
+ prune_tags = PRUNE_TAGS_BY_DEFAULT;
+ }
+
+ maybe_prune_tags = prune_tags_ok && prune_tags;
+ if (maybe_prune_tags && remote_via_config)
+ add_prune_tags_to_fetch_refspec(remote);
+
+ if (argc > 0 || (maybe_prune_tags && !remote_via_config)) {
+ size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1);
+ refs = xcalloc(nr_alloc, sizeof(const char *));
+ if (maybe_prune_tags) {
+ refs[j++] = xstrdup("refs/tags/*:refs/tags/*");
+ ref_nr++;
+ }
+ }
+
if (argc > 0) {
- int j = 0;
int i;
- refs = xcalloc(st_add(argc, 1), sizeof(const char *));
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "tag")) {
i++;
@@ -1359,9 +1396,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
argv[i], argv[i]);
} else
refs[j++] = argv[i];
+ ref_nr++;
}
- refs[j] = NULL;
- ref_nr = j;
}
sigchain_push_common(unlock_pack_on_signal);
@@ -1380,6 +1416,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
int result = 0;
+ int prune_tags_ok = 1;
struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
packet_trace_identity("fetch");
@@ -1446,6 +1483,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
} else {
/* Zero or one remotes */
remote = remote_get(argv[0]);
+ prune_tags_ok = (argc == 1);
argc--;
argv++;
}
@@ -1454,7 +1492,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (remote) {
if (filter_options.choice || repository_format_partial_clone)
fetch_one_setup_partial(remote);
- result = fetch_one(remote, argc, argv);
+ result = fetch_one(remote, argc, argv, prune_tags_ok);
} else {
if (filter_options.choice)
die(_("--filter can only be used with the remote configured in core.partialClone"));
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 8e8a15e..bd680be 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -485,10 +485,10 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
struct strbuf tagbuf = STRBUF_INIT;
for (i = 0; i < origins.nr; i++) {
- unsigned char *sha1 = origins.items[i].util;
+ struct object_id *oid = origins.items[i].util;
enum object_type type;
unsigned long size, len;
- char *buf = read_sha1_file(sha1, &type, &size);
+ char *buf = read_object_file(oid, &type, &size);
struct strbuf sig = STRBUF_INIT;
if (!buf || type != OBJ_TAG)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 7a8a679..0922558 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -65,12 +65,12 @@ static const char *printable_type(struct object *obj)
const char *ret;
if (obj->type == OBJ_NONE) {
- enum object_type type = sha1_object_info(obj->oid.hash, NULL);
+ enum object_type type = oid_object_info(&obj->oid, NULL);
if (type > 0)
object_as_type(obj, type, 0);
}
- ret = typename(obj->type);
+ ret = type_name(obj->type);
if (!ret)
ret = "unknown";
@@ -137,7 +137,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
printf("broken link from %7s %s\n",
printable_type(parent), describe_object(parent));
printf("broken link from %7s %s\n",
- (type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
+ (type == OBJ_ANY ? "unknown" : type_name(type)), "unknown");
errors_found |= ERROR_REACHABLE;
return 1;
}
@@ -180,7 +180,13 @@ static void mark_object_reachable(struct object *obj)
static int traverse_one_object(struct object *obj)
{
- return fsck_walk(obj, obj, &fsck_walk_options);
+ int result = fsck_walk(obj, obj, &fsck_walk_options);
+
+ if (obj->type == OBJ_TREE) {
+ struct tree *tree = (struct tree *)obj;
+ free_tree_buffer(tree);
+ }
+ return result;
}
static int traverse_reachable(void)
@@ -507,7 +513,7 @@ static struct object *parse_loose_object(const struct object_id *oid,
unsigned long size;
int eaten;
- if (read_loose_object(path, oid->hash, &type, &size, &contents) < 0)
+ if (read_loose_object(path, oid, &type, &size, &contents) < 0)
return NULL;
if (!contents && type != OBJ_BLOB)
diff --git a/builtin/gc.c b/builtin/gc.c
index 77fa720..f51e5a6 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -360,8 +360,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
N_("prune unreferenced objects"),
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
- OPT_BOOL(0, "auto", &auto_gc, N_("enable auto-gc mode")),
- OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")),
+ OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
+ PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL_F(0, "force", &force,
+ N_("force running gc even if there may be another gc running"),
+ PARSE_OPT_NOCOMPLETE),
OPT_END()
};
diff --git a/builtin/grep.c b/builtin/grep.c
index 3ca4ac8..668cb80 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -92,8 +92,7 @@ static pthread_cond_t cond_result;
static int skip_first_line;
-static void add_work(struct grep_opt *opt, enum grep_source_type type,
- const char *name, const char *path, const void *id)
+static void add_work(struct grep_opt *opt, const struct grep_source *gs)
{
grep_lock();
@@ -101,7 +100,7 @@ static void add_work(struct grep_opt *opt, enum grep_source_type type,
pthread_cond_wait(&cond_write, &grep_mutex);
}
- grep_source_init(&todo[todo_end].source, type, name, path, id);
+ todo[todo_end].source = *gs;
if (opt->binary != GREP_BINARY_TEXT)
grep_source_load_driver(&todo[todo_end].source);
todo[todo_end].done = 0;
@@ -307,7 +306,7 @@ static void *lock_and_read_oid_file(const struct object_id *oid, enum object_typ
void *data;
grep_read_lock();
- data = read_sha1_file(oid->hash, type, size);
+ data = read_object_file(oid, type, size);
grep_read_unlock();
return data;
}
@@ -317,6 +316,7 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
const char *path)
{
struct strbuf pathbuf = STRBUF_INIT;
+ struct grep_source gs;
if (opt->relative && opt->prefix_length) {
quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
@@ -325,19 +325,22 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
strbuf_addstr(&pathbuf, filename);
}
+ grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid);
+ strbuf_release(&pathbuf);
+
#ifndef NO_PTHREADS
if (num_threads) {
- add_work(opt, GREP_SOURCE_OID, pathbuf.buf, path, oid);
- strbuf_release(&pathbuf);
+ /*
+ * add_work() copies gs and thus assumes ownership of
+ * its fields, so do not call grep_source_clear()
+ */
+ add_work(opt, &gs);
return 0;
} else
#endif
{
- struct grep_source gs;
int hit;
- grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid);
- strbuf_release(&pathbuf);
hit = grep_source(opt, &gs);
grep_source_clear(&gs);
@@ -348,25 +351,29 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
static int grep_file(struct grep_opt *opt, const char *filename)
{
struct strbuf buf = STRBUF_INIT;
+ struct grep_source gs;
if (opt->relative && opt->prefix_length)
quote_path_relative(filename, opt->prefix, &buf);
else
strbuf_addstr(&buf, filename);
+ grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
+ strbuf_release(&buf);
+
#ifndef NO_PTHREADS
if (num_threads) {
- add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename);
- strbuf_release(&buf);
+ /*
+ * add_work() copies gs and thus assumes ownership of
+ * its fields, so do not call grep_source_clear()
+ */
+ add_work(opt, &gs);
return 0;
} else
#endif
{
- struct grep_source gs;
int hit;
- grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
- strbuf_release(&buf);
hit = grep_source(opt, &gs);
grep_source_clear(&gs);
@@ -445,7 +452,7 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
object = parse_object_or_die(oid, oid_to_hex(oid));
grep_read_lock();
- data = read_object_with_reference(object->oid.hash, tree_type,
+ data = read_object_with_reference(&object->oid, tree_type,
&size, NULL);
grep_read_unlock();
@@ -607,7 +614,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
int hit, len;
grep_read_lock();
- data = read_object_with_reference(obj->oid.hash, tree_type,
+ data = read_object_with_reference(&obj->oid, tree_type,
&size, NULL);
grep_read_unlock();
@@ -627,7 +634,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
free(data);
return hit;
}
- die(_("unable to grep from object of type %s"), typename(obj->type));
+ die(_("unable to grep from object of type %s"), type_name(obj->type));
}
static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
@@ -832,8 +839,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_BOOL('L', "files-without-match",
&opt.unmatch_name_only,
N_("show only the names of files without match")),
- OPT_BOOL('z', "null", &opt.null_following_name,
- N_("print NUL after filenames")),
+ OPT_BOOL_F('z', "null", &opt.null_following_name,
+ N_("print NUL after filenames"),
+ PARSE_OPT_NOCOMPLETE),
OPT_BOOL('c', "count", &opt.count,
N_("show the number of matches instead of matching lines")),
OPT__COLOR(&opt.color, N_("highlight matches")),
@@ -884,9 +892,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
N_("pager"), N_("show matching files in the pager"),
- PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
- OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored,
- N_("allow calling of grep(1) (ignored by this build)")),
+ PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE,
+ NULL, (intptr_t)default_pager },
+ OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored,
+ N_("allow calling of grep(1) (ignored by this build)"),
+ PARSE_OPT_NOCOMPLETE),
OPT_END()
};
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index c532ff9..526da5c 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -24,7 +24,8 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
if (strbuf_read(&buf, fd, 4096) < 0)
ret = -1;
else
- ret = hash_sha1_file_literally(buf.buf, buf.len, type, oid, flags);
+ ret = hash_object_file_literally(buf.buf, buf.len, type, oid,
+ flags);
strbuf_release(&buf);
return ret;
}
diff --git a/builtin/help.c b/builtin/help.c
index d3c8fc4..598867c 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -194,11 +194,11 @@ static void do_add_man_viewer_info(const char *name,
size_t len,
const char *value)
{
- struct man_viewer_info_list *new;
- FLEX_ALLOC_MEM(new, name, name, len);
- new->info = xstrdup(value);
- new->next = man_viewer_info_list;
- man_viewer_info_list = new;
+ struct man_viewer_info_list *new_man_viewer;
+ FLEX_ALLOC_MEM(new_man_viewer, name, name, len);
+ new_man_viewer->info = xstrdup(value);
+ new_man_viewer->next = man_viewer_info_list;
+ man_viewer_info_list = new_man_viewer;
}
static int add_man_viewer_path(const char *name,
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 5ebd370..657a5dd 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -49,6 +49,7 @@ struct thread_local {
int pack_fd;
};
+/* Remember to update object flag allocation in object.h */
#define FLAG_LINK (1u<<20)
#define FLAG_CHECKED (1u<<21)
@@ -58,7 +59,7 @@ struct ofs_delta_entry {
};
struct ref_delta_entry {
- unsigned char sha1[20];
+ struct object_id oid;
int obj_no;
};
@@ -91,7 +92,7 @@ static unsigned int input_offset, input_len;
static off_t consumed_bytes;
static off_t max_input_size;
static unsigned deepest_delta;
-static git_SHA_CTX input_ctx;
+static git_hash_ctx input_ctx;
static uint32_t input_crc32;
static int input_fd, output_fd;
static const char *curr_pack;
@@ -221,14 +222,14 @@ static unsigned check_object(struct object *obj)
if (!(obj->flags & FLAG_CHECKED)) {
unsigned long size;
- int type = sha1_object_info(obj->oid.hash, &size);
+ int type = oid_object_info(&obj->oid, &size);
if (type <= 0)
die(_("did not receive expected object %s"),
oid_to_hex(&obj->oid));
if (type != obj->type)
die(_("object %s: expected type %s, found %s"),
oid_to_hex(&obj->oid),
- typename(obj->type), typename(type));
+ type_name(obj->type), type_name(type));
obj->flags |= FLAG_CHECKED;
return 1;
}
@@ -253,7 +254,7 @@ static void flush(void)
if (input_offset) {
if (output_fd >= 0)
write_or_die(output_fd, input_buffer, input_offset);
- git_SHA1_Update(&input_ctx, input_buffer, input_offset);
+ the_hash_algo->update_fn(&input_ctx, input_buffer, input_offset);
memmove(input_buffer, input_buffer + input_offset, input_len);
input_offset = 0;
}
@@ -326,7 +327,7 @@ static const char *open_pack_file(const char *pack_name)
output_fd = -1;
nothread_data.pack_fd = input_fd;
}
- git_SHA1_Init(&input_ctx);
+ the_hash_algo->init_fn(&input_ctx);
return pack_name;
}
@@ -437,22 +438,22 @@ static int is_delta_type(enum object_type type)
}
static void *unpack_entry_data(off_t offset, unsigned long size,
- enum object_type type, unsigned char *sha1)
+ enum object_type type, struct object_id *oid)
{
static char fixed_buf[8192];
int status;
git_zstream stream;
void *buf;
- git_SHA_CTX c;
+ git_hash_ctx c;
char hdr[32];
int hdrlen;
if (!is_delta_type(type)) {
- hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), size) + 1;
- git_SHA1_Init(&c);
- git_SHA1_Update(&c, hdr, hdrlen);
+ hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), size) + 1;
+ the_hash_algo->init_fn(&c);
+ the_hash_algo->update_fn(&c, hdr, hdrlen);
} else
- sha1 = NULL;
+ oid = NULL;
if (type == OBJ_BLOB && size > big_file_threshold)
buf = fixed_buf;
else
@@ -469,8 +470,8 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
stream.avail_in = input_len;
status = git_inflate(&stream, 0);
use(input_len - stream.avail_in);
- if (sha1)
- git_SHA1_Update(&c, last_out, stream.next_out - last_out);
+ if (oid)
+ the_hash_algo->update_fn(&c, last_out, stream.next_out - last_out);
if (buf == fixed_buf) {
stream.next_out = buf;
stream.avail_out = sizeof(fixed_buf);
@@ -479,15 +480,15 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
if (stream.total_out != size || status != Z_STREAM_END)
bad_object(offset, _("inflate returned %d"), status);
git_inflate_end(&stream);
- if (sha1)
- git_SHA1_Final(sha1, &c);
+ if (oid)
+ the_hash_algo->final_fn(oid->hash, &c);
return buf == fixed_buf ? NULL : buf;
}
static void *unpack_raw_entry(struct object_entry *obj,
off_t *ofs_offset,
- unsigned char *ref_sha1,
- unsigned char *sha1)
+ struct object_id *ref_oid,
+ struct object_id *oid)
{
unsigned char *p;
unsigned long size, c;
@@ -515,8 +516,8 @@ static void *unpack_raw_entry(struct object_entry *obj,
switch (obj->type) {
case OBJ_REF_DELTA:
- hashcpy(ref_sha1, fill(20));
- use(20);
+ hashcpy(ref_oid->hash, fill(the_hash_algo->rawsz));
+ use(the_hash_algo->rawsz);
break;
case OBJ_OFS_DELTA:
p = fill(1);
@@ -546,7 +547,7 @@ static void *unpack_raw_entry(struct object_entry *obj,
}
obj->hdr_size = consumed_bytes - obj->idx.offset;
- data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
+ data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, oid);
obj->idx.crc32 = input_crc32;
return data;
}
@@ -671,18 +672,18 @@ static void find_ofs_delta_children(off_t offset,
*last_index = last;
}
-static int compare_ref_delta_bases(const unsigned char *sha1,
- const unsigned char *sha2,
+static int compare_ref_delta_bases(const struct object_id *oid1,
+ const struct object_id *oid2,
enum object_type type1,
enum object_type type2)
{
int cmp = type1 - type2;
if (cmp)
return cmp;
- return hashcmp(sha1, sha2);
+ return oidcmp(oid1, oid2);
}
-static int find_ref_delta(const unsigned char *sha1, enum object_type type)
+static int find_ref_delta(const struct object_id *oid, enum object_type type)
{
int first = 0, last = nr_ref_deltas;
@@ -691,7 +692,7 @@ static int find_ref_delta(const unsigned char *sha1, enum object_type type)
struct ref_delta_entry *delta = &ref_deltas[next];
int cmp;
- cmp = compare_ref_delta_bases(sha1, delta->sha1,
+ cmp = compare_ref_delta_bases(oid, &delta->oid,
type, objects[delta->obj_no].type);
if (!cmp)
return next;
@@ -704,11 +705,11 @@ static int find_ref_delta(const unsigned char *sha1, enum object_type type)
return -first-1;
}
-static void find_ref_delta_children(const unsigned char *sha1,
+static void find_ref_delta_children(const struct object_id *oid,
int *first_index, int *last_index,
enum object_type type)
{
- int first = find_ref_delta(sha1, type);
+ int first = find_ref_delta(oid, type);
int last = first;
int end = nr_ref_deltas - 1;
@@ -717,9 +718,9 @@ static void find_ref_delta_children(const unsigned char *sha1,
*last_index = -1;
return;
}
- while (first > 0 && !hashcmp(ref_deltas[first - 1].sha1, sha1))
+ while (first > 0 && !oidcmp(&ref_deltas[first - 1].oid, oid))
--first;
- while (last < end && !hashcmp(ref_deltas[last + 1].sha1, sha1))
+ while (last < end && !oidcmp(&ref_deltas[last + 1].oid, oid))
++last;
*first_index = first;
*last_index = last;
@@ -771,7 +772,7 @@ static int check_collison(struct object_entry *entry)
memset(&data, 0, sizeof(data));
data.entry = entry;
- data.st = open_istream(entry->idx.oid.hash, &type, &size, NULL);
+ data.st = open_istream(&entry->idx.oid, &type, &size, NULL);
if (!data.st)
return -1;
if (size != entry->size || type != entry->type)
@@ -810,12 +811,12 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
enum object_type has_type;
unsigned long has_size;
read_lock();
- has_type = sha1_object_info(oid->hash, &has_size);
+ has_type = oid_object_info(oid, &has_size);
if (has_type < 0)
die(_("cannot read existing object info %s"), oid_to_hex(oid));
if (has_type != type || has_size != size)
die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
- has_data = read_sha1_file(oid->hash, &has_type, &has_size);
+ has_data = read_object_file(oid, &has_type, &has_size);
read_unlock();
if (!data)
data = new_data = get_data_from_pack(obj_entry);
@@ -827,7 +828,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
free(has_data);
}
- if (strict) {
+ if (strict || do_fsck_object) {
read_lock();
if (type == OBJ_BLOB) {
struct blob *blob = lookup_blob(oid);
@@ -849,11 +850,11 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
obj = parse_object_buffer(oid, type, size, buf,
&eaten);
if (!obj)
- die(_("invalid %s"), typename(type));
+ die(_("invalid %s"), type_name(type));
if (do_fsck_object &&
fsck_object(obj, buf, size, &fsck_options))
die(_("Error in object"));
- if (fsck_walk(obj, NULL, &fsck_options))
+ if (strict && fsck_walk(obj, NULL, &fsck_options))
die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
if (obj->type == OBJ_TREE) {
@@ -958,9 +959,8 @@ static void resolve_delta(struct object_entry *delta_obj,
free(delta_data);
if (!result->data)
bad_object(delta_obj->idx.offset, _("failed to apply delta"));
- hash_sha1_file(result->data, result->size,
- typename(delta_obj->real_type),
- delta_obj->idx.oid.hash);
+ hash_object_file(result->data, result->size,
+ type_name(delta_obj->real_type), &delta_obj->idx.oid);
sha1_object(result->data, NULL, result->size, delta_obj->real_type,
&delta_obj->idx.oid);
counter_lock();
@@ -992,7 +992,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
struct base_data *prev_base)
{
if (base->ref_last == -1 && base->ofs_last == -1) {
- find_ref_delta_children(base->obj->idx.oid.hash,
+ find_ref_delta_children(&base->obj->idx.oid,
&base->ref_first, &base->ref_last,
OBJ_REF_DELTA);
@@ -1076,7 +1076,7 @@ static int compare_ref_delta_entry(const void *a, const void *b)
const struct ref_delta_entry *delta_a = a;
const struct ref_delta_entry *delta_b = b;
- return hashcmp(delta_a->sha1, delta_b->sha1);
+ return oidcmp(&delta_a->oid, &delta_b->oid);
}
static void resolve_base(struct object_entry *obj)
@@ -1119,11 +1119,11 @@ static void *threaded_second_pass(void *data)
* - calculate SHA1 of all non-delta objects;
* - remember base (SHA1 or offset) for all deltas.
*/
-static void parse_pack_objects(unsigned char *sha1)
+static void parse_pack_objects(unsigned char *hash)
{
int i, nr_delays = 0;
struct ofs_delta_entry *ofs_delta = ofs_deltas;
- unsigned char ref_delta_sha1[20];
+ struct object_id ref_delta_oid;
struct stat st;
if (verbose)
@@ -1133,8 +1133,8 @@ static void parse_pack_objects(unsigned char *sha1)
for (i = 0; i < nr_objects; i++) {
struct object_entry *obj = &objects[i];
void *data = unpack_raw_entry(obj, &ofs_delta->offset,
- ref_delta_sha1,
- obj->idx.oid.hash);
+ &ref_delta_oid,
+ &obj->idx.oid);
obj->real_type = obj->type;
if (obj->type == OBJ_OFS_DELTA) {
nr_ofs_deltas++;
@@ -1142,7 +1142,7 @@ static void parse_pack_objects(unsigned char *sha1)
ofs_delta++;
} else if (obj->type == OBJ_REF_DELTA) {
ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc);
- hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1);
+ oidcpy(&ref_deltas[nr_ref_deltas].oid, &ref_delta_oid);
ref_deltas[nr_ref_deltas].obj_no = i;
nr_ref_deltas++;
} else if (!data) {
@@ -1160,10 +1160,10 @@ static void parse_pack_objects(unsigned char *sha1)
/* Check pack integrity */
flush();
- git_SHA1_Final(sha1, &input_ctx);
- if (hashcmp(fill(20), sha1))
+ the_hash_algo->final_fn(hash, &input_ctx);
+ if (hashcmp(fill(the_hash_algo->rawsz), hash))
die(_("pack is corrupted (SHA1 mismatch)"));
- use(20);
+ use(the_hash_algo->rawsz);
/* If input_fd is a file, we should have reached its end now. */
if (fstat(input_fd, &st))
@@ -1239,21 +1239,21 @@ static void resolve_deltas(void)
/*
* Third pass:
* - append objects to convert thin pack to full pack if required
- * - write the final 20-byte SHA-1
+ * - write the final pack hash
*/
-static void fix_unresolved_deltas(struct sha1file *f);
-static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
+static void fix_unresolved_deltas(struct hashfile *f);
+static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_hash)
{
if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
stop_progress(&progress);
- /* Flush remaining pack final 20-byte SHA1. */
+ /* Flush remaining pack final hash. */
flush();
return;
}
if (fix_thin_pack) {
- struct sha1file *f;
- unsigned char read_sha1[20], tail_sha1[20];
+ struct hashfile *f;
+ unsigned char read_hash[GIT_MAX_RAWSZ], tail_hash[GIT_MAX_RAWSZ];
struct strbuf msg = STRBUF_INIT;
int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;
int nr_objects_initial = nr_objects;
@@ -1262,7 +1262,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
REALLOC_ARRAY(objects, nr_objects + nr_unresolved + 1);
memset(objects + nr_objects + 1, 0,
nr_unresolved * sizeof(*objects));
- f = sha1fd(output_fd, curr_pack);
+ f = hashfd(output_fd, curr_pack);
fix_unresolved_deltas(f);
strbuf_addf(&msg, Q_("completed with %d local object",
"completed with %d local objects",
@@ -1270,12 +1270,12 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
nr_objects - nr_objects_initial);
stop_progress_msg(&progress, msg.buf);
strbuf_release(&msg);
- sha1close(f, tail_sha1, 0);
- hashcpy(read_sha1, pack_sha1);
- fixup_pack_header_footer(output_fd, pack_sha1,
+ hashclose(f, tail_hash, 0);
+ hashcpy(read_hash, pack_hash);
+ fixup_pack_header_footer(output_fd, pack_hash,
curr_pack, nr_objects,
- read_sha1, consumed_bytes-20);
- if (hashcmp(read_sha1, tail_sha1) != 0)
+ read_hash, consumed_bytes-the_hash_algo->rawsz);
+ if (hashcmp(read_hash, tail_hash) != 0)
die(_("Unexpected tail checksum for %s "
"(disk corruption?)"), curr_pack);
}
@@ -1286,7 +1286,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);
}
-static int write_compressed(struct sha1file *f, void *in, unsigned int size)
+static int write_compressed(struct hashfile *f, void *in, unsigned int size)
{
git_zstream stream;
int status;
@@ -1300,7 +1300,7 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
stream.next_out = outbuf;
stream.avail_out = sizeof(outbuf);
status = git_deflate(&stream, Z_FINISH);
- sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
+ hashwrite(f, outbuf, sizeof(outbuf) - stream.avail_out);
} while (status == Z_OK);
if (status != Z_STREAM_END)
@@ -1310,7 +1310,7 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
return size;
}
-static struct object_entry *append_obj_to_pack(struct sha1file *f,
+static struct object_entry *append_obj_to_pack(struct hashfile *f,
const unsigned char *sha1, void *buf,
unsigned long size, enum object_type type)
{
@@ -1327,7 +1327,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
}
header[n++] = c;
crc32_begin(f);
- sha1write(f, header, n);
+ hashwrite(f, header, n);
obj[0].size = size;
obj[0].hdr_size = n;
obj[0].type = type;
@@ -1335,7 +1335,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
obj[1].idx.offset = obj[0].idx.offset + n;
obj[1].idx.offset += write_compressed(f, buf, size);
obj[0].idx.crc32 = crc32_end(f);
- sha1flush(f);
+ hashflush(f);
hashcpy(obj->idx.oid.hash, sha1);
return obj;
}
@@ -1347,7 +1347,7 @@ static int delta_pos_compare(const void *_a, const void *_b)
return a->obj_no - b->obj_no;
}
-static void fix_unresolved_deltas(struct sha1file *f)
+static void fix_unresolved_deltas(struct hashfile *f)
{
struct ref_delta_entry **sorted_by_pos;
int i;
@@ -1374,14 +1374,15 @@ static void fix_unresolved_deltas(struct sha1file *f)
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue;
- base_obj->data = read_sha1_file(d->sha1, &type, &base_obj->size);
+ base_obj->data = read_object_file(&d->oid, &type,
+ &base_obj->size);
if (!base_obj->data)
continue;
- if (check_sha1_signature(d->sha1, base_obj->data,
- base_obj->size, typename(type)))
- die(_("local object %s is corrupt"), sha1_to_hex(d->sha1));
- base_obj->obj = append_obj_to_pack(f, d->sha1,
+ if (check_object_signature(&d->oid, base_obj->data,
+ base_obj->size, type_name(type)))
+ die(_("local object %s is corrupt"), oid_to_hex(&d->oid));
+ base_obj->obj = append_obj_to_pack(f, d->oid.hash,
base_obj->data, base_obj->size, type);
find_unresolved_deltas(base_obj);
display_progress(progress, nr_resolved_deltas);
@@ -1403,7 +1404,7 @@ static const char *derive_filename(const char *pack_name, const char *suffix,
}
static void write_special_file(const char *suffix, const char *msg,
- const char *pack_name, const unsigned char *sha1,
+ const char *pack_name, const unsigned char *hash,
const char **report)
{
struct strbuf name_buf = STRBUF_INIT;
@@ -1414,7 +1415,7 @@ static void write_special_file(const char *suffix, const char *msg,
if (pack_name)
filename = derive_filename(pack_name, suffix, &name_buf);
else
- filename = odb_pack_name(&name_buf, sha1, suffix);
+ filename = odb_pack_name(&name_buf, hash, suffix);
fd = odb_pack_keep(filename);
if (fd < 0) {
@@ -1438,7 +1439,7 @@ static void write_special_file(const char *suffix, const char *msg,
static void final(const char *final_pack_name, const char *curr_pack_name,
const char *final_index_name, const char *curr_index_name,
const char *keep_msg, const char *promisor_msg,
- unsigned char *sha1)
+ unsigned char *hash)
{
const char *report = "pack";
struct strbuf pack_name = STRBUF_INIT;
@@ -1455,15 +1456,15 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
}
if (keep_msg)
- write_special_file("keep", keep_msg, final_pack_name, sha1,
+ write_special_file("keep", keep_msg, final_pack_name, hash,
&report);
if (promisor_msg)
write_special_file("promisor", promisor_msg, final_pack_name,
- sha1, NULL);
+ hash, NULL);
if (final_pack_name != curr_pack_name) {
if (!final_pack_name)
- final_pack_name = odb_pack_name(&pack_name, sha1, "pack");
+ final_pack_name = odb_pack_name(&pack_name, hash, "pack");
if (finalize_object_file(curr_pack_name, final_pack_name))
die(_("cannot store pack file"));
} else if (from_stdin)
@@ -1471,18 +1472,18 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (final_index_name != curr_index_name) {
if (!final_index_name)
- final_index_name = odb_pack_name(&index_name, sha1, "idx");
+ final_index_name = odb_pack_name(&index_name, hash, "idx");
if (finalize_object_file(curr_index_name, final_index_name))
die(_("cannot store index file"));
} else
chmod(final_index_name, 0444);
if (!from_stdin) {
- printf("%s\n", sha1_to_hex(sha1));
+ printf("%s\n", sha1_to_hex(hash));
} else {
struct strbuf buf = STRBUF_INIT;
- strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1));
+ strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(hash));
write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
@@ -1616,7 +1617,7 @@ static void show_pack_info(int stat_only)
continue;
printf("%s %-6s %lu %lu %"PRIuMAX,
oid_to_hex(&obj->idx.oid),
- typename(obj->real_type), obj->size,
+ type_name(obj->real_type), obj->size,
(unsigned long)(obj[1].idx.offset - obj->idx.offset),
(uintmax_t)obj->idx.offset);
if (is_delta_type(obj->type)) {
@@ -1653,7 +1654,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
struct strbuf index_name_buf = STRBUF_INIT;
struct pack_idx_entry **idx_objects;
struct pack_idx_option opts;
- unsigned char pack_sha1[20];
+ unsigned char pack_hash[GIT_MAX_RAWSZ];
unsigned foreign_nr = 1; /* zero is a "good" value, assume bad */
int report_end_of_input = 0;
@@ -1689,6 +1690,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
} else if (!strcmp(arg, "--check-self-contained-and-connected")) {
strict = 1;
check_self_contained_and_connected = 1;
+ } else if (!strcmp(arg, "--fsck-objects")) {
+ do_fsck_object = 1;
} else if (!strcmp(arg, "--verify")) {
verify = 1;
} else if (!strcmp(arg, "--verify-stat")) {
@@ -1790,11 +1793,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (show_stat)
obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
- parse_pack_objects(pack_sha1);
+ parse_pack_objects(pack_hash);
if (report_end_of_input)
write_in_full(2, "\0", 1);
resolve_deltas();
- conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
+ conclude_pack(fix_thin_pack, curr_pack, pack_hash);
free(ofs_deltas);
free(ref_deltas);
if (strict)
@@ -1806,14 +1809,14 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
ALLOC_ARRAY(idx_objects, nr_objects);
for (i = 0; i < nr_objects; i++)
idx_objects[i] = &objects[i].idx;
- curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);
+ curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
free(idx_objects);
if (!verify)
final(pack_name, curr_pack,
index_name, curr_index,
keep_msg, promisor_msg,
- pack_sha1);
+ pack_hash);
else
close(input_fd);
free(objects);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index c9b7946..68ff4ad 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -24,11 +24,11 @@ static int init_is_bare_repository = 0;
static int init_shared_repository = -1;
static const char *init_db_template_dir;
-static void copy_templates_1(struct strbuf *path, struct strbuf *template,
+static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
DIR *dir)
{
size_t path_baselen = path->len;
- size_t template_baselen = template->len;
+ size_t template_baselen = template_path->len;
struct dirent *de;
/* Note: if ".git/hooks" file exists in the repository being
@@ -44,12 +44,12 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template,
int exists = 0;
strbuf_setlen(path, path_baselen);
- strbuf_setlen(template, template_baselen);
+ strbuf_setlen(template_path, template_baselen);
if (de->d_name[0] == '.')
continue;
strbuf_addstr(path, de->d_name);
- strbuf_addstr(template, de->d_name);
+ strbuf_addstr(template_path, de->d_name);
if (lstat(path->buf, &st_git)) {
if (errno != ENOENT)
die_errno(_("cannot stat '%s'"), path->buf);
@@ -57,36 +57,36 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template,
else
exists = 1;
- if (lstat(template->buf, &st_template))
- die_errno(_("cannot stat template '%s'"), template->buf);
+ if (lstat(template_path->buf, &st_template))
+ die_errno(_("cannot stat template '%s'"), template_path->buf);
if (S_ISDIR(st_template.st_mode)) {
- DIR *subdir = opendir(template->buf);
+ DIR *subdir = opendir(template_path->buf);
if (!subdir)
- die_errno(_("cannot opendir '%s'"), template->buf);
+ die_errno(_("cannot opendir '%s'"), template_path->buf);
strbuf_addch(path, '/');
- strbuf_addch(template, '/');
- copy_templates_1(path, template, subdir);
+ strbuf_addch(template_path, '/');
+ copy_templates_1(path, template_path, subdir);
closedir(subdir);
}
else if (exists)
continue;
else if (S_ISLNK(st_template.st_mode)) {
struct strbuf lnk = STRBUF_INIT;
- if (strbuf_readlink(&lnk, template->buf, 0) < 0)
- die_errno(_("cannot readlink '%s'"), template->buf);
+ if (strbuf_readlink(&lnk, template_path->buf, 0) < 0)
+ die_errno(_("cannot readlink '%s'"), template_path->buf);
if (symlink(lnk.buf, path->buf))
die_errno(_("cannot symlink '%s' '%s'"),
lnk.buf, path->buf);
strbuf_release(&lnk);
}
else if (S_ISREG(st_template.st_mode)) {
- if (copy_file(path->buf, template->buf, st_template.st_mode))
+ if (copy_file(path->buf, template_path->buf, st_template.st_mode))
die_errno(_("cannot copy '%s' to '%s'"),
- template->buf, path->buf);
+ template_path->buf, path->buf);
}
else
- error(_("ignoring template %s"), template->buf);
+ error(_("ignoring template %s"), template_path->buf);
}
}
diff --git a/builtin/log.c b/builtin/log.c
index 46b4ca1..71f68a3 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -29,6 +29,8 @@
#include "gpg-interface.h"
#include "progress.h"
+#define MAIL_DEFAULT_WRAP 72
+
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@@ -516,7 +518,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
{
unsigned long size;
enum object_type type;
- char *buf = read_sha1_file(oid->hash, &type, &size);
+ char *buf = read_object_file(oid, &type, &size);
int offset = 0;
if (!buf)
@@ -539,7 +541,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
return 0;
}
-static int show_tree_object(const unsigned char *sha1,
+static int show_tree_object(const struct object_id *oid,
struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
@@ -1044,7 +1046,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
shortlog_init(&log);
log.wrap_lines = 1;
- log.wrap = 72;
+ log.wrap = MAIL_DEFAULT_WRAP;
log.in1 = 2;
log.in2 = 4;
log.file = rev->diffopt.file;
@@ -1061,6 +1063,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
memcpy(&opts, &rev->diffopt, sizeof(opts));
opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+ opts.stat_width = MAIL_DEFAULT_WRAP;
diff_setup_done(&opts);
@@ -1614,6 +1617,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
(!rev.diffopt.output_format ||
rev.diffopt.output_format == DIFF_FORMAT_PATCH))
rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;
+ if (!rev.diffopt.stat_width)
+ rev.diffopt.stat_width = MAIL_DEFAULT_WRAP;
/* Always generate a patch */
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
@@ -1868,12 +1873,12 @@ static void print_commit(char sign, struct commit *commit, int verbose,
{
if (!verbose) {
fprintf(file, "%c %s\n", sign,
- find_unique_abbrev(commit->object.oid.hash, abbrev));
+ find_unique_abbrev(&commit->object.oid, abbrev));
} else {
struct strbuf buf = STRBUF_INIT;
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
fprintf(file, "%c %s %s\n", sign,
- find_unique_abbrev(commit->object.oid.hash, abbrev),
+ find_unique_abbrev(&commit->object.oid, abbrev),
buf.buf);
strbuf_release(&buf);
}
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 2fc836e..a71f6bd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -240,7 +240,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,
printf("%s%06o %s %d\t",
tag,
ce->ce_mode,
- find_unique_abbrev(ce->oid.hash, abbrev),
+ find_unique_abbrev(&ce->oid, abbrev),
ce_stage(ce));
}
write_eolinfo(repo->index, ce, fullname);
@@ -271,7 +271,7 @@ static void show_ru_info(const struct index_state *istate)
if (!ui->mode[i])
continue;
printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
- find_unique_abbrev(ui->sha1[i], abbrev),
+ find_unique_abbrev(&ui->oid[i], abbrev),
i + 1);
write_name(path);
}
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index c4be98a..540d564 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -60,8 +60,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL),
OPT_BOOL(0, "get-url", &get_url,
N_("take url.<base>.insteadOf into account")),
- OPT_SET_INT(0, "exit-code", &status,
- N_("exit with exit code 2 if no matching refs are found"), 2),
+ OPT_SET_INT_F(0, "exit-code", &status,
+ N_("exit with exit code 2 if no matching refs are found"),
+ 2, PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "symref", &show_symref_target,
N_("show underlying ref in addition to the object pointed by it")),
OPT_END()
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index ef96540..d44b4f9 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -60,7 +60,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
return 0;
}
-static int show_tree(const unsigned char *sha1, struct strbuf *base,
+static int show_tree(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
int retval = 0;
@@ -94,7 +94,7 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,
char size_text[24];
if (!strcmp(type, blob_type)) {
unsigned long size;
- if (sha1_object_info(sha1, &size) == OBJ_BAD)
+ if (oid_object_info(oid, &size) == OBJ_BAD)
xsnprintf(size_text, sizeof(size_text),
"BAD");
else
@@ -103,11 +103,11 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,
} else
xsnprintf(size_text, sizeof(size_text), "-");
printf("%06o %s %s %7s\t", mode, type,
- find_unique_abbrev(sha1, abbrev),
+ find_unique_abbrev(oid, abbrev),
size_text);
} else
printf("%06o %s %s\t", mode, type,
- find_unique_abbrev(sha1, abbrev));
+ find_unique_abbrev(oid, abbrev));
}
baselen = base->len;
strbuf_addstr(base, pathname);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index d01ddec..32736e0 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -60,7 +60,7 @@ static void *result(struct merge_list *entry, unsigned long *size)
const char *path = entry->path;
if (!entry->stage)
- return read_sha1_file(entry->blob->object.oid.hash, &type, size);
+ return read_object_file(&entry->blob->object.oid, &type, size);
base = NULL;
if (entry->stage == 1) {
base = entry->blob;
@@ -82,7 +82,8 @@ static void *origin(struct merge_list *entry, unsigned long *size)
enum object_type type;
while (entry) {
if (entry->stage == 2)
- return read_sha1_file(entry->blob->object.oid.hash, &type, size);
+ return read_object_file(&entry->blob->object.oid,
+ &type, size);
entry = entry->link;
}
return NULL;
diff --git a/builtin/merge.c b/builtin/merge.c
index 30264cf..8746c5e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -33,6 +33,7 @@
#include "sequencer.h"
#include "string-list.h"
#include "packfile.h"
+#include "tag.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@@ -520,7 +521,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
strbuf_addf(msg, "%s\t\t%s '%s'\n",
oid_to_hex(&desc->obj->oid),
- typename(desc->obj->type),
+ type_name(desc->obj->type),
remote);
goto cleanup;
}
@@ -638,7 +639,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
static void write_tree_trivial(struct object_id *oid)
{
- if (write_cache_as_tree(oid->hash, 0, NULL))
+ if (write_cache_as_tree(oid, 0, NULL))
die(_("git write-tree failed to write a tree"));
}
@@ -651,10 +652,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
- if (active_cache_changed &&
- write_locked_index(&the_index, &lock, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
return error(_("Unable to write index."));
- rollback_lock_file(&lock);
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
int clean, x;
@@ -691,10 +691,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
remoteheads->item, reversed, &result);
if (clean < 0)
exit(128);
- if (active_cache_changed &&
- write_locked_index(&the_index, &lock, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
die (_("unable to write %s"), get_index_file());
- rollback_lock_file(&lock);
return clean ? 0 : 1;
} else {
return try_merge_command(strategy, xopts_nr, xopts,
@@ -810,18 +809,17 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
- if (active_cache_changed &&
- write_locked_index(&the_index, &lock, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
return error(_("Unable to write index."));
- rollback_lock_file(&lock);
write_tree_trivial(&result_tree);
printf(_("Wonderful.\n"));
pptr = commit_list_append(head, pptr);
pptr = commit_list_append(remoteheads->item, pptr);
prepare_to_commit(remoteheads);
- if (commit_tree(merge_msg.buf, merge_msg.len, result_tree.hash, parents,
- result_commit.hash, NULL, sign_commit))
+ if (commit_tree(merge_msg.buf, merge_msg.len, &result_tree, parents,
+ &result_commit, NULL, sign_commit))
die(_("failed to write commit object"));
finish(head, remoteheads, &result_commit, "In-index merge");
drop_save();
@@ -845,8 +843,8 @@ static int finish_automerge(struct commit *head,
commit_list_insert(head, &parents);
strbuf_addch(&merge_msg, '\n');
prepare_to_commit(remoteheads);
- if (commit_tree(merge_msg.buf, merge_msg.len, result_tree->hash, parents,
- result_commit.hash, NULL, sign_commit))
+ if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
+ &result_commit, NULL, sign_commit))
die(_("failed to write commit object"));
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
finish(head, remoteheads, &result_commit, buf.buf);
@@ -1125,6 +1123,43 @@ static struct commit_list *collect_parents(struct commit *head_commit,
return remoteheads;
}
+static int merging_a_throwaway_tag(struct commit *commit)
+{
+ char *tag_ref;
+ struct object_id oid;
+ int is_throwaway_tag = 0;
+
+ /* Are we merging a tag? */
+ if (!merge_remote_util(commit) ||
+ !merge_remote_util(commit)->obj ||
+ merge_remote_util(commit)->obj->type != OBJ_TAG)
+ return is_throwaway_tag;
+
+ /*
+ * Now we know we are merging a tag object. Are we downstream
+ * and following the tags from upstream? If so, we must have
+ * the tag object pointed at by "refs/tags/$T" where $T is the
+ * tagname recorded in the tag object. We want to allow such
+ * a "just to catch up" merge to fast-forward.
+ *
+ * Otherwise, we are playing an integrator's role, making a
+ * merge with a throw-away tag from a contributor with
+ * something like "git pull $contributor $signed_tag".
+ * We want to forbid such a merge from fast-forwarding
+ * by default; otherwise we would not keep the signature
+ * anywhere.
+ */
+ tag_ref = xstrfmt("refs/tags/%s",
+ ((struct tag *)merge_remote_util(commit)->obj)->tag);
+ if (!read_ref(tag_ref, &oid) &&
+ !oidcmp(&oid, &merge_remote_util(commit)->obj->oid))
+ is_throwaway_tag = 0;
+ else
+ is_throwaway_tag = 1;
+ free(tag_ref);
+ return is_throwaway_tag;
+}
+
int cmd_merge(int argc, const char **argv, const char *prefix)
{
struct object_id result_tree, stash, head_oid;
@@ -1289,7 +1324,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
check_commit_signature(commit, &signature_check);
- find_unique_abbrev_r(hex, commit->object.oid.hash, DEFAULT_ABBREV);
+ find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
switch (signature_check.result) {
case 'G':
break;
@@ -1322,10 +1357,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
oid_to_hex(&commit->object.oid));
setenv(buf.buf, merge_remote_util(commit)->name, 1);
strbuf_reset(&buf);
- if (fast_forward != FF_ONLY &&
- merge_remote_util(commit) &&
- merge_remote_util(commit)->obj &&
- merge_remote_util(commit)->obj->type == OBJ_TAG)
+ if (fast_forward != FF_ONLY && merging_a_throwaway_tag(commit))
fast_forward = FF_NO;
}
@@ -1385,9 +1417,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (verbosity >= 0) {
printf(_("Updating %s..%s\n"),
- find_unique_abbrev(head_commit->object.oid.hash,
+ find_unique_abbrev(&head_commit->object.oid,
DEFAULT_ABBREV),
- find_unique_abbrev(remoteheads->item->object.oid.hash,
+ find_unique_abbrev(&remoteheads->item->object.oid,
DEFAULT_ABBREV));
}
strbuf_addstr(&msg, "Fast-forward");
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 031b750..9f5a50a 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -18,17 +18,17 @@
/*
* We refuse to tag something we can't verify. Just because.
*/
-static int verify_object(const unsigned char *sha1, const char *expected_type)
+static int verify_object(const struct object_id *oid, const char *expected_type)
{
int ret = -1;
enum object_type type;
unsigned long size;
- void *buffer = read_sha1_file(sha1, &type, &size);
- const unsigned char *repl = lookup_replace_object(sha1);
+ void *buffer = read_object_file(oid, &type, &size);
+ const struct object_id *repl = lookup_replace_object(oid);
if (buffer) {
if (type == type_from_string(expected_type))
- ret = check_sha1_signature(repl, buffer, size, expected_type);
+ ret = check_object_signature(repl, buffer, size, expected_type);
free(buffer);
}
return ret;
@@ -38,8 +38,8 @@ static int verify_tag(char *buffer, unsigned long size)
{
int typelen;
char type[20];
- unsigned char sha1[20];
- const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb;
+ struct object_id oid;
+ const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb, *p;
size_t len;
if (size < 84)
@@ -52,11 +52,11 @@ static int verify_tag(char *buffer, unsigned long size)
if (memcmp(object, "object ", 7))
return error("char%d: does not start with \"object \"", 0);
- if (get_sha1_hex(object + 7, sha1))
+ if (parse_oid_hex(object + 7, &oid, &p))
return error("char%d: could not get SHA1 hash", 7);
/* Verify type line */
- type_line = object + 48;
+ type_line = p + 1;
if (memcmp(type_line - 1, "\ntype ", 6))
return error("char%d: could not find \"\\ntype \"", 47);
@@ -80,8 +80,8 @@ static int verify_tag(char *buffer, unsigned long size)
type[typelen] = 0;
/* Verify that the object matches */
- if (verify_object(sha1, type))
- return error("char%d: could not verify object %s", 7, sha1_to_hex(sha1));
+ if (verify_object(&oid, type))
+ return error("char%d: could not verify object %s", 7, oid_to_hex(&oid));
/* Verify the tag-name: we don't allow control characters or spaces in it */
tag_line += 4;
@@ -151,7 +151,7 @@ static int verify_tag(char *buffer, unsigned long size)
int cmd_mktag(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
- unsigned char result_sha1[20];
+ struct object_id result;
if (argc != 1)
usage("git mktag");
@@ -165,10 +165,10 @@ int cmd_mktag(int argc, const char **argv, const char *prefix)
if (verify_tag(buf.buf, buf.len) < 0)
die("invalid tag signature file");
- if (write_sha1_file(buf.buf, buf.len, tag_type, result_sha1) < 0)
+ if (write_object_file(buf.buf, buf.len, tag_type, &result) < 0)
die("unable to write tag file");
strbuf_release(&buf);
- printf("%s\n", sha1_to_hex(result_sha1));
+ printf("%s\n", oid_to_hex(&result));
return 0;
}
diff --git a/builtin/mktree.c b/builtin/mktree.c
index da0fd8c..263c530 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -10,13 +10,13 @@
static struct treeent {
unsigned mode;
- unsigned char sha1[20];
+ struct object_id oid;
int len;
char name[FLEX_ARRAY];
} **entries;
static int alloc, used;
-static void append_to_tree(unsigned mode, unsigned char *sha1, char *path)
+static void append_to_tree(unsigned mode, struct object_id *oid, char *path)
{
struct treeent *ent;
size_t len = strlen(path);
@@ -26,7 +26,7 @@ static void append_to_tree(unsigned mode, unsigned char *sha1, char *path)
FLEX_ALLOC_MEM(ent, name, path, len);
ent->mode = mode;
ent->len = len;
- hashcpy(ent->sha1, sha1);
+ oidcpy(&ent->oid, oid);
ALLOC_GROW(entries, used + 1, alloc);
entries[used++] = ent;
@@ -40,7 +40,7 @@ static int ent_compare(const void *a_, const void *b_)
b->name, b->len, b->mode);
}
-static void write_tree(unsigned char *sha1)
+static void write_tree(struct object_id *oid)
{
struct strbuf buf;
size_t size;
@@ -54,10 +54,10 @@ static void write_tree(unsigned char *sha1)
for (i = 0; i < used; i++) {
struct treeent *ent = entries[i];
strbuf_addf(&buf, "%o %s%c", ent->mode, ent->name, '\0');
- strbuf_add(&buf, ent->sha1, 20);
+ strbuf_add(&buf, ent->oid.hash, the_hash_algo->rawsz);
}
- write_sha1_file(buf.buf, buf.len, tree_type, sha1);
+ write_object_file(buf.buf, buf.len, tree_type, oid);
strbuf_release(&buf);
}
@@ -69,11 +69,12 @@ static const char *mktree_usage[] = {
static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_missing)
{
char *ptr, *ntr;
+ const char *p;
unsigned mode;
enum object_type mode_type; /* object type derived from mode */
enum object_type obj_type; /* object type derived from sha */
char *path, *to_free = NULL;
- unsigned char sha1[20];
+ struct object_id oid;
ptr = buf;
/*
@@ -85,9 +86,8 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
die("input format error: %s", buf);
ptr = ntr + 1; /* type */
ntr = strchr(ptr, ' ');
- if (!ntr || buf + len <= ntr + 40 ||
- ntr[41] != '\t' ||
- get_sha1_hex(ntr + 1, sha1))
+ if (!ntr || parse_oid_hex(ntr + 1, &oid, &p) ||
+ *p != '\t')
die("input format error: %s", buf);
/* It is perfectly normal if we do not have a commit from a submodule */
@@ -112,16 +112,16 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
mode_type = object_type(mode);
if (mode_type != type_from_string(ptr)) {
die("entry '%s' object type (%s) doesn't match mode type (%s)",
- path, ptr, typename(mode_type));
+ path, ptr, type_name(mode_type));
}
/* Check the type of object identified by sha1 */
- obj_type = sha1_object_info(sha1, NULL);
+ obj_type = oid_object_info(&oid, NULL);
if (obj_type < 0) {
if (allow_missing) {
; /* no problem - missing objects are presumed to be of the right type */
} else {
- die("entry '%s' object %s is unavailable", path, sha1_to_hex(sha1));
+ die("entry '%s' object %s is unavailable", path, oid_to_hex(&oid));
}
} else {
if (obj_type != mode_type) {
@@ -131,18 +131,18 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
* because the new tree entry will never be correct.
*/
die("entry '%s' object %s is a %s but specified type was (%s)",
- path, sha1_to_hex(sha1), typename(obj_type), typename(mode_type));
+ path, oid_to_hex(&oid), type_name(obj_type), type_name(mode_type));
}
}
- append_to_tree(mode, sha1, path);
+ append_to_tree(mode, &oid, path);
free(to_free);
}
int cmd_mktree(int ac, const char **av, const char *prefix)
{
struct strbuf sb = STRBUF_INIT;
- unsigned char sha1[20];
+ struct object_id oid;
int nul_term_line = 0;
int allow_missing = 0;
int is_batch_mode = 0;
@@ -181,8 +181,8 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
*/
; /* skip creating an empty tree */
} else {
- write_tree(sha1);
- puts(sha1_to_hex(sha1));
+ write_tree(&oid);
+ puts(oid_to_hex(&oid));
fflush(stdout);
}
used=0; /* reset tree entry buffer for re-use in batch mode */
diff --git a/builtin/mv.c b/builtin/mv.c
index cf3684d..6d141f7 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -122,7 +122,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
struct option builtin_mv_options[] = {
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT__DRY_RUN(&show_only, N_("dry run")),
- OPT__FORCE(&force, N_("force move/rename even if target exists")),
+ OPT__FORCE(&force, N_("force move/rename even if target exists"),
+ PARSE_OPT_NOCOMPLETE),
OPT_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")),
OPT_END(),
};
@@ -286,15 +287,14 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
pos = cache_name_pos(src, strlen(src));
assert(pos >= 0);
- if (!show_only)
- rename_cache_entry_at(pos, dst);
+ rename_cache_entry_at(pos, dst);
}
if (gitmodules_modified)
stage_updated_gitmodules(&the_index);
- if (active_cache_changed &&
- write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
return 0;
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 9e088eb..387ddf8 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -328,7 +328,7 @@ static void show_name(const struct object *obj,
else if (allow_undefined)
printf("undefined\n");
else if (always)
- printf("%s\n", find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
+ printf("%s\n", find_unique_abbrev(oid, DEFAULT_ABBREV));
else
die("cannot describe '%s'", oid_to_hex(oid));
strbuf_release(&buf);
diff --git a/builtin/notes.c b/builtin/notes.c
index 7c81761..921e08d 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -118,11 +118,11 @@ static int list_each_note(const struct object_id *object_oid,
return 0;
}
-static void copy_obj_to_fd(int fd, const unsigned char *sha1)
+static void copy_obj_to_fd(int fd, const struct object_id *oid)
{
unsigned long size;
enum object_type type;
- char *buf = read_sha1_file(sha1, &type, &size);
+ char *buf = read_object_file(oid, &type, &size);
if (buf) {
if (size)
write_or_die(fd, buf, size);
@@ -162,7 +162,7 @@ static void write_commented_object(int fd, const struct object_id *object)
}
static void prepare_note_data(const struct object_id *object, struct note_data *d,
- const unsigned char *old_note)
+ const struct object_id *old_note)
{
if (d->use_editor || !d->given) {
int fd;
@@ -198,9 +198,9 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
}
}
-static void write_note_data(struct note_data *d, unsigned char *sha1)
+static void write_note_data(struct note_data *d, struct object_id *oid)
{
- if (write_sha1_file(d->buf.buf, d->buf.len, blob_type, sha1)) {
+ if (write_object_file(d->buf.buf, d->buf.len, blob_type, oid)) {
error(_("unable to write note object"));
if (d->edit_path)
error(_("the note contents have been left in %s"),
@@ -253,7 +253,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
if (get_oid(arg, &object))
die(_("failed to resolve '%s' as a valid ref."), arg);
- if (!(buf = read_sha1_file(object.hash, &type, &len))) {
+ if (!(buf = read_object_file(&object, &type, &len))) {
free(buf);
die(_("failed to read object '%s'."), arg);
}
@@ -413,7 +413,7 @@ static int add(int argc, const char **argv, const char *prefix)
parse_reuse_arg},
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
- OPT__FORCE(&force, N_("replace existing notes")),
+ OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
OPT_END()
};
@@ -457,9 +457,9 @@ static int add(int argc, const char **argv, const char *prefix)
oid_to_hex(&object));
}
- prepare_note_data(&object, &d, note ? note->hash : NULL);
+ prepare_note_data(&object, &d, note);
if (d.buf.len || allow_empty) {
- write_note_data(&d, new_note.hash);
+ write_note_data(&d, &new_note);
if (add_note(t, &object, &new_note, combine_notes_overwrite))
die("BUG: combine_notes_overwrite failed");
commit_notes(t, "Notes added by 'git notes add'");
@@ -484,7 +484,7 @@ static int copy(int argc, const char **argv, const char *prefix)
struct notes_tree *t;
const char *rewrite_cmd = NULL;
struct option options[] = {
- OPT__FORCE(&force, N_("replace existing notes")),
+ OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "stdin", &from_stdin, N_("read objects from stdin")),
OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"),
N_("load rewriting config for <command> (implies "
@@ -602,13 +602,13 @@ static int append_edit(int argc, const char **argv, const char *prefix)
t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
note = get_note(t, &object);
- prepare_note_data(&object, &d, edit && note ? note->hash : NULL);
+ prepare_note_data(&object, &d, edit && note ? note : NULL);
if (note && !edit) {
/* Append buf to previous note contents */
unsigned long size;
enum object_type type;
- char *prev_buf = read_sha1_file(note->hash, &type, &size);
+ char *prev_buf = read_object_file(note, &type, &size);
strbuf_grow(&d.buf, size + 1);
if (d.buf.len && prev_buf && size)
@@ -619,7 +619,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
}
if (d.buf.len || allow_empty) {
- write_note_data(&d, new_note.hash);
+ write_note_data(&d, &new_note);
if (add_note(t, &object, &new_note, combine_notes_overwrite))
die("BUG: combine_notes_overwrite failed");
logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 83dcbc9..e7e6732 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -122,11 +122,10 @@ static void *get_delta(struct object_entry *entry)
void *buf, *base_buf, *delta_buf;
enum object_type type;
- buf = read_sha1_file(entry->idx.oid.hash, &type, &size);
+ buf = read_object_file(&entry->idx.oid, &type, &size);
if (!buf)
die("unable to read %s", oid_to_hex(&entry->idx.oid));
- base_buf = read_sha1_file(entry->delta->idx.oid.hash, &type,
- &base_size);
+ base_buf = read_object_file(&entry->delta->idx.oid, &type, &base_size);
if (!base_buf)
die("unable to read %s",
oid_to_hex(&entry->delta->idx.oid));
@@ -164,7 +163,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)
return stream.total_out;
}
-static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
+static unsigned long write_large_blob_data(struct git_istream *st, struct hashfile *f,
const struct object_id *oid)
{
git_zstream stream;
@@ -188,7 +187,7 @@ static unsigned long write_large_blob_data(struct git_istream *st, struct sha1fi
stream.next_out = obuf;
stream.avail_out = sizeof(obuf);
zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
- sha1write(f, obuf, stream.next_out - obuf);
+ hashwrite(f, obuf, stream.next_out - obuf);
olen += stream.next_out - obuf;
}
if (stream.avail_in)
@@ -233,7 +232,7 @@ static int check_pack_inflate(struct packed_git *p,
stream.total_in == len) ? 0 : -1;
}
-static void copy_pack_data(struct sha1file *f,
+static void copy_pack_data(struct hashfile *f,
struct packed_git *p,
struct pack_window **w_curs,
off_t offset,
@@ -246,14 +245,14 @@ static void copy_pack_data(struct sha1file *f,
in = use_pack(p, w_curs, offset, &avail);
if (avail > len)
avail = (unsigned long)len;
- sha1write(f, in, avail);
+ hashwrite(f, in, avail);
offset += avail;
len -= avail;
}
}
/* Return 0 if we will bust the pack-size limit */
-static unsigned long write_no_reuse_object(struct sha1file *f, struct object_entry *entry,
+static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
unsigned long limit, int usable_delta)
{
unsigned long size, datalen;
@@ -267,11 +266,10 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
if (!usable_delta) {
if (entry->type == OBJ_BLOB &&
entry->size > big_file_threshold &&
- (st = open_istream(entry->idx.oid.hash, &type, &size, NULL)) != NULL)
+ (st = open_istream(&entry->idx.oid, &type, &size, NULL)) != NULL)
buf = NULL;
else {
- buf = read_sha1_file(entry->idx.oid.hash, &type,
- &size);
+ buf = read_object_file(&entry->idx.oid, &type, &size);
if (!buf)
die(_("unable to read %s"),
oid_to_hex(&entry->idx.oid));
@@ -326,8 +324,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
free(buf);
return 0;
}
- sha1write(f, header, hdrlen);
- sha1write(f, dheader + pos, sizeof(dheader) - pos);
+ hashwrite(f, header, hdrlen);
+ hashwrite(f, dheader + pos, sizeof(dheader) - pos);
hdrlen += sizeof(dheader) - pos;
} else if (type == OBJ_REF_DELTA) {
/*
@@ -340,8 +338,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
free(buf);
return 0;
}
- sha1write(f, header, hdrlen);
- sha1write(f, entry->delta->idx.oid.hash, 20);
+ hashwrite(f, header, hdrlen);
+ hashwrite(f, entry->delta->idx.oid.hash, 20);
hdrlen += 20;
} else {
if (limit && hdrlen + datalen + 20 >= limit) {
@@ -350,13 +348,13 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
free(buf);
return 0;
}
- sha1write(f, header, hdrlen);
+ hashwrite(f, header, hdrlen);
}
if (st) {
datalen = write_large_blob_data(st, f, &entry->idx.oid);
close_istream(st);
} else {
- sha1write(f, buf, datalen);
+ hashwrite(f, buf, datalen);
free(buf);
}
@@ -364,7 +362,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
}
/* Return 0 if we will bust the pack-size limit */
-static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
+static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
unsigned long limit, int usable_delta)
{
struct packed_git *p = entry->in_pack;
@@ -415,8 +413,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
unuse_pack(&w_curs);
return 0;
}
- sha1write(f, header, hdrlen);
- sha1write(f, dheader + pos, sizeof(dheader) - pos);
+ hashwrite(f, header, hdrlen);
+ hashwrite(f, dheader + pos, sizeof(dheader) - pos);
hdrlen += sizeof(dheader) - pos;
reused_delta++;
} else if (type == OBJ_REF_DELTA) {
@@ -424,8 +422,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
unuse_pack(&w_curs);
return 0;
}
- sha1write(f, header, hdrlen);
- sha1write(f, entry->delta->idx.oid.hash, 20);
+ hashwrite(f, header, hdrlen);
+ hashwrite(f, entry->delta->idx.oid.hash, 20);
hdrlen += 20;
reused_delta++;
} else {
@@ -433,7 +431,7 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
unuse_pack(&w_curs);
return 0;
}
- sha1write(f, header, hdrlen);
+ hashwrite(f, header, hdrlen);
}
copy_pack_data(f, p, &w_curs, offset, datalen);
unuse_pack(&w_curs);
@@ -442,7 +440,7 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
}
/* Return 0 if we will bust the pack-size limit */
-static off_t write_object(struct sha1file *f,
+static off_t write_object(struct hashfile *f,
struct object_entry *entry,
off_t write_offset)
{
@@ -515,7 +513,7 @@ enum write_one_status {
WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
};
-static enum write_one_status write_one(struct sha1file *f,
+static enum write_one_status write_one(struct hashfile *f,
struct object_entry *e,
off_t *offset)
{
@@ -734,7 +732,7 @@ static struct object_entry **compute_write_order(void)
return wo;
}
-static off_t write_reused_pack(struct sha1file *f)
+static off_t write_reused_pack(struct hashfile *f)
{
unsigned char buffer[8192];
off_t to_write, total;
@@ -765,7 +763,7 @@ static off_t write_reused_pack(struct sha1file *f)
if (read_pack > to_write)
read_pack = to_write;
- sha1write(f, buffer, read_pack);
+ hashwrite(f, buffer, read_pack);
to_write -= read_pack;
/*
@@ -794,7 +792,7 @@ static const char no_split_warning[] = N_(
static void write_pack_file(void)
{
uint32_t i = 0, j;
- struct sha1file *f;
+ struct hashfile *f;
off_t offset;
uint32_t nr_remaining = nr_result;
time_t last_mtime = 0;
@@ -810,7 +808,7 @@ static void write_pack_file(void)
char *pack_tmp_name = NULL;
if (pack_to_stdout)
- f = sha1fd_throughput(1, "<stdout>", progress_state);
+ f = hashfd_throughput(1, "<stdout>", progress_state);
else
f = create_tmp_packfile(&pack_tmp_name);
@@ -837,11 +835,11 @@ static void write_pack_file(void)
* If so, rewrite it like in fast-import
*/
if (pack_to_stdout) {
- sha1close(f, oid.hash, CSUM_CLOSE);
+ hashclose(f, oid.hash, CSUM_CLOSE);
} else if (nr_written == nr_remaining) {
- sha1close(f, oid.hash, CSUM_FSYNC);
+ hashclose(f, oid.hash, CSUM_FSYNC);
} else {
- int fd = sha1close(f, oid.hash, 0);
+ int fd = hashclose(f, oid.hash, 0);
fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
nr_written, oid.hash, offset);
close(fd);
@@ -1190,7 +1188,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
/* Did not find one. Either we got a bogus request or
* we need to read and perhaps cache.
*/
- data = read_sha1_file(oid->hash, &type, &size);
+ data = read_object_file(oid, &type, &size);
if (!data)
return NULL;
if (type != OBJ_TREE) {
@@ -1351,7 +1349,7 @@ static void add_preferred_base(struct object_id *oid)
if (window <= num_preferred_base++)
return;
- data = read_object_with_reference(oid->hash, tree_type, &size, tree_oid.hash);
+ data = read_object_with_reference(oid, tree_type, &size, &tree_oid);
if (!data)
return;
@@ -1379,10 +1377,10 @@ static void cleanup_preferred_base(void)
it = pbase_tree;
pbase_tree = NULL;
while (it) {
- struct pbase_tree *this = it;
- it = this->next;
- free(this->pcache.tree_data);
- free(this);
+ struct pbase_tree *tmp = it;
+ it = tmp->next;
+ free(tmp->pcache.tree_data);
+ free(tmp);
}
for (i = 0; i < ARRAY_SIZE(pbase_tree_cache); i++) {
@@ -1516,7 +1514,7 @@ static void check_object(struct object_entry *entry)
unuse_pack(&w_curs);
}
- entry->type = sha1_object_info(entry->idx.oid.hash, &entry->size);
+ entry->type = oid_object_info(&entry->idx.oid, &entry->size);
/*
* The error condition is checked in prepare_pack(). This is
* to permit a missing preferred base object to be ignored
@@ -1578,8 +1576,7 @@ static void drop_reused_delta(struct object_entry *entry)
* And if that fails, the error will be recorded in entry->type
* and dealt with in prepare_pack().
*/
- entry->type = sha1_object_info(entry->idx.oid.hash,
- &entry->size);
+ entry->type = oid_object_info(&entry->idx.oid, &entry->size);
}
}
@@ -1871,8 +1868,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
/* Load data if not already done */
if (!trg->data) {
read_lock();
- trg->data = read_sha1_file(trg_entry->idx.oid.hash, &type,
- &sz);
+ trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
read_unlock();
if (!trg->data)
die("object %s cannot be read",
@@ -1885,8 +1881,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
}
if (!src->data) {
read_lock();
- src->data = read_sha1_file(src_entry->idx.oid.hash, &type,
- &sz);
+ src->data = read_object_file(&src_entry->idx.oid, &type, &sz);
read_unlock();
if (!src->data) {
if (src_entry->preferred_base) {
@@ -2549,6 +2544,7 @@ static void read_object_list_from_stdin(void)
}
}
+/* Remember to update object flag allocation in object.h */
#define OBJECT_ADDED (1u<<20)
static void show_commit(struct commit *commit, void *data)
@@ -2708,7 +2704,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
static int add_loose_object(const struct object_id *oid, const char *path,
void *data)
{
- enum object_type type = sha1_object_info(oid->hash, NULL);
+ enum object_type type = oid_object_info(oid, NULL);
if (type < 0) {
warning("loose object at %s could not be examined", path);
@@ -2793,7 +2789,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
if (!packlist_find(&to_pack, oid.hash, NULL) &&
!has_sha1_pack_kept_or_nonlocal(&oid) &&
!loosened_object_can_be_discarded(&oid, p->mtime))
- if (force_object_loose(oid.hash, p->mtime))
+ if (force_object_loose(&oid, p->mtime))
die("unable to force loose object");
}
}
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index aaa8136..991e1bb 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -48,17 +48,17 @@ static inline void llist_item_put(struct llist_item *item)
static inline struct llist_item *llist_item_get(void)
{
- struct llist_item *new;
+ struct llist_item *new_item;
if ( free_nodes ) {
- new = free_nodes;
+ new_item = free_nodes;
free_nodes = free_nodes->next;
} else {
int i = 1;
- ALLOC_ARRAY(new, BLKSIZE);
+ ALLOC_ARRAY(new_item, BLKSIZE);
for (; i < BLKSIZE; i++)
- llist_item_put(&new[i]);
+ llist_item_put(&new_item[i]);
}
- return new;
+ return new_item;
}
static void llist_free(struct llist *list)
@@ -80,26 +80,26 @@ static inline void llist_init(struct llist **list)
static struct llist * llist_copy(struct llist *list)
{
struct llist *ret;
- struct llist_item *new, *old, *prev;
+ struct llist_item *new_item, *old_item, *prev;
llist_init(&ret);
if ((ret->size = list->size) == 0)
return ret;
- new = ret->front = llist_item_get();
- new->sha1 = list->front->sha1;
+ new_item = ret->front = llist_item_get();
+ new_item->sha1 = list->front->sha1;
- old = list->front->next;
- while (old) {
- prev = new;
- new = llist_item_get();
- prev->next = new;
- new->sha1 = old->sha1;
- old = old->next;
+ old_item = list->front->next;
+ while (old_item) {
+ prev = new_item;
+ new_item = llist_item_get();
+ prev->next = new_item;
+ new_item->sha1 = old_item->sha1;
+ old_item = old_item->next;
}
- new->next = NULL;
- ret->back = new;
+ new_item->next = NULL;
+ ret->back = new_item;
return ret;
}
@@ -108,24 +108,24 @@ static inline struct llist_item *llist_insert(struct llist *list,
struct llist_item *after,
const unsigned char *sha1)
{
- struct llist_item *new = llist_item_get();
- new->sha1 = sha1;
- new->next = NULL;
+ struct llist_item *new_item = llist_item_get();
+ new_item->sha1 = sha1;
+ new_item->next = NULL;
if (after != NULL) {
- new->next = after->next;
- after->next = new;
+ new_item->next = after->next;
+ after->next = new_item;
if (after == list->back)
- list->back = new;
+ list->back = new_item;
} else {/* insert in front */
if (list->size == 0)
- list->back = new;
+ list->back = new_item;
else
- new->next = list->front;
- list->front = new;
+ new_item->next = list->front;
+ list->front = new_item;
}
list->size++;
- return new;
+ return new_item;
}
static inline struct llist_item *llist_insert_back(struct llist *list,
diff --git a/builtin/prune.c b/builtin/prune.c
index 4cfec82..38ced18 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -50,9 +50,9 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
if (st.st_mtime > expire)
return 0;
if (show_only || verbose) {
- enum object_type type = sha1_object_info(oid->hash, NULL);
+ enum object_type type = oid_object_info(oid, NULL);
printf("%s %s\n", oid_to_hex(oid),
- (type > 0) ? typename(type) : "unknown");
+ (type > 0) ? type_name(type) : "unknown");
}
if (!show_only)
unlink_or_warn(fullpath);
diff --git a/builtin/pull.c b/builtin/pull.c
index 511dbbe..e32d6cd 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -193,7 +193,7 @@ static struct option pull_options[] = {
OPT_PASSTHRU(0, "upload-pack", &opt_upload_pack, N_("path"),
N_("path to upload pack on remote end"),
0),
- OPT__FORCE(&opt_force, N_("force overwrite of local branch")),
+ OPT__FORCE(&opt_force, N_("force overwrite of local branch"), 0),
OPT_PASSTHRU('t', "tags", &opt_tags, NULL,
N_("fetch all tags and associated objects"),
PARSE_OPT_NOARG),
@@ -574,6 +574,7 @@ static int rebase_submodules(void)
cp.no_stdin = 1;
argv_array_pushl(&cp.args, "submodule", "update",
"--recursive", "--rebase", NULL);
+ argv_push_verbosity(&cp.args);
return run_command(&cp);
}
@@ -586,6 +587,7 @@ static int update_submodules(void)
cp.no_stdin = 1;
argv_array_pushl(&cp.args, "submodule", "update",
"--recursive", "--checkout", NULL);
+ argv_push_verbosity(&cp.args);
return run_command(&cp);
}
diff --git a/builtin/push.c b/builtin/push.c
index 1c28427..013c20d 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -548,7 +548,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "check|on-demand|no",
N_("control recursive pushing of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
- OPT_BOOL( 0 , "thin", &thin, N_("use thin pack")),
+ OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),
OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")),
OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"),
diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c
index 00faf14..ad07470 100644
--- a/builtin/rebase--helper.c
+++ b/builtin/rebase--helper.c
@@ -22,6 +22,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
+ OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
+ N_("allow commits with empty messages")),
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
CONTINUE),
OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index b7ce7c7..2bf7f2d 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -69,7 +69,7 @@ static int sent_capabilities;
static int shallow_update;
static const char *alt_shallow_file;
static struct strbuf push_cert = STRBUF_INIT;
-static unsigned char push_cert_sha1[20];
+static struct object_id push_cert_oid;
static struct signature_check sigcheck;
static const char *push_cert_nonce;
static const char *cert_nonce_seed;
@@ -633,8 +633,9 @@ static void prepare_push_cert_sha1(struct child_process *proc)
int bogs /* beginning_of_gpg_sig */;
already_done = 1;
- if (write_sha1_file(push_cert.buf, push_cert.len, "blob", push_cert_sha1))
- hashclr(push_cert_sha1);
+ if (write_object_file(push_cert.buf, push_cert.len, "blob",
+ &push_cert_oid))
+ oidclr(&push_cert_oid);
memset(&sigcheck, '\0', sizeof(sigcheck));
sigcheck.result = 'N';
@@ -655,9 +656,9 @@ static void prepare_push_cert_sha1(struct child_process *proc)
strbuf_release(&gpg_status);
nonce_status = check_nonce(push_cert.buf, bogs);
}
- if (!is_null_sha1(push_cert_sha1)) {
+ if (!is_null_oid(&push_cert_oid)) {
argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT=%s",
- sha1_to_hex(push_cert_sha1));
+ oid_to_hex(&push_cert_oid));
argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_SIGNER=%s",
sigcheck.signer ? sigcheck.signer : "");
argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_KEY=%s",
@@ -1241,11 +1242,11 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
" its target '%s' (%s..%s)",
cmd->ref_name,
- find_unique_abbrev(cmd->old_oid.hash, DEFAULT_ABBREV),
- find_unique_abbrev(cmd->new_oid.hash, DEFAULT_ABBREV),
+ find_unique_abbrev(&cmd->old_oid, DEFAULT_ABBREV),
+ find_unique_abbrev(&cmd->new_oid, DEFAULT_ABBREV),
dst_cmd->ref_name,
- find_unique_abbrev(dst_cmd->old_oid.hash, DEFAULT_ABBREV),
- find_unique_abbrev(dst_cmd->new_oid.hash, DEFAULT_ABBREV));
+ find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV),
+ find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV));
cmd->error_string = dst_cmd->error_string =
"inconsistent aliased update";
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 2233725..a89bd1d 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -52,6 +52,7 @@ struct collect_reflog_cb {
int nr;
};
+/* Remember to update object flag allocation in object.h */
#define INCOMPLETE (1u<<10)
#define STUDYING (1u<<11)
#define REACHABLE (1u<<12)
@@ -74,7 +75,7 @@ static int tree_is_complete(const struct object_id *oid)
if (!tree->buffer) {
enum object_type type;
unsigned long size;
- void *data = read_sha1_file(oid->hash, &type, &size);
+ void *data = read_object_file(oid, &type, &size);
if (!data) {
tree->object.flags |= INCOMPLETE;
return 0;
@@ -289,20 +290,20 @@ static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *no
const char *message, void *cb_data)
{
struct expire_reflog_policy_cb *cb = cb_data;
- struct commit *old, *new;
+ struct commit *old_commit, *new_commit;
if (timestamp < cb->cmd.expire_total)
return 1;
- old = new = NULL;
+ old_commit = new_commit = NULL;
if (cb->cmd.stalefix &&
- (!keep_entry(&old, ooid) || !keep_entry(&new, noid)))
+ (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
return 1;
if (timestamp < cb->cmd.expire_unreachable) {
if (cb->unreachable_expire_kind == UE_ALWAYS)
return 1;
- if (unreachable(cb, old, ooid) || unreachable(cb, new, noid))
+ if (unreachable(cb, old_commit, ooid) || unreachable(cb, new_commit, noid))
return 1;
}
diff --git a/builtin/remote.c b/builtin/remote.c
index d95bf90..805ffc0 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -168,7 +168,7 @@ static int add(int argc, const char **argv)
OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
{ OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"),
N_("set up remote as a mirror to push to or fetch from"),
- PARSE_OPT_OPTARG, parse_mirror_opt },
+ PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt },
OPT_END()
};
@@ -322,7 +322,7 @@ static void read_branches(void)
struct ref_states {
struct remote *remote;
- struct string_list new, stale, tracked, heads, push;
+ struct string_list new_refs, stale, tracked, heads, push;
int queried;
};
@@ -337,12 +337,12 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
die(_("Could not get fetch map for refspec %s"),
states->remote->fetch_refspec[i]);
- states->new.strdup_strings = 1;
+ states->new_refs.strdup_strings = 1;
states->tracked.strdup_strings = 1;
states->stale.strdup_strings = 1;
for (ref = fetch_map; ref; ref = ref->next) {
if (!ref->peer_ref || !ref_exists(ref->peer_ref->name))
- string_list_append(&states->new, abbrev_branch(ref->name));
+ string_list_append(&states->new_refs, abbrev_branch(ref->name));
else
string_list_append(&states->tracked, abbrev_branch(ref->name));
}
@@ -356,7 +356,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
free_refs(stale_refs);
free_refs(fetch_map);
- string_list_sort(&states->new);
+ string_list_sort(&states->new_refs);
string_list_sort(&states->tracked);
string_list_sort(&states->stale);
@@ -546,8 +546,8 @@ static int add_branch_for_removal(const char *refname,
}
struct rename_info {
- const char *old;
- const char *new;
+ const char *old_name;
+ const char *new_name;
struct string_list *remote_branches;
};
@@ -560,7 +560,7 @@ static int read_remote_branches(const char *refname,
int flag;
const char *symref;
- strbuf_addf(&buf, "refs/remotes/%s/", rename->old);
+ strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
if (starts_with(refname, buf.buf)) {
item = string_list_append(rename->remote_branches, xstrdup(refname));
symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
@@ -615,36 +615,36 @@ static int mv(int argc, const char **argv)
if (argc != 3)
usage_with_options(builtin_remote_rename_usage, options);
- rename.old = argv[1];
- rename.new = argv[2];
+ rename.old_name = argv[1];
+ rename.new_name = argv[2];
rename.remote_branches = &remote_branches;
- oldremote = remote_get(rename.old);
+ oldremote = remote_get(rename.old_name);
if (!remote_is_configured(oldremote, 1))
- die(_("No such remote: %s"), rename.old);
+ die(_("No such remote: %s"), rename.old_name);
- if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG)
+ if (!strcmp(rename.old_name, rename.new_name) && oldremote->origin != REMOTE_CONFIG)
return migrate_file(oldremote);
- newremote = remote_get(rename.new);
+ newremote = remote_get(rename.new_name);
if (remote_is_configured(newremote, 1))
- die(_("remote %s already exists."), rename.new);
+ die(_("remote %s already exists."), rename.new_name);
- strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new);
+ strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new_name);
if (!valid_fetch_refspec(buf.buf))
- die(_("'%s' is not a valid remote name"), rename.new);
+ die(_("'%s' is not a valid remote name"), rename.new_name);
strbuf_reset(&buf);
- strbuf_addf(&buf, "remote.%s", rename.old);
- strbuf_addf(&buf2, "remote.%s", rename.new);
+ strbuf_addf(&buf, "remote.%s", rename.old_name);
+ strbuf_addf(&buf2, "remote.%s", rename.new_name);
if (git_config_rename_section(buf.buf, buf2.buf) < 1)
return error(_("Could not rename config section '%s' to '%s'"),
buf.buf, buf2.buf);
strbuf_reset(&buf);
- strbuf_addf(&buf, "remote.%s.fetch", rename.new);
+ strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
git_config_set_multivar(buf.buf, NULL, NULL, 1);
- strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old);
+ strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
char *ptr;
@@ -655,8 +655,8 @@ static int mv(int argc, const char **argv)
refspec_updated = 1;
strbuf_splice(&buf2,
ptr-buf2.buf + strlen(":refs/remotes/"),
- strlen(rename.old), rename.new,
- strlen(rename.new));
+ strlen(rename.old_name), rename.new_name,
+ strlen(rename.new_name));
} else
warning(_("Not updating non-default fetch refspec\n"
"\t%s\n"
@@ -670,10 +670,10 @@ static int mv(int argc, const char **argv)
for (i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util;
- if (info->remote_name && !strcmp(info->remote_name, rename.old)) {
+ if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", item->string);
- git_config_set(buf.buf, rename.new);
+ git_config_set(buf.buf, rename.new_name);
}
}
@@ -703,8 +703,8 @@ static int mv(int argc, const char **argv)
continue;
strbuf_reset(&buf);
strbuf_addstr(&buf, item->string);
- strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old),
- rename.new, strlen(rename.new));
+ strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
+ rename.new_name, strlen(rename.new_name));
strbuf_reset(&buf2);
strbuf_addf(&buf2, "remote: renamed %s to %s",
item->string, buf.buf);
@@ -718,12 +718,12 @@ static int mv(int argc, const char **argv)
continue;
strbuf_reset(&buf);
strbuf_addstr(&buf, item->string);
- strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old),
- rename.new, strlen(rename.new));
+ strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
+ rename.new_name, strlen(rename.new_name));
strbuf_reset(&buf2);
strbuf_addstr(&buf2, item->util);
- strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old),
- rename.new, strlen(rename.new));
+ strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old_name),
+ rename.new_name, strlen(rename.new_name));
strbuf_reset(&buf3);
strbuf_addf(&buf3, "remote: renamed %s to %s",
item->string, buf.buf);
@@ -822,7 +822,7 @@ static void clear_push_info(void *util, const char *string)
static void free_remote_ref_states(struct ref_states *states)
{
- string_list_clear(&states->new, 0);
+ string_list_clear(&states->new_refs, 0);
string_list_clear(&states->stale, 1);
string_list_clear(&states->tracked, 0);
string_list_clear(&states->heads, 0);
@@ -907,7 +907,7 @@ static int show_remote_info_item(struct string_list_item *item, void *cb_data)
if (states->queried) {
const char *fmt = "%s";
const char *arg = "";
- if (string_list_has_string(&states->new, name)) {
+ if (string_list_has_string(&states->new_refs, name)) {
fmt = _(" new (next fetch will store in remotes/%s)");
arg = states->remote->name;
} else if (string_list_has_string(&states->tracked, name))
@@ -1176,7 +1176,7 @@ static int show(int argc, const char **argv)
/* remote branch info */
info.width = 0;
- for_each_string_list(&states.new, add_remote_to_show_info, &info);
+ for_each_string_list(&states.new_refs, add_remote_to_show_info, &info);
for_each_string_list(&states.tracked, add_remote_to_show_info, &info);
for_each_string_list(&states.stale, add_remote_to_show_info, &info);
if (info.list->nr)
diff --git a/builtin/replace.c b/builtin/replace.c
index 10078ae..935647b 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -53,11 +53,11 @@ static int show_reference(const char *refname, const struct object_id *oid,
if (get_oid(refname, &object))
return error("Failed to resolve '%s' as a valid ref.", refname);
- obj_type = sha1_object_info(object.hash, NULL);
- repl_type = sha1_object_info(oid->hash, NULL);
+ obj_type = oid_object_info(&object, NULL);
+ repl_type = oid_object_info(oid, NULL);
- printf("%s (%s) -> %s (%s)\n", refname, typename(obj_type),
- oid_to_hex(oid), typename(repl_type));
+ printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
+ oid_to_hex(oid), type_name(repl_type));
}
}
@@ -162,14 +162,14 @@ static int replace_object_oid(const char *object_ref,
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
- obj_type = sha1_object_info(object->hash, NULL);
- repl_type = sha1_object_info(repl->hash, NULL);
+ obj_type = oid_object_info(object, NULL);
+ repl_type = oid_object_info(repl, NULL);
if (!force && obj_type != repl_type)
die("Objects must be of the same type.\n"
"'%s' points to a replaced object of type '%s'\n"
"while '%s' points to a replacement object of type '%s'.",
- object_ref, typename(obj_type),
- replace_ref, typename(repl_type));
+ object_ref, type_name(obj_type),
+ replace_ref, type_name(repl_type));
check_ref_valid(object, &prev, &ref, force);
@@ -215,7 +215,7 @@ static void export_object(const struct object_id *oid, enum object_type type,
argv_array_push(&cmd.args, "--no-replace-objects");
argv_array_push(&cmd.args, "cat-file");
if (raw)
- argv_array_push(&cmd.args, typename(type));
+ argv_array_push(&cmd.args, type_name(type));
else
argv_array_push(&cmd.args, "-p");
argv_array_push(&cmd.args, oid_to_hex(oid));
@@ -284,30 +284,30 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
{
char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
enum object_type type;
- struct object_id old, new, prev;
+ struct object_id old_oid, new_oid, prev;
struct strbuf ref = STRBUF_INIT;
- if (get_oid(object_ref, &old) < 0)
+ if (get_oid(object_ref, &old_oid) < 0)
die("Not a valid object name: '%s'", object_ref);
- type = sha1_object_info(old.hash, NULL);
+ type = oid_object_info(&old_oid, NULL);
if (type < 0)
- die("unable to get object type for %s", oid_to_hex(&old));
+ die("unable to get object type for %s", oid_to_hex(&old_oid));
- check_ref_valid(&old, &prev, &ref, force);
+ check_ref_valid(&old_oid, &prev, &ref, force);
strbuf_release(&ref);
- export_object(&old, type, raw, tmpfile);
+ export_object(&old_oid, type, raw, tmpfile);
if (launch_editor(tmpfile, NULL, NULL) < 0)
die("editing object file failed");
- import_object(&new, type, raw, tmpfile);
+ import_object(&new_oid, type, raw, tmpfile);
free(tmpfile);
- if (!oidcmp(&old, &new))
- return error("new object is the same as the old one: '%s'", oid_to_hex(&old));
+ if (!oidcmp(&old_oid, &new_oid))
+ return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid));
- return replace_object_oid(object_ref, &old, "replacement", &new, force);
+ return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
}
static void replace_parents(struct strbuf *buf, int argc, const char **argv)
@@ -355,7 +355,7 @@ static void check_one_mergetag(struct commit *commit,
struct tag *tag;
int i;
- hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_oid.hash);
+ hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid);
tag = lookup_tag(&tag_oid);
if (!tag)
die(_("bad mergetag in commit '%s'"), ref);
@@ -386,16 +386,16 @@ static void check_mergetags(struct commit *commit, int argc, const char **argv)
static int create_graft(int argc, const char **argv, int force)
{
- struct object_id old, new;
+ struct object_id old_oid, new_oid;
const char *old_ref = argv[0];
struct commit *commit;
struct strbuf buf = STRBUF_INIT;
const char *buffer;
unsigned long size;
- if (get_oid(old_ref, &old) < 0)
+ if (get_oid(old_ref, &old_oid) < 0)
die(_("Not a valid object name: '%s'"), old_ref);
- commit = lookup_commit_or_die(&old, old_ref);
+ commit = lookup_commit_or_die(&old_oid, old_ref);
buffer = get_commit_buffer(commit, &size);
strbuf_add(&buf, buffer, size);
@@ -410,15 +410,15 @@ static int create_graft(int argc, const char **argv, int force)
check_mergetags(commit, argc, argv);
- if (write_sha1_file(buf.buf, buf.len, commit_type, new.hash))
+ if (write_object_file(buf.buf, buf.len, commit_type, &new_oid))
die(_("could not write replacement commit for: '%s'"), old_ref);
strbuf_release(&buf);
- if (!oidcmp(&old, &new))
- return error("new commit is the same as the old one: '%s'", oid_to_hex(&old));
+ if (!oidcmp(&old_oid, &new_oid))
+ return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid));
- return replace_object_oid(old_ref, &old, "replacement", &new, force);
+ return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force);
}
int cmd_replace(int argc, const char **argv, const char *prefix)
@@ -439,7 +439,8 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE),
OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT),
OPT_CMDMODE('g', "graft", &cmdmode, N_("change a commit's parents"), MODE_GRAFT),
- OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
+ OPT_BOOL_F('f', "force", &force, N_("replace the ref if it exists"),
+ PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")),
OPT_STRING(0, "format", &format, N_("format"), N_("use this format")),
OPT_END()
diff --git a/builtin/reset.c b/builtin/reset.c
index e15f595..7f1c3f0 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -106,24 +106,16 @@ out:
static void print_new_head_line(struct commit *commit)
{
- const char *hex, *body;
- const char *msg;
-
- hex = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);
- printf(_("HEAD is now at %s"), hex);
- msg = logmsg_reencode(commit, NULL, get_log_output_encoding());
- body = strstr(msg, "\n\n");
- if (body) {
- const char *eol;
- size_t len;
- body = skip_blank_lines(body + 2);
- eol = strchr(body, '\n');
- len = eol ? eol - body : strlen(body);
- printf(" %.*s\n", (int) len, body);
- }
- else
- printf("\n");
- unuse_commit_buffer(commit, msg);
+ struct strbuf buf = STRBUF_INIT;
+
+ printf(_("HEAD is now at %s"),
+ find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+
+ pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
+ if (buf.len > 0)
+ printf(" %s", buf.buf);
+ putchar('\n');
+ strbuf_release(&buf);
}
static void update_index_from_diff(struct diff_queue_struct *q,
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 48300d9..fadd3ec 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -108,7 +108,7 @@ static void show_commit(struct commit *commit, void *data)
if (!revs->graph)
fputs(get_revision_mark(revs, commit), stdout);
if (revs->abbrev_commit && revs->abbrev)
- fputs(find_unique_abbrev(commit->object.oid.hash, revs->abbrev),
+ fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev),
stdout);
else
fputs(oid_to_hex(&commit->object.oid), stdout);
@@ -134,7 +134,7 @@ static void show_commit(struct commit *commit, void *data)
else
putchar('\n');
- if (revs->verbose_header && get_cached_commit_buffer(commit, NULL)) {
+ if (revs->verbose_header) {
struct strbuf buf = STRBUF_INIT;
struct pretty_print_context ctx = {0};
ctx.abbrev = revs->abbrev;
@@ -536,7 +536,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
mark_edges_uninteresting(&revs, show_edge);
if (bisect_list) {
- int reaches = reaches, all = all;
+ int reaches, all;
find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 96d06a5..36b2087 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -159,7 +159,7 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
}
}
else if (abbrev)
- show_with_type(type, find_unique_abbrev(oid->hash, abbrev));
+ show_with_type(type, find_unique_abbrev(oid, abbrev));
else
show_with_type(type, oid_to_hex(oid));
}
@@ -243,28 +243,28 @@ static int show_file(const char *arg, int output_prefix)
static int try_difference(const char *arg)
{
char *dotdot;
- struct object_id oid;
- struct object_id end;
- const char *next;
- const char *this;
+ struct object_id start_oid;
+ struct object_id end_oid;
+ const char *end;
+ const char *start;
int symmetric;
static const char head_by_default[] = "HEAD";
if (!(dotdot = strstr(arg, "..")))
return 0;
- next = dotdot + 2;
- this = arg;
- symmetric = (*next == '.');
+ end = dotdot + 2;
+ start = arg;
+ symmetric = (*end == '.');
*dotdot = 0;
- next += symmetric;
+ end += symmetric;
- if (!*next)
- next = head_by_default;
+ if (!*end)
+ end = head_by_default;
if (dotdot == arg)
- this = head_by_default;
+ start = head_by_default;
- if (this == head_by_default && next == head_by_default &&
+ if (start == head_by_default && end == head_by_default &&
!symmetric) {
/*
* Just ".."? That is not a range but the
@@ -274,14 +274,14 @@ static int try_difference(const char *arg)
return 0;
}
- if (!get_oid_committish(this, &oid) && !get_oid_committish(next, &end)) {
- show_rev(NORMAL, &end, next);
- show_rev(symmetric ? NORMAL : REVERSED, &oid, this);
+ if (!get_oid_committish(start, &start_oid) && !get_oid_committish(end, &end_oid)) {
+ show_rev(NORMAL, &end_oid, end);
+ show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
if (symmetric) {
struct commit_list *exclude;
struct commit *a, *b;
- a = lookup_commit_reference(&oid);
- b = lookup_commit_reference(&end);
+ a = lookup_commit_reference(&start_oid);
+ b = lookup_commit_reference(&end_oid);
exclude = get_merge_bases(a, b);
while (exclude) {
struct commit *commit = pop_commit(&exclude);
diff --git a/builtin/rm.c b/builtin/rm.c
index 4a2fcca..5b6fc7e 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -178,7 +178,7 @@ static int check_local_mod(struct object_id *head, int index_only)
* way as changed from the HEAD.
*/
if (no_head
- || get_tree_entry(head->hash, name, oid.hash, &mode)
+ || get_tree_entry(head, name, &oid, &mode)
|| ce->ce_mode != create_ce_mode(mode)
|| oidcmp(&ce->oid, &oid))
staged_changes = 1;
@@ -242,7 +242,7 @@ static struct option builtin_rm_options[] = {
OPT__DRY_RUN(&show_only, N_("dry run")),
OPT__QUIET(&quiet, N_("do not list removed files")),
OPT_BOOL( 0 , "cached", &index_only, N_("only remove from the index")),
- OPT__FORCE(&force, N_("override the up-to-date check")),
+ OPT__FORCE(&force, N_("override the up-to-date check"), PARSE_OPT_NOCOMPLETE),
OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")),
OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
N_("exit with a zero status even if nothing matched")),
@@ -385,10 +385,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
stage_updated_gitmodules(&the_index);
}
- if (active_cache_changed) {
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
- die(_("Unable to write new index file"));
- }
+ if (write_locked_index(&the_index, &lock_file,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ die(_("Unable to write new index file"));
return 0;
}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index e29875b..608d6ba 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -11,7 +11,8 @@
#include "parse-options.h"
static char const * const shortlog_usage[] = {
- N_("git shortlog [<options>] [<revision-range>] [[--] [<path>...]]"),
+ N_("git shortlog [<options>] [<revision-range>] [[--] <path>...]"),
+ N_("git log --pretty=short | git shortlog [<options>]"),
NULL
};
@@ -283,6 +284,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
for (;;) {
switch (parse_options_step(&ctx, options, shortlog_usage)) {
case PARSE_OPT_HELP:
+ case PARSE_OPT_ERROR:
exit(129);
case PARSE_OPT_DONE:
goto parse_done;
@@ -292,6 +294,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
parse_done:
argc = parse_options_end(&ctx);
+ if (nongit && argc > 1) {
+ error(_("too many arguments given outside repository"));
+ usage_with_options(shortlog_usage, options);
+ }
+
if (setup_revisions(argc, argv, &rev, NULL) != 1) {
error(_("unrecognized argument: %s"), argv[1]);
usage_with_options(shortlog_usage, options);
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index e8a4aa4..6c2148b 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -292,7 +292,7 @@ static void show_one_commit(struct commit *commit, int no_name)
}
else
printf("[%s] ",
- find_unique_abbrev(commit->object.oid.hash,
+ find_unique_abbrev(&commit->object.oid,
DEFAULT_ABBREV));
}
puts(pretty_str);
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 41e5e71..f2eb1a7 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -29,7 +29,7 @@ static void show_one(const char *refname, const struct object_id *oid)
if (quiet)
return;
- hex = find_unique_abbrev(oid->hash, abbrev);
+ hex = find_unique_abbrev(oid, abbrev);
if (hash_only)
printf("%s\n", hex);
else
@@ -39,7 +39,7 @@ static void show_one(const char *refname, const struct object_id *oid)
return;
if (!peel_ref(refname, &peeled)) {
- hex = find_unique_abbrev(peeled.hash, abbrev);
+ hex = find_unique_abbrev(&peeled, abbrev);
printf("%s %s^{}\n", hex, refname);
}
}
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b1daca9..6ba8587 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1019,7 +1019,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
struct option module_deinit_options[] = {
OPT__QUIET(&quiet, N_("Suppress submodule status output")),
- OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes")),
+ OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes"), 0),
OPT_BOOL(0, "all", &all, N_("Unregister all submodules")),
OPT_END()
};
@@ -1042,7 +1042,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
die(_("Use '--all' if you really want to deinitialize all submodules"));
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
- BUG("module_list_compute should not choke on empty pathspec");
+ return 1;
info.prefix = prefix;
if (quiet)
diff --git a/builtin/tag.c b/builtin/tag.c
index a7e6a5b..8cff6d0 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -99,7 +99,8 @@ static int delete_tag(const char *name, const char *ref,
{
if (delete_ref(NULL, ref, oid, 0))
return 1;
- printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
+ printf(_("Deleted tag '%s' (was %s)\n"), name,
+ find_unique_abbrev(oid, DEFAULT_ABBREV));
return 0;
}
@@ -167,7 +168,7 @@ static void write_tag_body(int fd, const struct object_id *oid)
enum object_type type;
char *buf, *sp;
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf)
return;
/* skip header */
@@ -187,13 +188,14 @@ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *resu
{
if (sign && do_sign(buf) < 0)
return error(_("unable to sign the tag"));
- if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0)
+ if (write_object_file(buf->buf, buf->len, tag_type, result) < 0)
return error(_("unable to write tag file"));
return 0;
}
struct create_tag_options {
unsigned int message_given:1;
+ unsigned int use_editor:1;
unsigned int sign;
enum {
CLEANUP_NONE,
@@ -210,7 +212,7 @@ static void create_tag(const struct object_id *object, const char *tag,
struct strbuf header = STRBUF_INIT;
char *path = NULL;
- type = sha1_object_info(object->hash, NULL);
+ type = oid_object_info(object, NULL);
if (type <= OBJ_NONE)
die(_("bad object type."));
@@ -220,11 +222,11 @@ static void create_tag(const struct object_id *object, const char *tag,
"tag %s\n"
"tagger %s\n\n",
oid_to_hex(object),
- typename(type),
+ type_name(type),
tag,
git_committer_info(IDENT_STRICT));
- if (!opt->message_given) {
+ if (!opt->message_given || opt->use_editor) {
int fd;
/* write the template message before editing: */
@@ -233,7 +235,10 @@ static void create_tag(const struct object_id *object, const char *tag,
if (fd < 0)
die_errno(_("could not create file '%s'"), path);
- if (!is_null_oid(prev)) {
+ if (opt->message_given) {
+ write_or_die(fd, buf->buf, buf->len);
+ strbuf_reset(buf);
+ } else if (!is_null_oid(prev)) {
write_tag_body(fd, prev);
} else {
struct strbuf buf = STRBUF_INIT;
@@ -289,17 +294,17 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
strbuf_addstr(sb, rla);
} else {
strbuf_addstr(sb, "tag: tagging ");
- strbuf_add_unique_abbrev(sb, oid->hash, DEFAULT_ABBREV);
+ strbuf_add_unique_abbrev(sb, oid, DEFAULT_ABBREV);
}
strbuf_addstr(sb, " (");
- type = sha1_object_info(oid->hash, NULL);
+ type = oid_object_info(oid, NULL);
switch (type) {
default:
strbuf_addstr(sb, "object of unknown type");
break;
case OBJ_COMMIT:
- if ((buf = read_sha1_file(oid->hash, &type, &size)) != NULL) {
+ if ((buf = read_object_file(oid, &type, &size)) != NULL) {
subject_len = find_commit_subject(buf, &subject_start);
strbuf_insert(sb, sb->len, subject_start, subject_len);
} else {
@@ -372,6 +377,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
struct ref_format format = REF_FORMAT_INIT;
int icase = 0;
+ int edit_flag = 0;
struct option options[] = {
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"),
@@ -386,12 +392,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_CALLBACK('m', "message", &msg, N_("message"),
N_("tag message"), parse_msg_arg),
OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
+ OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
N_("how to strip spaces and #comments from message")),
OPT_STRING('u', "local-user", &keyid, N_("key-id"),
N_("use another key to sign the tag")),
- OPT__FORCE(&force, N_("replace the tag if exists")),
+ OPT__FORCE(&force, N_("replace the tag if exists"), 0),
OPT_BOOL(0, "create-reflog", &create_reflog, N_("create a reflog")),
OPT_GROUP(N_("Tag listing options")),
@@ -524,6 +531,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die(_("tag '%s' already exists"), tag);
opt.message_given = msg.given || msgfile;
+ opt.use_editor = edit_flag;
if (!cleanup_arg || !strcmp(cleanup_arg, "strip"))
opt.cleanup_mode = CLEANUP_ALL;
@@ -551,7 +559,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die("%s", err.buf);
ref_transaction_free(transaction);
if (force && !is_null_oid(&prev) && oidcmp(&prev, &object))
- printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV));
+ printf(_("Updated tag '%s' (was %s)\n"), tag,
+ find_unique_abbrev(&prev, DEFAULT_ABBREV));
UNLEAK(buf);
UNLEAK(ref);
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 32e0155..300eb59 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -9,7 +9,7 @@ static char *create_temp_file(struct object_id *oid)
unsigned long size;
int fd;
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(oid));
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 62ea264..b7755c6 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -21,7 +21,7 @@ static unsigned char buffer[4096];
static unsigned int offset, len;
static off_t consumed_bytes;
static off_t max_input_size;
-static git_SHA_CTX ctx;
+static git_hash_ctx ctx;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
/*
@@ -62,7 +62,7 @@ static void *fill(int min)
if (min > sizeof(buffer))
die("cannot fill %d bytes", min);
if (offset) {
- git_SHA1_Update(&ctx, buffer, offset);
+ the_hash_algo->update_fn(&ctx, buffer, offset);
memmove(buffer, buffer + offset, len);
offset = 0;
}
@@ -158,6 +158,7 @@ struct obj_info {
struct object *obj;
};
+/* Remember to update object flag allocation in object.h */
#define FLAG_OPEN (1u<<20)
#define FLAG_WRITTEN (1u<<21)
@@ -172,7 +173,8 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
{
struct object_id oid;
- if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0)
+ if (write_object_file(obj_buf->buffer, obj_buf->size,
+ type_name(obj->type), &oid) < 0)
die("failed to write object %s", oid_to_hex(&obj->oid));
obj->flags |= FLAG_WRITTEN;
}
@@ -197,7 +199,7 @@ static int check_object(struct object *obj, int type, void *data, struct fsck_op
if (!(obj->flags & FLAG_OPEN)) {
unsigned long size;
- int type = sha1_object_info(obj->oid.hash, &size);
+ int type = oid_object_info(&obj->oid, &size);
if (type != obj->type || type <= 0)
die("object of unexpected type");
obj->flags |= FLAG_WRITTEN;
@@ -237,14 +239,16 @@ static void write_object(unsigned nr, enum object_type type,
void *buf, unsigned long size)
{
if (!strict) {
- if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
+ if (write_object_file(buf, size, type_name(type),
+ &obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
free(buf);
obj_list[nr].obj = NULL;
} else if (type == OBJ_BLOB) {
struct blob *blob;
- if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
+ if (write_object_file(buf, size, type_name(type),
+ &obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
free(buf);
@@ -258,12 +262,12 @@ static void write_object(unsigned nr, enum object_type type,
} else {
struct object *obj;
int eaten;
- hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash);
+ hash_object_file(buf, size, type_name(type), &obj_list[nr].oid);
added_object(nr, type, buf, size);
obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
&eaten);
if (!obj)
- die("invalid %s", typename(type));
+ die("invalid %s", type_name(type));
add_object_buffer(obj, buf, size);
obj->flags |= FLAG_OPEN;
obj_list[nr].obj = obj;
@@ -345,8 +349,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
struct object_id base_oid;
if (type == OBJ_REF_DELTA) {
- hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ));
- use(GIT_SHA1_RAWSZ);
+ hashcpy(base_oid.hash, fill(the_hash_algo->rawsz));
+ use(the_hash_algo->rawsz);
delta_data = get_data(delta_size);
if (dry_run || !delta_data) {
free(delta_data);
@@ -419,7 +423,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
if (resolve_against_held(nr, &base_oid, delta_data, delta_size))
return;
- base = read_sha1_file(base_oid.hash, &type, &base_size);
+ base = read_object_file(&base_oid, &type, &base_size);
if (!base) {
error("failed to read delta-pack base object %s",
oid_to_hex(&base_oid));
@@ -564,15 +568,15 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
/* We don't take any non-flag arguments now.. Maybe some day */
usage(unpack_usage);
}
- git_SHA1_Init(&ctx);
+ the_hash_algo->init_fn(&ctx);
unpack_all();
- git_SHA1_Update(&ctx, buffer, offset);
- git_SHA1_Final(oid.hash, &ctx);
+ the_hash_algo->update_fn(&ctx, buffer, offset);
+ the_hash_algo->final_fn(oid.hash, &ctx);
if (strict)
write_rest();
- if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash))
+ if (hashcmp(fill(the_hash_algo->rawsz), oid.hash))
die("final sha1 did not match");
- use(GIT_SHA1_RAWSZ);
+ use(the_hash_algo->rawsz);
/* Write the last part of the buffer to stdout */
while (len) {
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 58d1c2d..10d070a 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -592,7 +592,7 @@ static struct cache_entry *read_one_ent(const char *which,
int size;
struct cache_entry *ce;
- if (get_tree_entry(ent->hash, path, oid.hash, &mode)) {
+ if (get_tree_entry(ent, path, &oid, &mode)) {
if (which)
error("%s: not in %s branch.", path, which);
return NULL;
@@ -1059,6 +1059,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
break;
switch (parseopt_state) {
case PARSE_OPT_HELP:
+ case PARSE_OPT_ERROR:
exit(129);
case PARSE_OPT_NON_OPTION:
case PARSE_OPT_DONE:
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 873070e..4321a34 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -12,7 +12,7 @@ int cmd_update_server_info(int argc, const char **argv, const char *prefix)
{
int force = 0;
struct option options[] = {
- OPT__FORCE(&force, N_("update the info files from scratch")),
+ OPT__FORCE(&force, N_("update the info files from scratch"), 0),
OPT_END()
};
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index ba38ac9..dcdaada 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -44,12 +44,12 @@ static int verify_commit(const char *name, unsigned flags)
if (get_oid(name, &oid))
return error("commit '%s' not found.", name);
- buf = read_sha1_file(oid.hash, &type, &size);
+ buf = read_object_file(&oid, &type, &size);
if (!buf)
return error("%s: unable to read file.", name);
if (type != OBJ_COMMIT)
return error("%s: cannot verify a non-commit object of type %s.",
- name, typename(type));
+ name, type_name(type));
ret = run_gpg_verify(&oid, buf, size, flags);
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7cef5b1..40a438e 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -14,10 +14,12 @@
#include "worktree.h"
static const char * const worktree_usage[] = {
- N_("git worktree add [<options>] <path> [<branch>]"),
+ N_("git worktree add [<options>] <path> [<commit-ish>]"),
N_("git worktree list [<options>]"),
N_("git worktree lock [<options>] <path>"),
+ N_("git worktree move <worktree> <new-path>"),
N_("git worktree prune [<options>]"),
+ N_("git worktree remove [<options>] <worktree>"),
N_("git worktree unlock <path>"),
NULL
};
@@ -99,16 +101,9 @@ static int prune_worktree(const char *id, struct strbuf *reason)
}
path[len] = '\0';
if (!file_exists(path)) {
- struct stat st_link;
free(path);
- /*
- * the repo is moved manually and has not been
- * accessed since?
- */
- if (!stat(git_path("worktrees/%s/link", id), &st_link) &&
- st_link.st_nlink > 1)
- return 0;
- if (st.st_mtime <= expire) {
+ if (stat(git_path("worktrees/%s/index", id), &st) ||
+ st.st_mtime <= expire) {
strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id);
return 1;
} else {
@@ -345,9 +340,23 @@ done:
* Hook failure does not warrant worktree deletion, so run hook after
* is_junk is cleared, but do return appropriate code when hook fails.
*/
- if (!ret && opts->checkout)
- ret = run_hook_le(NULL, "post-checkout", oid_to_hex(&null_oid),
- oid_to_hex(&commit->object.oid), "1", NULL);
+ if (!ret && opts->checkout) {
+ const char *hook = find_hook("post-checkout");
+ if (hook) {
+ const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
+ cp.git_cmd = 0;
+ cp.no_stdin = 1;
+ cp.stdout_to_stderr = 1;
+ cp.dir = path;
+ cp.env = env;
+ cp.argv = NULL;
+ argv_array_pushl(&cp.args, absolute_path(hook),
+ oid_to_hex(&null_oid),
+ oid_to_hex(&commit->object.oid),
+ "1", NULL);
+ ret = run_command(&cp);
+ }
+ }
argv_array_clear(&child_env);
strbuf_release(&sb);
@@ -365,7 +374,9 @@ static int add(int ac, const char **av, const char *prefix)
const char *branch;
const char *opt_track = NULL;
struct option options[] = {
- OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
+ OPT__FORCE(&opts.force,
+ N_("checkout <branch> even if already checked out in other worktree"),
+ PARSE_OPT_NOCOMPLETE),
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
N_("create a new branch")),
OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
@@ -484,7 +495,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
strbuf_addstr(&sb, "(bare)");
else {
strbuf_addf(&sb, "%-*s ", abbrev_len,
- find_unique_abbrev(wt->head_oid.hash, DEFAULT_ABBREV));
+ find_unique_abbrev(&wt->head_oid, DEFAULT_ABBREV));
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
else if (wt->head_ref) {
@@ -509,7 +520,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
if (path_len > *maxlen)
*maxlen = path_len;
- sha1_len = strlen(find_unique_abbrev(wt[i]->head_oid.hash, *abbrev));
+ sha1_len = strlen(find_unique_abbrev(&wt[i]->head_oid, *abbrev));
if (sha1_len > *abbrev)
*abbrev = sha1_len;
}
@@ -605,6 +616,220 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
return ret;
}
+static void validate_no_submodules(const struct worktree *wt)
+{
+ struct index_state istate = { NULL };
+ int i, found_submodules = 0;
+
+ if (read_index_from(&istate, worktree_git_path(wt, "index"),
+ get_worktree_git_dir(wt)) > 0) {
+ for (i = 0; i < istate.cache_nr; i++) {
+ struct cache_entry *ce = istate.cache[i];
+
+ if (S_ISGITLINK(ce->ce_mode)) {
+ found_submodules = 1;
+ break;
+ }
+ }
+ }
+ discard_index(&istate);
+
+ if (found_submodules)
+ die(_("working trees containing submodules cannot be moved or removed"));
+}
+
+static int move_worktree(int ac, const char **av, const char *prefix)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ struct worktree **worktrees, *wt;
+ struct strbuf dst = STRBUF_INIT;
+ struct strbuf errmsg = STRBUF_INIT;
+ const char *reason;
+ char *path;
+
+ ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ if (ac != 2)
+ usage_with_options(worktree_usage, options);
+
+ path = prefix_filename(prefix, av[1]);
+ strbuf_addstr(&dst, path);
+ free(path);
+
+ worktrees = get_worktrees(0);
+ wt = find_worktree(worktrees, prefix, av[0]);
+ if (!wt)
+ die(_("'%s' is not a working tree"), av[0]);
+ if (is_main_worktree(wt))
+ die(_("'%s' is a main working tree"), av[0]);
+ if (is_directory(dst.buf)) {
+ const char *sep = find_last_dir_sep(wt->path);
+
+ if (!sep)
+ die(_("could not figure out destination name from '%s'"),
+ wt->path);
+ strbuf_trim_trailing_dir_sep(&dst);
+ strbuf_addstr(&dst, sep);
+ }
+ if (file_exists(dst.buf))
+ die(_("target '%s' already exists"), dst.buf);
+
+ validate_no_submodules(wt);
+
+ reason = is_worktree_locked(wt);
+ if (reason) {
+ if (*reason)
+ die(_("cannot move a locked working tree, lock reason: %s"),
+ reason);
+ die(_("cannot move a locked working tree"));
+ }
+ if (validate_worktree(wt, &errmsg, 0))
+ die(_("validation failed, cannot move working tree: %s"),
+ errmsg.buf);
+ strbuf_release(&errmsg);
+
+ if (rename(wt->path, dst.buf) == -1)
+ die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf);
+
+ update_worktree_location(wt, dst.buf);
+
+ strbuf_release(&dst);
+ free_worktrees(worktrees);
+ return 0;
+}
+
+/*
+ * Note, "git status --porcelain" is used to determine if it's safe to
+ * delete a whole worktree. "git status" does not ignore user
+ * configuration, so if a normal "git status" shows "clean" for the
+ * user, then it's ok to remove it.
+ *
+ * This assumption may be a bad one. We may want to ignore
+ * (potentially bad) user settings and only delete a worktree when
+ * it's absolutely safe to do so from _our_ point of view because we
+ * know better.
+ */
+static void check_clean_worktree(struct worktree *wt,
+ const char *original_path)
+{
+ struct argv_array child_env = ARGV_ARRAY_INIT;
+ struct child_process cp;
+ char buf[1];
+ int ret;
+
+ /*
+ * Until we sort this out, all submodules are "dirty" and
+ * will abort this function.
+ */
+ validate_no_submodules(wt);
+
+ argv_array_pushf(&child_env, "%s=%s/.git",
+ GIT_DIR_ENVIRONMENT, wt->path);
+ argv_array_pushf(&child_env, "%s=%s",
+ GIT_WORK_TREE_ENVIRONMENT, wt->path);
+ memset(&cp, 0, sizeof(cp));
+ argv_array_pushl(&cp.args, "status",
+ "--porcelain", "--ignore-submodules=none",
+ NULL);
+ cp.env = child_env.argv;
+ cp.git_cmd = 1;
+ cp.dir = wt->path;
+ cp.out = -1;
+ ret = start_command(&cp);
+ if (ret)
+ die_errno(_("failed to run 'git status' on '%s'"),
+ original_path);
+ ret = xread(cp.out, buf, sizeof(buf));
+ if (ret)
+ die(_("'%s' is dirty, use --force to delete it"),
+ original_path);
+ close(cp.out);
+ ret = finish_command(&cp);
+ if (ret)
+ die_errno(_("failed to run 'git status' on '%s', code %d"),
+ original_path, ret);
+}
+
+static int delete_git_work_tree(struct worktree *wt)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addstr(&sb, wt->path);
+ if (remove_dir_recursively(&sb, 0)) {
+ error_errno(_("failed to delete '%s'"), sb.buf);
+ ret = -1;
+ }
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int delete_git_dir(struct worktree *wt)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addstr(&sb, git_common_path("worktrees/%s", wt->id));
+ if (remove_dir_recursively(&sb, 0)) {
+ error_errno(_("failed to delete '%s'"), sb.buf);
+ ret = -1;
+ }
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int remove_worktree(int ac, const char **av, const char *prefix)
+{
+ int force = 0;
+ struct option options[] = {
+ OPT_BOOL(0, "force", &force,
+ N_("force removing even if the worktree is dirty")),
+ OPT_END()
+ };
+ struct worktree **worktrees, *wt;
+ struct strbuf errmsg = STRBUF_INIT;
+ const char *reason;
+ int ret = 0;
+
+ ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ if (ac != 1)
+ usage_with_options(worktree_usage, options);
+
+ worktrees = get_worktrees(0);
+ wt = find_worktree(worktrees, prefix, av[0]);
+ if (!wt)
+ die(_("'%s' is not a working tree"), av[0]);
+ if (is_main_worktree(wt))
+ die(_("'%s' is a main working tree"), av[0]);
+ reason = is_worktree_locked(wt);
+ if (reason) {
+ if (*reason)
+ die(_("cannot remove a locked working tree, lock reason: %s"),
+ reason);
+ die(_("cannot remove a locked working tree"));
+ }
+ if (validate_worktree(wt, &errmsg, WT_VALIDATE_WORKTREE_MISSING_OK))
+ die(_("validation failed, cannot remove working tree: %s"),
+ errmsg.buf);
+ strbuf_release(&errmsg);
+
+ if (file_exists(wt->path)) {
+ if (!force)
+ check_clean_worktree(wt, av[0]);
+
+ ret |= delete_git_work_tree(wt);
+ }
+ /*
+ * continue on even if ret is non-zero, there's no going back
+ * from here.
+ */
+ ret |= delete_git_dir(wt);
+
+ free_worktrees(worktrees);
+ return ret;
+}
+
int cmd_worktree(int ac, const char **av, const char *prefix)
{
struct option options[] = {
@@ -627,5 +852,9 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
return lock_worktree(ac - 1, av + 1, prefix);
if (!strcmp(av[1], "unlock"))
return unlock_worktree(ac - 1, av + 1, prefix);
+ if (!strcmp(av[1], "move"))
+ return move_worktree(ac - 1, av + 1, prefix);
+ if (!strcmp(av[1], "remove"))
+ return remove_worktree(ac - 1, av + 1, prefix);
usage_with_options(worktree_usage, options);
}
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index bd0a78a..c9d3c54 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -19,7 +19,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
{
int flags = 0, ret;
const char *prefix = NULL;
- unsigned char sha1[20];
+ struct object_id oid;
const char *me = "git-write-tree";
struct option write_tree_options[] = {
OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"),
@@ -38,10 +38,10 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
argc = parse_options(argc, argv, unused_prefix, write_tree_options,
write_tree_usage, 0);
- ret = write_cache_as_tree(sha1, flags, prefix);
+ ret = write_cache_as_tree(&oid, flags, prefix);
switch (ret) {
case 0:
- printf("%s\n", sha1_to_hex(sha1));
+ printf("%s\n", oid_to_hex(&oid));
break;
case WRITE_TREE_UNREADABLE_INDEX:
die("%s: error reading the index", me);
diff --git a/bulk-checkin.c b/bulk-checkin.c
index 3310fd2..e5ce2a7 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -12,7 +12,7 @@ static struct bulk_checkin_state {
unsigned plugged:1;
char *pack_tmp_name;
- struct sha1file *f;
+ struct hashfile *f;
off_t offset;
struct pack_idx_option pack_idx_opts;
@@ -35,9 +35,9 @@ static void finish_bulk_checkin(struct bulk_checkin_state *state)
unlink(state->pack_tmp_name);
goto clear_exit;
} else if (state->nr_written == 1) {
- sha1close(state->f, oid.hash, CSUM_FSYNC);
+ hashclose(state->f, oid.hash, CSUM_FSYNC);
} else {
- int fd = sha1close(state->f, oid.hash, 0);
+ int fd = hashclose(state->f, oid.hash, 0);
fixup_pack_header_footer(fd, oid.hash, state->pack_tmp_name,
state->nr_written, oid.hash,
state->offset);
@@ -60,17 +60,17 @@ clear_exit:
reprepare_packed_git();
}
-static int already_written(struct bulk_checkin_state *state, unsigned char sha1[])
+static int already_written(struct bulk_checkin_state *state, struct object_id *oid)
{
int i;
/* The object may already exist in the repository */
- if (has_sha1_file(sha1))
+ if (has_sha1_file(oid->hash))
return 1;
/* Might want to keep the list sorted */
for (i = 0; i < state->nr_written; i++)
- if (!hashcmp(state->written[i]->oid.hash, sha1))
+ if (!oidcmp(&state->written[i]->oid, oid))
return 1;
/* This is a new object we need to keep */
@@ -93,7 +93,7 @@ static int already_written(struct bulk_checkin_state *state, unsigned char sha1[
* with a new pack.
*/
static int stream_to_pack(struct bulk_checkin_state *state,
- git_SHA_CTX *ctx, off_t *already_hashed_to,
+ git_hash_ctx *ctx, off_t *already_hashed_to,
int fd, size_t size, enum object_type type,
const char *path, unsigned flags)
{
@@ -127,7 +127,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
if (rsize < hsize)
hsize = rsize;
if (hsize)
- git_SHA1_Update(ctx, ibuf, hsize);
+ the_hash_algo->update_fn(ctx, ibuf, hsize);
*already_hashed_to = offset;
}
s.next_in = ibuf;
@@ -149,7 +149,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
return -1;
}
- sha1write(state->f, obuf, written);
+ hashwrite(state->f, obuf, written);
state->offset += written;
}
s.next_out = obuf;
@@ -186,16 +186,16 @@ static void prepare_to_stream(struct bulk_checkin_state *state,
}
static int deflate_to_pack(struct bulk_checkin_state *state,
- unsigned char result_sha1[],
+ struct object_id *result_oid,
int fd, size_t size,
enum object_type type, const char *path,
unsigned flags)
{
off_t seekback, already_hashed_to;
- git_SHA_CTX ctx;
+ git_hash_ctx ctx;
unsigned char obuf[16384];
unsigned header_len;
- struct sha1file_checkpoint checkpoint;
+ struct hashfile_checkpoint checkpoint;
struct pack_idx_entry *idx = NULL;
seekback = lseek(fd, 0, SEEK_CUR);
@@ -203,9 +203,9 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
return error("cannot find the current offset");
header_len = xsnprintf((char *)obuf, sizeof(obuf), "%s %" PRIuMAX,
- typename(type), (uintmax_t)size) + 1;
- git_SHA1_Init(&ctx);
- git_SHA1_Update(&ctx, obuf, header_len);
+ type_name(type), (uintmax_t)size) + 1;
+ the_hash_algo->init_fn(&ctx);
+ the_hash_algo->update_fn(&ctx, obuf, header_len);
/* Note: idx is non-NULL when we are writing */
if ((flags & HASH_WRITE_OBJECT) != 0)
@@ -216,7 +216,7 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
while (1) {
prepare_to_stream(state, flags);
if (idx) {
- sha1file_checkpoint(state->f, &checkpoint);
+ hashfile_checkpoint(state->f, &checkpoint);
idx->offset = state->offset;
crc32_begin(state->f);
}
@@ -230,23 +230,23 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
*/
if (!idx)
die("BUG: should not happen");
- sha1file_truncate(state->f, &checkpoint);
+ hashfile_truncate(state->f, &checkpoint);
state->offset = checkpoint.offset;
finish_bulk_checkin(state);
if (lseek(fd, seekback, SEEK_SET) == (off_t) -1)
return error("cannot seek back");
}
- git_SHA1_Final(result_sha1, &ctx);
+ the_hash_algo->final_fn(result_oid->hash, &ctx);
if (!idx)
return 0;
idx->crc32 = crc32_end(state->f);
- if (already_written(state, result_sha1)) {
- sha1file_truncate(state->f, &checkpoint);
+ if (already_written(state, result_oid)) {
+ hashfile_truncate(state->f, &checkpoint);
state->offset = checkpoint.offset;
free(idx);
} else {
- hashcpy(idx->oid.hash, result_sha1);
+ oidcpy(&idx->oid, result_oid);
ALLOC_GROW(state->written,
state->nr_written + 1,
state->alloc_written);
@@ -255,11 +255,11 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
return 0;
}
-int index_bulk_checkin(unsigned char *sha1,
+int index_bulk_checkin(struct object_id *oid,
int fd, size_t size, enum object_type type,
const char *path, unsigned flags)
{
- int status = deflate_to_pack(&state, sha1, fd, size, type,
+ int status = deflate_to_pack(&state, oid, fd, size, type,
path, flags);
if (!state.plugged)
finish_bulk_checkin(&state);
diff --git a/bulk-checkin.h b/bulk-checkin.h
index fbd40fc..a855273 100644
--- a/bulk-checkin.h
+++ b/bulk-checkin.h
@@ -4,7 +4,7 @@
#ifndef BULK_CHECKIN_H
#define BULK_CHECKIN_H
-extern int index_bulk_checkin(unsigned char sha1[],
+extern int index_bulk_checkin(struct object_id *oid,
int fd, size_t size, enum object_type type,
const char *path, unsigned flags);
diff --git a/bundle.c b/bundle.c
index efe547e..902c9b5 100644
--- a/bundle.c
+++ b/bundle.c
@@ -222,7 +222,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)
if (revs->max_age == -1 && revs->min_age == -1)
goto out;
- buf = read_sha1_file(tag->oid.hash, &type, &size);
+ buf = read_object_file(&tag->oid, &type, &size);
if (!buf)
goto out;
line = memmem(buf, size, "\ntagger ", 8);
diff --git a/cache-tree.c b/cache-tree.c
index 3841cef..6a555f4 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -320,7 +320,7 @@ static int update_one(struct cache_tree *it,
struct cache_tree_sub *sub = NULL;
const char *path, *slash;
int pathlen, entlen;
- const unsigned char *sha1;
+ const struct object_id *oid;
unsigned mode;
int expected_missing = 0;
int contains_ita = 0;
@@ -338,7 +338,7 @@ static int update_one(struct cache_tree *it,
die("cache-tree.c: '%.*s' in '%s' not found",
entlen, path + baselen, path);
i += sub->count;
- sha1 = sub->cache_tree->oid.hash;
+ oid = &sub->cache_tree->oid;
mode = S_IFDIR;
contains_ita = sub->cache_tree->entry_count < 0;
if (contains_ita) {
@@ -347,19 +347,19 @@ static int update_one(struct cache_tree *it,
}
}
else {
- sha1 = ce->oid.hash;
+ oid = &ce->oid;
mode = ce->ce_mode;
entlen = pathlen - baselen;
i++;
}
- if (is_null_sha1(sha1) ||
- (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))) {
+ if (is_null_oid(oid) ||
+ (mode != S_IFGITLINK && !missing_ok && !has_object_file(oid))) {
strbuf_release(&buffer);
if (expected_missing)
return -1;
return error("invalid object %06o %s for '%.*s'",
- mode, sha1_to_hex(sha1), entlen+baselen, path);
+ mode, oid_to_hex(oid), entlen+baselen, path);
}
/*
@@ -385,12 +385,12 @@ static int update_one(struct cache_tree *it,
/*
* "sub" can be an empty tree if all subentries are i-t-a.
*/
- if (contains_ita && !hashcmp(sha1, EMPTY_TREE_SHA1_BIN))
+ if (contains_ita && !oidcmp(oid, &empty_tree_oid))
continue;
strbuf_grow(&buffer, entlen + 100);
strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
- strbuf_add(&buffer, sha1, 20);
+ strbuf_add(&buffer, oid->hash, the_hash_algo->rawsz);
#if DEBUG
fprintf(stderr, "cache-tree update-one %o %.*s\n",
@@ -399,16 +399,16 @@ static int update_one(struct cache_tree *it,
}
if (repair) {
- unsigned char sha1[20];
- hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
- if (has_sha1_file(sha1))
- hashcpy(it->oid.hash, sha1);
+ struct object_id oid;
+ hash_object_file(buffer.buf, buffer.len, tree_type, &oid);
+ if (has_object_file(&oid))
+ oidcpy(&it->oid, &oid);
else
to_invalidate = 1;
- } else if (dryrun)
- hash_sha1_file(buffer.buf, buffer.len, tree_type,
- it->oid.hash);
- else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->oid.hash)) {
+ } else if (dryrun) {
+ hash_object_file(buffer.buf, buffer.len, tree_type, &it->oid);
+ } else if (write_object_file(buffer.buf, buffer.len, tree_type,
+ &it->oid)) {
strbuf_release(&buffer);
return -1;
}
@@ -465,7 +465,7 @@ static void write_one(struct strbuf *buffer, struct cache_tree *it,
#endif
if (0 <= it->entry_count) {
- strbuf_add(buffer, it->oid.hash, 20);
+ strbuf_add(buffer, it->oid.hash, the_hash_algo->rawsz);
}
for (i = 0; i < it->subtree_nr; i++) {
struct cache_tree_sub *down = it->down[i];
@@ -492,6 +492,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
char *ep;
struct cache_tree *it;
int i, subtree_nr;
+ const unsigned rawsz = the_hash_algo->rawsz;
it = NULL;
/* skip name, but make sure name exists */
@@ -520,11 +521,11 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
goto free_return;
buf++; size--;
if (0 <= it->entry_count) {
- if (size < 20)
+ if (size < rawsz)
goto free_return;
- hashcpy(it->oid.hash, (const unsigned char*)buf);
- buf += 20;
- size -= 20;
+ memcpy(it->oid.hash, (const unsigned char*)buf, rawsz);
+ buf += rawsz;
+ size -= rawsz;
}
#if DEBUG
@@ -599,7 +600,7 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
return it;
}
-int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
+int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
{
int entries, was_valid;
struct lock_file lock_file = LOCK_INIT;
@@ -640,19 +641,19 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
ret = WRITE_TREE_PREFIX_ERROR;
goto out;
}
- hashcpy(sha1, subtree->oid.hash);
+ oidcpy(oid, &subtree->oid);
}
else
- hashcpy(sha1, index_state->cache_tree->oid.hash);
+ oidcpy(oid, &index_state->cache_tree->oid);
out:
rollback_lock_file(&lock_file);
return ret;
}
-int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
+int write_cache_as_tree(struct object_id *oid, int flags, const char *prefix)
{
- return write_index_as_tree(sha1, &the_index, get_index_file(), flags, prefix);
+ return write_index_as_tree(oid, &the_index, get_index_file(), flags, prefix);
}
static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
diff --git a/cache-tree.h b/cache-tree.h
index f7b9cab..cfd5328 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -47,8 +47,8 @@ int update_main_cache_tree(int);
#define WRITE_TREE_UNMERGED_INDEX (-2)
#define WRITE_TREE_PREFIX_ERROR (-3)
-int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix);
-int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix);
+int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix);
+int write_cache_as_tree(struct object_id *oid, int flags, const char *prefix);
void prime_cache_tree(struct index_state *, struct tree *);
extern int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
diff --git a/cache.h b/cache.h
index 41ba67c..6e45c1b 100644
--- a/cache.h
+++ b/cache.h
@@ -16,31 +16,6 @@
#include "sha1-array.h"
#include "repository.h"
-#ifndef platform_SHA_CTX
-/*
- * platform's underlying implementation of SHA-1; could be OpenSSL,
- * blk_SHA, Apple CommonCrypto, etc... Note that including
- * SHA1_HEADER may have already defined platform_SHA_CTX for our
- * own implementations like block-sha1 and ppc-sha1, so we list
- * the default for OpenSSL compatible SHA-1 implementations here.
- */
-#define platform_SHA_CTX SHA_CTX
-#define platform_SHA1_Init SHA1_Init
-#define platform_SHA1_Update SHA1_Update
-#define platform_SHA1_Final SHA1_Final
-#endif
-
-#define git_SHA_CTX platform_SHA_CTX
-#define git_SHA1_Init platform_SHA1_Init
-#define git_SHA1_Update platform_SHA1_Update
-#define git_SHA1_Final platform_SHA1_Final
-
-#ifdef SHA1_MAX_BLOCK_SIZE
-#include "compat/sha1-chunked.h"
-#undef git_SHA1_Update
-#define git_SHA1_Update git_SHA1_Update_Chunked
-#endif
-
#include <zlib.h>
typedef struct git_zstream {
z_stream z;
@@ -624,6 +599,7 @@ extern int read_index_unmerged(struct index_state *);
/* For use with `write_locked_index()`. */
#define COMMIT_LOCK (1 << 0)
+#define SKIP_IF_UNCHANGED (1 << 1)
/*
* Write the index while holding an already-taken lock. Close the lock,
@@ -640,6 +616,9 @@ extern int read_index_unmerged(struct index_state *);
* With `COMMIT_LOCK`, the lock is always committed or rolled back.
* Without it, the lock is closed, but neither committed nor rolled
* back.
+ *
+ * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing
+ * is written (and the lock is rolled back if `COMMIT_LOCK` is given).
*/
extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
@@ -976,14 +955,14 @@ extern void sha1_file_name(struct strbuf *buf, const unsigned char *sha1);
* more calls to find_unique_abbrev are made.
*
* The `_r` variant writes to a buffer supplied by the caller, which must be at
- * least `GIT_SHA1_HEXSZ + 1` bytes. The return value is the number of bytes
+ * least `GIT_MAX_HEXSZ + 1` bytes. The return value is the number of bytes
* written (excluding the NUL terminator).
*
* Note that while this version avoids the static buffer, it is not fully
* reentrant, as it calls into other non-reentrant git code.
*/
-extern const char *find_unique_abbrev(const unsigned char *sha1, int len);
-extern int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len);
+extern const char *find_unique_abbrev(const struct object_id *oid, int len);
+extern int find_unique_abbrev_r(char *hex, const struct object_id *oid, int len);
extern const unsigned char null_sha1[GIT_MAX_RAWSZ];
extern const struct object_id null_oid;
@@ -1032,7 +1011,7 @@ static inline void hashclr(unsigned char *hash)
static inline void oidclr(struct object_id *oid)
{
- hashclr(oid->hash);
+ memset(oid->hash, 0, GIT_MAX_RAWSZ);
}
@@ -1050,8 +1029,6 @@ extern const struct object_id empty_tree_oid;
"\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
"\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
extern const struct object_id empty_blob_oid;
-#define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
-
static inline int is_empty_blob_sha1(const unsigned char *sha1)
{
@@ -1212,19 +1189,19 @@ extern char *xdg_config_home(const char *filename);
*/
extern char *xdg_cache_home(const char *filename);
-extern void *read_sha1_file_extended(const unsigned char *sha1,
- enum object_type *type,
- unsigned long *size, int lookup_replace);
-static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
+extern void *read_object_file_extended(const struct object_id *oid,
+ enum object_type *type,
+ unsigned long *size, int lookup_replace);
+static inline void *read_object_file(const struct object_id *oid, enum object_type *type, unsigned long *size)
{
- return read_sha1_file_extended(sha1, type, size, 1);
+ return read_object_file_extended(oid, type, size, 1);
}
/*
* This internal function is only declared here for the benefit of
* lookup_replace_object(). Please do not call it directly.
*/
-extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
+extern const struct object_id *do_lookup_replace_object(const struct object_id *oid);
/*
* If object sha1 should be replaced, return the replacement object's
@@ -1232,39 +1209,50 @@ extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
* either sha1 or a pointer to a permanently-allocated value. When
* object replacement is suppressed, always return sha1.
*/
-static inline const unsigned char *lookup_replace_object(const unsigned char *sha1)
+static inline const struct object_id *lookup_replace_object(const struct object_id *oid)
{
if (!check_replace_refs)
- return sha1;
- return do_lookup_replace_object(sha1);
+ return oid;
+ return do_lookup_replace_object(oid);
}
-/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
-extern int sha1_object_info(const unsigned char *, unsigned long *);
-extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
-extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
-extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, struct object_id *oid, unsigned flags);
-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);
+/* Read and unpack an object file into memory, write memory to an object file */
+extern int oid_object_info(const struct object_id *, unsigned long *);
+
+extern int hash_object_file(const void *buf, unsigned long len,
+ const char *type, struct object_id *oid);
+
+extern int write_object_file(const void *buf, unsigned long len,
+ const char *type, struct object_id *oid);
+
+extern int hash_object_file_literally(const void *buf, unsigned long len,
+ const char *type, struct object_id *oid,
+ unsigned flags);
+
+extern int pretend_object_file(void *, unsigned long, enum object_type,
+ struct object_id *oid);
+
+extern int force_object_loose(const struct object_id *oid, time_t mtime);
+
extern int git_open_cloexec(const char *name, int flags);
#define git_open(name) git_open_cloexec(name, O_RDONLY)
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);
-extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
+extern int check_object_signature(const struct object_id *oid, void *buf, unsigned long size, const char *type);
extern int finalize_object_file(const char *tmpfile, const char *filename);
/*
- * Open the loose object at path, check its sha1, and return the contents,
+ * Open the loose object at path, check its hash, and return the contents,
* type, and size. If the object is a blob, then "contents" may return NULL,
* to allow streaming of large blobs.
*
* Returns 0 on success, negative on error (details may be written to stderr).
*/
int read_loose_object(const char *path,
- const unsigned char *expected_sha1,
+ const struct object_id *expected_oid,
enum object_type *type,
unsigned long *size,
void **contents);
@@ -1291,7 +1279,7 @@ extern int has_object_file_with_flags(const struct object_id *oid, int flags);
*/
extern int has_loose_object_nonlocal(const unsigned char *sha1);
-extern void assert_sha1_type(const unsigned char *sha1, enum object_type expect);
+extern void assert_oid_type(const struct object_id *oid, enum object_type expect);
/* Helper to check and "touch" a file */
extern int check_and_freshen_file(const char *fn, int freshen);
@@ -1447,10 +1435,10 @@ extern int df_name_compare(const char *name1, int len1, int mode1, const char *n
extern int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
-extern void *read_object_with_reference(const unsigned char *sha1,
+extern void *read_object_with_reference(const struct object_id *oid,
const char *required_type,
unsigned long *size,
- unsigned char *sha1_ret);
+ struct object_id *oid_ret);
extern struct object *peel_to_type(const char *name, int namelen,
struct object *o, enum object_type);
@@ -1677,7 +1665,7 @@ struct pack_entry {
* usual "XXXXXX" trailer, and the resulting filename is written into the
* "template" buffer. Returns the open descriptor.
*/
-extern int odb_mkstemp(struct strbuf *template, const char *pattern);
+extern int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
/*
* Create a pack .keep file named "name" (which should generally be the output
@@ -1748,7 +1736,7 @@ struct object_info {
unsigned long *sizep;
off_t *disk_sizep;
unsigned char *delta_base_sha1;
- struct strbuf *typename;
+ struct strbuf *type_name;
void **contentp;
/* Response */
@@ -1789,7 +1777,9 @@ struct object_info {
#define OBJECT_INFO_SKIP_CACHED 4
/* Do not retry packed storage after checking packed and loose storage */
#define OBJECT_INFO_QUICK 8
-extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
+/* Do not check loose object */
+#define OBJECT_INFO_IGNORE_LOOSE 16
+extern int oid_object_info_extended(const struct object_id *, struct object_info *, unsigned flags);
/*
* Set this to 0 to prevent sha1_object_info_extended() from fetching missing
diff --git a/ci/lib-travisci.sh b/ci/lib-travisci.sh
index 1efee55..109ef28 100755
--- a/ci/lib-travisci.sh
+++ b/ci/lib-travisci.sh
@@ -97,7 +97,7 @@ fi
export DEVELOPER=1
export DEFAULT_TEST_TARGET=prove
export GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
-export GIT_TEST_OPTS="--verbose-log"
+export GIT_TEST_OPTS="--verbose-log -x"
export GIT_TEST_CLONE_2GB=YesPlease
case "$jobname" in
diff --git a/ci/run-tests.sh b/ci/run-build-and-tests.sh
index 73e273f..3735ce4 100755
--- a/ci/run-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -1,12 +1,13 @@
#!/bin/sh
#
-# Test Git
+# Build and test Git
#
. ${0%/*}/lib-travisci.sh
ln -s "$cache_dir/.prove" t/.prove
+make --jobs=2
make --quiet test
if test "$jobname" = "linux-gcc"
then
diff --git a/ci/run-build.sh b/ci/run-build.sh
deleted file mode 100755
index 4f940d1..0000000
--- a/ci/run-build.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-#
-# Build Git
-#
-
-. ${0%/*}/lib-travisci.sh
-
-make --jobs=2
diff --git a/color.c b/color.c
index d48dd94..f277e72 100644
--- a/color.c
+++ b/color.c
@@ -161,11 +161,6 @@ int color_parse(const char *value, char *dst)
return color_parse_mem(value, strlen(value), dst);
}
-void color_set(char *dst, const char *color_bytes)
-{
- xsnprintf(dst, COLOR_MAXLEN, "%s", color_bytes);
-}
-
/*
* Write the ANSI color codes for "c" to "out"; the string should
* already have the ANSI escape code in it. "out" should have enough
@@ -399,8 +394,6 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
return r;
}
-
-
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
{
va_list args;
diff --git a/color.h b/color.h
index fd2b688..cd0bced 100644
--- a/color.h
+++ b/color.h
@@ -76,22 +76,46 @@ int git_color_config(const char *var, const char *value, void *cb);
int git_color_default_config(const char *var, const char *value, void *cb);
/*
- * Set the color buffer (which must be COLOR_MAXLEN bytes)
- * to the raw color bytes; this is useful for initializing
- * default color variables.
+ * Parse a config option, which can be a boolean or one of
+ * "never", "auto", "always". Return a constant of
+ * GIT_COLOR_NEVER for "never" or negative boolean,
+ * GIT_COLOR_ALWAYS for "always" or a positive boolean,
+ * and GIT_COLOR_AUTO for "auto".
*/
-void color_set(char *dst, const char *color_bytes);
-
int git_config_colorbool(const char *var, const char *value);
+
+/*
+ * Return a boolean whether to use color, where the argument 'var' is
+ * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.
+ */
int want_color(int var);
+
+/*
+ * Translate a Git color from 'value' into a string that the terminal can
+ * interpret and store it into 'dst'. The Git color values are of the form
+ * "foreground [background] [attr]" where fore- and background can be a color
+ * name ("red"), a RGB code (#0xFF0000) or a 256-color-mode from the terminal.
+ */
int color_parse(const char *value, char *dst);
int color_parse_mem(const char *value, int len, char *dst);
+
+/*
+ * Output the formatted string in the specified color (and then reset to normal
+ * color so subsequent output is uncolored). Omits the color encapsulation if
+ * `color` is NULL. The `color_fprintf_ln` prints a new line after resetting
+ * the color. The `color_print_strbuf` prints the contents of the given
+ * strbuf (BUG: but only up to its first NUL character).
+ */
__attribute__((format (printf, 3, 4)))
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
__attribute__((format (printf, 3, 4)))
int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
+/*
+ * Check if the given color is GIT_COLOR_NIL that means "no color selected".
+ * The caller needs to replace the color with the actual desired color.
+ */
int color_is_nil(const char *color);
#endif /* COLOR_H */
diff --git a/combine-diff.c b/combine-diff.c
index 18c74da..2ef4959 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -162,7 +162,7 @@ enum coalesce_direction { MATCH, BASE, NEW };
/* Coalesce new lines into base by finding LCS */
static struct lline *coalesce_lines(struct lline *base, int *lenbase,
- struct lline *new, int lennew,
+ struct lline *newline, int lennew,
unsigned long parent, long flags)
{
int **lcs;
@@ -170,12 +170,12 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
struct lline *baseend, *newend = NULL;
int i, j, origbaselen = *lenbase;
- if (new == NULL)
+ if (newline == NULL)
return base;
if (base == NULL) {
*lenbase = lennew;
- return new;
+ return newline;
}
/*
@@ -200,7 +200,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
directions[0][j] = NEW;
for (i = 1, baseend = base; i < origbaselen + 1; i++) {
- for (j = 1, newend = new; j < lennew + 1; j++) {
+ for (j = 1, newend = newline; j < lennew + 1; j++) {
if (match_string_spaces(baseend->line, baseend->len,
newend->line, newend->len, flags)) {
lcs[i][j] = lcs[i - 1][j - 1] + 1;
@@ -241,7 +241,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
if (lline->prev)
lline->prev->next = lline->next;
else
- new = lline->next;
+ newline = lline->next;
if (lline->next)
lline->next->prev = lline->prev;
@@ -270,7 +270,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
}
}
- newend = new;
+ newend = newline;
while (newend) {
struct lline *lline = newend;
newend = newend->next;
@@ -306,7 +306,7 @@ static char *grab_blob(const struct object_id *oid, unsigned int mode,
*size = fill_textconv(textconv, df, &blob);
free_filespec(df);
} else {
- blob = read_sha1_file(oid->hash, &type, size);
+ blob = read_object_file(oid, &type, size);
if (type != OBJ_BLOB)
die("object '%s' is not a blob!", oid_to_hex(oid));
}
@@ -915,11 +915,11 @@ static void show_combined_header(struct combine_diff_path *elem,
"", elem->path, line_prefix, c_meta, c_reset);
printf("%s%sindex ", line_prefix, c_meta);
for (i = 0; i < num_parent; i++) {
- abb = find_unique_abbrev(elem->parent[i].oid.hash,
+ abb = find_unique_abbrev(&elem->parent[i].oid,
abbrev);
printf("%s%s", i ? "," : "", abb);
}
- abb = find_unique_abbrev(elem->oid.hash, abbrev);
+ abb = find_unique_abbrev(&elem->oid, abbrev);
printf("..%s%s\n", abb, c_reset);
if (mode_differs) {
diff --git a/commit.c b/commit.c
index c948c8b..ca474a7 100644
--- a/commit.c
+++ b/commit.c
@@ -266,13 +266,13 @@ const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
if (!ret) {
enum object_type type;
unsigned long size;
- ret = read_sha1_file(commit->object.oid.hash, &type, &size);
+ ret = read_object_file(&commit->object.oid, &type, &size);
if (!ret)
die("cannot read commit object %s",
oid_to_hex(&commit->object.oid));
if (type != OBJ_COMMIT)
die("expected commit for %s, got %s",
- oid_to_hex(&commit->object.oid), typename(type));
+ oid_to_hex(&commit->object.oid), type_name(type));
if (sizep)
*sizep = size;
}
@@ -383,7 +383,7 @@ int parse_commit_gently(struct commit *item, int quiet_on_missing)
return -1;
if (item->object.parsed)
return 0;
- buffer = read_sha1_file(item->object.oid.hash, &type, &size);
+ buffer = read_object_file(&item->object.oid, &type, &size);
if (!buffer)
return quiet_on_missing ? -1 :
error("Could not read %s",
@@ -859,19 +859,19 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
commit_list_insert(in->item, &ret);
for (i = in->next; i; i = i->next) {
- struct commit_list *new = NULL, *end = NULL;
+ struct commit_list *new_commits = NULL, *end = NULL;
for (j = ret; j; j = j->next) {
struct commit_list *bases;
bases = get_merge_bases(i->item, j->item);
- if (!new)
- new = bases;
+ if (!new_commits)
+ new_commits = bases;
else
end->next = bases;
for (k = bases; k; k = k->next)
end = k;
}
- ret = new;
+ ret = new_commits;
}
return ret;
}
@@ -1206,7 +1206,7 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
desc = merge_remote_util(parent);
if (!desc || !desc->obj)
return;
- buf = read_sha1_file(desc->obj->oid.hash, &type, &size);
+ buf = read_object_file(&desc->obj->oid, &type, &size);
if (!buf || type != OBJ_TAG)
goto free_return;
len = parse_signature(buf, size);
@@ -1378,9 +1378,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
}
}
-int commit_tree(const char *msg, size_t msg_len,
- const unsigned char *tree,
- struct commit_list *parents, unsigned char *ret,
+int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
+ struct commit_list *parents, struct object_id *ret,
const char *author, const char *sign_commit)
{
struct commit_extra_header *extra = NULL, **tail = &extra;
@@ -1509,8 +1508,8 @@ N_("Warning: commit message did not conform to UTF-8.\n"
"variable i18n.commitencoding to the encoding your project uses.\n");
int commit_tree_extended(const char *msg, size_t msg_len,
- const unsigned char *tree,
- struct commit_list *parents, unsigned char *ret,
+ const struct object_id *tree,
+ struct commit_list *parents, struct object_id *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *extra)
{
@@ -1518,7 +1517,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
int encoding_is_utf8;
struct strbuf buffer;
- assert_sha1_type(tree, OBJ_TREE);
+ assert_oid_type(tree, OBJ_TREE);
if (memchr(msg, '\0', msg_len))
return error("a NUL byte in commit log message not allowed.");
@@ -1527,7 +1526,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
- strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree));
+ strbuf_addf(&buffer, "tree %s\n", oid_to_hex(tree));
/*
* NOTE! This ordering means that the same exact tree merged with a
@@ -1566,7 +1565,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
goto out;
}
- result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
+ result = write_object_file(buffer.buf, buffer.len, commit_type, ret);
out:
strbuf_release(&buffer);
return result;
@@ -1615,11 +1614,11 @@ struct commit *get_merge_parent(const char *name)
struct commit_list **commit_list_append(struct commit *commit,
struct commit_list **next)
{
- struct commit_list *new = xmalloc(sizeof(struct commit_list));
- new->item = commit;
- *next = new;
- new->next = NULL;
- return &new->next;
+ struct commit_list *new_commit = xmalloc(sizeof(struct commit_list));
+ new_commit->item = commit;
+ *next = new_commit;
+ new_commit->next = NULL;
+ return &new_commit->next;
}
const char *find_commit_header(const char *msg, const char *key, size_t *out_len)
diff --git a/commit.h b/commit.h
index 425f402..0fb8271 100644
--- a/commit.h
+++ b/commit.h
@@ -262,14 +262,15 @@ extern void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail);
extern int commit_tree(const char *msg, size_t msg_len,
- const unsigned char *tree,
- struct commit_list *parents, unsigned char *ret,
+ const struct object_id *tree,
+ struct commit_list *parents, struct object_id *ret,
const char *author, const char *sign_commit);
extern int commit_tree_extended(const char *msg, size_t msg_len,
- const unsigned char *tree,
- struct commit_list *parents, unsigned char *ret,
- const char *author, const char *sign_commit,
+ const struct object_id *tree,
+ struct commit_list *parents,
+ struct object_id *ret, const char *author,
+ const char *sign_commit,
struct commit_extra_header *);
extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
diff --git a/compat/mingw.c b/compat/mingw.c
index 2d44d21..a67872b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -761,6 +761,17 @@ revert_attrs:
return rc;
}
+#undef strftime
+size_t mingw_strftime(char *s, size_t max,
+ const char *format, const struct tm *tm)
+{
+ size_t ret = strftime(s, max, format, tm);
+
+ if (!ret && errno == EINVAL)
+ die("invalid strftime format: '%s'", format);
+ return ret;
+}
+
unsigned int sleep (unsigned int seconds)
{
Sleep(seconds*1000);
diff --git a/compat/mingw.h b/compat/mingw.h
index e03aecf..571019d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -361,6 +361,9 @@ int mingw_fstat(int fd, struct stat *buf);
int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime
+size_t mingw_strftime(char *s, size_t max,
+ const char *format, const struct tm *tm);
+#define strftime mingw_strftime
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
const char *dir,
diff --git a/config.c b/config.c
index b0c20e6..c698988 100644
--- a/config.c
+++ b/config.c
@@ -1488,7 +1488,7 @@ int git_config_from_blob_oid(config_fn_t fn,
unsigned long size;
int ret;
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf)
return error("unable to load config blob object '%s'", name);
if (type != OBJ_BLOB) {
diff --git a/config.mak.uname b/config.mak.uname
index 685a80d..6a1d0de 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -182,7 +182,6 @@ ifeq ($(uname_O),Cygwin)
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
X = .exe
UNRELIABLE_FSTAT = UnfortunatelyYes
- SPARSE_FLAGS = -isystem /usr/include/w32api -Wno-one-bit-signed-bitfield
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
MMAP_PREVENTS_DELETE = UnfortunatelyYes
COMPAT_OBJS += compat/cygwin.o
diff --git a/configure.ac b/configure.ac
index 7f84151..6f1fd9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -254,25 +254,25 @@ GIT_PARSE_WITH([openssl]))
# Perl-compatible regular expressions instead of standard or extended
# POSIX regular expressions.
#
-# Currently USE_LIBPCRE is a synonym for USE_LIBPCRE1, define
-# USE_LIBPCRE2 instead if you'd like to use version 2 of the PCRE
-# library. The USE_LIBPCRE flag will likely be changed to mean v2 by
-# default in future releases.
+# USE_LIBPCRE is a synonym for USE_LIBPCRE2, define USE_LIBPCRE1
+# instead if you'd like to use the legacy version 1 of the PCRE
+# library. Support for version 1 will likely be removed in some future
+# release of Git, as upstream has all but abandoned it.
#
# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
#
AC_ARG_WITH(libpcre,
-AS_HELP_STRING([--with-libpcre],[synonym for --with-libpcre1]),
+AS_HELP_STRING([--with-libpcre],[synonym for --with-libpcre2]),
if test "$withval" = "no"; then
- USE_LIBPCRE1=
+ USE_LIBPCRE2=
elif test "$withval" = "yes"; then
- USE_LIBPCRE1=YesPlease
+ USE_LIBPCRE2=YesPlease
else
- USE_LIBPCRE1=YesPlease
+ USE_LIBPCRE2=YesPlease
LIBPCREDIR=$withval
AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR])
- dnl USE_LIBPCRE1 can still be modified below, so don't substitute
+ dnl USE_LIBPCRE2 can still be modified below, so don't substitute
dnl it yet.
GIT_CONF_SUBST([LIBPCREDIR])
fi)
@@ -296,6 +296,10 @@ AS_HELP_STRING([], [ARG can be also prefix for libpcre library and hea
AC_ARG_WITH(libpcre2,
AS_HELP_STRING([--with-libpcre2],[support Perl-compatible regexes via libpcre2 (default is NO)])
AS_HELP_STRING([], [ARG can be also prefix for libpcre library and headers]),
+ if test -n "$USE_LIBPCRE2"; then
+ AC_MSG_ERROR([Only supply one of --with-libpcre or its synonym --with-libpcre2!])
+ fi
+
if test -n "$USE_LIBPCRE1"; then
AC_MSG_ERROR([Only supply one of --with-libpcre1 or --with-libpcre2!])
fi
@@ -549,8 +553,8 @@ if test -n "$USE_LIBPCRE1"; then
GIT_STASH_FLAGS($LIBPCREDIR)
AC_CHECK_LIB([pcre], [pcre_version],
-[USE_LIBPCRE=YesPlease],
-[USE_LIBPCRE=])
+[USE_LIBPCRE1=YesPlease],
+[USE_LIBPCRE1=])
GIT_UNSTASH_FLAGS($LIBPCREDIR)
diff --git a/contrib/coccinelle/strbuf.cocci b/contrib/coccinelle/strbuf.cocci
index 6fe8727..e34eada 100644
--- a/contrib/coccinelle/strbuf.cocci
+++ b/contrib/coccinelle/strbuf.cocci
@@ -1,21 +1,6 @@
@ strbuf_addf_with_format_only @
expression E;
-constant fmt;
-@@
- strbuf_addf(E,
-(
- fmt
-|
- _(fmt)
-)
- );
-
-@ script:python @
-fmt << strbuf_addf_with_format_only.fmt;
-@@
-cocci.include_match("%" not in fmt)
-
-@ extends strbuf_addf_with_format_only @
+constant fmt !~ "%";
@@
- strbuf_addf
+ strbuf_addstr
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 88813e9..b09c8a2 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -280,6 +280,43 @@ __gitcomp ()
esac
}
+# Clear the variables caching builtins' options when (re-)sourcing
+# the completion script.
+unset $(set |sed -ne 's/^\(__gitcomp_builtin_[a-zA-Z0-9_][a-zA-Z0-9_]*\)=.*/\1/p') 2>/dev/null
+
+# This function is equivalent to
+#
+# __gitcomp "$(git xxx --git-completion-helper) ..."
+#
+# except that the output is cached. Accept 1-3 arguments:
+# 1: the git command to execute, this is also the cache key
+# 2: extra options to be added on top (e.g. negative forms)
+# 3: options to be excluded
+__gitcomp_builtin ()
+{
+ # spaces must be replaced with underscore for multi-word
+ # commands, e.g. "git remote add" becomes remote_add.
+ local cmd="$1"
+ local incl="$2"
+ local excl="$3"
+
+ local var=__gitcomp_builtin_"${cmd/-/_}"
+ local options
+ eval "options=\$$var"
+
+ if [ -z "$options" ]; then
+ # leading and trailing spaces are significant to make
+ # option removal work correctly.
+ options=" $(__git ${cmd/_/ } --git-completion-helper) $incl "
+ for i in $excl; do
+ options="${options/ $i / }"
+ done
+ eval "$var=\"$options\""
+ fi
+
+ __gitcomp "$options"
+}
+
# Variation of __gitcomp_nl () that appends to the existing list of
# completion candidates, COMPREPLY.
__gitcomp_nl_append ()
@@ -439,7 +476,7 @@ __git_refs ()
track=""
;;
*)
- for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
+ for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do
case "$i" in
$match*)
if [ -e "$dir/$i" ]; then
@@ -1072,12 +1109,13 @@ __git_count_arguments ()
}
__git_whitespacelist="nowarn warn error error-all fix"
+__git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch"
_git_am ()
{
__git_find_repo_path
if [ -d "$__git_repo_path"/rebase-apply ]; then
- __gitcomp "--skip --continue --resolved --abort"
+ __gitcomp "$__git_am_inprogress_options"
return
fi
case "$cur" in
@@ -1086,12 +1124,8 @@ _git_am ()
return
;;
--*)
- __gitcomp "
- --3way --committer-date-is-author-date --ignore-date
- --ignore-whitespace --ignore-space-change
- --interactive --keep --no-utf8 --signoff --utf8
- --whitespace= --scissors
- "
+ __gitcomp_builtin am "--no-utf8" \
+ "$__git_am_inprogress_options"
return
esac
}
@@ -1104,14 +1138,7 @@ _git_apply ()
return
;;
--*)
- __gitcomp "
- --stat --numstat --summary --check --index
- --cached --index-info --reverse --reject --unidiff-zero
- --apply --no-add --exclude=
- --ignore-whitespace --ignore-space-change
- --whitespace= --inaccurate-eof --verbose
- --recount --directory=
- "
+ __gitcomp_builtin apply
return
esac
}
@@ -1120,10 +1147,7 @@ _git_add ()
{
case "$cur" in
--*)
- __gitcomp "
- --interactive --refresh --patch --update --dry-run
- --ignore-errors --intent-to-add --force --edit --chmod=
- "
+ __gitcomp_builtin add
return
esac
@@ -1200,12 +1224,8 @@ _git_branch ()
__git_complete_refs --cur="${cur##--set-upstream-to=}"
;;
--*)
- __gitcomp "
- --color --no-color --verbose --abbrev= --no-abbrev
- --track --no-track --contains --no-contains --merged --no-merged
- --set-upstream-to= --edit-description --list
- --unset-upstream --delete --move --copy --remotes
- --column --no-column --sort= --points-at
+ __gitcomp_builtin branch "--no-color --no-abbrev
+ --no-track --no-column
"
;;
*)
@@ -1247,11 +1267,7 @@ _git_checkout ()
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
;;
--*)
- __gitcomp "
- --quiet --ours --theirs --track --no-track --merge
- --conflict= --orphan --patch --detach --ignore-skip-worktree-bits
- --recurse-submodules --no-recurse-submodules
- "
+ __gitcomp_builtin checkout "--no-track --no-recurse-submodules"
;;
*)
# check if --track, --no-track, or --no-guess was specified
@@ -1271,16 +1287,19 @@ _git_cherry ()
__git_complete_refs
}
+__git_cherry_pick_inprogress_options="--continue --quit --abort"
+
_git_cherry_pick ()
{
__git_find_repo_path
if [ -f "$__git_repo_path"/CHERRY_PICK_HEAD ]; then
- __gitcomp "--continue --quit --abort"
+ __gitcomp "$__git_cherry_pick_inprogress_options"
return
fi
case "$cur" in
--*)
- __gitcomp "--edit --no-commit --signoff --strategy= --mainline"
+ __gitcomp_builtin cherry-pick "" \
+ "$__git_cherry_pick_inprogress_options"
;;
*)
__git_complete_refs
@@ -1292,7 +1311,7 @@ _git_clean ()
{
case "$cur" in
--*)
- __gitcomp "--dry-run --quiet"
+ __gitcomp_builtin clean
return
;;
esac
@@ -1305,26 +1324,7 @@ _git_clone ()
{
case "$cur" in
--*)
- __gitcomp "
- --local
- --no-hardlinks
- --shared
- --reference
- --quiet
- --no-checkout
- --bare
- --mirror
- --origin
- --upload-pack
- --template=
- --depth
- --single-branch
- --no-tags
- --branch
- --recurse-submodules
- --no-single-branch
- --shallow-submodules
- "
+ __gitcomp_builtin clone "--no-single-branch"
return
;;
esac
@@ -1357,16 +1357,7 @@ _git_commit ()
return
;;
--*)
- __gitcomp "
- --all --author= --signoff --verify --no-verify
- --edit --no-edit
- --amend --include --only --interactive
- --dry-run --reuse-message= --reedit-message=
- --reset-author --file= --message= --template=
- --cleanup= --untracked-files --untracked-files=
- --verbose --quiet --fixup= --squash=
- --patch --short --date --allow-empty
- "
+ __gitcomp_builtin commit "--no-edit --verify"
return
esac
@@ -1382,11 +1373,7 @@ _git_describe ()
{
case "$cur" in
--*)
- __gitcomp "
- --all --tags --contains --abbrev= --candidates=
- --exact-match --debug --long --match --always --first-parent
- --exclude --dirty --broken
- "
+ __gitcomp_builtin describe
return
esac
__git_complete_refs
@@ -1411,7 +1398,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
--dirstat --dirstat= --dirstat-by-file
--dirstat-by-file= --cumulative
--diff-algorithm=
- --submodule --submodule=
+ --submodule --submodule= --ignore-submodules
"
_git_diff ()
@@ -1452,11 +1439,11 @@ _git_difftool ()
return
;;
--*)
- __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
- --base --ours --theirs
- --no-renames --diff-filter= --find-copies-harder
- --relative --ignore-submodules
- --tool="
+ __gitcomp_builtin difftool "$__git_diff_common_options
+ --base --cached --ours --theirs
+ --pickaxe-all --pickaxe-regex
+ --relative --staged
+ "
return
;;
esac
@@ -1465,12 +1452,6 @@ _git_difftool ()
__git_fetch_recurse_submodules="yes on-demand no"
-__git_fetch_options="
- --quiet --verbose --append --upload-pack --force --keep --depth=
- --tags --no-tags --all --prune --dry-run --recurse-submodules=
- --unshallow --update-shallow
-"
-
_git_fetch ()
{
case "$cur" in
@@ -1479,7 +1460,7 @@ _git_fetch ()
return
;;
--*)
- __gitcomp "$__git_fetch_options"
+ __gitcomp_builtin fetch "--no-tags"
return
;;
esac
@@ -1516,10 +1497,7 @@ _git_fsck ()
{
case "$cur" in
--*)
- __gitcomp "
- --tags --root --unreachable --cache --no-reflogs --full
- --strict --verbose --lost-found --name-objects
- "
+ __gitcomp_builtin fsck "--no-reflogs"
return
;;
esac
@@ -1529,7 +1507,7 @@ _git_gc ()
{
case "$cur" in
--*)
- __gitcomp "--prune --aggressive"
+ __gitcomp_builtin gc
return
;;
esac
@@ -1585,21 +1563,7 @@ _git_grep ()
case "$cur" in
--*)
- __gitcomp "
- --cached
- --text --ignore-case --word-regexp --invert-match
- --full-name --line-number
- --extended-regexp --basic-regexp --fixed-strings
- --perl-regexp
- --threads
- --files-with-matches --name-only
- --files-without-match
- --max-depth
- --count
- --and --or --not --all-match
- --break --heading --show-function --function-context
- --untracked --no-index
- "
+ __gitcomp_builtin grep
return
;;
esac
@@ -1617,7 +1581,7 @@ _git_help ()
{
case "$cur" in
--*)
- __gitcomp "--all --guides --info --man --web"
+ __gitcomp_builtin help
return
;;
esac
@@ -1640,7 +1604,7 @@ _git_init ()
return
;;
--*)
- __gitcomp "--quiet --bare --template= --shared --shared="
+ __gitcomp_builtin init
return
;;
esac
@@ -1650,13 +1614,7 @@ _git_ls_files ()
{
case "$cur" in
--*)
- __gitcomp "--cached --deleted --modified --others --ignored
- --stage --directory --no-empty-directory --unmerged
- --killed --exclude= --exclude-from=
- --exclude-per-directory= --exclude-standard
- --error-unmatch --with-tree= --full-name
- --abbrev --ignored --exclude-per-directory
- "
+ __gitcomp_builtin ls-files "--no-empty-directory"
return
;;
esac
@@ -1670,7 +1628,7 @@ _git_ls_remote ()
{
case "$cur" in
--*)
- __gitcomp "--heads --tags --refs --get-url --symref"
+ __gitcomp_builtin ls-remote
return
;;
esac
@@ -1794,22 +1752,18 @@ _git_log ()
__git_complete_revlist
}
-# Common merge options shared by git-merge(1) and git-pull(1).
-__git_merge_options="
- --no-commit --no-stat --log --no-log --squash --strategy
- --commit --stat --no-squash --ff --no-ff --ff-only --edit --no-edit
- --verify-signatures --no-verify-signatures --gpg-sign
- --quiet --verbose --progress --no-progress
-"
-
_git_merge ()
{
__git_complete_strategy && return
case "$cur" in
--*)
- __gitcomp "$__git_merge_options
- --rerere-autoupdate --no-rerere-autoupdate --abort --continue"
+ __gitcomp_builtin merge "--no-rerere-autoupdate
+ --no-commit --no-edit --no-ff
+ --no-log --no-progress
+ --no-squash --no-stat
+ --no-verify-signatures
+ "
return
esac
__git_complete_refs
@@ -1833,7 +1787,7 @@ _git_merge_base ()
{
case "$cur" in
--*)
- __gitcomp "--octopus --independent --is-ancestor --fork-point"
+ __gitcomp_builtin merge-base
return
;;
esac
@@ -1844,7 +1798,7 @@ _git_mv ()
{
case "$cur" in
--*)
- __gitcomp "--dry-run"
+ __gitcomp_builtin mv
return
;;
esac
@@ -1860,17 +1814,17 @@ _git_mv ()
_git_name_rev ()
{
- __gitcomp "--tags --all --stdin"
+ __gitcomp_builtin name-rev
}
_git_notes ()
{
- local subcommands='add append copy edit list prune remove show'
+ local subcommands='add append copy edit get-ref list merge prune remove show'
local subcommand="$(__git_find_on_cmdline "$subcommands")"
case "$subcommand,$cur" in
,--*)
- __gitcomp '--ref'
+ __gitcomp_builtin notes
;;
,*)
case "$prev" in
@@ -1882,21 +1836,14 @@ _git_notes ()
;;
esac
;;
- add,--reuse-message=*|append,--reuse-message=*|\
- add,--reedit-message=*|append,--reedit-message=*)
+ *,--reuse-message=*|*,--reedit-message=*)
__git_complete_refs --cur="${cur#*=}"
;;
- add,--*|append,--*)
- __gitcomp '--file= --message= --reedit-message=
- --reuse-message='
+ *,--*)
+ __gitcomp_builtin notes_$subcommand
;;
- copy,--*)
- __gitcomp '--stdin'
- ;;
- prune,--*)
- __gitcomp '--dry-run --verbose'
- ;;
- prune,*)
+ prune,*|get-ref,*)
+ # this command does not take a ref, do not complete it
;;
*)
case "$prev" in
@@ -1920,12 +1867,11 @@ _git_pull ()
return
;;
--*)
- __gitcomp "
- --rebase --no-rebase
- --autostash --no-autostash
- $__git_merge_options
- $__git_fetch_options
- "
+ __gitcomp_builtin pull "--no-autostash --no-commit --no-edit
+ --no-ff --no-log --no-progress --no-rebase
+ --no-squash --no-stat --no-tags
+ --no-verify-signatures"
+
return
;;
esac
@@ -1976,12 +1922,7 @@ _git_push ()
return
;;
--*)
- __gitcomp "
- --all --mirror --tags --dry-run --force --verbose
- --quiet --prune --delete --follow-tags
- --receive-pack= --repo= --set-upstream
- --force-with-lease --force-with-lease= --recurse-submodules=
- "
+ __gitcomp_builtin push
return
;;
esac
@@ -1992,11 +1933,11 @@ _git_rebase ()
{
__git_find_repo_path
if [ -f "$__git_repo_path"/rebase-merge/interactive ]; then
- __gitcomp "--continue --skip --abort --quit --edit-todo"
+ __gitcomp "--continue --skip --abort --quit --edit-todo --show-current-patch"
return
elif [ -d "$__git_repo_path"/rebase-apply ] || \
[ -d "$__git_repo_path"/rebase-merge ]; then
- __gitcomp "--continue --skip --abort --quit"
+ __gitcomp "--continue --skip --abort --quit --show-current-patch"
return
fi
__git_complete_strategy && return
@@ -2016,6 +1957,7 @@ _git_rebase ()
--autostash --no-autostash
--verify --no-verify
--keep-empty --root --force-rebase --no-ff
+ --rerere-autoupdate
--exec
"
@@ -2081,7 +2023,7 @@ _git_send_email ()
--compose --confirm= --dry-run --envelope-sender
--from --identity
--in-reply-to --no-chain-reply-to --no-signed-off-by-cc
- --no-suppress-from --no-thread --quiet
+ --no-suppress-from --no-thread --quiet --reply-to
--signed-off-by-cc --smtp-pass --smtp-server
--smtp-server-port --smtp-encryption= --smtp-user
--subject --suppress-cc= --suppress-from --thread --to
@@ -2119,11 +2061,7 @@ _git_status ()
return
;;
--*)
- __gitcomp "
- --short --branch --porcelain --long --verbose
- --untracked-files= --ignore-submodules= --ignored
- --column= --no-column
- "
+ __gitcomp_builtin status "--no-column"
return
;;
esac
@@ -2265,14 +2203,7 @@ _git_config ()
esac
case "$cur" in
--*)
- __gitcomp "
- --system --global --local --file=
- --list --replace-all
- --get --get-all --get-regexp
- --add --unset --unset-all
- --remove-section --rename-section
- --name-only
- "
+ __gitcomp_builtin config
return
;;
branch.*.*)
@@ -2672,7 +2603,7 @@ _git_remote ()
if [ -z "$subcommand" ]; then
case "$cur" in
--*)
- __gitcomp "--verbose"
+ __gitcomp_builtin remote
;;
*)
__gitcomp "$subcommands"
@@ -2683,33 +2614,33 @@ _git_remote ()
case "$subcommand,$cur" in
add,--*)
- __gitcomp "--track --master --fetch --tags --no-tags --mirror="
+ __gitcomp_builtin remote_add "--no-tags"
;;
add,*)
;;
set-head,--*)
- __gitcomp "--auto --delete"
+ __gitcomp_builtin remote_set-head
;;
set-branches,--*)
- __gitcomp "--add"
+ __gitcomp_builtin remote_set-branches
;;
set-head,*|set-branches,*)
__git_complete_remote_or_refspec
;;
update,--*)
- __gitcomp "--prune"
+ __gitcomp_builtin remote_update
;;
update,*)
__gitcomp "$(__git_get_config_variables "remotes")"
;;
set-url,--*)
- __gitcomp "--push --add --delete"
+ __gitcomp_builtin remote_set-url
;;
get-url,--*)
- __gitcomp "--push --all"
+ __gitcomp_builtin remote_get-url
;;
prune,--*)
- __gitcomp "--dry-run"
+ __gitcomp_builtin remote_prune
;;
*)
__gitcomp_nl "$(__git_remotes)"
@@ -2721,7 +2652,7 @@ _git_replace ()
{
case "$cur" in
--*)
- __gitcomp "--edit --graft --format= --list --delete"
+ __gitcomp_builtin replace
return
;;
esac
@@ -2745,26 +2676,26 @@ _git_reset ()
case "$cur" in
--*)
- __gitcomp "--merge --mixed --hard --soft --patch --keep"
+ __gitcomp_builtin reset
return
;;
esac
__git_complete_refs
}
+__git_revert_inprogress_options="--continue --quit --abort"
+
_git_revert ()
{
__git_find_repo_path
if [ -f "$__git_repo_path"/REVERT_HEAD ]; then
- __gitcomp "--continue --quit --abort"
+ __gitcomp "$__git_revert_inprogress_options"
return
fi
case "$cur" in
--*)
- __gitcomp "
- --edit --mainline --no-edit --no-commit --signoff
- --strategy= --strategy-option=
- "
+ __gitcomp_builtin revert "--no-edit" \
+ "$__git_revert_inprogress_options"
return
;;
esac
@@ -2775,7 +2706,7 @@ _git_rm ()
{
case "$cur" in
--*)
- __gitcomp "--cached --dry-run --ignore-unmatch --quiet"
+ __gitcomp_builtin rm
return
;;
esac
@@ -2833,12 +2764,7 @@ _git_show_branch ()
{
case "$cur" in
--*)
- __gitcomp "
- --all --remotes --topo-order --date-order --current --more=
- --list --independent --merge-base --no-name
- --color --no-color
- --sha1-name --sparse --topics --reflog
- "
+ __gitcomp_builtin show-branch "--no-color"
return
;;
esac
@@ -3045,7 +2971,7 @@ _git_tag ()
while [ $c -lt $cword ]; do
i="${words[c]}"
case "$i" in
- -d|-v)
+ -d|--delete|-v|--verify)
__gitcomp_direct "$(__git_tags "" "$cur" " ")"
return
;;
@@ -3071,11 +2997,7 @@ _git_tag ()
case "$cur" in
--*)
- __gitcomp "
- --list --delete --verify --annotate --message --file
- --sign --cleanup --local-user --force --column --sort=
- --contains --no-contains --points-at --merged --no-merged --create-reflog
- "
+ __gitcomp_builtin tag
;;
esac
}
@@ -3087,23 +3009,26 @@ _git_whatchanged ()
_git_worktree ()
{
- local subcommands="add list lock prune unlock"
+ local subcommands="add list lock move prune remove unlock"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
else
case "$subcommand,$cur" in
add,--*)
- __gitcomp "--detach"
+ __gitcomp_builtin worktree_add
;;
list,--*)
- __gitcomp "--porcelain"
+ __gitcomp_builtin worktree_list
;;
lock,--*)
- __gitcomp "--reason"
+ __gitcomp_builtin worktree_lock
;;
prune,--*)
- __gitcomp "--dry-run --expire --verbose"
+ __gitcomp_builtin worktree_prune
+ ;;
+ remove,--*)
+ __gitcomp "--force"
;;
*)
;;
diff --git a/contrib/examples/builtin-fetch--tool.c b/contrib/examples/builtin-fetch--tool.c
index a3eb19d..22648c3 100644
--- a/contrib/examples/builtin-fetch--tool.c
+++ b/contrib/examples/builtin-fetch--tool.c
@@ -15,7 +15,7 @@ static char *get_stdin(void)
static void show_new(enum object_type type, unsigned char *sha1_new)
{
- fprintf(stderr, " %s: %s\n", typename(type),
+ fprintf(stderr, " %s: %s\n", type_name(type),
find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
}
diff --git a/contrib/examples/git-difftool.perl b/contrib/examples/git-difftool.perl
index fb0fd0b..b2ea80f 100755
--- a/contrib/examples/git-difftool.perl
+++ b/contrib/examples/git-difftool.perl
@@ -13,7 +13,7 @@
use 5.008;
use strict;
use warnings;
-use Git::Error qw(:try);
+use Git::LoadCPAN::Error qw(:try);
use File::Basename qw(dirname);
use File::Copy;
use File::Find;
diff --git a/contrib/examples/git-svnimport.perl b/contrib/examples/git-svnimport.perl
index c414f0d..75a43e2 100755
--- a/contrib/examples/git-svnimport.perl
+++ b/contrib/examples/git-svnimport.perl
@@ -238,7 +238,7 @@ sub pdate($) {
my($d) = @_;
$d =~ m#(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)#
or die "Unparseable date: $d\n";
- my $y=$1; $y-=1900 if $y>1900;
+ my $y=$1; $y+=1900 if $y<1000;
return timegm($6||0,$5,$4,$3,$2-1,$y);
}
diff --git a/contrib/hooks/pre-auto-gc-battery b/contrib/hooks/pre-auto-gc-battery
index 6a2cdeb..7ba78c4 100755
--- a/contrib/hooks/pre-auto-gc-battery
+++ b/contrib/hooks/pre-auto-gc-battery
@@ -17,7 +17,7 @@
# ln -sf /usr/share/git-core/contrib/hooks/pre-auto-gc-battery \
# hooks/pre-auto-gc
-if test -x /sbin/on_ac_power && /sbin/on_ac_power
+if test -x /sbin/on_ac_power && (/sbin/on_ac_power;test $? -ne 1)
then
exit 0
elif test "$(cat /sys/class/power_supply/AC/online 2>/dev/null)" = 1
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index dec085a..d3f39a8 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -297,7 +297,7 @@ find_latest_squash () {
main=
sub=
git log --grep="^git-subtree-dir: $dir/*\$" \
- --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD |
+ --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD |
while read a b junk
do
debug "$a $b $junk"
@@ -341,7 +341,7 @@ find_existing_splits () {
main=
sub=
git log --grep="^git-subtree-dir: $dir/*\$" \
- --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
+ --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
while read a b junk
do
case "$a" in
@@ -382,7 +382,7 @@ copy_commit () {
# We're going to set some environment vars here, so
# do it in a subshell to get rid of them safely later
debug copy_commit "{$1}" "{$2}" "{$3}"
- git log -1 --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" |
+ git log -1 --no-show-signature --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" |
(
read GIT_AUTHOR_NAME
read GIT_AUTHOR_EMAIL
@@ -462,8 +462,8 @@ squash_msg () {
oldsub_short=$(git rev-parse --short "$oldsub")
echo "Squashed '$dir/' changes from $oldsub_short..$newsub_short"
echo
- git log --pretty=tformat:'%h %s' "$oldsub..$newsub"
- git log --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub"
+ git log --no-show-signature --pretty=tformat:'%h %s' "$oldsub..$newsub"
+ git log --no-show-signature --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub"
else
echo "Squashed '$dir/' content from commit $newsub_short"
fi
@@ -475,7 +475,7 @@ squash_msg () {
toptree_for_commit () {
commit="$1"
- git log -1 --pretty=format:'%T' "$commit" -- || exit $?
+ git rev-parse --verify "$commit^{tree}" || exit $?
}
subtree_for_commit () {
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 60d76cd..352deda 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -28,7 +28,7 @@ as a subdirectory of your application.
Subtrees are not to be confused with submodules, which are meant for
the same task. Unlike submodules, subtrees do not need any special
-constructions (like .gitmodule files or gitlinks) be present in
+constructions (like .gitmodules files or gitlinks) be present in
your repository, and do not force end-users of your
repository to do anything special or to understand how subtrees
work. A subtree is just a subdirectory that can be
diff --git a/convert.c b/convert.c
index b976eb9..c480097 100644
--- a/convert.c
+++ b/convert.c
@@ -898,7 +898,7 @@ static int ident_to_git(const char *path, const char *src, size_t len,
static int ident_to_worktree(const char *path, const char *src, size_t len,
struct strbuf *buf, int ident)
{
- unsigned char sha1[20];
+ struct object_id oid;
char *to_free = NULL, *dollar, *spc;
int cnt;
@@ -912,9 +912,9 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
/* are we "faking" in place editing ? */
if (src == buf->buf)
to_free = strbuf_detach(buf, NULL);
- hash_sha1_file(src, len, "blob", sha1);
+ hash_object_file(src, len, "blob", &oid);
- strbuf_grow(buf, len + cnt * 43);
+ strbuf_grow(buf, len + cnt * (the_hash_algo->hexsz + 3));
for (;;) {
/* step 1: run to the next '$' */
dollar = memchr(src, '$', len);
@@ -969,7 +969,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
/* step 4: substitute */
strbuf_addstr(buf, "Id: ");
- strbuf_add(buf, sha1_to_hex(sha1), 40);
+ strbuf_addstr(buf, oid_to_hex(&oid));
strbuf_addstr(buf, " $");
}
strbuf_add(buf, src, len);
@@ -1510,7 +1510,7 @@ struct ident_filter {
struct stream_filter filter;
struct strbuf left;
int state;
- char ident[45]; /* ": x40 $" */
+ char ident[GIT_MAX_HEXSZ + 5]; /* ": x40 $" */
};
static int is_foreign_ident(const char *str)
@@ -1635,12 +1635,12 @@ static struct stream_filter_vtbl ident_vtbl = {
ident_free_fn,
};
-static struct stream_filter *ident_filter(const unsigned char *sha1)
+static struct stream_filter *ident_filter(const struct object_id *oid)
{
struct ident_filter *ident = xmalloc(sizeof(*ident));
xsnprintf(ident->ident, sizeof(ident->ident),
- ": %s $", sha1_to_hex(sha1));
+ ": %s $", oid_to_hex(oid));
strbuf_init(&ident->left, 0);
ident->filter.vtbl = &ident_vtbl;
ident->state = 0;
@@ -1655,7 +1655,7 @@ static struct stream_filter *ident_filter(const unsigned char *sha1)
* Note that you would be crazy to set CRLF, smuge/clean or ident to a
* large binary blob you would want us not to slurp into the memory!
*/
-struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)
+struct stream_filter *get_stream_filter(const char *path, const struct object_id *oid)
{
struct conv_attrs ca;
struct stream_filter *filter = NULL;
@@ -1668,7 +1668,7 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
return NULL;
if (ca.ident)
- filter = ident_filter(sha1);
+ filter = ident_filter(oid);
if (output_eol(ca.crlf_action) == EOL_CRLF)
filter = cascade_filter(filter, lf_to_crlf_filter());
diff --git a/convert.h b/convert.h
index 65ab3e5..2e9b4f4 100644
--- a/convert.h
+++ b/convert.h
@@ -93,7 +93,7 @@ extern int would_convert_to_git_filter_fd(const char *path);
struct stream_filter; /* opaque */
-extern struct stream_filter *get_stream_filter(const char *path, const unsigned char *);
+extern struct stream_filter *get_stream_filter(const char *path, const struct object_id *);
extern void free_stream_filter(struct stream_filter *);
extern int is_null_stream_filter(struct stream_filter *);
diff --git a/csum-file.c b/csum-file.c
index 2adae04..5eda7fb 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -11,7 +11,7 @@
#include "progress.h"
#include "csum-file.h"
-static void flush(struct sha1file *f, const void *buf, unsigned int count)
+static void flush(struct hashfile *f, const void *buf, unsigned int count)
{
if (0 <= f->check_fd && count) {
unsigned char check_buffer[8192];
@@ -42,28 +42,28 @@ static void flush(struct sha1file *f, const void *buf, unsigned int count)
}
}
-void sha1flush(struct sha1file *f)
+void hashflush(struct hashfile *f)
{
unsigned offset = f->offset;
if (offset) {
- git_SHA1_Update(&f->ctx, f->buffer, offset);
+ the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
flush(f, f->buffer, offset);
f->offset = 0;
}
}
-int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
+int hashclose(struct hashfile *f, unsigned char *result, unsigned int flags)
{
int fd;
- sha1flush(f);
- git_SHA1_Final(f->buffer, &f->ctx);
+ hashflush(f);
+ the_hash_algo->final_fn(f->buffer, &f->ctx);
if (result)
hashcpy(result, f->buffer);
if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
/* write checksum and close fd */
- flush(f, f->buffer, 20);
+ flush(f, f->buffer, the_hash_algo->rawsz);
if (flags & CSUM_FSYNC)
fsync_or_die(f->fd, f->name);
if (close(f->fd))
@@ -86,7 +86,7 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
return fd;
}
-void sha1write(struct sha1file *f, const void *buf, unsigned int count)
+void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
{
while (count) {
unsigned offset = f->offset;
@@ -110,7 +110,7 @@ void sha1write(struct sha1file *f, const void *buf, unsigned int count)
buf = (char *) buf + nr;
left -= nr;
if (!left) {
- git_SHA1_Update(&f->ctx, data, offset);
+ the_hash_algo->update_fn(&f->ctx, data, offset);
flush(f, data, offset);
offset = 0;
}
@@ -118,15 +118,15 @@ void sha1write(struct sha1file *f, const void *buf, unsigned int count)
}
}
-struct sha1file *sha1fd(int fd, const char *name)
+struct hashfile *hashfd(int fd, const char *name)
{
- return sha1fd_throughput(fd, name, NULL);
+ return hashfd_throughput(fd, name, NULL);
}
-struct sha1file *sha1fd_check(const char *name)
+struct hashfile *hashfd_check(const char *name)
{
int sink, check;
- struct sha1file *f;
+ struct hashfile *f;
sink = open("/dev/null", O_WRONLY);
if (sink < 0)
@@ -134,14 +134,14 @@ struct sha1file *sha1fd_check(const char *name)
check = open(name, O_RDONLY);
if (check < 0)
die_errno("unable to open '%s'", name);
- f = sha1fd(sink, name);
+ f = hashfd(sink, name);
f->check_fd = check;
return f;
}
-struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
+struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp)
{
- struct sha1file *f = xmalloc(sizeof(*f));
+ struct hashfile *f = xmalloc(sizeof(*f));
f->fd = fd;
f->check_fd = -1;
f->offset = 0;
@@ -149,18 +149,18 @@ struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp
f->tp = tp;
f->name = name;
f->do_crc = 0;
- git_SHA1_Init(&f->ctx);
+ the_hash_algo->init_fn(&f->ctx);
return f;
}
-void sha1file_checkpoint(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
+void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
{
- sha1flush(f);
+ hashflush(f);
checkpoint->offset = f->total;
checkpoint->ctx = f->ctx;
}
-int sha1file_truncate(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
+int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
{
off_t offset = checkpoint->offset;
@@ -169,17 +169,17 @@ int sha1file_truncate(struct sha1file *f, struct sha1file_checkpoint *checkpoint
return -1;
f->total = offset;
f->ctx = checkpoint->ctx;
- f->offset = 0; /* sha1flush() was called in checkpoint */
+ f->offset = 0; /* hashflush() was called in checkpoint */
return 0;
}
-void crc32_begin(struct sha1file *f)
+void crc32_begin(struct hashfile *f)
{
f->crc32 = crc32(0, NULL, 0);
f->do_crc = 1;
}
-uint32_t crc32_end(struct sha1file *f)
+uint32_t crc32_end(struct hashfile *f)
{
f->do_crc = 0;
return f->crc32;
diff --git a/csum-file.h b/csum-file.h
index 7530927..992e5c0 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -4,11 +4,11 @@
struct progress;
/* A SHA1-protected file */
-struct sha1file {
+struct hashfile {
int fd;
int check_fd;
unsigned int offset;
- git_SHA_CTX ctx;
+ git_hash_ctx ctx;
off_t total;
struct progress *tp;
const char *name;
@@ -18,36 +18,36 @@ struct sha1file {
};
/* Checkpoint */
-struct sha1file_checkpoint {
+struct hashfile_checkpoint {
off_t offset;
- git_SHA_CTX ctx;
+ git_hash_ctx ctx;
};
-extern void sha1file_checkpoint(struct sha1file *, struct sha1file_checkpoint *);
-extern int sha1file_truncate(struct sha1file *, struct sha1file_checkpoint *);
+extern void hashfile_checkpoint(struct hashfile *, struct hashfile_checkpoint *);
+extern int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *);
-/* sha1close flags */
+/* hashclose flags */
#define CSUM_CLOSE 1
#define CSUM_FSYNC 2
-extern struct sha1file *sha1fd(int fd, const char *name);
-extern struct sha1file *sha1fd_check(const char *name);
-extern struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp);
-extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
-extern void sha1write(struct sha1file *, const void *, unsigned int);
-extern void sha1flush(struct sha1file *f);
-extern void crc32_begin(struct sha1file *);
-extern uint32_t crc32_end(struct sha1file *);
+extern struct hashfile *hashfd(int fd, const char *name);
+extern struct hashfile *hashfd_check(const char *name);
+extern struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp);
+extern int hashclose(struct hashfile *, unsigned char *, unsigned int);
+extern void hashwrite(struct hashfile *, const void *, unsigned int);
+extern void hashflush(struct hashfile *f);
+extern void crc32_begin(struct hashfile *);
+extern uint32_t crc32_end(struct hashfile *);
-static inline void sha1write_u8(struct sha1file *f, uint8_t data)
+static inline void hashwrite_u8(struct hashfile *f, uint8_t data)
{
- sha1write(f, &data, sizeof(data));
+ hashwrite(f, &data, sizeof(data));
}
-static inline void sha1write_be32(struct sha1file *f, uint32_t data)
+static inline void hashwrite_be32(struct hashfile *f, uint32_t data)
{
data = htonl(data);
- sha1write(f, &data, sizeof(data));
+ hashwrite(f, &data, sizeof(data));
}
#endif
diff --git a/daemon.c b/daemon.c
index 72dfeaf..fe833ea 100644
--- a/daemon.c
+++ b/daemon.c
@@ -9,7 +9,12 @@
#define initgroups(x, y) (0) /* nothing */
#endif
-static int log_syslog;
+static enum log_destination {
+ LOG_DESTINATION_UNSET = -1,
+ LOG_DESTINATION_NONE = 0,
+ LOG_DESTINATION_STDERR = 1,
+ LOG_DESTINATION_SYSLOG = 2,
+} log_destination = LOG_DESTINATION_UNSET;
static int verbose;
static int reuseaddr;
static int informative_errors;
@@ -25,6 +30,7 @@ static const char daemon_usage[] =
" [--access-hook=<path>]\n"
" [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
" [--detach] [--user=<user> [--group=<group>]]\n"
+" [--log-destination=(stderr|syslog|none)]\n"
" [<directory>...]";
/* List of acceptable pathname prefixes */
@@ -74,11 +80,14 @@ static const char *get_ip_address(struct hostinfo *hi)
static void logreport(int priority, const char *err, va_list params)
{
- if (log_syslog) {
+ switch (log_destination) {
+ case LOG_DESTINATION_SYSLOG: {
char buf[1024];
vsnprintf(buf, sizeof(buf), err, params);
syslog(priority, "%s", buf);
- } else {
+ break;
+ }
+ case LOG_DESTINATION_STDERR:
/*
* Since stderr is set to buffered mode, the
* logging of different processes will not overlap
@@ -88,6 +97,11 @@ static void logreport(int priority, const char *err, va_list params)
vfprintf(stderr, err, params);
fputc('\n', stderr);
fflush(stderr);
+ break;
+ case LOG_DESTINATION_NONE:
+ break;
+ case LOG_DESTINATION_UNSET:
+ BUG("log destination not initialized correctly");
}
}
@@ -1286,7 +1300,6 @@ int cmd_main(int argc, const char **argv)
}
if (!strcmp(arg, "--inetd")) {
inetd_mode = 1;
- log_syslog = 1;
continue;
}
if (!strcmp(arg, "--verbose")) {
@@ -1294,9 +1307,22 @@ int cmd_main(int argc, const char **argv)
continue;
}
if (!strcmp(arg, "--syslog")) {
- log_syslog = 1;
+ log_destination = LOG_DESTINATION_SYSLOG;
continue;
}
+ if (skip_prefix(arg, "--log-destination=", &v)) {
+ if (!strcmp(v, "syslog")) {
+ log_destination = LOG_DESTINATION_SYSLOG;
+ continue;
+ } else if (!strcmp(v, "stderr")) {
+ log_destination = LOG_DESTINATION_STDERR;
+ continue;
+ } else if (!strcmp(v, "none")) {
+ log_destination = LOG_DESTINATION_NONE;
+ continue;
+ } else
+ die("unknown log destination '%s'", v);
+ }
if (!strcmp(arg, "--export-all")) {
export_all_trees = 1;
continue;
@@ -1353,7 +1379,6 @@ int cmd_main(int argc, const char **argv)
}
if (!strcmp(arg, "--detach")) {
detach = 1;
- log_syslog = 1;
continue;
}
if (skip_prefix(arg, "--user=", &v)) {
@@ -1399,7 +1424,14 @@ int cmd_main(int argc, const char **argv)
usage(daemon_usage);
}
- if (log_syslog) {
+ if (log_destination == LOG_DESTINATION_UNSET) {
+ if (inetd_mode || detach)
+ log_destination = LOG_DESTINATION_SYSLOG;
+ else
+ log_destination = LOG_DESTINATION_STDERR;
+ }
+
+ if (log_destination == LOG_DESTINATION_SYSLOG) {
openlog("git-daemon", LOG_PID, LOG_DAEMON);
set_die_routine(daemon_die);
} else
diff --git a/diff-lib.c b/diff-lib.c
index 8104603..104f954 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -92,6 +92,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
int diff_unmerged_stage = revs->max_count;
unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
? CE_MATCH_RACY_IS_DIRTY : 0);
+ uint64_t start = getnanotime();
diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
@@ -246,6 +247,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
}
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
+ trace_performance_since(start, "diff-files");
return 0;
}
@@ -302,7 +304,7 @@ static int get_stat_data(const struct cache_entry *ce,
}
static void show_new_file(struct rev_info *revs,
- const struct cache_entry *new,
+ const struct cache_entry *new_file,
int cached, int match_missing)
{
const struct object_id *oid;
@@ -313,16 +315,16 @@ static void show_new_file(struct rev_info *revs,
* New file in the index: it might actually be different in
* the working tree.
*/
- if (get_stat_data(new, &oid, &mode, cached, match_missing,
+ if (get_stat_data(new_file, &oid, &mode, cached, match_missing,
&dirty_submodule, &revs->diffopt) < 0)
return;
- diff_index_show_file(revs, "+", new, oid, !is_null_oid(oid), mode, dirty_submodule);
+ diff_index_show_file(revs, "+", new_file, oid, !is_null_oid(oid), mode, dirty_submodule);
}
static int show_modified(struct rev_info *revs,
- const struct cache_entry *old,
- const struct cache_entry *new,
+ const struct cache_entry *old_entry,
+ const struct cache_entry *new_entry,
int report_missing,
int cached, int match_missing)
{
@@ -330,47 +332,47 @@ static int show_modified(struct rev_info *revs,
const struct object_id *oid;
unsigned dirty_submodule = 0;
- if (get_stat_data(new, &oid, &mode, cached, match_missing,
+ if (get_stat_data(new_entry, &oid, &mode, cached, match_missing,
&dirty_submodule, &revs->diffopt) < 0) {
if (report_missing)
- diff_index_show_file(revs, "-", old,
- &old->oid, 1, old->ce_mode,
+ diff_index_show_file(revs, "-", old_entry,
+ &old_entry->oid, 1, old_entry->ce_mode,
0);
return -1;
}
if (revs->combine_merges && !cached &&
- (oidcmp(oid, &old->oid) || oidcmp(&old->oid, &new->oid))) {
+ (oidcmp(oid, &old_entry->oid) || oidcmp(&old_entry->oid, &new_entry->oid))) {
struct combine_diff_path *p;
- int pathlen = ce_namelen(new);
+ int pathlen = ce_namelen(new_entry);
p = xmalloc(combine_diff_path_size(2, pathlen));
p->path = (char *) &p->parent[2];
p->next = NULL;
- memcpy(p->path, new->name, pathlen);
+ memcpy(p->path, new_entry->name, pathlen);
p->path[pathlen] = 0;
p->mode = mode;
oidclr(&p->oid);
memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
p->parent[0].status = DIFF_STATUS_MODIFIED;
- p->parent[0].mode = new->ce_mode;
- oidcpy(&p->parent[0].oid, &new->oid);
+ p->parent[0].mode = new_entry->ce_mode;
+ oidcpy(&p->parent[0].oid, &new_entry->oid);
p->parent[1].status = DIFF_STATUS_MODIFIED;
- p->parent[1].mode = old->ce_mode;
- oidcpy(&p->parent[1].oid, &old->oid);
+ p->parent[1].mode = old_entry->ce_mode;
+ oidcpy(&p->parent[1].oid, &old_entry->oid);
show_combined_diff(p, 2, revs->dense_combined_merges, revs);
free(p);
return 0;
}
- oldmode = old->ce_mode;
- if (mode == oldmode && !oidcmp(oid, &old->oid) && !dirty_submodule &&
+ oldmode = old_entry->ce_mode;
+ if (mode == oldmode && !oidcmp(oid, &old_entry->oid) && !dirty_submodule &&
!revs->diffopt.flags.find_copies_harder)
return 0;
diff_change(&revs->diffopt, oldmode, mode,
- &old->oid, oid, 1, !is_null_oid(oid),
- old->name, 0, dirty_submodule);
+ &old_entry->oid, oid, 1, !is_null_oid(oid),
+ old_entry->name, 0, dirty_submodule);
return 0;
}
@@ -512,6 +514,7 @@ static int diff_cache(struct rev_info *revs,
int run_diff_index(struct rev_info *revs, int cached)
{
struct object_array_entry *ent;
+ uint64_t start = getnanotime();
ent = revs->pending.objects;
if (diff_cache(revs, &ent->item->oid, ent->name, cached))
@@ -521,6 +524,7 @@ int run_diff_index(struct rev_info *revs, int cached)
diffcore_fix_diff_index(&revs->diffopt);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
+ trace_performance_since(start, "diff-index");
return 0;
}
diff --git a/diff.c b/diff.c
index 21c3838..1289df4 100644
--- a/diff.c
+++ b/diff.c
@@ -1504,7 +1504,7 @@ struct diff_words_style_elem {
struct diff_words_style {
enum diff_words_type type;
- struct diff_words_style_elem new, old, ctx;
+ struct diff_words_style_elem new_word, old_word, ctx;
const char *newline;
};
@@ -1655,12 +1655,12 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
}
if (minus_begin != minus_end) {
fn_out_diff_words_write_helper(diff_words->opt,
- &style->old, style->newline,
+ &style->old_word, style->newline,
minus_end - minus_begin, minus_begin);
}
if (plus_begin != plus_end) {
fn_out_diff_words_write_helper(diff_words->opt,
- &style->new, style->newline,
+ &style->new_word, style->newline,
plus_end - plus_begin, plus_begin);
}
@@ -1758,7 +1758,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
emit_diff_symbol(diff_words->opt, DIFF_SYMBOL_WORD_DIFF,
line_prefix, strlen(line_prefix), 0);
fn_out_diff_words_write_helper(diff_words->opt,
- &style->old, style->newline,
+ &style->old_word, style->newline,
diff_words->minus.text.size,
diff_words->minus.text.ptr);
diff_words->minus.text.size = 0;
@@ -1883,8 +1883,8 @@ static void init_diff_words_data(struct emit_callback *ecbdata,
}
if (want_color(o->use_color)) {
struct diff_words_style *st = ecbdata->diff_words->style;
- st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD);
- st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW);
+ st->old_word.color = diff_get_color_opt(o, DIFF_FILE_OLD);
+ st->new_word.color = diff_get_color_opt(o, DIFF_FILE_NEW);
st->ctx.color = diff_get_color_opt(o, DIFF_CONTEXT);
}
}
@@ -2045,11 +2045,10 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
}
}
-static char *pprint_rename(const char *a, const char *b)
+static void pprint_rename(struct strbuf *name, const char *a, const char *b)
{
- const char *old = a;
- const char *new = b;
- struct strbuf name = STRBUF_INIT;
+ const char *old_name = a;
+ const char *new_name = b;
int pfx_length, sfx_length;
int pfx_adjust_for_slash;
int len_a = strlen(a);
@@ -2059,24 +2058,24 @@ static char *pprint_rename(const char *a, const char *b)
int qlen_b = quote_c_style(b, NULL, NULL, 0);
if (qlen_a || qlen_b) {
- quote_c_style(a, &name, NULL, 0);
- strbuf_addstr(&name, " => ");
- quote_c_style(b, &name, NULL, 0);
- return strbuf_detach(&name, NULL);
+ quote_c_style(a, name, NULL, 0);
+ strbuf_addstr(name, " => ");
+ quote_c_style(b, name, NULL, 0);
+ return;
}
/* Find common prefix */
pfx_length = 0;
- while (*old && *new && *old == *new) {
- if (*old == '/')
- pfx_length = old - a + 1;
- old++;
- new++;
+ while (*old_name && *new_name && *old_name == *new_name) {
+ if (*old_name == '/')
+ pfx_length = old_name - a + 1;
+ old_name++;
+ new_name++;
}
/* Find common suffix */
- old = a + len_a;
- new = b + len_b;
+ old_name = a + len_a;
+ new_name = b + len_b;
sfx_length = 0;
/*
* If there is a common prefix, it must end in a slash. In
@@ -2087,13 +2086,13 @@ static char *pprint_rename(const char *a, const char *b)
* underrun the input strings.
*/
pfx_adjust_for_slash = (pfx_length ? 1 : 0);
- while (a + pfx_length - pfx_adjust_for_slash <= old &&
- b + pfx_length - pfx_adjust_for_slash <= new &&
- *old == *new) {
- if (*old == '/')
- sfx_length = len_a - (old - a);
- old--;
- new--;
+ while (a + pfx_length - pfx_adjust_for_slash <= old_name &&
+ b + pfx_length - pfx_adjust_for_slash <= new_name &&
+ *old_name == *new_name) {
+ if (*old_name == '/')
+ sfx_length = len_a - (old_name - a);
+ old_name--;
+ new_name--;
}
/*
@@ -2109,19 +2108,18 @@ static char *pprint_rename(const char *a, const char *b)
if (b_midlen < 0)
b_midlen = 0;
- strbuf_grow(&name, pfx_length + a_midlen + b_midlen + sfx_length + 7);
+ strbuf_grow(name, pfx_length + a_midlen + b_midlen + sfx_length + 7);
if (pfx_length + sfx_length) {
- strbuf_add(&name, a, pfx_length);
- strbuf_addch(&name, '{');
+ strbuf_add(name, a, pfx_length);
+ strbuf_addch(name, '{');
}
- strbuf_add(&name, a + pfx_length, a_midlen);
- strbuf_addstr(&name, " => ");
- strbuf_add(&name, b + pfx_length, b_midlen);
+ strbuf_add(name, a + pfx_length, a_midlen);
+ strbuf_addstr(name, " => ");
+ strbuf_add(name, b + pfx_length, b_midlen);
if (pfx_length + sfx_length) {
- strbuf_addch(&name, '}');
- strbuf_add(&name, a + len_a - sfx_length, sfx_length);
+ strbuf_addch(name, '}');
+ strbuf_add(name, a + len_a - sfx_length, sfx_length);
}
- return strbuf_detach(&name, NULL);
}
struct diffstat_t {
@@ -2131,6 +2129,7 @@ struct diffstat_t {
char *from_name;
char *name;
char *print_name;
+ const char *comments;
unsigned is_unmerged:1;
unsigned is_binary:1;
unsigned is_renamed:1;
@@ -2197,23 +2196,20 @@ static void show_graph(struct strbuf *out, char ch, int cnt,
static void fill_print_name(struct diffstat_file *file)
{
- char *pname;
+ struct strbuf pname = STRBUF_INIT;
if (file->print_name)
return;
- if (!file->is_renamed) {
- struct strbuf buf = STRBUF_INIT;
- if (quote_c_style(file->name, &buf, NULL, 0)) {
- pname = strbuf_detach(&buf, NULL);
- } else {
- pname = file->name;
- strbuf_release(&buf);
- }
- } else {
- pname = pprint_rename(file->from_name, file->name);
- }
- file->print_name = pname;
+ if (file->is_renamed)
+ pprint_rename(&pname, file->from_name, file->name);
+ else
+ quote_c_style(file->name, &pname, NULL, 0);
+
+ if (file->comments)
+ strbuf_addf(&pname, " (%s)", file->comments);
+
+ file->print_name = strbuf_detach(&pname, NULL);
}
static void print_stat_summary_inserts_deletes(struct diff_options *options,
@@ -2594,14 +2590,14 @@ struct dirstat_dir {
static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir,
unsigned long changed, const char *base, int baselen)
{
- unsigned long this_dir = 0;
+ unsigned long sum_changes = 0;
unsigned int sources = 0;
const char *line_prefix = diff_line_prefix(opt);
while (dir->nr) {
struct dirstat_file *f = dir->files;
int namelen = strlen(f->name);
- unsigned long this;
+ unsigned long changes;
char *slash;
if (namelen < baselen)
@@ -2611,15 +2607,15 @@ static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir,
slash = strchr(f->name + baselen, '/');
if (slash) {
int newbaselen = slash + 1 - f->name;
- this = gather_dirstat(opt, dir, changed, f->name, newbaselen);
+ changes = gather_dirstat(opt, dir, changed, f->name, newbaselen);
sources++;
} else {
- this = f->changed;
+ changes = f->changed;
dir->files++;
dir->nr--;
sources += 2;
}
- this_dir += this;
+ sum_changes += changes;
}
/*
@@ -2629,8 +2625,8 @@ static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir,
* under this directory (sources == 1).
*/
if (baselen && sources != 1) {
- if (this_dir) {
- int permille = this_dir * 1000 / changed;
+ if (sum_changes) {
+ int permille = sum_changes * 1000 / changed;
if (permille >= dir->permille) {
fprintf(opt->file, "%s%4d.%01d%% %.*s\n", line_prefix,
permille / 10, permille % 10, baselen, base);
@@ -2639,7 +2635,7 @@ static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir,
}
}
}
- return this_dir;
+ return sum_changes;
}
static int dirstat_compare(const void *_a, const void *_b)
@@ -2797,8 +2793,7 @@ static void free_diffstat_info(struct diffstat_t *diffstat)
int i;
for (i = 0; i < diffstat->nr; i++) {
struct diffstat_file *f = diffstat->files[i];
- if (f->name != f->print_name)
- free(f->print_name);
+ free(f->print_name);
free(f->name);
free(f->from_name);
free(f);
@@ -3248,6 +3243,32 @@ static void builtin_diff(const char *name_a,
return;
}
+static char *get_compact_summary(const struct diff_filepair *p, int is_renamed)
+{
+ if (!is_renamed) {
+ if (p->status == DIFF_STATUS_ADDED) {
+ if (S_ISLNK(p->two->mode))
+ return "new +l";
+ else if ((p->two->mode & 0777) == 0755)
+ return "new +x";
+ else
+ return "new";
+ } else if (p->status == DIFF_STATUS_DELETED)
+ return "gone";
+ }
+ if (S_ISLNK(p->one->mode) && !S_ISLNK(p->two->mode))
+ return "mode -l";
+ else if (!S_ISLNK(p->one->mode) && S_ISLNK(p->two->mode))
+ return "mode +l";
+ else if ((p->one->mode & 0777) == 0644 &&
+ (p->two->mode & 0777) == 0755)
+ return "mode +x";
+ else if ((p->one->mode & 0777) == 0755 &&
+ (p->two->mode & 0777) == 0644)
+ return "mode -x";
+ return NULL;
+}
+
static void builtin_diffstat(const char *name_a, const char *name_b,
struct diff_filespec *one,
struct diff_filespec *two,
@@ -3267,6 +3288,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
data = diffstat_add(diffstat, name_a, name_b);
data->is_interesting = p->status != DIFF_STATUS_UNKNOWN;
+ if (o->flags.stat_with_summary)
+ data->comments = get_compact_summary(p, data->is_renamed);
if (!one || !two) {
data->is_unmerged = 1;
@@ -3615,7 +3638,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
else {
enum object_type type;
if (size_only || (flags & CHECK_BINARY)) {
- type = sha1_object_info(s->oid.hash, &s->size);
+ type = oid_object_info(&s->oid, &s->size);
if (type < 0)
die("unable to read %s",
oid_to_hex(&s->oid));
@@ -3626,7 +3649,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
return 0;
}
}
- s->data = read_sha1_file(s->oid.hash, &type, &s->size);
+ s->data = read_object_file(&s->oid, &type, &s->size);
if (!s->data)
die("unable to read %s", oid_to_hex(&s->oid));
s->should_free = 1;
@@ -3660,15 +3683,15 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
int mode)
{
struct strbuf buf = STRBUF_INIT;
- struct strbuf template = STRBUF_INIT;
+ struct strbuf tempfile = STRBUF_INIT;
char *path_dup = xstrdup(path);
const char *base = basename(path_dup);
/* Generate "XXXXXX_basename.ext" */
- strbuf_addstr(&template, "XXXXXX_");
- strbuf_addstr(&template, base);
+ strbuf_addstr(&tempfile, "XXXXXX_");
+ strbuf_addstr(&tempfile, base);
- temp->tempfile = mks_tempfile_ts(template.buf, strlen(base) + 1);
+ temp->tempfile = mks_tempfile_ts(tempfile.buf, strlen(base) + 1);
if (!temp->tempfile)
die_errno("unable to create temp-file");
if (convert_to_working_tree(path,
@@ -3683,7 +3706,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
oid_to_hex_r(temp->hex, oid);
xsnprintf(temp->mode, sizeof(temp->mode), "%06o", mode);
strbuf_release(&buf);
- strbuf_release(&template);
+ strbuf_release(&tempfile);
free(path_dup);
}
@@ -3811,7 +3834,7 @@ static int similarity_index(struct diff_filepair *p)
static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev)
{
if (startup_info->have_repository)
- return find_unique_abbrev(oid->hash, abbrev);
+ return find_unique_abbrev(oid, abbrev);
else {
char *hex = oid_to_hex(oid);
if (abbrev < 0)
@@ -4553,6 +4576,11 @@ int diff_opt_parse(struct diff_options *options,
else if (starts_with(arg, "--stat"))
/* --stat, --stat-width, --stat-name-width, or --stat-count */
return stat_opt(options, av);
+ else if (!strcmp(arg, "--compact-summary")) {
+ options->flags.stat_with_summary = 1;
+ options->output_format |= DIFF_FORMAT_DIFFSTAT;
+ } else if (!strcmp(arg, "--no-compact-summary"))
+ options->flags.stat_with_summary = 0;
/* renames options */
else if (starts_with(arg, "-B") ||
@@ -5241,10 +5269,12 @@ static void show_rename_copy(struct diff_options *opt, const char *renamecopy,
struct diff_filepair *p)
{
struct strbuf sb = STRBUF_INIT;
- char *names = pprint_rename(p->one->path, p->two->path);
+ struct strbuf names = STRBUF_INIT;
+
+ pprint_rename(&names, p->one->path, p->two->path);
strbuf_addf(&sb, " %s %s (%d%%)\n",
- renamecopy, names, similarity_index(p));
- free(names);
+ renamecopy, names.buf, similarity_index(p));
+ strbuf_release(&names);
emit_diff_symbol(opt, DIFF_SYMBOL_SUMMARY,
sb.buf, sb.len, 0);
show_mode_change(opt, p, 0);
diff --git a/diff.h b/diff.h
index 6bd278a..d29560f 100644
--- a/diff.h
+++ b/diff.h
@@ -93,6 +93,7 @@ struct diff_flags {
unsigned dirstat_by_line:1;
unsigned funccontext:1;
unsigned default_follow_renames:1;
+ unsigned stat_with_summary:1;
};
static inline void diff_flags_or(struct diff_flags *a,
diff --git a/diffcore-delta.c b/diffcore-delta.c
index ebe70fb..c83d45a 100644
--- a/diffcore-delta.c
+++ b/diffcore-delta.c
@@ -48,16 +48,16 @@ struct spanhash_top {
static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig)
{
- struct spanhash_top *new;
+ struct spanhash_top *new_spanhash;
int i;
int osz = 1 << orig->alloc_log2;
int sz = osz << 1;
- new = xmalloc(st_add(sizeof(*orig),
+ new_spanhash = xmalloc(st_add(sizeof(*orig),
st_mult(sizeof(struct spanhash), sz)));
- new->alloc_log2 = orig->alloc_log2 + 1;
- new->free = INITIAL_FREE(new->alloc_log2);
- memset(new->data, 0, sizeof(struct spanhash) * sz);
+ new_spanhash->alloc_log2 = orig->alloc_log2 + 1;
+ new_spanhash->free = INITIAL_FREE(new_spanhash->alloc_log2);
+ memset(new_spanhash->data, 0, sizeof(struct spanhash) * sz);
for (i = 0; i < osz; i++) {
struct spanhash *o = &(orig->data[i]);
int bucket;
@@ -65,11 +65,11 @@ static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig)
continue;
bucket = o->hashval & (sz - 1);
while (1) {
- struct spanhash *h = &(new->data[bucket++]);
+ struct spanhash *h = &(new_spanhash->data[bucket++]);
if (!h->cnt) {
h->hashval = o->hashval;
h->cnt = o->cnt;
- new->free--;
+ new_spanhash->free--;
break;
}
if (sz <= bucket)
@@ -77,7 +77,7 @@ static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig)
}
}
free(orig);
- return new;
+ return new_spanhash;
}
static struct spanhash_top *add_spanhash(struct spanhash_top *top,
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 888a4b0..0b7e498 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -260,8 +260,8 @@ static unsigned int hash_filespec(struct diff_filespec *filespec)
if (!filespec->oid_valid) {
if (diff_populate_filespec(filespec, 0))
return 0;
- hash_sha1_file(filespec->data, filespec->size, "blob",
- filespec->oid.hash);
+ hash_object_file(filespec->data, filespec->size, "blob",
+ &filespec->oid);
}
return sha1hash(filespec->oid.hash);
}
diff --git a/dir.c b/dir.c
index ce6e50d..63a917b 100644
--- a/dir.c
+++ b/dir.c
@@ -231,12 +231,10 @@ int within_depth(const char *name, int namelen,
* 1 along with { data, size } of the (possibly augmented) buffer
* when successful.
*
- * Optionally updates the given sha1_stat with the given OID (when valid).
+ * Optionally updates the given oid_stat with the given OID (when valid).
*/
-static int do_read_blob(const struct object_id *oid,
- struct sha1_stat *sha1_stat,
- size_t *size_out,
- char **data_out)
+static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,
+ size_t *size_out, char **data_out)
{
enum object_type type;
unsigned long sz;
@@ -245,15 +243,15 @@ static int do_read_blob(const struct object_id *oid,
*size_out = 0;
*data_out = NULL;
- data = read_sha1_file(oid->hash, &type, &sz);
+ data = read_object_file(oid, &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return -1;
}
- if (sha1_stat) {
- memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
- hashcpy(sha1_stat->sha1, oid->hash);
+ if (oid_stat) {
+ memset(&oid_stat->stat, 0, sizeof(oid_stat->stat));
+ oidcpy(&oid_stat->oid, oid);
}
if (sz == 0) {
@@ -654,9 +652,8 @@ void add_exclude(const char *string, const char *base,
static int read_skip_worktree_file_from_index(const struct index_state *istate,
const char *path,
- size_t *size_out,
- char **data_out,
- struct sha1_stat *sha1_stat)
+ size_t *size_out, char **data_out,
+ struct oid_stat *oid_stat)
{
int pos, len;
@@ -667,7 +664,7 @@ static int read_skip_worktree_file_from_index(const struct index_state *istate,
if (!ce_skip_worktree(istate->cache[pos]))
return -1;
- return do_read_blob(&istate->cache[pos]->oid, sha1_stat, size_out, data_out);
+ return do_read_blob(&istate->cache[pos]->oid, oid_stat, size_out, data_out);
}
/*
@@ -774,7 +771,16 @@ static void invalidate_directory(struct untracked_cache *uc,
struct untracked_cache_dir *dir)
{
int i;
- uc->dir_invalidated++;
+
+ /*
+ * Invalidation increment here is just roughly correct. If
+ * untracked_nr or any of dirs[].recurse is non-zero, we
+ * should increment dir_invalidated too. But that's more
+ * expensive to do.
+ */
+ if (dir->valid)
+ uc->dir_invalidated++;
+
dir->valid = 0;
dir->untracked_nr = 0;
for (i = 0; i < dir->dirs_nr; i++)
@@ -795,9 +801,8 @@ static int add_excludes_from_buffer(char *buf, size_t size,
* ss_valid is non-zero, "ss" must contain good value as input.
*/
static int add_excludes(const char *fname, const char *base, int baselen,
- struct exclude_list *el,
- struct index_state *istate,
- struct sha1_stat *sha1_stat)
+ struct exclude_list *el, struct index_state *istate,
+ struct oid_stat *oid_stat)
{
struct stat st;
int r;
@@ -815,16 +820,16 @@ static int add_excludes(const char *fname, const char *base, int baselen,
return -1;
r = read_skip_worktree_file_from_index(istate, fname,
&size, &buf,
- sha1_stat);
+ oid_stat);
if (r != 1)
return r;
} else {
size = xsize_t(st.st_size);
if (size == 0) {
- if (sha1_stat) {
- fill_stat_data(&sha1_stat->stat, &st);
- hashcpy(sha1_stat->sha1, EMPTY_BLOB_SHA1_BIN);
- sha1_stat->valid = 1;
+ if (oid_stat) {
+ fill_stat_data(&oid_stat->stat, &st);
+ oidcpy(&oid_stat->oid, &empty_blob_oid);
+ oid_stat->valid = 1;
}
close(fd);
return 0;
@@ -837,22 +842,23 @@ static int add_excludes(const char *fname, const char *base, int baselen,
}
buf[size++] = '\n';
close(fd);
- if (sha1_stat) {
+ if (oid_stat) {
int pos;
- if (sha1_stat->valid &&
- !match_stat_data_racy(istate, &sha1_stat->stat, &st))
+ if (oid_stat->valid &&
+ !match_stat_data_racy(istate, &oid_stat->stat, &st))
; /* no content change, ss->sha1 still good */
else if (istate &&
(pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&
!ce_stage(istate->cache[pos]) &&
ce_uptodate(istate->cache[pos]) &&
!would_convert_to_git(istate, fname))
- hashcpy(sha1_stat->sha1,
- istate->cache[pos]->oid.hash);
+ oidcpy(&oid_stat->oid,
+ &istate->cache[pos]->oid);
else
- hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
- fill_stat_data(&sha1_stat->stat, &st);
- sha1_stat->valid = 1;
+ hash_object_file(buf, size, "blob",
+ &oid_stat->oid);
+ fill_stat_data(&oid_stat->stat, &st);
+ oid_stat->valid = 1;
}
}
@@ -930,7 +936,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir,
* Used to set up core.excludesfile and .git/info/exclude lists.
*/
static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
- struct sha1_stat *sha1_stat)
+ struct oid_stat *oid_stat)
{
struct exclude_list *el;
/*
@@ -941,7 +947,7 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
if (!dir->untracked)
dir->unmanaged_exclude_files++;
el = add_exclude_list(dir, EXC_FILE, fname);
- if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0)
+ if (add_excludes(fname, "", 0, el, NULL, oid_stat) < 0)
die("cannot use %s as an exclude file", fname);
}
@@ -1180,7 +1186,7 @@ static void prep_exclude(struct dir_struct *dir,
while (current < baselen) {
const char *cp;
- struct sha1_stat sha1_stat;
+ struct oid_stat oid_stat;
stk = xcalloc(1, sizeof(*stk));
if (current < 0) {
@@ -1223,8 +1229,8 @@ static void prep_exclude(struct dir_struct *dir,
}
/* Try to read per-directory file */
- hashclr(sha1_stat.sha1);
- sha1_stat.valid = 0;
+ oidclr(&oid_stat.oid);
+ oid_stat.valid = 0;
if (dir->exclude_per_dir &&
/*
* If we know that no files have been added in
@@ -1252,7 +1258,7 @@ static void prep_exclude(struct dir_struct *dir,
strbuf_addstr(&sb, dir->exclude_per_dir);
el->src = strbuf_detach(&sb, NULL);
add_excludes(el->src, el->src, stk->baselen, el, istate,
- untracked ? &sha1_stat : NULL);
+ untracked ? &oid_stat : NULL);
}
/*
* NEEDSWORK: when untracked cache is enabled, prep_exclude()
@@ -1269,9 +1275,9 @@ static void prep_exclude(struct dir_struct *dir,
* order, though, if you do that.
*/
if (untracked &&
- hashcmp(sha1_stat.sha1, untracked->exclude_sha1)) {
+ hashcmp(oid_stat.oid.hash, untracked->exclude_sha1)) {
invalidate_gitignore(dir->untracked, untracked);
- hashcpy(untracked->exclude_sha1, sha1_stat.sha1);
+ hashcpy(untracked->exclude_sha1, oid_stat.oid.hash);
}
dir->exclude_stack = stk;
current = stk->baselen;
@@ -1773,7 +1779,7 @@ static enum path_treatment treat_path(struct dir_struct *dir,
if (!de)
return treat_path_fast(dir, untracked, cdir, istate, path,
baselen, pathspec);
- if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
+ if (is_dot_or_dotdot(de->d_name) || !fspathcmp(de->d_name, ".git"))
return path_none;
strbuf_setlen(path, baselen);
strbuf_addstr(path, de->d_name);
@@ -1809,24 +1815,19 @@ static int valid_cached_dir(struct dir_struct *dir,
*/
refresh_fsmonitor(istate);
if (!(dir->untracked->use_fsmonitor && untracked->valid)) {
- if (stat(path->len ? path->buf : ".", &st)) {
- invalidate_directory(dir->untracked, untracked);
+ if (lstat(path->len ? path->buf : ".", &st)) {
memset(&untracked->stat_data, 0, sizeof(untracked->stat_data));
return 0;
}
if (!untracked->valid ||
match_stat_data_racy(istate, &untracked->stat_data, &st)) {
- if (untracked->valid)
- invalidate_directory(dir->untracked, untracked);
fill_stat_data(&untracked->stat_data, &st);
return 0;
}
}
- if (untracked->check_only != !!check_only) {
- invalidate_directory(dir->untracked, untracked);
+ if (untracked->check_only != !!check_only)
return 0;
- }
/*
* prep_exclude will be called eventually on this directory,
@@ -1853,13 +1854,20 @@ static int open_cached_dir(struct cached_dir *cdir,
struct strbuf *path,
int check_only)
{
+ const char *c_path;
+
memset(cdir, 0, sizeof(*cdir));
cdir->untracked = untracked;
if (valid_cached_dir(dir, untracked, istate, path, check_only))
return 0;
- cdir->fdir = opendir(path->len ? path->buf : ".");
- if (dir->untracked)
+ c_path = path->len ? path->buf : ".";
+ cdir->fdir = opendir(c_path);
+ if (!cdir->fdir)
+ warning_errno(_("could not open directory '%s'"), c_path);
+ if (dir->untracked) {
+ invalidate_directory(dir->untracked, untracked);
dir->untracked->dir_opened++;
+ }
if (!cdir->fdir)
return -1;
return 0;
@@ -2164,8 +2172,13 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
const struct pathspec *pathspec)
{
struct untracked_cache_dir *root;
+ static int untracked_cache_disabled = -1;
- if (!dir->untracked || getenv("GIT_DISABLE_UNTRACKED_CACHE"))
+ if (!dir->untracked)
+ return NULL;
+ if (untracked_cache_disabled < 0)
+ untracked_cache_disabled = git_env_bool("GIT_DISABLE_UNTRACKED_CACHE", 0);
+ if (untracked_cache_disabled)
return NULL;
/*
@@ -2228,13 +2241,13 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
/* Validate $GIT_DIR/info/exclude and core.excludesfile */
root = dir->untracked->root;
- if (hashcmp(dir->ss_info_exclude.sha1,
- dir->untracked->ss_info_exclude.sha1)) {
+ if (oidcmp(&dir->ss_info_exclude.oid,
+ &dir->untracked->ss_info_exclude.oid)) {
invalidate_gitignore(dir->untracked, root);
dir->untracked->ss_info_exclude = dir->ss_info_exclude;
}
- if (hashcmp(dir->ss_excludes_file.sha1,
- dir->untracked->ss_excludes_file.sha1)) {
+ if (oidcmp(&dir->ss_excludes_file.oid,
+ &dir->untracked->ss_excludes_file.oid)) {
invalidate_gitignore(dir->untracked, root);
dir->untracked->ss_excludes_file = dir->ss_excludes_file;
}
@@ -2248,6 +2261,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
const char *path, int len, const struct pathspec *pathspec)
{
struct untracked_cache_dir *untracked;
+ uint64_t start = getnanotime();
if (has_symlink_leading_path(path, len))
return dir->nr;
@@ -2286,8 +2300,14 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
dir->nr = i;
}
+ trace_performance_since(start, "read directory %.*s", len, path);
if (dir->untracked) {
+ static int force_untracked_cache = -1;
static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
+
+ if (force_untracked_cache < 0)
+ force_untracked_cache =
+ git_env_bool("GIT_FORCE_UNTRACKED_CACHE", 0);
trace_printf_key(&trace_untracked_stats,
"node creation: %u\n"
"gitignore invalidation: %u\n"
@@ -2297,7 +2317,8 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
dir->untracked->gitignore_invalidated,
dir->untracked->dir_invalidated,
dir->untracked->dir_opened);
- if (dir->untracked == istate->untracked &&
+ if (force_untracked_cache &&
+ dir->untracked == istate->untracked &&
(dir->untracked->dir_opened ||
dir->untracked->gitignore_invalidated ||
dir->untracked->dir_invalidated))
@@ -2638,8 +2659,8 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);
stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
- hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
- hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
+ hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.oid.hash);
+ hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.oid.hash);
ouc->dir_flags = htonl(untracked->dir_flags);
varint_len = encode_varint(untracked->ident.len, varbuf);
@@ -2816,13 +2837,12 @@ static void read_sha1(size_t pos, void *cb)
rd->data += 20;
}
-static void load_sha1_stat(struct sha1_stat *sha1_stat,
- const unsigned char *data,
- const unsigned char *sha1)
+static void load_oid_stat(struct oid_stat *oid_stat, const unsigned char *data,
+ const unsigned char *sha1)
{
- stat_data_from_disk(&sha1_stat->stat, data);
- hashcpy(sha1_stat->sha1, sha1);
- sha1_stat->valid = 1;
+ stat_data_from_disk(&oid_stat->stat, data);
+ hashcpy(oid_stat->oid.hash, sha1);
+ oid_stat->valid = 1;
}
struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
@@ -2850,12 +2870,12 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
uc = xcalloc(1, sizeof(*uc));
strbuf_init(&uc->ident, ident_len);
strbuf_add(&uc->ident, ident, ident_len);
- load_sha1_stat(&uc->ss_info_exclude,
- next + ouc_offset(info_exclude_stat),
- next + ouc_offset(info_exclude_sha1));
- load_sha1_stat(&uc->ss_excludes_file,
- next + ouc_offset(excludes_file_stat),
- next + ouc_offset(excludes_file_sha1));
+ load_oid_stat(&uc->ss_info_exclude,
+ next + ouc_offset(info_exclude_stat),
+ next + ouc_offset(info_exclude_sha1));
+ load_oid_stat(&uc->ss_excludes_file,
+ next + ouc_offset(excludes_file_stat),
+ next + ouc_offset(excludes_file_sha1));
uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
exclude_per_dir = (const char *)next + ouc_offset(exclude_per_dir);
uc->exclude_per_dir = xstrdup(exclude_per_dir);
@@ -2968,10 +2988,12 @@ static int invalidate_one_component(struct untracked_cache *uc,
}
void untracked_cache_invalidate_path(struct index_state *istate,
- const char *path)
+ const char *path, int safe_path)
{
if (!istate->untracked || !istate->untracked->root)
return;
+ if (!safe_path && !verify_path(path))
+ return;
invalidate_one_component(istate->untracked, istate->untracked->root,
path, strlen(path));
}
@@ -2979,13 +3001,13 @@ void untracked_cache_invalidate_path(struct index_state *istate,
void untracked_cache_remove_from_index(struct index_state *istate,
const char *path)
{
- untracked_cache_invalidate_path(istate, path);
+ untracked_cache_invalidate_path(istate, path, 1);
}
void untracked_cache_add_to_index(struct index_state *istate,
const char *path)
{
- untracked_cache_invalidate_path(istate, path);
+ untracked_cache_invalidate_path(istate, path, 1);
}
/* Update gitfile and core.worktree setting to connect work tree and git dir */
diff --git a/dir.h b/dir.h
index 11a047b..b0758b8 100644
--- a/dir.h
+++ b/dir.h
@@ -74,9 +74,9 @@ struct exclude_list_group {
struct exclude_list *el;
};
-struct sha1_stat {
+struct oid_stat {
struct stat_data stat;
- unsigned char sha1[20];
+ struct object_id oid;
int valid;
};
@@ -124,8 +124,8 @@ struct untracked_cache_dir {
};
struct untracked_cache {
- struct sha1_stat ss_info_exclude;
- struct sha1_stat ss_excludes_file;
+ struct oid_stat ss_info_exclude;
+ struct oid_stat ss_excludes_file;
const char *exclude_per_dir;
struct strbuf ident;
/*
@@ -195,8 +195,8 @@ struct dir_struct {
/* Enable untracked file cache if set */
struct untracked_cache *untracked;
- struct sha1_stat ss_info_exclude;
- struct sha1_stat ss_excludes_file;
+ struct oid_stat ss_info_exclude;
+ struct oid_stat ss_excludes_file;
unsigned unmanaged_exclude_files;
};
@@ -350,7 +350,7 @@ static inline int dir_path_match(const struct dir_entry *ent,
int cmp_dir_entry(const void *p1, const void *p2);
int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in);
-void untracked_cache_invalidate_path(struct index_state *, const char *);
+void untracked_cache_invalidate_path(struct index_state *, const char *, int safe_path);
void untracked_cache_remove_from_index(struct index_state *, const char *);
void untracked_cache_add_to_index(struct index_state *, const char *);
diff --git a/entry.c b/entry.c
index 3021144..2101201 100644
--- a/entry.c
+++ b/entry.c
@@ -85,12 +85,12 @@ static int create_file(const char *path, unsigned int mode)
static void *read_blob_entry(const struct cache_entry *ce, unsigned long *size)
{
enum object_type type;
- void *new = read_sha1_file(ce->oid.hash, &type, size);
+ void *blob_data = read_object_file(&ce->oid, &type, size);
- if (new) {
+ if (blob_data) {
if (type == OBJ_BLOB)
- return new;
- free(new);
+ return blob_data;
+ free(blob_data);
}
return NULL;
}
@@ -256,7 +256,7 @@ static int write_entry(struct cache_entry *ce,
unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
struct delayed_checkout *dco = state->delayed_checkout;
int fd, ret, fstat_done = 0;
- char *new;
+ char *new_blob;
struct strbuf buf = STRBUF_INIT;
unsigned long size;
ssize_t wrote;
@@ -266,7 +266,7 @@ static int write_entry(struct cache_entry *ce,
if (ce_mode_s_ifmt == S_IFREG) {
struct stream_filter *filter = get_stream_filter(ce->name,
- ce->oid.hash);
+ &ce->oid);
if (filter &&
!streaming_write_entry(ce, path, filter,
state, to_tempfile,
@@ -276,8 +276,8 @@ static int write_entry(struct cache_entry *ce,
switch (ce_mode_s_ifmt) {
case S_IFLNK:
- new = read_blob_entry(ce, &size);
- if (!new)
+ new_blob = read_blob_entry(ce, &size);
+ if (!new_blob)
return error("unable to read sha1 file of %s (%s)",
path, oid_to_hex(&ce->oid));
@@ -288,8 +288,8 @@ static int write_entry(struct cache_entry *ce,
if (!has_symlinks || to_tempfile)
goto write_file_entry;
- ret = symlink(new, path);
- free(new);
+ ret = symlink(new_blob, path);
+ free(new_blob);
if (ret)
return error_errno("unable to create symlink %s", path);
break;
@@ -300,11 +300,11 @@ static int write_entry(struct cache_entry *ce,
* bother reading it at all.
*/
if (dco && dco->state == CE_RETRY) {
- new = NULL;
+ new_blob = NULL;
size = 0;
} else {
- new = read_blob_entry(ce, &size);
- if (!new)
+ new_blob = read_blob_entry(ce, &size);
+ if (!new_blob)
return error("unable to read sha1 file of %s (%s)",
path, oid_to_hex(&ce->oid));
}
@@ -313,18 +313,18 @@ static int write_entry(struct cache_entry *ce,
* Convert from git internal format to working tree format
*/
if (dco && dco->state != CE_NO_DELAY) {
- ret = async_convert_to_working_tree(ce->name, new,
+ ret = async_convert_to_working_tree(ce->name, new_blob,
size, &buf, dco);
if (ret && string_list_has_string(&dco->paths, ce->name)) {
- free(new);
+ free(new_blob);
goto delayed;
}
} else
- ret = convert_to_working_tree(ce->name, new, size, &buf);
+ ret = convert_to_working_tree(ce->name, new_blob, size, &buf);
if (ret) {
- free(new);
- new = strbuf_detach(&buf, &newsize);
+ free(new_blob);
+ new_blob = strbuf_detach(&buf, &newsize);
size = newsize;
}
/*
@@ -336,15 +336,15 @@ static int write_entry(struct cache_entry *ce,
write_file_entry:
fd = open_output_fd(path, ce, to_tempfile);
if (fd < 0) {
- free(new);
+ free(new_blob);
return error_errno("unable to create file %s", path);
}
- wrote = write_in_full(fd, new, size);
+ wrote = write_in_full(fd, new_blob, size);
if (!to_tempfile)
fstat_done = fstat_output(fd, state, &st);
close(fd);
- free(new);
+ free(new_blob);
if (wrote < 0)
return error("unable to write file %s", path);
break;
diff --git a/environment.c b/environment.c
index a5eaa97..21565c3 100644
--- a/environment.c
+++ b/environment.c
@@ -101,7 +101,7 @@ int ignore_untracked_cache_config;
/* This is set by setup_git_dir_gently() and/or git_default_config() */
char *git_work_tree_cfg;
-static char *namespace;
+static char *git_namespace;
static const char *super_prefix;
@@ -184,8 +184,8 @@ void setup_git_env(const char *git_dir)
free(git_replace_ref_base);
git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
: "refs/replace/");
- free(namespace);
- namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
+ free(git_namespace);
+ git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
if (shallow_file)
set_alternate_shallow_file(shallow_file, 0);
@@ -219,9 +219,9 @@ const char *get_git_common_dir(void)
const char *get_git_namespace(void)
{
- if (!namespace)
+ if (!git_namespace)
BUG("git environment hasn't been setup");
- return namespace;
+ return git_namespace;
}
const char *strip_namespace(const char *namespaced_ref)
@@ -275,7 +275,7 @@ char *get_object_directory(void)
return the_repository->objectdir;
}
-int odb_mkstemp(struct strbuf *template, const char *pattern)
+int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
{
int fd;
/*
@@ -283,16 +283,16 @@ int odb_mkstemp(struct strbuf *template, const char *pattern)
* restrictive except to remove write permission.
*/
int mode = 0444;
- git_path_buf(template, "objects/%s", pattern);
- fd = git_mkstemp_mode(template->buf, mode);
+ git_path_buf(temp_filename, "objects/%s", pattern);
+ fd = git_mkstemp_mode(temp_filename->buf, mode);
if (0 <= fd)
return fd;
/* slow path */
- /* some mkstemp implementations erase template on failure */
- git_path_buf(template, "objects/%s", pattern);
- safe_create_leading_directories(template->buf);
- return xmkstemp_mode(template->buf, mode);
+ /* some mkstemp implementations erase temp_filename on failure */
+ git_path_buf(temp_filename, "objects/%s", pattern);
+ safe_create_leading_directories(temp_filename->buf);
+ return xmkstemp_mode(temp_filename->buf, mode);
}
int odb_pack_keep(const char *name)
diff --git a/fast-import.c b/fast-import.c
index b70ac02..a2e8b1d 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -316,7 +316,7 @@ static struct atom_str **atom_table;
/* The .pack file being generated */
static struct pack_idx_option pack_idx_opts;
static unsigned int pack_id;
-static struct sha1file *pack_file;
+static struct hashfile *pack_file;
static struct packed_git *pack_data;
static struct packed_git **all_packs;
static off_t pack_size;
@@ -905,12 +905,12 @@ static void start_packfile(void)
p->pack_fd = pack_fd;
p->do_not_close = 1;
- pack_file = sha1fd(pack_fd, p->pack_name);
+ pack_file = hashfd(pack_fd, p->pack_name);
hdr.hdr_signature = htonl(PACK_SIGNATURE);
hdr.hdr_version = htonl(2);
hdr.hdr_entries = 0;
- sha1write(pack_file, &hdr, sizeof(hdr));
+ hashwrite(pack_file, &hdr, sizeof(hdr));
pack_data = p;
pack_size = sizeof(hdr);
@@ -1016,7 +1016,7 @@ static void end_packfile(void)
struct tag *t;
close_pack_windows(pack_data);
- sha1close(pack_file, cur_pack_oid.hash, 0);
+ hashclose(pack_file, cur_pack_oid.hash, 0);
fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
pack_data->pack_name, object_count,
cur_pack_oid.hash, pack_size);
@@ -1092,15 +1092,15 @@ static int store_object(
unsigned char hdr[96];
struct object_id oid;
unsigned long hdrlen, deltalen;
- git_SHA_CTX c;
+ git_hash_ctx c;
git_zstream s;
hdrlen = xsnprintf((char *)hdr, sizeof(hdr), "%s %lu",
- typename(type), (unsigned long)dat->len) + 1;
- git_SHA1_Init(&c);
- git_SHA1_Update(&c, hdr, hdrlen);
- git_SHA1_Update(&c, dat->buf, dat->len);
- git_SHA1_Final(oid.hash, &c);
+ type_name(type), (unsigned long)dat->len) + 1;
+ the_hash_algo->init_fn(&c);
+ the_hash_algo->update_fn(&c, hdr, hdrlen);
+ the_hash_algo->update_fn(&c, dat->buf, dat->len);
+ the_hash_algo->final_fn(oid.hash, &c);
if (oidout)
oidcpy(oidout, &oid);
@@ -1118,11 +1118,13 @@ static int store_object(
return 1;
}
- if (last && last->data.buf && last->depth < max_depth && dat->len > 20) {
+ if (last && last->data.buf && last->depth < max_depth
+ && dat->len > the_hash_algo->rawsz) {
+
delta_count_attempts_by_type[type]++;
delta = diff_delta(last->data.buf, last->data.len,
dat->buf, dat->len,
- &deltalen, dat->len - 20);
+ &deltalen, dat->len - the_hash_algo->rawsz);
} else
delta = NULL;
@@ -1180,23 +1182,23 @@ static int store_object(
hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr),
OBJ_OFS_DELTA, deltalen);
- sha1write(pack_file, hdr, hdrlen);
+ hashwrite(pack_file, hdr, hdrlen);
pack_size += hdrlen;
hdr[pos] = ofs & 127;
while (ofs >>= 7)
hdr[--pos] = 128 | (--ofs & 127);
- sha1write(pack_file, hdr + pos, sizeof(hdr) - pos);
+ hashwrite(pack_file, hdr + pos, sizeof(hdr) - pos);
pack_size += sizeof(hdr) - pos;
} else {
e->depth = 0;
hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr),
type, dat->len);
- sha1write(pack_file, hdr, hdrlen);
+ hashwrite(pack_file, hdr, hdrlen);
pack_size += hdrlen;
}
- sha1write(pack_file, out, s.total_out);
+ hashwrite(pack_file, out, s.total_out);
pack_size += s.total_out;
e->idx.crc32 = crc32_end(pack_file);
@@ -1215,9 +1217,9 @@ static int store_object(
return 0;
}
-static void truncate_pack(struct sha1file_checkpoint *checkpoint)
+static void truncate_pack(struct hashfile_checkpoint *checkpoint)
{
- if (sha1file_truncate(pack_file, checkpoint))
+ if (hashfile_truncate(pack_file, checkpoint))
die_errno("cannot truncate pack to skip duplicate");
pack_size = checkpoint->offset;
}
@@ -1231,9 +1233,9 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
struct object_id oid;
unsigned long hdrlen;
off_t offset;
- git_SHA_CTX c;
+ git_hash_ctx c;
git_zstream s;
- struct sha1file_checkpoint checkpoint;
+ struct hashfile_checkpoint checkpoint;
int status = Z_OK;
/* Determine if we should auto-checkpoint. */
@@ -1241,13 +1243,13 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
|| (pack_size + 60 + len) < pack_size)
cycle_packfile();
- sha1file_checkpoint(pack_file, &checkpoint);
+ hashfile_checkpoint(pack_file, &checkpoint);
offset = checkpoint.offset;
hdrlen = xsnprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1;
- git_SHA1_Init(&c);
- git_SHA1_Update(&c, out_buf, hdrlen);
+ the_hash_algo->init_fn(&c);
+ the_hash_algo->update_fn(&c, out_buf, hdrlen);
crc32_begin(pack_file);
@@ -1265,7 +1267,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
if (!n && feof(stdin))
die("EOF in data (%" PRIuMAX " bytes remaining)", len);
- git_SHA1_Update(&c, in_buf, n);
+ the_hash_algo->update_fn(&c, in_buf, n);
s.next_in = in_buf;
s.avail_in = n;
len -= n;
@@ -1275,7 +1277,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
if (!s.avail_out || status == Z_STREAM_END) {
size_t n = s.next_out - out_buf;
- sha1write(pack_file, out_buf, n);
+ hashwrite(pack_file, out_buf, n);
pack_size += n;
s.next_out = out_buf;
s.avail_out = out_sz;
@@ -1291,7 +1293,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
}
}
git_deflate_end(&s);
- git_SHA1_Final(oid.hash, &c);
+ the_hash_algo->final_fn(oid.hash, &c);
if (oidout)
oidcpy(oidout, &oid);
@@ -1350,25 +1352,25 @@ static void *gfi_unpack_entry(
{
enum object_type type;
struct packed_git *p = all_packs[oe->pack_id];
- if (p == pack_data && p->pack_size < (pack_size + 20)) {
+ if (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {
/* The object is stored in the packfile we are writing to
* and we have modified it since the last time we scanned
* back to read a previously written object. If an old
- * window covered [p->pack_size, p->pack_size + 20) its
+ * window covered [p->pack_size, p->pack_size + rawsz) its
* data is stale and is not valid. Closing all windows
* and updating the packfile length ensures we can read
* the newly written data.
*/
close_pack_windows(p);
- sha1flush(pack_file);
+ hashflush(pack_file);
- /* We have to offer 20 bytes additional on the end of
+ /* We have to offer rawsz bytes additional on the end of
* the packfile as the core unpacker code assumes the
* footer is present at the file end and must promise
- * at least 20 bytes within any window it maps. But
+ * at least rawsz bytes within any window it maps. But
* we don't actually create the footer here.
*/
- p->pack_size = pack_size + 20;
+ p->pack_size = pack_size + the_hash_algo->rawsz;
}
return unpack_entry(p, oe->idx.offset, &type, sizep);
}
@@ -1410,7 +1412,7 @@ static void load_tree(struct tree_entry *root)
die("Can't load tree %s", oid_to_hex(oid));
} else {
enum object_type type;
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf || type != OBJ_TREE)
die("Can't load tree %s", oid_to_hex(oid));
}
@@ -1911,7 +1913,7 @@ static void read_marks(void)
die("corrupt mark line: %s", line);
e = find_object(&oid);
if (!e) {
- enum object_type type = sha1_object_info(oid.hash, NULL);
+ enum object_type type = oid_object_info(&oid, NULL);
if (type < 0)
die("object not found: %s", oid_to_hex(&oid));
e = insert_object(&oid);
@@ -2204,7 +2206,7 @@ static void construct_path_with_fanout(const char *hex_sha1,
unsigned char fanout, char *path)
{
unsigned int i = 0, j = 0;
- if (fanout >= 20)
+ if (fanout >= the_hash_algo->rawsz)
die("Too large fanout (%u)", fanout);
while (fanout) {
path[i++] = hex_sha1[j++];
@@ -2212,8 +2214,8 @@ static void construct_path_with_fanout(const char *hex_sha1,
path[i++] = '/';
fanout--;
}
- memcpy(path + i, hex_sha1 + j, GIT_SHA1_HEXSZ - j);
- path[i + GIT_SHA1_HEXSZ - j] = '\0';
+ memcpy(path + i, hex_sha1 + j, the_hash_algo->hexsz - j);
+ path[i + the_hash_algo->hexsz - j] = '\0';
}
static uintmax_t do_change_note_fanout(
@@ -2421,7 +2423,7 @@ static void file_change_m(const char *p, struct branch *b)
else if (oe) {
if (oe->type != OBJ_COMMIT)
die("Not a commit (actually a %s): %s",
- typename(oe->type), command_buf.buf);
+ type_name(oe->type), command_buf.buf);
}
/*
* Accept the sha1 without checking; it expected to be in
@@ -2441,14 +2443,14 @@ static void file_change_m(const char *p, struct branch *b)
enum object_type expected = S_ISDIR(mode) ?
OBJ_TREE: OBJ_BLOB;
enum object_type type = oe ? oe->type :
- sha1_object_info(oid.hash, NULL);
+ oid_object_info(&oid, NULL);
if (type < 0)
die("%s not found: %s",
S_ISDIR(mode) ? "Tree" : "Blob",
command_buf.buf);
if (type != expected)
die("Not a %s (actually a %s): %s",
- typename(expected), typename(type),
+ type_name(expected), type_name(type),
command_buf.buf);
}
@@ -2581,8 +2583,9 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
oidcpy(&commit_oid, &commit_oe->idx.oid);
} else if (!get_oid(p, &commit_oid)) {
unsigned long size;
- char *buf = read_object_with_reference(commit_oid.hash,
- commit_type, &size, commit_oid.hash);
+ char *buf = read_object_with_reference(&commit_oid,
+ commit_type, &size,
+ &commit_oid);
if (!buf || size < 46)
die("Not a valid commit: %s", p);
free(buf);
@@ -2599,14 +2602,14 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
} else if (oe) {
if (oe->type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
- typename(oe->type), command_buf.buf);
+ type_name(oe->type), command_buf.buf);
} else if (!is_null_oid(&oid)) {
- enum object_type type = sha1_object_info(oid.hash, NULL);
+ enum object_type type = oid_object_info(&oid, NULL);
if (type < 0)
die("Blob not found: %s", command_buf.buf);
if (type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
- typename(type), command_buf.buf);
+ type_name(type), command_buf.buf);
}
construct_path_with_fanout(oid_to_hex(&commit_oid), *old_fanout, path);
@@ -2651,9 +2654,8 @@ static void parse_from_existing(struct branch *b)
unsigned long size;
char *buf;
- buf = read_object_with_reference(b->oid.hash,
- commit_type, &size,
- b->oid.hash);
+ buf = read_object_with_reference(&b->oid, commit_type, &size,
+ &b->oid);
parse_from_commit(b, buf, size);
free(buf);
}
@@ -2730,8 +2732,9 @@ static struct hash_list *parse_merge(unsigned int *count)
oidcpy(&n->oid, &oe->idx.oid);
} else if (!get_oid(from, &n->oid)) {
unsigned long size;
- char *buf = read_object_with_reference(n->oid.hash,
- commit_type, &size, n->oid.hash);
+ char *buf = read_object_with_reference(&n->oid,
+ commit_type,
+ &size, &n->oid);
if (!buf || size < 46)
die("Not a valid commit: %s", from);
free(buf);
@@ -2888,7 +2891,7 @@ static void parse_new_tag(const char *arg)
} else if (!get_oid(from, &oid)) {
struct object_entry *oe = find_object(&oid);
if (!oe) {
- type = sha1_object_info(oid.hash, NULL);
+ type = oid_object_info(&oid, NULL);
if (type < 0)
die("Not a valid object: %s", from);
} else
@@ -2914,7 +2917,7 @@ static void parse_new_tag(const char *arg)
"object %s\n"
"type %s\n"
"tag %s\n",
- oid_to_hex(&oid), typename(type), t->name);
+ oid_to_hex(&oid), type_name(type), t->name);
if (tagger)
strbuf_addf(&new_data,
"tagger %s\n", tagger);
@@ -2964,7 +2967,7 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
char *buf;
if (!oe || oe->pack_id == MAX_PACK_ID) {
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
} else {
type = oe->type;
buf = gfi_unpack_entry(oe, &size);
@@ -2985,10 +2988,10 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
die("Can't read object %s", oid_to_hex(oid));
if (type != OBJ_BLOB)
die("Object %s is a %s but a blob was expected.",
- oid_to_hex(oid), typename(type));
+ oid_to_hex(oid), type_name(type));
strbuf_reset(&line);
strbuf_addf(&line, "%s %s %lu\n", oid_to_hex(oid),
- typename(type), size);
+ type_name(type), size);
cat_blob_write(line.buf, line.len);
strbuf_release(&line);
cat_blob_write(buf, size);
@@ -3003,7 +3006,7 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
static void parse_get_mark(const char *p)
{
- struct object_entry *oe = oe;
+ struct object_entry *oe;
char output[GIT_MAX_HEXSZ + 2];
/* get-mark SP <object> LF */
@@ -3020,7 +3023,7 @@ static void parse_get_mark(const char *p)
static void parse_cat_blob(const char *p)
{
- struct object_entry *oe = oe;
+ struct object_entry *oe;
struct object_id oid;
/* cat-blob SP <object> LF */
@@ -3046,7 +3049,7 @@ static struct object_entry *dereference(struct object_entry *oe,
unsigned long size;
char *buf = NULL;
if (!oe) {
- enum object_type type = sha1_object_info(oid->hash, NULL);
+ enum object_type type = oid_object_info(oid, NULL);
if (type < 0)
die("object not found: %s", oid_to_hex(oid));
/* cache it! */
@@ -3069,7 +3072,7 @@ static struct object_entry *dereference(struct object_entry *oe,
buf = gfi_unpack_entry(oe, &size);
} else {
enum object_type unused;
- buf = read_sha1_file(oid->hash, &unused, &size);
+ buf = read_object_file(oid, &unused, &size);
}
if (!buf)
die("Can't load object %s", oid_to_hex(oid));
diff --git a/fetch-pack.c b/fetch-pack.c
index 8253d74..52932b3 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -261,8 +261,8 @@ static enum ack_type get_ack(int fd, struct object_id *result_oid)
char *line = packet_read_line(fd, &len);
const char *arg;
- if (!len)
- die(_("git fetch-pack: expected ACK/NAK, got EOF"));
+ if (!line)
+ die(_("git fetch-pack: expected ACK/NAK, got a flush packet"));
if (!strcmp(line, "NAK"))
return NAK;
if (skip_prefix(line, "ACK ", &arg)) {
@@ -711,6 +711,28 @@ static void mark_alternate_complete(struct object *obj)
mark_complete(&obj->oid);
}
+struct loose_object_iter {
+ struct oidset *loose_object_set;
+ struct ref *refs;
+};
+
+/*
+ * If the number of refs is not larger than the number of loose objects,
+ * this function stops inserting.
+ */
+static int add_loose_objects_to_set(const struct object_id *oid,
+ const char *path,
+ void *data)
+{
+ struct loose_object_iter *iter = data;
+ oidset_insert(iter->loose_object_set, oid);
+ if (iter->refs == NULL)
+ return 1;
+
+ iter->refs = iter->refs->next;
+ return 0;
+}
+
static int everything_local(struct fetch_pack_args *args,
struct ref **refs,
struct ref **sought, int nr_sought)
@@ -719,16 +741,31 @@ static int everything_local(struct fetch_pack_args *args,
int retval;
int old_save_commit_buffer = save_commit_buffer;
timestamp_t cutoff = 0;
+ struct oidset loose_oid_set = OIDSET_INIT;
+ int use_oidset = 0;
+ struct loose_object_iter iter = {&loose_oid_set, *refs};
+
+ /* Enumerate all loose objects or know refs are not so many. */
+ use_oidset = !for_each_loose_object(add_loose_objects_to_set,
+ &iter, 0);
save_commit_buffer = 0;
for (ref = *refs; ref; ref = ref->next) {
struct object *o;
+ unsigned int flags = OBJECT_INFO_QUICK;
- if (!has_object_file_with_flags(&ref->old_oid,
- OBJECT_INFO_QUICK))
- continue;
+ if (use_oidset &&
+ !oidset_contains(&loose_oid_set, &ref->old_oid)) {
+ /*
+ * I know this does not exist in the loose form,
+ * so check if it exists in a non-loose form.
+ */
+ flags |= OBJECT_INFO_IGNORE_LOOSE;
+ }
+ if (!has_object_file_with_flags(&ref->old_oid, flags))
+ continue;
o = parse_object(&ref->old_oid);
if (!o)
continue;
@@ -744,6 +781,8 @@ static int everything_local(struct fetch_pack_args *args,
}
}
+ oidset_clear(&loose_oid_set);
+
if (!args->no_dependents) {
if (!args->deepen) {
for_each_ref(mark_complete_oid, NULL);
@@ -886,8 +925,17 @@ static int get_pack(struct fetch_pack_args *args,
? fetch_fsck_objects
: transfer_fsck_objects >= 0
? transfer_fsck_objects
- : 0)
- argv_array_push(&cmd.args, "--strict");
+ : 0) {
+ if (args->from_promisor)
+ /*
+ * We cannot use --strict in index-pack because it
+ * checks both broken objects and links, but we only
+ * want to check for broken objects.
+ */
+ argv_array_push(&cmd.args, "--fsck-objects");
+ else
+ argv_array_push(&cmd.args, "--strict");
+ }
cmd.in = demux.out;
cmd.git_cmd = 1;
diff --git a/fsck.c b/fsck.c
index 032699e..9218c2a 100644
--- a/fsck.c
+++ b/fsck.c
@@ -811,7 +811,7 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
enum object_type type;
buffer = to_free =
- read_sha1_file(tag->object.oid.hash, &type, &size);
+ read_object_file(&tag->object.oid, &type, &size);
if (!buffer)
return report(options, &tag->object,
FSCK_MSG_MISSING_TAG_OBJECT,
@@ -821,7 +821,7 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
ret = report(options, &tag->object,
FSCK_MSG_TAG_OBJECT_NOT_TAG,
"expected tag got %s",
- typename(type));
+ type_name(type));
goto done;
}
}
diff --git a/fsmonitor.c b/fsmonitor.c
index 0af7c4e..6d7bcd5 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -130,7 +130,7 @@ static void fsmonitor_refresh_callback(struct index_state *istate, const char *n
* as it could be a new untracked file.
*/
trace_printf_key(&trace_fsmonitor, "fsmonitor_refresh_callback '%s'", name);
- untracked_cache_invalidate_path(istate, name);
+ untracked_cache_invalidate_path(istate, name, 0);
}
void refresh_fsmonitor(struct index_state *istate)
diff --git a/fsmonitor.h b/fsmonitor.h
index cd3cc0c..65f3743 100644
--- a/fsmonitor.h
+++ b/fsmonitor.h
@@ -65,7 +65,7 @@ static inline void mark_fsmonitor_invalid(struct index_state *istate, struct cac
{
if (core_fsmonitor) {
ce->ce_flags &= ~CE_FSMONITOR_VALID;
- untracked_cache_invalidate_path(istate, ce->name);
+ untracked_cache_invalidate_path(istate, ce->name, 1);
trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_invalid '%s'", ce->name);
}
}
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 964c3a7..c1f52e4 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -677,7 +677,7 @@ sub add_untracked_cmd {
sub run_git_apply {
my $cmd = shift;
my $fh;
- open $fh, '| git ' . $cmd . " --recount --allow-overlap";
+ open $fh, '| git ' . $cmd . " --allow-overlap";
print $fh @_;
return close $fh;
}
@@ -705,6 +705,14 @@ sub parse_diff {
}
my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
+ if (@colored && @colored != @diff) {
+ print STDERR
+ "fatal: mismatched output from interactive.diffFilter\n",
+ "hint: Your filter must maintain a one-to-one correspondence\n",
+ "hint: between its input and output lines.\n";
+ exit 1;
+ }
+
for (my $i = 0; $i < @diff; $i++) {
if ($diff[$i] =~ /^@@ /) {
push @hunk, { TEXT => [], DISPLAY => [],
@@ -751,6 +759,15 @@ sub parse_hunk_header {
return ($o_ofs, $o_cnt, $n_ofs, $n_cnt);
}
+sub format_hunk_header {
+ my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) = @_;
+ return ("@@ -$o_ofs" .
+ (($o_cnt != 1) ? ",$o_cnt" : '') .
+ " +$n_ofs" .
+ (($n_cnt != 1) ? ",$n_cnt" : '') .
+ " @@\n");
+}
+
sub split_hunk {
my ($text, $display) = @_;
my @split = ();
@@ -784,6 +801,11 @@ sub split_hunk {
while (++$i < @$text) {
my $line = $text->[$i];
my $display = $display->[$i];
+ if ($line =~ /^\\/) {
+ push @{$this->{TEXT}}, $line;
+ push @{$this->{DISPLAY}}, $display;
+ next;
+ }
if ($line =~ /^ /) {
if ($this->{ADDDEL} &&
!defined $next_hunk_start) {
@@ -838,11 +860,7 @@ sub split_hunk {
my $o_cnt = $hunk->{OCNT};
my $n_cnt = $hunk->{NCNT};
- my $head = ("@@ -$o_ofs" .
- (($o_cnt != 1) ? ",$o_cnt" : '') .
- " +$n_ofs" .
- (($n_cnt != 1) ? ",$n_cnt" : '') .
- " @@\n");
+ my $head = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
my $display_head = $head;
unshift @{$hunk->{TEXT}}, $head;
if ($diff_use_color) {
@@ -886,6 +904,9 @@ sub merge_hunk {
$n_cnt++;
push @line, $line;
next;
+ } elsif ($line =~ /^\\/) {
+ push @line, $line;
+ next;
}
last if ($o1_ofs <= $ofs);
@@ -904,6 +925,9 @@ sub merge_hunk {
$n_cnt++;
push @line, $line;
next;
+ } elsif ($line =~ /^\\/) {
+ push @line, $line;
+ next;
}
$ofs++;
$o_cnt++;
@@ -912,11 +936,7 @@ sub merge_hunk {
}
push @line, $line;
}
- my $head = ("@@ -$o0_ofs" .
- (($o_cnt != 1) ? ",$o_cnt" : '') .
- " +$n0_ofs" .
- (($n_cnt != 1) ? ",$n_cnt" : '') .
- " @@\n");
+ my $head = format_hunk_header($o0_ofs, $o_cnt, $n0_ofs, $n_cnt);
@{$prev->{TEXT}} = ($head, @line);
}
@@ -925,14 +945,35 @@ sub coalesce_overlapping_hunks {
my @out = ();
my ($last_o_ctx, $last_was_dirty);
+ my $ofs_delta = 0;
- for (grep { $_->{USE} } @in) {
+ for (@in) {
if ($_->{TYPE} ne 'hunk') {
push @out, $_;
next;
}
my $text = $_->{TEXT};
- my ($o_ofs) = parse_hunk_header($text->[0]);
+ my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
+ parse_hunk_header($text->[0]);
+ unless ($_->{USE}) {
+ $ofs_delta += $o_cnt - $n_cnt;
+ # If this hunk has been edited then subtract
+ # the delta that is due to the edit.
+ if ($_->{OFS_DELTA}) {
+ $ofs_delta -= $_->{OFS_DELTA};
+ }
+ next;
+ }
+ if ($ofs_delta) {
+ $n_ofs += $ofs_delta;
+ $_->{TEXT}->[0] = format_hunk_header($o_ofs, $o_cnt,
+ $n_ofs, $n_cnt);
+ }
+ # If this hunk was edited then adjust the offset delta
+ # to reflect the edit.
+ if ($_->{OFS_DELTA}) {
+ $ofs_delta += $_->{OFS_DELTA};
+ }
if (defined $last_o_ctx &&
$o_ofs <= $last_o_ctx &&
!$_->{DIRTY} &&
@@ -1004,6 +1045,30 @@ marked for discarding."),
marked for applying."),
);
+sub recount_edited_hunk {
+ local $_;
+ my ($oldtext, $newtext) = @_;
+ my ($o_cnt, $n_cnt) = (0, 0);
+ for (@{$newtext}[1..$#{$newtext}]) {
+ my $mode = substr($_, 0, 1);
+ if ($mode eq '-') {
+ $o_cnt++;
+ } elsif ($mode eq '+') {
+ $n_cnt++;
+ } elsif ($mode eq ' ') {
+ $o_cnt++;
+ $n_cnt++;
+ }
+ }
+ my ($o_ofs, undef, $n_ofs, undef) =
+ parse_hunk_header($newtext->[0]);
+ $newtext->[0] = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
+ my (undef, $orig_o_cnt, undef, $orig_n_cnt) =
+ parse_hunk_header($oldtext->[0]);
+ # Return the change in the number of lines inserted by this hunk
+ return $orig_o_cnt - $orig_n_cnt - $o_cnt + $n_cnt;
+}
+
sub edit_hunk_manually {
my ($oldtext) = @_;
@@ -1102,25 +1167,32 @@ sub prompt_yesno {
}
sub edit_hunk_loop {
- my ($head, $hunk, $ix) = @_;
- my $text = $hunk->[$ix]->{TEXT};
+ my ($head, $hunks, $ix) = @_;
+ my $hunk = $hunks->[$ix];
+ my $text = $hunk->{TEXT};
while (1) {
- $text = edit_hunk_manually($text);
- if (!defined $text) {
+ my $newtext = edit_hunk_manually($text);
+ if (!defined $newtext) {
return undef;
}
my $newhunk = {
- TEXT => $text,
- TYPE => $hunk->[$ix]->{TYPE},
+ TEXT => $newtext,
+ TYPE => $hunk->{TYPE},
USE => 1,
DIRTY => 1,
};
+ $newhunk->{OFS_DELTA} = recount_edited_hunk($text, $newtext);
+ # If this hunk has already been edited then add the
+ # offset delta of the previous edit to get the real
+ # delta from the original unedited hunk.
+ $hunk->{OFS_DELTA} and
+ $newhunk->{OFS_DELTA} += $hunk->{OFS_DELTA};
if (diff_applies($head,
- @{$hunk}[0..$ix-1],
+ @{$hunks}[0..$ix-1],
$newhunk,
- @{$hunk}[$ix+1..$#{$hunk}])) {
- $newhunk->{DISPLAY} = [color_diff(@{$text})];
+ @{$hunks}[$ix+1..$#{$hunks}])) {
+ $newhunk->{DISPLAY} = [color_diff(@{$newtext})];
return $newhunk;
}
else {
@@ -1184,7 +1256,13 @@ d - do not apply this hunk or any of the later hunks in the file"),
);
sub help_patch_cmd {
- print colored $help_color, __($help_patch_modes{$patch_mode}), "\n", __ <<EOF ;
+ local $_;
+ my $other = $_[0] . ",?";
+ print colored $help_color, __($help_patch_modes{$patch_mode}), "\n",
+ map { "$_\n" } grep {
+ my $c = quotemeta(substr($_, 0, 1));
+ $other =~ /,$c/
+ } split "\n", __ <<EOF ;
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
@@ -1302,39 +1380,39 @@ sub display_hunks {
my %patch_update_prompt_modes = (
stage => {
- mode => N__("Stage mode change [y,n,q,a,d,/%s,?]? "),
- deletion => N__("Stage deletion [y,n,q,a,d,/%s,?]? "),
- hunk => N__("Stage this hunk [y,n,q,a,d,/%s,?]? "),
+ mode => N__("Stage mode change [y,n,q,a,d%s,?]? "),
+ deletion => N__("Stage deletion [y,n,q,a,d%s,?]? "),
+ hunk => N__("Stage this hunk [y,n,q,a,d%s,?]? "),
},
stash => {
- mode => N__("Stash mode change [y,n,q,a,d,/%s,?]? "),
- deletion => N__("Stash deletion [y,n,q,a,d,/%s,?]? "),
- hunk => N__("Stash this hunk [y,n,q,a,d,/%s,?]? "),
+ mode => N__("Stash mode change [y,n,q,a,d%s,?]? "),
+ deletion => N__("Stash deletion [y,n,q,a,d%s,?]? "),
+ hunk => N__("Stash this hunk [y,n,q,a,d%s,?]? "),
},
reset_head => {
- mode => N__("Unstage mode change [y,n,q,a,d,/%s,?]? "),
- deletion => N__("Unstage deletion [y,n,q,a,d,/%s,?]? "),
- hunk => N__("Unstage this hunk [y,n,q,a,d,/%s,?]? "),
+ mode => N__("Unstage mode change [y,n,q,a,d%s,?]? "),
+ deletion => N__("Unstage deletion [y,n,q,a,d%s,?]? "),
+ hunk => N__("Unstage this hunk [y,n,q,a,d%s,?]? "),
},
reset_nothead => {
- mode => N__("Apply mode change to index [y,n,q,a,d,/%s,?]? "),
- deletion => N__("Apply deletion to index [y,n,q,a,d,/%s,?]? "),
- hunk => N__("Apply this hunk to index [y,n,q,a,d,/%s,?]? "),
+ mode => N__("Apply mode change to index [y,n,q,a,d%s,?]? "),
+ deletion => N__("Apply deletion to index [y,n,q,a,d%s,?]? "),
+ hunk => N__("Apply this hunk to index [y,n,q,a,d%s,?]? "),
},
checkout_index => {
- mode => N__("Discard mode change from worktree [y,n,q,a,d,/%s,?]? "),
- deletion => N__("Discard deletion from worktree [y,n,q,a,d,/%s,?]? "),
- hunk => N__("Discard this hunk from worktree [y,n,q,a,d,/%s,?]? "),
+ mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
+ deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+ hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
},
checkout_head => {
- mode => N__("Discard mode change from index and worktree [y,n,q,a,d,/%s,?]? "),
- deletion => N__("Discard deletion from index and worktree [y,n,q,a,d,/%s,?]? "),
- hunk => N__("Discard this hunk from index and worktree [y,n,q,a,d,/%s,?]? "),
+ mode => N__("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
+ deletion => N__("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
+ hunk => N__("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
checkout_nothead => {
- mode => N__("Apply mode change to index and worktree [y,n,q,a,d,/%s,?]? "),
- deletion => N__("Apply deletion to index and worktree [y,n,q,a,d,/%s,?]? "),
- hunk => N__("Apply this hunk to index and worktree [y,n,q,a,d,/%s,?]? "),
+ mode => N__("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
+ deletion => N__("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
+ hunk => N__("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
);
@@ -1390,7 +1468,7 @@ sub patch_update_file {
$other .= ',J';
}
if ($num > 1) {
- $other .= ',g';
+ $other .= ',g,/';
}
for ($i = 0; $i < $num; $i++) {
if (!defined $hunk[$i]{USE}) {
@@ -1431,8 +1509,12 @@ sub patch_update_file {
}
next;
}
- elsif ($other =~ /g/ && $line =~ /^g(.*)/) {
+ elsif ($line =~ /^g(.*)/) {
my $response = $1;
+ unless ($other =~ /g/) {
+ error_msg __("No other hunks to goto\n");
+ next;
+ }
my $no = $ix > 10 ? $ix - 10 : 0;
while ($response eq '') {
$no = display_hunks(\@hunk, $no);
@@ -1478,7 +1560,11 @@ sub patch_update_file {
}
elsif ($line =~ m|^/(.*)|) {
my $regex = $1;
- if ($1 eq "") {
+ unless ($other =~ m|/|) {
+ error_msg __("No other hunks to search\n");
+ next;
+ }
+ if ($regex eq "") {
print colored $prompt_color, __("search for regex? ");
$regex = <STDIN>;
if (defined $regex) {
@@ -1546,7 +1632,11 @@ sub patch_update_file {
next;
}
}
- elsif ($other =~ /s/ && $line =~ /^s/) {
+ elsif ($line =~ /^s/) {
+ unless ($other =~ /s/) {
+ error_msg __("Sorry, cannot split this hunk\n");
+ next;
+ }
my @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});
if (1 < @split) {
print colored $header_color, sprintf(
@@ -1558,7 +1648,11 @@ sub patch_update_file {
$num = scalar @hunk;
next;
}
- elsif ($other =~ /e/ && $line =~ /^e/) {
+ elsif ($line =~ /^e/) {
+ unless ($other =~ /e/) {
+ error_msg __("Sorry, cannot edit this hunk\n");
+ next;
+ }
my $newhunk = edit_hunk_loop($head, \@hunk, $ix);
if (defined $newhunk) {
splice @hunk, $ix, 1, $newhunk;
diff --git a/git-compat-util.h b/git-compat-util.h
index 68b2ad5..07e3832 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -826,8 +826,8 @@ extern ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
extern int xdup(int fd);
extern FILE *xfopen(const char *path, const char *mode);
extern FILE *xfdopen(int fd, const char *mode);
-extern int xmkstemp(char *template);
-extern int xmkstemp_mode(char *template, int mode);
+extern int xmkstemp(char *temp_filename);
+extern int xmkstemp_mode(char *temp_filename, int mode);
extern char *xgetcwd(void);
extern FILE *fopen_for_writing(const char *path);
extern FILE *fopen_or_warn(const char *path, const char *mode);
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 2d8df83..b31613c 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -601,7 +601,9 @@ sub pdate($) {
my ($d) = @_;
m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
or die "Unparseable date: $d\n";
- my $y=$1; $y-=1900 if $y>1900;
+ my $y=$1;
+ $y+=100 if $y<70;
+ $y+=1900 if $y<1000;
return timegm($6||0,$5,$4,$3,$2-1,$y);
}
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 1b7e4b2..2587a01 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -310,7 +310,7 @@ git rev-list --reverse --topo-order --default HEAD \
die "Could not get the commits"
commits=$(wc -l <../revs | tr -d " ")
-test $commits -eq 0 && die "Found nothing to rewrite"
+test $commits -eq 0 && die_with_status 2 "Found nothing to rewrite"
# Rewrite the commits
report_progress ()
@@ -627,12 +627,12 @@ then
print H "$_:$f\n" or die;
}
close(H) or die;' || die "Unable to save state")
- state_tree=$(/bin/echo -e "100644 blob $state_blob\tfilter.map" | git mktree)
+ state_tree=$(printf '100644 blob %s\tfilter.map\n' "$state_blob" | git mktree)
if test -n "$state_commit"
then
- state_commit=$(/bin/echo "Sync" | git commit-tree "$state_tree" -p "$state_commit")
+ state_commit=$(echo "Sync" | git commit-tree "$state_tree" -p "$state_commit")
else
- state_commit=$(/bin/echo "Sync" | git commit-tree "$state_tree" )
+ state_commit=$(echo "Sync" | git commit-tree "$state_tree" )
fi
git update-ref "$state_branch" "$state_commit"
fi
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index 14c5078..be3f068 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -27,6 +27,9 @@ skip)
move_to_original_branch
return
;;
+show-current-patch)
+ exec git am --show-current-patch
+ ;;
esac
if test -z "$rebase_root"
@@ -46,6 +49,7 @@ then
# makes this easy
git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \
$allow_rerere_autoupdate --right-only "$revisions" \
+ $allow_empty_message \
${restrict_revision+^$restrict_revision}
ret=$?
else
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index d47bd29..331c8df 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -199,12 +199,14 @@ make_patch () {
die_with_patch () {
echo "$1" > "$state_dir"/stopped-sha
+ git update-ref REBASE_HEAD "$1"
make_patch "$1"
die "$2"
}
exit_with_patch () {
echo "$1" > "$state_dir"/stopped-sha
+ git update-ref REBASE_HEAD "$1"
make_patch $1
git rev-parse --verify HEAD > "$amend"
gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
@@ -281,7 +283,7 @@ pick_one () {
test -d "$rewritten" &&
pick_one_preserving_merges "$@" && return
- output eval git cherry-pick $allow_rerere_autoupdate \
+ output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \
${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
"$strategy_args" $empty_args $ff "$@"
@@ -396,7 +398,7 @@ pick_one_preserving_merges () {
--sq-quote "$gpg_sign_opt")} \
$allow_rerere_autoupdate "$merge_args" \
"$strategy_args" \
- -m $(git rev-parse --sq-quote "$msg_content") \
+ -m "$(git rev-parse --sq-quote "$msg_content")" \
"$new_parents"
then
printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
@@ -406,6 +408,7 @@ pick_one_preserving_merges () {
;;
*)
output eval git cherry-pick $allow_rerere_autoupdate \
+ $allow_empty_message \
${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
"$strategy_args" "$@" ||
die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
@@ -559,7 +562,8 @@ do_next () {
mark_action_done
do_pick $sha1 "$rest"
- git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
+ git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} \
+ $allow_empty_message || {
warn "$(eval_gettext "\
Could not amend commit after successfully picking \$sha1... \$rest
This is most likely due to an empty commit message, or the pre-commit hook
@@ -607,7 +611,7 @@ you are able to reword the commit.")"
# 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" \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+ ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
die_failed_squash $sha1 "$rest"
;;
*)
@@ -615,13 +619,13 @@ you are able to reword the commit.")"
if test -f "$fixup_msg"
then
do_with_author git commit --amend --no-verify -F "$fixup_msg" \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+ ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
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 \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+ ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
die_failed_squash $sha1 "$rest"
fi
rm -f "$squash_msg" "$fixup_msg"
@@ -754,7 +758,8 @@ case "$action" in
continue)
if test ! -d "$rewritten"
then
- exec git rebase--helper ${force_rebase:+--no-ff} --continue
+ exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+ --continue
fi
# do we have anything to commit?
if git diff-index --cached --quiet HEAD --
@@ -794,11 +799,11 @@ In both cases, once you're done, continue with:
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 \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+ ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
die "$(gettext "Could not commit staged changes.")"
else
do_with_author git commit --no-verify -F "$msg" -e \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+ ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
die "$(gettext "Could not commit staged changes.")"
fi
fi
@@ -817,7 +822,8 @@ skip)
if test ! -d "$rewritten"
then
- exec git rebase--helper ${force_rebase:+--no-ff} --continue
+ exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+ --continue
fi
do_rest
return 0
@@ -840,6 +846,9 @@ To continue rebase after editing, run:
exit
;;
+show-current-patch)
+ exec git show REBASE_HEAD --
+ ;;
esac
comment_for_reflog start
@@ -855,6 +864,7 @@ fi
orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
+rm -f "$(git rev-parse --git-path REBASE_HEAD)"
: > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
write_basic_state
@@ -1016,7 +1026,8 @@ checkout_onto
if test -z "$rebase_root" && test ! -d "$rewritten"
then
require_clean_work_tree "rebase"
- exec git rebase--helper ${force_rebase:+--no-ff} --continue
+ exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+ --continue
fi
do_rest
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index 06a4723..ceb7154 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -27,7 +27,8 @@ continue_merge () {
cmt=$(cat "$state_dir/current")
if ! git diff-index --quiet --ignore-submodules HEAD --
then
- if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt"
+ if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message \
+ --no-verify -C "$cmt"
then
echo "Commit failed, please do not call \"git commit\""
echo "directly, but instead do one of the following: "
@@ -57,6 +58,7 @@ call_merge () {
echo "$msgnum" >"$state_dir/msgnum"
cmt="$(cat "$state_dir/cmt.$msgnum")"
echo "$cmt" > "$state_dir/current"
+ git update-ref REBASE_HEAD "$cmt"
hd=$(git rev-parse --verify HEAD)
cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@ -137,11 +139,15 @@ skip)
finish_rb_merge
return
;;
+show-current-patch)
+ exec git show REBASE_HEAD --
+ ;;
esac
mkdir -p "$state_dir"
echo "$onto_name" > "$state_dir/onto_name"
write_basic_state
+rm -f "$(git rev-parse --git-path REBASE_HEAD)"
msgnum=0
for cmt in $(git rev-list --reverse --no-merges "$revisions")
diff --git a/git-rebase.sh b/git-rebase.sh
index fd72a35..a1f6e5d 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -24,6 +24,7 @@ m,merge! use merging strategies to rebase
i,interactive! let the user edit the list of commits to rebase
x,exec=! add exec lines after each commit of the editable list
k,keep-empty preserve empty commits during rebase
+allow-empty-message allow rebasing commits with empty messages
f,force-rebase! force rebase even if branch is up to date
X,strategy-option=! pass the argument through to the merge strategy
stat! display a diffstat of what changed upstream
@@ -45,6 +46,7 @@ abort! abort and check out the original branch
skip! skip current patch and continue
edit-todo! edit the todo list during an interactive rebase
quit! abort but keep HEAD where it is
+show-current-patch! show the patch file being applied or merged
"
. git-sh-setup
set_reflog_action rebase
@@ -89,6 +91,7 @@ action=
preserve_merges=
autosquash=
keep_empty=
+allow_empty_message=
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
case "$(git config --bool commit.gpgsign)" in
true) gpg_sign_opt=-S ;;
@@ -181,6 +184,7 @@ You can run "git stash pop" or "git stash drop" at any time.
}
finish_rebase () {
+ rm -f "$(git rev-parse --git-path REBASE_HEAD)"
apply_autostash &&
{ git gc --auto || true; } &&
rm -rf "$state_dir"
@@ -245,7 +249,7 @@ do
--verify)
ok_to_skip_pre_rebase=
;;
- --continue|--skip|--abort|--quit|--edit-todo)
+ --continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
test $total_argc -eq 2 || usage
action=${1##--}
;;
@@ -262,6 +266,9 @@ do
--keep-empty)
keep_empty=yes
;;
+ --allow-empty-message)
+ allow_empty_message=--allow-empty-message
+ ;;
--preserve-merges)
preserve_merges=t
test -z "$interactive_rebase" && interactive_rebase=implied
@@ -412,6 +419,10 @@ quit)
edit-todo)
run_specific_rebase
;;
+show-current-patch)
+ run_specific_rebase
+ die "BUG: run_specific_rebase is not supposed to return here"
+ ;;
esac
# Make sure no rebase is in progress
diff --git a/git-send-email.perl b/git-send-email.perl
index bbf4dea..2fa7818 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -26,11 +26,13 @@ use Text::ParseWords;
use Term::ANSIColor;
use File::Temp qw/ tempdir tempfile /;
use File::Spec::Functions qw(catdir catfile);
-use Git::Error qw(:try);
+use Git::LoadCPAN::Error qw(:try);
use Cwd qw(abs_path cwd);
use Git;
use Git::I18N;
-use Git::Mail::Address;
+use Net::Domain ();
+use Net::SMTP ();
+use Git::LoadCPAN::Mail::Address;
Getopt::Long::Configure qw/ pass_through /;
@@ -57,6 +59,7 @@ git send-email --dump-aliases
--[no-]cc <str> * Email Cc:
--[no-]bcc <str> * Email Bcc:
--subject <str> * Email "Subject:"
+ --reply-to <str> * Email "Reply-To:"
--in-reply-to <str> * Email "In-Reply-To:"
--[no-]xmailer * Add "X-Mailer:" header (default).
--[no-]annotate * Review each patch that will be sent in an editor.
@@ -167,13 +170,13 @@ my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
# Variables we fill in automatically, or via prompting:
my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
- $initial_reply_to,$initial_subject,@files,
+ $initial_in_reply_to,$reply_to,$initial_subject,@files,
$author,$sender,$smtp_authpass,$annotate,$use_xmailer,$compose,$time);
my $envelope_sender;
# Example reply to:
-#$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
+#$initial_in_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
my $repo = eval { Git->repository() };
my @repo = $repo ? ($repo) : ();
@@ -315,7 +318,8 @@ die __("--dump-aliases incompatible with other options\n")
if !$help and $dump_aliases and @ARGV;
$rc = GetOptions(
"sender|from=s" => \$sender,
- "in-reply-to=s" => \$initial_reply_to,
+ "in-reply-to=s" => \$initial_in_reply_to,
+ "reply-to=s" => \$reply_to,
"subject=s" => \$initial_subject,
"to=s" => \@initial_to,
"to-cmd=s" => \$to_cmd,
@@ -379,6 +383,10 @@ unless ($rc) {
die __("Cannot run git format-patch from outside a repository\n")
if $format_patch and not $repo;
+die __("`batch-size` and `relogin` must be specified together " .
+ "(via command-line or configuration option)\n")
+ if defined $relogin_delay and not defined $batch_size;
+
# Now, let's fill any that aren't set in with defaults:
sub read_config {
@@ -677,7 +685,8 @@ if ($compose) {
my $tpl_sender = $sender || $repoauthor || $repocommitter || '';
my $tpl_subject = $initial_subject || '';
- my $tpl_reply_to = $initial_reply_to || '';
+ my $tpl_in_reply_to = $initial_in_reply_to || '';
+ my $tpl_reply_to = $reply_to || '';
print $c <<EOT1, Git::prefix_lines("GIT: ", __ <<EOT2), <<EOT3;
From $tpl_sender # This line is ignored.
@@ -689,8 +698,9 @@ for the patch you are writing.
Clear the body content if you don't wish to send a summary.
EOT2
From: $tpl_sender
+Reply-To: $tpl_reply_to
Subject: $tpl_subject
-In-Reply-To: $tpl_reply_to
+In-Reply-To: $tpl_in_reply_to
EOT3
for my $f (@files) {
@@ -704,57 +714,73 @@ EOT3
do_edit($compose_filename);
}
- open my $c2, ">", $compose_filename . ".final"
- or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
-
open $c, "<", $compose_filename
or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
- my $need_8bit_cte = file_has_nonascii($compose_filename);
- my $in_body = 0;
- my $summary_empty = 1;
if (!defined $compose_encoding) {
$compose_encoding = "UTF-8";
}
- while(<$c>) {
- next if m/^GIT:/;
- if ($in_body) {
- $summary_empty = 0 unless (/^\n$/);
- } elsif (/^\n$/) {
- $in_body = 1;
- if ($need_8bit_cte) {
- print $c2 "MIME-Version: 1.0\n",
- "Content-Type: text/plain; ",
- "charset=$compose_encoding\n",
- "Content-Transfer-Encoding: 8bit\n";
- }
- } elsif (/^MIME-Version:/i) {
- $need_8bit_cte = 0;
- } elsif (/^Subject:\s*(.+)\s*$/i) {
- $initial_subject = $1;
- my $subject = $initial_subject;
- $_ = "Subject: " .
- quote_subject($subject, $compose_encoding) .
- "\n";
- } elsif (/^In-Reply-To:\s*(.+)\s*$/i) {
- $initial_reply_to = $1;
- next;
- } elsif (/^From:\s*(.+)\s*$/i) {
- $sender = $1;
- next;
- } elsif (/^(?:To|Cc|Bcc):/i) {
- print __("To/Cc/Bcc fields are not interpreted yet, they have been ignored\n");
- next;
+
+ my %parsed_email;
+ while (my $line = <$c>) {
+ next if $line =~ m/^GIT:/;
+ parse_header_line($line, \%parsed_email);
+ if ($line =~ /^$/) {
+ $parsed_email{'body'} = filter_body($c);
}
- print $c2 $_;
}
close $c;
- close $c2;
- if ($summary_empty) {
+ open my $c2, ">", $compose_filename . ".final"
+ or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
+
+
+ if ($parsed_email{'From'}) {
+ $sender = delete($parsed_email{'From'});
+ }
+ if ($parsed_email{'In-Reply-To'}) {
+ $initial_in_reply_to = delete($parsed_email{'In-Reply-To'});
+ }
+ if ($parsed_email{'Reply-To'}) {
+ $reply_to = delete($parsed_email{'Reply-To'});
+ }
+ if ($parsed_email{'Subject'}) {
+ $initial_subject = delete($parsed_email{'Subject'});
+ print $c2 "Subject: " .
+ quote_subject($initial_subject, $compose_encoding) .
+ "\n";
+ }
+
+ if ($parsed_email{'MIME-Version'}) {
+ print $c2 "MIME-Version: $parsed_email{'MIME-Version'}\n",
+ "Content-Type: $parsed_email{'Content-Type'};\n",
+ "Content-Transfer-Encoding: $parsed_email{'Content-Transfer-Encoding'}\n";
+ delete($parsed_email{'MIME-Version'});
+ delete($parsed_email{'Content-Type'});
+ delete($parsed_email{'Content-Transfer-Encoding'});
+ } elsif (file_has_nonascii($compose_filename)) {
+ my $content_type = (delete($parsed_email{'Content-Type'}) or
+ "text/plain; charset=$compose_encoding");
+ print $c2 "MIME-Version: 1.0\n",
+ "Content-Type: $content_type\n",
+ "Content-Transfer-Encoding: 8bit\n";
+ }
+ # Preserve unknown headers
+ foreach my $key (keys %parsed_email) {
+ next if $key eq 'body';
+ print $c2 "$key: $parsed_email{$key}";
+ }
+
+ if ($parsed_email{'body'}) {
+ print $c2 "\n$parsed_email{'body'}\n";
+ delete($parsed_email{'body'});
+ } else {
print __("Summary email is empty, skipping it\n");
$compose = -1;
}
+
+ close $c2;
+
} elsif ($annotate) {
do_edit(@files);
}
@@ -793,6 +819,32 @@ sub ask {
return;
}
+sub parse_header_line {
+ my $lines = shift;
+ my $parsed_line = shift;
+ my $addr_pat = join "|", qw(To Cc Bcc);
+
+ foreach (split(/\n/, $lines)) {
+ if (/^($addr_pat):\s*(.+)$/i) {
+ $parsed_line->{$1} = [ parse_address_line($2) ];
+ } elsif (/^([^:]*):\s*(.+)\s*$/i) {
+ $parsed_line->{$1} = $2;
+ }
+ }
+}
+
+sub filter_body {
+ my $c = shift;
+ my $body = "";
+ while (my $body_line = <$c>) {
+ if ($body_line !~ m/^GIT:/) {
+ $body .= $body_line;
+ }
+ }
+ return $body;
+}
+
+
my %broken_encoding;
sub file_declares_8bit_cte {
@@ -873,16 +925,22 @@ sub expand_one_alias {
@initial_cc = process_address_list(@initial_cc);
@bcclist = process_address_list(@bcclist);
-if ($thread && !defined $initial_reply_to && $prompting) {
- $initial_reply_to = ask(
+if ($thread && !defined $initial_in_reply_to && $prompting) {
+ $initial_in_reply_to = ask(
__("Message-ID to be used as In-Reply-To for the first email (if any)? "),
default => "",
valid_re => qr/\@.*\./, confirm_only => 1);
}
-if (defined $initial_reply_to) {
- $initial_reply_to =~ s/^\s*<?//;
- $initial_reply_to =~ s/>?\s*$//;
- $initial_reply_to = "<$initial_reply_to>" if $initial_reply_to ne '';
+if (defined $initial_in_reply_to) {
+ $initial_in_reply_to =~ s/^\s*<?//;
+ $initial_in_reply_to =~ s/>?\s*$//;
+ $initial_in_reply_to = "<$initial_in_reply_to>" if $initial_in_reply_to ne '';
+}
+
+if (defined $reply_to) {
+ $reply_to =~ s/^\s+|\s+$//g;
+ ($reply_to) = expand_aliases($reply_to);
+ $reply_to = sanitize_address($reply_to);
}
if (!defined $smtp_server) {
@@ -902,7 +960,7 @@ if ($compose && $compose > 0) {
}
# Variables we set as part of the loop over files
-our ($message_id, %mail, $subject, $reply_to, $references, $message,
+our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
$needs_confirm, $message_num, $ask_default);
sub extract_valid_address {
@@ -1143,10 +1201,8 @@ sub valid_fqdn {
sub maildomain_net {
my $maildomain;
- if (eval { require Net::Domain; 1 }) {
- my $domain = Net::Domain::domainname();
- $maildomain = $domain if valid_fqdn($domain);
- }
+ my $domain = Net::Domain::domainname();
+ $maildomain = $domain if valid_fqdn($domain);
return $maildomain;
}
@@ -1154,17 +1210,15 @@ sub maildomain_net {
sub maildomain_mta {
my $maildomain;
- if (eval { require Net::SMTP; 1 }) {
- for my $host (qw(mailhost localhost)) {
- my $smtp = Net::SMTP->new($host);
- if (defined $smtp) {
- my $domain = $smtp->domain;
- $smtp->quit;
+ for my $host (qw(mailhost localhost)) {
+ my $smtp = Net::SMTP->new($host);
+ if (defined $smtp) {
+ my $domain = $smtp->domain;
+ $smtp->quit;
- $maildomain = $domain if valid_fqdn($domain);
+ $maildomain = $domain if valid_fqdn($domain);
- last if $maildomain;
- }
+ last if $maildomain;
}
}
@@ -1311,11 +1365,14 @@ Message-Id: $message_id
if ($use_xmailer) {
$header .= "X-Mailer: git-send-email $gitversion\n";
}
- if ($reply_to) {
+ if ($in_reply_to) {
- $header .= "In-Reply-To: $reply_to\n";
+ $header .= "In-Reply-To: $in_reply_to\n";
$header .= "References: $references\n";
}
+ if ($reply_to) {
+ $header .= "Reply-To: $reply_to\n";
+ }
if (@xh) {
$header .= join("\n", @xh) . "\n";
}
@@ -1490,8 +1547,8 @@ EOF
return 1;
}
-$reply_to = $initial_reply_to;
-$references = $initial_reply_to || '';
+$in_reply_to = $initial_in_reply_to;
+$references = $initial_in_reply_to || '';
$subject = $initial_subject;
$message_num = 0;
@@ -1701,9 +1758,9 @@ foreach my $t (@files) {
# set up for the next message
if ($thread && $message_was_sent &&
- ($chain_reply_to || !defined $reply_to || length($reply_to) == 0 ||
+ ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
$message_num == 1)) {
- $reply_to = $message_id;
+ $in_reply_to = $message_id;
if (length $references > 0) {
$references .= "\n $message_id";
} else {
diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh
index 1ef1889..9d065fb 100644
--- a/git-sh-i18n.sh
+++ b/git-sh-i18n.sh
@@ -17,15 +17,15 @@ export TEXTDOMAINDIR
# First decide what scheme to use...
GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough
-if test -n "@@USE_GETTEXT_SCHEME@@"
+if test -n "$GIT_GETTEXT_POISON"
+then
+ GIT_INTERNAL_GETTEXT_SH_SCHEME=poison
+elif test -n "@@USE_GETTEXT_SCHEME@@"
then
GIT_INTERNAL_GETTEXT_SH_SCHEME="@@USE_GETTEXT_SCHEME@@"
elif test -n "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS"
then
: no probing necessary
-elif test -n "$GIT_GETTEXT_POISON"
-then
- GIT_INTERNAL_GETTEXT_SH_SCHEME=poison
elif type gettext.sh >/dev/null 2>&1
then
# GNU libintl's gettext.sh
diff --git a/git-stash.sh b/git-stash.sh
index fc8f8ae..94793c1 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -39,7 +39,7 @@ fi
no_changes () {
git diff-index --quiet --cached HEAD --ignore-submodules -- "$@" &&
git diff-files --quiet --ignore-submodules -- "$@" &&
- (test -z "$untracked" || test -z "$(untracked_files)")
+ (test -z "$untracked" || test -z "$(untracked_files "$@")")
}
untracked_files () {
@@ -315,16 +315,18 @@ push_stash () {
if test -z "$patch_mode"
then
test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
- if test -n "$untracked"
+ if test -n "$untracked" && test $# = 0
then
- git clean --force --quiet -d $CLEAN_X_OPTION -- "$@"
+ git clean --force --quiet -d $CLEAN_X_OPTION
fi
if test $# != 0
then
- git add -u -- "$@" |
- git checkout-index -z --force --stdin
- git diff-index -p --cached --binary HEAD -- "$@" | git apply --index -R
+ test -z "$untracked" && UPDATE_OPTION="-u" || UPDATE_OPTION=
+ test "$untracked" = "all" && FORCE_OPTION="--force" || FORCE_OPTION=
+ git add $UPDATE_OPTION $FORCE_OPTION -- "$@"
+ git diff-index -p --cached --binary HEAD -- "$@" |
+ git apply --index -R
else
git reset --hard -q
fi
diff --git a/git.c b/git.c
index c870b97..ceaa58e 100644
--- a/git.c
+++ b/git.c
@@ -5,11 +5,11 @@
#include "run-command.h"
const char git_usage_string[] =
- "git [--version] [--help] [-C <path>] [-c name=value]\n"
- " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
- " [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
- " [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
- " <command> [<args>]";
+ N_("git [--version] [--help] [-C <path>] [-c <name>=<value>]\n"
+ " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
+ " [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
+ " [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
+ " <command> [<args>]");
const char git_more_info_string[] =
N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -92,7 +92,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--git-dir")) {
if (*argc < 2) {
- fprintf(stderr, "No directory given for --git-dir.\n" );
+ fprintf(stderr, _("no directory given for --git-dir\n" ));
usage(git_usage_string);
}
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
@@ -106,7 +106,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--namespace")) {
if (*argc < 2) {
- fprintf(stderr, "No namespace given for --namespace.\n" );
+ fprintf(stderr, _("no namespace given for --namespace\n" ));
usage(git_usage_string);
}
setenv(GIT_NAMESPACE_ENVIRONMENT, (*argv)[1], 1);
@@ -120,7 +120,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--work-tree")) {
if (*argc < 2) {
- fprintf(stderr, "No directory given for --work-tree.\n" );
+ fprintf(stderr, _("no directory given for --work-tree\n" ));
usage(git_usage_string);
}
setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
@@ -134,7 +134,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--super-prefix")) {
if (*argc < 2) {
- fprintf(stderr, "No prefix given for --super-prefix.\n" );
+ fprintf(stderr, _("no prefix given for --super-prefix\n" ));
usage(git_usage_string);
}
setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
@@ -156,7 +156,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "-c")) {
if (*argc < 2) {
- fprintf(stderr, "-c expects a configuration string\n" );
+ fprintf(stderr, _("-c expects a configuration string\n" ));
usage(git_usage_string);
}
git_config_push_parameter((*argv)[1]);
@@ -194,12 +194,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "-C")) {
if (*argc < 2) {
- fprintf(stderr, "No directory given for -C.\n" );
+ fprintf(stderr, _("no directory given for -C\n" ));
usage(git_usage_string);
}
if ((*argv)[1][0]) {
if (chdir((*argv)[1]))
- die_errno("Cannot change to '%s'", (*argv)[1]);
+ die_errno("cannot change to '%s'", (*argv)[1]);
if (envchanged)
*envchanged = 1;
}
@@ -209,7 +209,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
list_builtins();
exit(0);
} else {
- fprintf(stderr, "Unknown option: %s\n", cmd);
+ fprintf(stderr, _("unknown option: %s\n"), cmd);
usage(git_usage_string);
}
@@ -247,7 +247,7 @@ static int handle_alias(int *argcp, const char ***argv)
if (ret >= 0) /* normal exit */
exit(ret);
- die_errno("While expanding alias '%s': '%s'",
+ die_errno("while expanding alias '%s': '%s'",
alias_command, alias_string + 1);
}
count = split_cmdline(alias_string, &new_argv);
@@ -256,8 +256,8 @@ static int handle_alias(int *argcp, const char ***argv)
split_cmdline_strerror(count));
option_count = handle_options(&new_argv, &count, &envchanged);
if (envchanged)
- die("alias '%s' changes environment variables\n"
- "You can use '!git' in the alias to do this.",
+ die("alias '%s' changes environment variables.\n"
+ "You can use '!git' in the alias to do this",
alias_command);
memmove(new_argv - option_count, new_argv,
count * sizeof(char *));
@@ -389,7 +389,7 @@ static struct cmd_struct commands[] = {
{ "column", cmd_column, RUN_SETUP_GENTLY },
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
- { "config", cmd_config, RUN_SETUP_GENTLY },
+ { "config", cmd_config, RUN_SETUP_GENTLY | DELAY_PAGER_CONFIG },
{ "count-objects", cmd_count_objects, RUN_SETUP },
{ "credential", cmd_credential, RUN_SETUP_GENTLY },
{ "describe", cmd_describe, RUN_SETUP },
@@ -684,8 +684,8 @@ int cmd_main(int argc, const char **argv)
if (errno != ENOENT)
break;
if (was_alias) {
- fprintf(stderr, "Expansion of alias '%s' failed; "
- "'%s' is not a git command\n",
+ fprintf(stderr, _("expansion of alias '%s' failed; "
+ "'%s' is not a git command\n"),
cmd, argv[0]);
exit(1);
}
@@ -696,7 +696,7 @@ int cmd_main(int argc, const char **argv)
break;
}
- fprintf(stderr, "Failed to run command '%s': %s\n",
+ fprintf(stderr, _("failed to run command '%s': %s\n"),
cmd, strerror(errno));
return 1;
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 408f285..a58e6b3 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -29,12 +29,11 @@ Requirements
------------
- Core git tools
- - Perl
+ - Perl 5.8
- Perl modules: CGI, Encode, Fcntl, File::Find, File::Basename.
- web server
The following optional Perl modules are required for extra features
- - Digest::MD5 - for gravatar support
- CGI::Fast and FCGI - for running gitweb as FastCGI script
- HTML::TagCloud - for fancy tag cloud in project list view
- HTTP::Date or Time::ParseDate - to support If-Modified-Since for feeds
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 2417057..2594a4b 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -20,6 +20,8 @@ use Fcntl ':mode';
use File::Find qw();
use File::Basename qw(basename);
use Time::HiRes qw(gettimeofday tv_interval);
+use Digest::MD5 qw(md5_hex);
+
binmode STDOUT, ':utf8';
if (!defined($CGI::VERSION) || $CGI::VERSION < 4.08) {
@@ -490,7 +492,6 @@ our %feature = (
# Currently available providers are gravatar and picon.
# If an unknown provider is specified, the feature is disabled.
- # Gravatar depends on Digest::MD5.
# Picon currently relies on the indiana.edu database.
# To enable system wide have in $GITWEB_CONFIG
@@ -1166,18 +1167,8 @@ sub configure_gitweb_features {
our @snapshot_fmts = gitweb_get_feature('snapshot');
@snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts);
- # check that the avatar feature is set to a known provider name,
- # and for each provider check if the dependencies are satisfied.
- # if the provider name is invalid or the dependencies are not met,
- # reset $git_avatar to the empty string.
our ($git_avatar) = gitweb_get_feature('avatar');
- if ($git_avatar eq 'gravatar') {
- $git_avatar = '' unless (eval { require Digest::MD5; 1; });
- } elsif ($git_avatar eq 'picon') {
- # no dependencies
- } else {
- $git_avatar = '';
- }
+ $git_avatar = '' unless $git_avatar =~ /^(?:gravatar|picon)$/s;
our @extra_branch_refs = gitweb_get_feature('extra-branch-refs');
@extra_branch_refs = filter_and_validate_refs (@extra_branch_refs);
@@ -2167,7 +2158,7 @@ sub gravatar_url {
my $size = shift;
$avatar_cache{$email} ||=
"//www.gravatar.com/avatar/" .
- Digest::MD5::md5_hex($email) . "?s=";
+ md5_hex($email) . "?s=";
return $avatar_cache{$email} . $size;
}
diff --git a/grep.c b/grep.c
index 3d7cd0e..65b90c1 100644
--- a/grep.c
+++ b/grep.c
@@ -18,6 +18,11 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)
fwrite(buf, size, 1, stdout);
}
+static void color_set(char *dst, const char *color_bytes)
+{
+ xsnprintf(dst, COLOR_MAXLEN, "%s", color_bytes);
+}
+
/*
* Initialize the grep_defaults template with hardcoded defaults.
* We could let the compiler do this, but without C99 initializers
@@ -2010,7 +2015,7 @@ static int grep_source_load_oid(struct grep_source *gs)
enum object_type type;
grep_read_lock();
- gs->buf = read_sha1_file(gs->identifier, &type, &gs->size);
+ gs->buf = read_object_file(gs->identifier, &type, &gs->size);
grep_read_unlock();
if (!gs->buf)
diff --git a/hash.h b/hash.h
index 7d7a864..7c8238b 100644
--- a/hash.h
+++ b/hash.h
@@ -15,6 +15,31 @@
#include "block-sha1/sha1.h"
#endif
+#ifndef platform_SHA_CTX
+/*
+ * platform's underlying implementation of SHA-1; could be OpenSSL,
+ * blk_SHA, Apple CommonCrypto, etc... Note that the relevant
+ * SHA-1 header may have already defined platform_SHA_CTX for our
+ * own implementations like block-sha1 and ppc-sha1, so we list
+ * the default for OpenSSL compatible SHA-1 implementations here.
+ */
+#define platform_SHA_CTX SHA_CTX
+#define platform_SHA1_Init SHA1_Init
+#define platform_SHA1_Update SHA1_Update
+#define platform_SHA1_Final SHA1_Final
+#endif
+
+#define git_SHA_CTX platform_SHA_CTX
+#define git_SHA1_Init platform_SHA1_Init
+#define git_SHA1_Update platform_SHA1_Update
+#define git_SHA1_Final platform_SHA1_Final
+
+#ifdef SHA1_MAX_BLOCK_SIZE
+#include "compat/sha1-chunked.h"
+#undef git_SHA1_Update
+#define git_SHA1_Update git_SHA1_Update_Chunked
+#endif
+
/*
* Note that these constants are suitable for indexing the hash_algos array and
* comparing against each other, but are otherwise arbitrary, so they should not
@@ -30,9 +55,15 @@
/* Number of algorithms supported (including unknown). */
#define GIT_HASH_NALGOS (GIT_HASH_SHA1 + 1)
-typedef void (*git_hash_init_fn)(void *ctx);
-typedef void (*git_hash_update_fn)(void *ctx, const void *in, size_t len);
-typedef void (*git_hash_final_fn)(unsigned char *hash, void *ctx);
+/* A suitably aligned type for stack allocations of hash contexts. */
+union git_hash_ctx {
+ git_SHA_CTX sha1;
+};
+typedef union git_hash_ctx git_hash_ctx;
+
+typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
+typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
+typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
struct git_hash_algo {
/*
@@ -44,9 +75,6 @@ struct git_hash_algo {
/* A four-byte version identifier, used in pack indices. */
uint32_t format_id;
- /* The size of a hash context (e.g. git_SHA_CTX). */
- size_t ctxsz;
-
/* The length of the hash in binary. */
size_t rawsz;
diff --git a/http-push.c b/http-push.c
index 0913f8a..ff82b63 100644
--- a/http-push.c
+++ b/http-push.c
@@ -361,8 +361,8 @@ static void start_put(struct transfer_request *request)
ssize_t size;
git_zstream stream;
- unpacked = read_sha1_file(request->obj->oid.hash, &type, &len);
- hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), len) + 1;
+ unpacked = read_object_file(&request->obj->oid, &type, &len);
+ hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), len) + 1;
/* Set it up */
git_deflate_init(&stream, zlib_compression_level);
diff --git a/http-walker.c b/http-walker.c
index 07c2b1a..f506f39 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -22,7 +22,7 @@ enum object_request_state {
struct object_request {
struct walker *walker;
- unsigned char sha1[20];
+ struct object_id oid;
struct alt_base *repo;
enum object_request_state state;
struct http_object_request *req;
@@ -56,7 +56,7 @@ static void start_object_request(struct walker *walker,
struct active_request_slot *slot;
struct http_object_request *req;
- req = new_http_object_request(obj_req->repo->base, obj_req->sha1);
+ req = new_http_object_request(obj_req->repo->base, obj_req->oid.hash);
if (req == NULL) {
obj_req->state = ABORTED;
return;
@@ -82,7 +82,7 @@ static void finish_object_request(struct object_request *obj_req)
return;
if (obj_req->req->rename == 0)
- walker_say(obj_req->walker, "got %s\n", sha1_to_hex(obj_req->sha1));
+ walker_say(obj_req->walker, "got %s\n", oid_to_hex(&obj_req->oid));
}
static void process_object_response(void *callback_data)
@@ -129,7 +129,7 @@ static int fill_active_slot(struct walker *walker)
list_for_each_safe(pos, tmp, head) {
obj_req = list_entry(pos, struct object_request, node);
if (obj_req->state == WAITING) {
- if (has_sha1_file(obj_req->sha1))
+ if (has_sha1_file(obj_req->oid.hash))
obj_req->state = COMPLETE;
else {
start_object_request(walker, obj_req);
@@ -148,7 +148,7 @@ static void prefetch(struct walker *walker, unsigned char *sha1)
newreq = xmalloc(sizeof(*newreq));
newreq->walker = walker;
- hashcpy(newreq->sha1, sha1);
+ hashcpy(newreq->oid.hash, sha1);
newreq->repo = data->alt;
newreq->state = WAITING;
newreq->req = NULL;
@@ -481,13 +481,13 @@ static int fetch_object(struct walker *walker, unsigned char *sha1)
list_for_each(pos, head) {
obj_req = list_entry(pos, struct object_request, node);
- if (!hashcmp(obj_req->sha1, sha1))
+ if (!hashcmp(obj_req->oid.hash, sha1))
break;
}
if (obj_req == NULL)
return error("Couldn't find request for %s in the queue", hex);
- if (has_sha1_file(obj_req->sha1)) {
+ if (has_sha1_file(obj_req->oid.hash)) {
if (obj_req->req != NULL)
abort_http_object_request(obj_req->req);
abort_object_request(obj_req);
@@ -541,7 +541,7 @@ static int fetch_object(struct walker *walker, unsigned char *sha1)
} else if (req->zret != Z_STREAM_END) {
walker->corrupt_object_found++;
ret = error("File %s (%s) corrupt", hex, req->url);
- } else if (hashcmp(obj_req->sha1, req->real_sha1)) {
+ } else if (hashcmp(obj_req->oid.hash, req->real_sha1)) {
ret = error("File %s has bad hash", hex);
} else if (req->rename < 0) {
struct strbuf buf = STRBUF_INIT;
diff --git a/http.c b/http.c
index 3175502..a5bd5d6 100644
--- a/http.c
+++ b/http.c
@@ -69,6 +69,9 @@ static const char *ssl_key;
#if LIBCURL_VERSION_NUM >= 0x070908
static const char *ssl_capath;
#endif
+#if LIBCURL_VERSION_NUM >= 0x071304
+static const char *curl_no_proxy;
+#endif
#if LIBCURL_VERSION_NUM >= 0x072c00
static const char *ssl_pinnedkey;
#endif
@@ -77,7 +80,6 @@ static long curl_low_speed_limit = -1;
static long curl_low_speed_time = -1;
static int curl_ftp_no_epsv;
static const char *curl_http_proxy;
-static const char *curl_no_proxy;
static const char *http_proxy_authmethod;
static struct {
const char *name;
@@ -1260,14 +1262,14 @@ static struct fill_chain *fill_cfg;
void add_fill_function(void *data, int (*fill)(void *))
{
- struct fill_chain *new = xmalloc(sizeof(*new));
+ struct fill_chain *new_fill = xmalloc(sizeof(*new_fill));
struct fill_chain **linkp = &fill_cfg;
- new->data = data;
- new->fill = fill;
- new->next = NULL;
+ new_fill->data = data;
+ new_fill->fill = fill;
+ new_fill->next = NULL;
while (*linkp)
linkp = &(*linkp)->next;
- *linkp = new;
+ *linkp = new_fill;
}
void fill_active_slots(void)
diff --git a/imap-send.c b/imap-send.c
index 36c7c1b..ffb0a6e 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1189,11 +1189,11 @@ bail:
*/
static void lf_to_crlf(struct strbuf *msg)
{
- char *new;
+ char *new_msg;
size_t i, j;
char lastc;
- /* First pass: tally, in j, the size of the new string: */
+ /* First pass: tally, in j, the size of the new_msg string: */
for (i = j = 0, lastc = '\0'; i < msg->len; i++) {
if (msg->buf[i] == '\n' && lastc != '\r')
j++; /* a CR will need to be added here */
@@ -1201,18 +1201,18 @@ static void lf_to_crlf(struct strbuf *msg)
j++;
}
- new = xmallocz(j);
+ new_msg = xmallocz(j);
/*
- * Second pass: write the new string. Note that this loop is
+ * Second pass: write the new_msg string. Note that this loop is
* otherwise identical to the first pass.
*/
for (i = j = 0, lastc = '\0'; i < msg->len; i++) {
if (msg->buf[i] == '\n' && lastc != '\r')
- new[j++] = '\r';
- lastc = new[j++] = msg->buf[i];
+ new_msg[j++] = '\r';
+ lastc = new_msg[j++] = msg->buf[i];
}
- strbuf_attach(msg, new, j, j + 1);
+ strbuf_attach(msg, new_msg, j, j + 1);
}
/*
diff --git a/line-log.c b/line-log.c
index 545ad0f..ecdce08 100644
--- a/line-log.c
+++ b/line-log.c
@@ -151,29 +151,29 @@ static void range_set_union(struct range_set *out,
assert(out->nr == 0);
while (i < a->nr || j < b->nr) {
- struct range *new;
+ struct range *new_range;
if (i < a->nr && j < b->nr) {
if (ra[i].start < rb[j].start)
- new = &ra[i++];
+ new_range = &ra[i++];
else if (ra[i].start > rb[j].start)
- new = &rb[j++];
+ new_range = &rb[j++];
else if (ra[i].end < rb[j].end)
- new = &ra[i++];
+ new_range = &ra[i++];
else
- new = &rb[j++];
+ new_range = &rb[j++];
} else if (i < a->nr) /* b exhausted */
- new = &ra[i++];
+ new_range = &ra[i++];
else /* a exhausted */
- new = &rb[j++];
- if (new->start == new->end)
+ new_range = &rb[j++];
+ if (new_range->start == new_range->end)
; /* empty range */
- else if (!out->nr || out->ranges[out->nr-1].end < new->start) {
+ else if (!out->nr || out->ranges[out->nr-1].end < new_range->start) {
range_set_grow(out, 1);
- out->ranges[out->nr].start = new->start;
- out->ranges[out->nr].end = new->end;
+ out->ranges[out->nr].start = new_range->start;
+ out->ranges[out->nr].end = new_range->end;
out->nr++;
- } else if (out->ranges[out->nr-1].end < new->end) {
- out->ranges[out->nr-1].end = new->end;
+ } else if (out->ranges[out->nr-1].end < new_range->end) {
+ out->ranges[out->nr-1].end = new_range->end;
}
}
}
@@ -501,8 +501,7 @@ static void fill_blob_sha1(struct commit *commit, struct diff_filespec *spec)
unsigned mode;
struct object_id oid;
- if (get_tree_entry(commit->object.oid.hash, spec->path,
- oid.hash, &mode))
+ if (get_tree_entry(&commit->object.oid, spec->path, &oid, &mode))
die("There is no path %s in the commit", spec->path);
fill_filespec(spec, &oid, 1, mode);
@@ -696,18 +695,18 @@ static struct line_log_data *line_log_data_merge(struct line_log_data *a,
static void add_line_range(struct rev_info *revs, struct commit *commit,
struct line_log_data *range)
{
- struct line_log_data *old = NULL;
- struct line_log_data *new = NULL;
+ struct line_log_data *old_line = NULL;
+ struct line_log_data *new_line = NULL;
- old = lookup_decoration(&revs->line_log_data, &commit->object);
- if (old && range) {
- new = line_log_data_merge(old, range);
- free_line_log_data(old);
+ old_line = lookup_decoration(&revs->line_log_data, &commit->object);
+ if (old_line && range) {
+ new_line = line_log_data_merge(old_line, range);
+ free_line_log_data(old_line);
} else if (range)
- new = line_log_data_copy(range);
+ new_line = line_log_data_copy(range);
- if (new)
- add_decoration(&revs->line_log_data, &commit->object, new);
+ if (new_line)
+ add_decoration(&revs->line_log_data, &commit->object, new_line);
}
static void clear_commit_line_range(struct rev_info *revs, struct commit *commit)
@@ -1042,12 +1041,12 @@ static int process_diff_filepair(struct rev_info *rev,
static struct diff_filepair *diff_filepair_dup(struct diff_filepair *pair)
{
- struct diff_filepair *new = xmalloc(sizeof(struct diff_filepair));
- new->one = pair->one;
- new->two = pair->two;
- new->one->count++;
- new->two->count++;
- return new;
+ struct diff_filepair *new_filepair = xmalloc(sizeof(struct diff_filepair));
+ new_filepair->one = pair->one;
+ new_filepair->two = pair->two;
+ new_filepair->one->count++;
+ new_filepair->two->count++;
+ return new_filepair;
}
static void free_diffqueues(int n, struct diff_queue_struct *dq)
diff --git a/list-objects-filter.c b/list-objects-filter.c
index 4356c45..0ec83aa 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -117,7 +117,7 @@ static enum list_objects_filter_result filter_blobs_limit(
assert(obj->type == OBJ_BLOB);
assert((obj->flags & SEEN) == 0);
- t = sha1_object_info(obj->oid.hash, &object_length);
+ t = oid_object_info(&obj->oid, &object_length);
if (t != OBJ_BLOB) { /* probably OBJ_NONE */
/*
* We DO NOT have the blob locally, so we cannot
diff --git a/log-tree.c b/log-tree.c
index fca29d4..d1c0bed 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -177,7 +177,7 @@ static void show_parents(struct commit *commit, int abbrev, FILE *file)
struct commit_list *p;
for (p = commit->parents; p ; p = p->next) {
struct commit *parent = p->item;
- fprintf(file, " %s", find_unique_abbrev(parent->object.oid.hash, abbrev));
+ fprintf(file, " %s", find_unique_abbrev(&parent->object.oid, abbrev));
}
}
@@ -185,7 +185,7 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
{
struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
for ( ; p; p = p->next) {
- fprintf(opt->diffopt.file, " %s", find_unique_abbrev(p->item->object.oid.hash, abbrev));
+ fprintf(opt->diffopt.file, " %s", find_unique_abbrev(&p->item->object.oid, abbrev));
}
}
@@ -499,7 +499,7 @@ static void show_one_mergetag(struct commit *commit,
int status, nth;
size_t payload_size, gpg_message_offset;
- hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), oid.hash);
+ hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &oid);
tag = lookup_tag(&oid);
if (!tag)
return; /* error message already given */
@@ -558,7 +558,7 @@ void show_log(struct rev_info *opt)
if (!opt->graph)
put_revision_mark(opt, commit);
- fputs(find_unique_abbrev(commit->object.oid.hash, abbrev_commit), opt->diffopt.file);
+ fputs(find_unique_abbrev(&commit->object.oid, abbrev_commit), opt->diffopt.file);
if (opt->print_parents)
show_parents(commit, abbrev_commit, opt->diffopt.file);
if (opt->children.name)
@@ -620,7 +620,8 @@ void show_log(struct rev_info *opt)
if (!opt->graph)
put_revision_mark(opt, commit);
- fputs(find_unique_abbrev(commit->object.oid.hash, abbrev_commit),
+ fputs(find_unique_abbrev(&commit->object.oid,
+ abbrev_commit),
opt->diffopt.file);
if (opt->print_parents)
show_parents(commit, abbrev_commit, opt->diffopt.file);
@@ -628,8 +629,7 @@ void show_log(struct rev_info *opt)
show_children(opt, commit, abbrev_commit);
if (parent)
fprintf(opt->diffopt.file, " (from %s)",
- find_unique_abbrev(parent->object.oid.hash,
- abbrev_commit));
+ find_unique_abbrev(&parent->object.oid, abbrev_commit));
fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), opt->diffopt.file);
show_decorations(opt, commit);
if (opt->commit_format == CMIT_FMT_ONELINE) {
@@ -659,9 +659,6 @@ void show_log(struct rev_info *opt)
show_mergetag(opt, commit);
}
- if (!get_cached_commit_buffer(commit, NULL))
- return;
-
if (opt->show_notes) {
int raw;
struct strbuf notebuf = STRBUF_INIT;
diff --git a/mailmap.c b/mailmap.c
index cb921b4..13f0d28 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -224,7 +224,7 @@ static int read_mailmap_blob(struct string_list *map,
if (get_oid(name, &oid) < 0)
return 0;
- buf = read_sha1_file(oid.hash, &type, &size);
+ buf = read_object_file(&oid, &type, &size);
if (!buf)
return error("unable to read mailmap object at %s", name);
if (type != OBJ_BLOB)
diff --git a/match-trees.c b/match-trees.c
index 396b733..72cc2ba 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -54,7 +54,7 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
enum object_type type;
unsigned long size;
- buffer = read_sha1_file(hash->hash, &type, &size);
+ buffer = read_object_file(hash, &type, &size);
if (!buffer)
die("unable to read tree (%s)", oid_to_hex(hash));
if (type != OBJ_TREE)
@@ -158,22 +158,20 @@ static void match_trees(const struct object_id *hash1,
}
/*
- * A tree "hash1" has a subdirectory at "prefix". Come up with a
- * tree object by replacing it with another tree "hash2".
+ * A tree "oid1" has a subdirectory at "prefix". Come up with a tree object by
+ * replacing it with another tree "oid2".
*/
-static int splice_tree(const unsigned char *hash1,
- const char *prefix,
- const unsigned char *hash2,
- unsigned char *result)
+static int splice_tree(const struct object_id *oid1, const char *prefix,
+ const struct object_id *oid2, struct object_id *result)
{
char *subpath;
int toplen;
char *buf;
unsigned long sz;
struct tree_desc desc;
- unsigned char *rewrite_here;
- const unsigned char *rewrite_with;
- unsigned char subtree[20];
+ struct object_id *rewrite_here;
+ const struct object_id *rewrite_with;
+ struct object_id subtree;
enum object_type type;
int status;
@@ -182,9 +180,9 @@ static int splice_tree(const unsigned char *hash1,
if (*subpath)
subpath++;
- buf = read_sha1_file(hash1, &type, &sz);
+ buf = read_object_file(oid1, &type, &sz);
if (!buf)
- die("cannot read tree %s", sha1_to_hex(hash1));
+ die("cannot read tree %s", oid_to_hex(oid1));
init_tree_desc(&desc, buf, sz);
rewrite_here = NULL;
@@ -197,26 +195,26 @@ static int splice_tree(const unsigned char *hash1,
if (strlen(name) == toplen &&
!memcmp(name, prefix, toplen)) {
if (!S_ISDIR(mode))
- die("entry %s in tree %s is not a tree",
- name, sha1_to_hex(hash1));
- rewrite_here = (unsigned char *) oid->hash;
+ die("entry %s in tree %s is not a tree", name,
+ oid_to_hex(oid1));
+ rewrite_here = (struct object_id *)oid;
break;
}
update_tree_entry(&desc);
}
if (!rewrite_here)
- die("entry %.*s not found in tree %s",
- toplen, prefix, sha1_to_hex(hash1));
+ die("entry %.*s not found in tree %s", toplen, prefix,
+ oid_to_hex(oid1));
if (*subpath) {
- status = splice_tree(rewrite_here, subpath, hash2, subtree);
+ status = splice_tree(rewrite_here, subpath, oid2, &subtree);
if (status)
return status;
- rewrite_with = subtree;
+ rewrite_with = &subtree;
+ } else {
+ rewrite_with = oid2;
}
- else
- rewrite_with = hash2;
- hashcpy(rewrite_here, rewrite_with);
- status = write_sha1_file(buf, sz, tree_type, result);
+ oidcpy(rewrite_here, rewrite_with);
+ status = write_object_file(buf, sz, tree_type, result);
free(buf);
return status;
}
@@ -271,7 +269,7 @@ void shift_tree(const struct object_id *hash1,
if (!*del_prefix)
return;
- if (get_tree_entry(hash2->hash, del_prefix, shifted->hash, &mode))
+ if (get_tree_entry(hash2, del_prefix, shifted, &mode))
die("cannot find path %s in tree %s",
del_prefix, oid_to_hex(hash2));
return;
@@ -280,7 +278,7 @@ void shift_tree(const struct object_id *hash1,
if (!*add_prefix)
return;
- splice_tree(hash1->hash, add_prefix, hash2->hash, shifted->hash);
+ splice_tree(hash1, add_prefix, hash2, shifted);
}
/*
@@ -298,12 +296,12 @@ void shift_tree_by(const struct object_id *hash1,
unsigned candidate = 0;
/* Can hash2 be a tree at shift_prefix in tree hash1? */
- if (!get_tree_entry(hash1->hash, shift_prefix, sub1.hash, &mode1) &&
+ if (!get_tree_entry(hash1, shift_prefix, &sub1, &mode1) &&
S_ISDIR(mode1))
candidate |= 1;
/* Can hash1 be a tree at shift_prefix in tree hash2? */
- if (!get_tree_entry(hash2->hash, shift_prefix, sub2.hash, &mode2) &&
+ if (!get_tree_entry(hash2, shift_prefix, &sub2, &mode2) &&
S_ISDIR(mode2))
candidate |= 2;
@@ -334,7 +332,7 @@ void shift_tree_by(const struct object_id *hash1,
* shift tree2 down by adding shift_prefix above it
* to match tree1.
*/
- splice_tree(hash1->hash, shift_prefix, hash2->hash, shifted->hash);
+ splice_tree(hash1, shift_prefix, hash2, shifted);
else
/*
* shift tree2 up by removing shift_prefix from it
diff --git a/merge-blobs.c b/merge-blobs.c
index 9b6eac2..fa49c17 100644
--- a/merge-blobs.c
+++ b/merge-blobs.c
@@ -11,7 +11,7 @@ static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
unsigned long size;
enum object_type type;
- buf = read_sha1_file(obj->object.oid.hash, &type, &size);
+ buf = read_object_file(&obj->object.oid, &type, &size);
if (!buf)
return -1;
if (type != OBJ_BLOB) {
@@ -66,7 +66,7 @@ void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct
return NULL;
if (!our)
our = their;
- return read_sha1_file(our->object.oid.hash, &type, size);
+ return read_object_file(&our->object.oid, &type, size);
}
if (fill_mmfile_blob(&f1, our) < 0)
diff --git a/merge-recursive.c b/merge-recursive.c
index cc5fa0a..9c05eb7 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -49,6 +49,67 @@ static unsigned int path_hash(const char *path)
return ignore_case ? strihash(path) : strhash(path);
}
+static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,
+ char *dir)
+{
+ struct dir_rename_entry key;
+
+ if (dir == NULL)
+ return NULL;
+ hashmap_entry_init(&key, strhash(dir));
+ key.dir = dir;
+ return hashmap_get(hashmap, &key, NULL);
+}
+
+static int dir_rename_cmp(const void *unused_cmp_data,
+ const void *entry,
+ const void *entry_or_key,
+ const void *unused_keydata)
+{
+ const struct dir_rename_entry *e1 = entry;
+ const struct dir_rename_entry *e2 = entry_or_key;
+
+ return strcmp(e1->dir, e2->dir);
+}
+
+static void dir_rename_init(struct hashmap *map)
+{
+ hashmap_init(map, dir_rename_cmp, NULL, 0);
+}
+
+static void dir_rename_entry_init(struct dir_rename_entry *entry,
+ char *directory)
+{
+ hashmap_entry_init(entry, strhash(directory));
+ entry->dir = directory;
+ entry->non_unique_new_dir = 0;
+ strbuf_init(&entry->new_dir, 0);
+ string_list_init(&entry->possible_new_dirs, 0);
+}
+
+static struct collision_entry *collision_find_entry(struct hashmap *hashmap,
+ char *target_file)
+{
+ struct collision_entry key;
+
+ hashmap_entry_init(&key, strhash(target_file));
+ key.target_file = target_file;
+ return hashmap_get(hashmap, &key, NULL);
+}
+
+static int collision_cmp(void *unused_cmp_data,
+ const struct collision_entry *e1,
+ const struct collision_entry *e2,
+ const void *unused_keydata)
+{
+ return strcmp(e1->target_file, e2->target_file);
+}
+
+static void collision_init(struct hashmap *map)
+{
+ hashmap_init(map, (hashmap_cmp_fn) collision_cmp, NULL, 0);
+}
+
static void flush_output(struct merge_options *o)
{
if (o->buffer_output < 2 && o->obuf.len) {
@@ -119,6 +180,7 @@ static int oid_eq(const struct object_id *a, const struct object_id *b)
enum rename_type {
RENAME_NORMAL = 0,
+ RENAME_DIR,
RENAME_DELETE,
RENAME_ONE_FILE_TO_ONE,
RENAME_ONE_FILE_TO_TWO,
@@ -228,7 +290,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
strbuf_addf(&o->obuf, "virtual %s\n",
merge_remote_util(commit)->name);
else {
- strbuf_add_unique_abbrev(&o->obuf, commit->object.oid.hash,
+ strbuf_add_unique_abbrev(&o->obuf, &commit->object.oid,
DEFAULT_ABBREV);
strbuf_addch(&o->obuf, ' ');
if (parse_commit(commit) != 0)
@@ -275,32 +337,37 @@ static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
init_tree_desc(desc, tree->buffer, tree->size);
}
-static int git_merge_trees(int index_only,
+static int git_merge_trees(struct merge_options *o,
struct tree *common,
struct tree *head,
struct tree *merge)
{
int rc;
struct tree_desc t[3];
- struct unpack_trees_options opts;
- memset(&opts, 0, sizeof(opts));
- if (index_only)
- opts.index_only = 1;
+ memset(&o->unpack_opts, 0, sizeof(o->unpack_opts));
+ if (o->call_depth)
+ o->unpack_opts.index_only = 1;
else
- opts.update = 1;
- opts.merge = 1;
- opts.head_idx = 2;
- opts.fn = threeway_merge;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
- setup_unpack_trees_porcelain(&opts, "merge");
+ o->unpack_opts.update = 1;
+ o->unpack_opts.merge = 1;
+ o->unpack_opts.head_idx = 2;
+ o->unpack_opts.fn = threeway_merge;
+ o->unpack_opts.src_index = &the_index;
+ o->unpack_opts.dst_index = &the_index;
+ setup_unpack_trees_porcelain(&o->unpack_opts, "merge");
init_tree_desc_from_tree(t+0, common);
init_tree_desc_from_tree(t+1, head);
init_tree_desc_from_tree(t+2, merge);
- rc = unpack_trees(3, t, &opts);
+ rc = unpack_trees(3, t, &o->unpack_opts);
+ /*
+ * unpack_trees NULLifies src_index, but it's used in verify_uptodate,
+ * so set to the new index which will usually have modification
+ * timestamp info copied over.
+ */
+ o->unpack_opts.src_index = &the_index;
cache_tree_free(&active_cache_tree);
return rc;
}
@@ -335,7 +402,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
return result;
}
-static int save_files_dirs(const unsigned char *sha1,
+static int save_files_dirs(const struct object_id *oid,
struct strbuf *base, const char *path,
unsigned int mode, int stage, void *context)
{
@@ -360,6 +427,21 @@ static void get_files_dirs(struct merge_options *o, struct tree *tree)
read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o);
}
+static int get_tree_entry_if_blob(struct tree *tree,
+ const char *path,
+ struct object_id *hashy,
+ unsigned int *mode_o)
+{
+ int ret;
+
+ ret = get_tree_entry(&tree->object.oid, path, hashy, mode_o);
+ if (S_ISDIR(*mode_o)) {
+ oidcpy(hashy, &null_oid);
+ *mode_o = 0;
+ }
+ return ret;
+}
+
/*
* Returns an index_entry instance which doesn't have to correspond to
* a real cache entry in Git's index.
@@ -370,12 +452,12 @@ static struct stage_data *insert_stage_data(const char *path,
{
struct string_list_item *item;
struct stage_data *e = xcalloc(1, sizeof(struct stage_data));
- get_tree_entry(o->object.oid.hash, path,
- e->stages[1].oid.hash, &e->stages[1].mode);
- get_tree_entry(a->object.oid.hash, path,
- e->stages[2].oid.hash, &e->stages[2].mode);
- get_tree_entry(b->object.oid.hash, path,
- e->stages[3].oid.hash, &e->stages[3].mode);
+ get_tree_entry_if_blob(o, path,
+ &e->stages[1].oid, &e->stages[1].mode);
+ get_tree_entry_if_blob(a, path,
+ &e->stages[2].oid, &e->stages[2].mode);
+ get_tree_entry_if_blob(b, path,
+ &e->stages[3].oid, &e->stages[3].mode);
item = string_list_insert(entries, path);
item->util = e;
return e;
@@ -513,80 +595,31 @@ static void record_df_conflict_files(struct merge_options *o,
struct rename {
struct diff_filepair *pair;
+ /*
+ * Purpose of src_entry and dst_entry:
+ *
+ * If 'before' is renamed to 'after' then src_entry will contain
+ * the versions of 'before' from the merge_base, HEAD, and MERGE in
+ * stages 1, 2, and 3; dst_entry will contain the respective
+ * versions of 'after' in corresponding locations. Thus, we have a
+ * total of six modes and oids, though some will be null. (Stage 0
+ * is ignored; we're interested in handling conflicts.)
+ *
+ * Since we don't turn on break-rewrites by default, neither
+ * src_entry nor dst_entry can have all three of their stages have
+ * non-null oids, meaning at most four of the six will be non-null.
+ * Also, since this is a rename, both src_entry and dst_entry will
+ * have at least one non-null oid, meaning at least two will be
+ * non-null. Of the six oids, a typical rename will have three be
+ * non-null. Only two implies a rename/delete, and four implies a
+ * rename/add.
+ */
struct stage_data *src_entry;
struct stage_data *dst_entry;
+ unsigned add_turned_into_rename:1;
unsigned processed:1;
};
-/*
- * Get information of all renames which occurred between 'o_tree' and
- * 'tree'. We need the three trees in the merge ('o_tree', 'a_tree' and
- * 'b_tree') to be able to associate the correct cache entries with
- * the rename information. 'tree' is always equal to either a_tree or b_tree.
- */
-static struct string_list *get_renames(struct merge_options *o,
- struct tree *tree,
- struct tree *o_tree,
- struct tree *a_tree,
- struct tree *b_tree,
- struct string_list *entries)
-{
- int i;
- struct string_list *renames;
- struct diff_options opts;
-
- renames = xcalloc(1, sizeof(struct string_list));
- if (!o->detect_rename)
- return renames;
-
- diff_setup(&opts);
- opts.flags.recursive = 1;
- opts.flags.rename_empty = 0;
- opts.detect_rename = DIFF_DETECT_RENAME;
- opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
- o->diff_rename_limit >= 0 ? o->diff_rename_limit :
- 1000;
- opts.rename_score = o->rename_score;
- opts.show_rename_progress = o->show_rename_progress;
- opts.output_format = DIFF_FORMAT_NO_OUTPUT;
- diff_setup_done(&opts);
- diff_tree_oid(&o_tree->object.oid, &tree->object.oid, "", &opts);
- diffcore_std(&opts);
- if (opts.needed_rename_limit > o->needed_rename_limit)
- o->needed_rename_limit = opts.needed_rename_limit;
- for (i = 0; i < diff_queued_diff.nr; ++i) {
- struct string_list_item *item;
- struct rename *re;
- struct diff_filepair *pair = diff_queued_diff.queue[i];
- if (pair->status != 'R') {
- diff_free_filepair(pair);
- continue;
- }
- re = xmalloc(sizeof(*re));
- re->processed = 0;
- re->pair = pair;
- item = string_list_lookup(entries, re->pair->one->path);
- if (!item)
- re->src_entry = insert_stage_data(re->pair->one->path,
- o_tree, a_tree, b_tree, entries);
- else
- re->src_entry = item->util;
-
- item = string_list_lookup(entries, re->pair->two->path);
- if (!item)
- re->dst_entry = insert_stage_data(re->pair->two->path,
- o_tree, a_tree, b_tree, entries);
- else
- re->dst_entry = item->util;
- item = string_list_insert(renames, pair->one->path);
- item->util = re;
- }
- opts.output_format = DIFF_FORMAT_NO_OUTPUT;
- diff_queued_diff.nr = 0;
- diff_flush(&opts);
- return renames;
-}
-
static int update_stages(struct merge_options *opt, const char *path,
const struct diff_filespec *o,
const struct diff_filespec *a,
@@ -618,6 +651,27 @@ static int update_stages(struct merge_options *opt, const char *path,
return 0;
}
+static int update_stages_for_stage_data(struct merge_options *opt,
+ const char *path,
+ const struct stage_data *stage_data)
+{
+ struct diff_filespec o, a, b;
+
+ o.mode = stage_data->stages[1].mode;
+ oidcpy(&o.oid, &stage_data->stages[1].oid);
+
+ a.mode = stage_data->stages[2].mode;
+ oidcpy(&a.oid, &stage_data->stages[2].oid);
+
+ b.mode = stage_data->stages[3].mode;
+ oidcpy(&b.oid, &stage_data->stages[3].oid);
+
+ return update_stages(opt, path,
+ is_null_oid(&o.oid) ? NULL : &o,
+ is_null_oid(&a.oid) ? NULL : &a,
+ is_null_oid(&b.oid) ? NULL : &b);
+}
+
static void update_entry(struct stage_data *entry,
struct diff_filespec *o,
struct diff_filespec *a,
@@ -746,6 +800,20 @@ static int would_lose_untracked(const char *path)
return !was_tracked(path) && file_exists(path);
}
+static int was_dirty(struct merge_options *o, const char *path)
+{
+ struct cache_entry *ce;
+ int dirty = 1;
+
+ if (o->call_depth || !was_tracked(path))
+ return !dirty;
+
+ ce = cache_file_exists(path, strlen(path), ignore_case);
+ dirty = (ce->ce_stat_data.sd_mtime.sec > 0 &&
+ verify_uptodate(ce, &o->unpack_opts) != 0);
+ return dirty;
+}
+
static int make_room_for_path(struct merge_options *o, const char *path)
{
int status, i;
@@ -823,7 +891,7 @@ static int update_file_flags(struct merge_options *o,
goto update_index;
}
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf)
return err(o, _("cannot read object %s '%s'"), oid_to_hex(oid), path);
if (type != OBJ_BLOB) {
@@ -1009,8 +1077,9 @@ static int merge_file_1(struct merge_options *o,
if ((merge_status < 0) || !result_buf.ptr)
ret = err(o, _("Failed to execute internal merge"));
- if (!ret && write_sha1_file(result_buf.ptr, result_buf.size,
- blob_type, result->oid.hash))
+ if (!ret &&
+ write_object_file(result_buf.ptr, result_buf.size,
+ blob_type, &result->oid))
ret = err(o, _("Unable to add %s to database"),
a->path);
@@ -1094,6 +1163,38 @@ static int merge_file_one(struct merge_options *o,
return merge_file_1(o, &one, &a, &b, branch1, branch2, mfi);
}
+static int conflict_rename_dir(struct merge_options *o,
+ struct diff_filepair *pair,
+ const char *rename_branch,
+ const char *other_branch)
+{
+ const struct diff_filespec *dest = pair->two;
+
+ if (!o->call_depth && would_lose_untracked(dest->path)) {
+ char *alt_path = unique_path(o, dest->path, rename_branch);
+
+ output(o, 1, _("Error: Refusing to lose untracked file at %s; "
+ "writing to %s instead."),
+ dest->path, alt_path);
+ /*
+ * Write the file in worktree at alt_path, but not in the
+ * index. Instead, write to dest->path for the index but
+ * only at the higher appropriate stage.
+ */
+ if (update_file(o, 0, &dest->oid, dest->mode, alt_path))
+ return -1;
+ free(alt_path);
+ return update_stages(o, dest->path, NULL,
+ rename_branch == o->branch1 ? dest : NULL,
+ rename_branch == o->branch1 ? NULL : dest);
+ }
+
+ /* Update dest->path both in index and in worktree */
+ if (update_file(o, 1, &dest->oid, dest->mode, dest->path))
+ return -1;
+ return 0;
+}
+
static int handle_change_delete(struct merge_options *o,
const char *path, const char *old_path,
const struct object_id *o_oid, int o_mode,
@@ -1107,7 +1208,8 @@ static int handle_change_delete(struct merge_options *o,
const char *update_path = path;
int ret = 0;
- if (dir_in_way(path, !o->call_depth, 0)) {
+ if (dir_in_way(path, !o->call_depth, 0) ||
+ (!o->call_depth && would_lose_untracked(path))) {
update_path = alt_path = unique_path(o, path, change_branch);
}
@@ -1222,17 +1324,34 @@ static int handle_file(struct merge_options *o,
add = filespec_from_entry(&other, dst_entry, stage ^ 1);
if (add) {
+ int ren_src_was_dirty = was_dirty(o, rename->path);
char *add_name = unique_path(o, rename->path, other_branch);
if (update_file(o, 0, &add->oid, add->mode, add_name))
return -1;
- remove_file(o, 0, rename->path, 0);
+ if (ren_src_was_dirty) {
+ output(o, 1, _("Refusing to lose dirty file at %s"),
+ rename->path);
+ }
+ /*
+ * Because the double negatives somehow keep confusing me...
+ * 1) update_wd iff !ren_src_was_dirty.
+ * 2) no_wd iff !update_wd
+ * 3) so, no_wd == !!ren_src_was_dirty == ren_src_was_dirty
+ */
+ remove_file(o, 0, rename->path, ren_src_was_dirty);
dst_name = unique_path(o, rename->path, cur_branch);
} else {
if (dir_in_way(rename->path, !o->call_depth, 0)) {
dst_name = unique_path(o, rename->path, cur_branch);
output(o, 1, _("%s is a directory in %s adding as %s instead"),
rename->path, other_branch, dst_name);
+ } else if (!o->call_depth &&
+ would_lose_untracked(rename->path)) {
+ dst_name = unique_path(o, rename->path, cur_branch);
+ output(o, 1, _("Refusing to lose untracked file at %s; "
+ "adding as %s instead"),
+ rename->path, dst_name);
}
}
if ((ret = update_file(o, 0, &rename->oid, rename->mode, dst_name)))
@@ -1358,11 +1477,43 @@ static int conflict_rename_rename_2to1(struct merge_options *o,
char *new_path2 = unique_path(o, path, ci->branch2);
output(o, 1, _("Renaming %s to %s and %s to %s instead"),
a->path, new_path1, b->path, new_path2);
- remove_file(o, 0, path, 0);
+ if (was_dirty(o, path))
+ output(o, 1, _("Refusing to lose dirty file at %s"),
+ path);
+ else if (would_lose_untracked(path))
+ /*
+ * Only way we get here is if both renames were from
+ * a directory rename AND user had an untracked file
+ * at the location where both files end up after the
+ * two directory renames. See testcase 10d of t6043.
+ */
+ output(o, 1, _("Refusing to lose untracked file at "
+ "%s, even though it's in the way."),
+ path);
+ else
+ remove_file(o, 0, path, 0);
ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, new_path1);
if (!ret)
ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
new_path2);
+ /*
+ * unpack_trees() actually populates the index for us for
+ * "normal" rename/rename(2to1) situtations so that the
+ * correct entries are at the higher stages, which would
+ * make the call below to update_stages_for_stage_data
+ * unnecessary. However, if either of the renames came
+ * from a directory rename, then unpack_trees() will not
+ * have gotten the right data loaded into the index, so we
+ * need to do so now. (While it'd be tempting to move this
+ * call to update_stages_for_stage_data() to
+ * apply_directory_rename_modifications(), that would break
+ * our intermediate calls to would_lose_untracked() since
+ * those rely on the current in-memory index. See also the
+ * big "NOTE" in update_stages()).
+ */
+ if (update_stages_for_stage_data(o, path, ci->dst_entry1))
+ ret = -1;
+
free(new_path2);
free(new_path1);
}
@@ -1370,6 +1521,754 @@ static int conflict_rename_rename_2to1(struct merge_options *o,
return ret;
}
+/*
+ * Get the diff_filepairs changed between o_tree and tree.
+ */
+static struct diff_queue_struct *get_diffpairs(struct merge_options *o,
+ struct tree *o_tree,
+ struct tree *tree)
+{
+ struct diff_queue_struct *ret;
+ struct diff_options opts;
+
+ diff_setup(&opts);
+ opts.flags.recursive = 1;
+ opts.flags.rename_empty = 0;
+ opts.detect_rename = DIFF_DETECT_RENAME;
+ opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
+ o->diff_rename_limit >= 0 ? o->diff_rename_limit :
+ 1000;
+ opts.rename_score = o->rename_score;
+ opts.show_rename_progress = o->show_rename_progress;
+ opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_setup_done(&opts);
+ diff_tree_oid(&o_tree->object.oid, &tree->object.oid, "", &opts);
+ diffcore_std(&opts);
+ if (opts.needed_rename_limit > o->needed_rename_limit)
+ o->needed_rename_limit = opts.needed_rename_limit;
+
+ ret = xmalloc(sizeof(*ret));
+ *ret = diff_queued_diff;
+
+ opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_queued_diff.nr = 0;
+ diff_queued_diff.queue = NULL;
+ diff_flush(&opts);
+ return ret;
+}
+
+static int tree_has_path(struct tree *tree, const char *path)
+{
+ struct object_id hashy;
+ unsigned int mode_o;
+
+ return !get_tree_entry(&tree->object.oid, path,
+ &hashy, &mode_o);
+}
+
+/*
+ * Return a new string that replaces the beginning portion (which matches
+ * entry->dir), with entry->new_dir. In perl-speak:
+ * new_path_name = (old_path =~ s/entry->dir/entry->new_dir/);
+ * NOTE:
+ * Caller must ensure that old_path starts with entry->dir + '/'.
+ */
+static char *apply_dir_rename(struct dir_rename_entry *entry,
+ const char *old_path)
+{
+ struct strbuf new_path = STRBUF_INIT;
+ int oldlen, newlen;
+
+ if (entry->non_unique_new_dir)
+ return NULL;
+
+ oldlen = strlen(entry->dir);
+ newlen = entry->new_dir.len + (strlen(old_path) - oldlen) + 1;
+ strbuf_grow(&new_path, newlen);
+ strbuf_addbuf(&new_path, &entry->new_dir);
+ strbuf_addstr(&new_path, &old_path[oldlen]);
+
+ return strbuf_detach(&new_path, NULL);
+}
+
+static void get_renamed_dir_portion(const char *old_path, const char *new_path,
+ char **old_dir, char **new_dir)
+{
+ char *end_of_old, *end_of_new;
+ int old_len, new_len;
+
+ *old_dir = NULL;
+ *new_dir = NULL;
+
+ /*
+ * For
+ * "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
+ * the "e/foo.c" part is the same, we just want to know that
+ * "a/b/c/d" was renamed to "a/b/some/thing/else"
+ * so, for this example, this function returns "a/b/c/d" in
+ * *old_dir and "a/b/some/thing/else" in *new_dir.
+ *
+ * Also, if the basename of the file changed, we don't care. We
+ * want to know which portion of the directory, if any, changed.
+ */
+ end_of_old = strrchr(old_path, '/');
+ end_of_new = strrchr(new_path, '/');
+
+ if (end_of_old == NULL || end_of_new == NULL)
+ return;
+ while (*--end_of_new == *--end_of_old &&
+ end_of_old != old_path &&
+ end_of_new != new_path)
+ ; /* Do nothing; all in the while loop */
+ /*
+ * We've found the first non-matching character in the directory
+ * paths. That means the current directory we were comparing
+ * represents the rename. Move end_of_old and end_of_new back
+ * to the full directory name.
+ */
+ if (*end_of_old == '/')
+ end_of_old++;
+ if (*end_of_old != '/')
+ end_of_new++;
+ end_of_old = strchr(end_of_old, '/');
+ end_of_new = strchr(end_of_new, '/');
+
+ /*
+ * It may have been the case that old_path and new_path were the same
+ * directory all along. Don't claim a rename if they're the same.
+ */
+ old_len = end_of_old - old_path;
+ new_len = end_of_new - new_path;
+
+ if (old_len != new_len || strncmp(old_path, new_path, old_len)) {
+ *old_dir = xstrndup(old_path, old_len);
+ *new_dir = xstrndup(new_path, new_len);
+ }
+}
+
+static void remove_hashmap_entries(struct hashmap *dir_renames,
+ struct string_list *items_to_remove)
+{
+ int i;
+ struct dir_rename_entry *entry;
+
+ for (i = 0; i < items_to_remove->nr; i++) {
+ entry = items_to_remove->items[i].util;
+ hashmap_remove(dir_renames, entry, NULL);
+ }
+ string_list_clear(items_to_remove, 0);
+}
+
+/*
+ * See if there is a directory rename for path, and if there are any file
+ * level conflicts for the renamed location. If there is a rename and
+ * there are no conflicts, return the new name. Otherwise, return NULL.
+ */
+static char *handle_path_level_conflicts(struct merge_options *o,
+ const char *path,
+ struct dir_rename_entry *entry,
+ struct hashmap *collisions,
+ struct tree *tree)
+{
+ char *new_path = NULL;
+ struct collision_entry *collision_ent;
+ int clean = 1;
+ struct strbuf collision_paths = STRBUF_INIT;
+
+ /*
+ * entry has the mapping of old directory name to new directory name
+ * that we want to apply to path.
+ */
+ new_path = apply_dir_rename(entry, path);
+
+ if (!new_path) {
+ /* This should only happen when entry->non_unique_new_dir set */
+ if (!entry->non_unique_new_dir)
+ BUG("entry->non_unqiue_dir not set and !new_path");
+ output(o, 1, _("CONFLICT (directory rename split): "
+ "Unclear where to place %s because directory "
+ "%s was renamed to multiple other directories, "
+ "with no destination getting a majority of the "
+ "files."),
+ path, entry->dir);
+ clean = 0;
+ return NULL;
+ }
+
+ /*
+ * The caller needs to have ensured that it has pre-populated
+ * collisions with all paths that map to new_path. Do a quick check
+ * to ensure that's the case.
+ */
+ collision_ent = collision_find_entry(collisions, new_path);
+ if (collision_ent == NULL)
+ BUG("collision_ent is NULL");
+
+ /*
+ * Check for one-sided add/add/.../add conflicts, i.e.
+ * where implicit renames from the other side doing
+ * directory rename(s) can affect this side of history
+ * to put multiple paths into the same location. Warn
+ * and bail on directory renames for such paths.
+ */
+ if (collision_ent->reported_already) {
+ clean = 0;
+ } else if (tree_has_path(tree, new_path)) {
+ collision_ent->reported_already = 1;
+ strbuf_add_separated_string_list(&collision_paths, ", ",
+ &collision_ent->source_files);
+ output(o, 1, _("CONFLICT (implicit dir rename): Existing "
+ "file/dir at %s in the way of implicit "
+ "directory rename(s) putting the following "
+ "path(s) there: %s."),
+ new_path, collision_paths.buf);
+ clean = 0;
+ } else if (collision_ent->source_files.nr > 1) {
+ collision_ent->reported_already = 1;
+ strbuf_add_separated_string_list(&collision_paths, ", ",
+ &collision_ent->source_files);
+ output(o, 1, _("CONFLICT (implicit dir rename): Cannot map "
+ "more than one path to %s; implicit directory "
+ "renames tried to put these paths there: %s"),
+ new_path, collision_paths.buf);
+ clean = 0;
+ }
+
+ /* Free memory we no longer need */
+ strbuf_release(&collision_paths);
+ if (!clean && new_path) {
+ free(new_path);
+ return NULL;
+ }
+
+ return new_path;
+}
+
+/*
+ * There are a couple things we want to do at the directory level:
+ * 1. Check for both sides renaming to the same thing, in order to avoid
+ * implicit renaming of files that should be left in place. (See
+ * testcase 6b in t6043 for details.)
+ * 2. Prune directory renames if there are still files left in the
+ * the original directory. These represent a partial directory rename,
+ * i.e. a rename where only some of the files within the directory
+ * were renamed elsewhere. (Technically, this could be done earlier
+ * in get_directory_renames(), except that would prevent us from
+ * doing the previous check and thus failing testcase 6b.)
+ * 3. Check for rename/rename(1to2) conflicts (at the directory level).
+ * In the future, we could potentially record this info as well and
+ * omit reporting rename/rename(1to2) conflicts for each path within
+ * the affected directories, thus cleaning up the merge output.
+ * NOTE: We do NOT check for rename/rename(2to1) conflicts at the
+ * directory level, because merging directories is fine. If it
+ * causes conflicts for files within those merged directories, then
+ * that should be detected at the individual path level.
+ */
+static void handle_directory_level_conflicts(struct merge_options *o,
+ struct hashmap *dir_re_head,
+ struct tree *head,
+ struct hashmap *dir_re_merge,
+ struct tree *merge)
+{
+ struct hashmap_iter iter;
+ struct dir_rename_entry *head_ent;
+ struct dir_rename_entry *merge_ent;
+
+ struct string_list remove_from_head = STRING_LIST_INIT_NODUP;
+ struct string_list remove_from_merge = STRING_LIST_INIT_NODUP;
+
+ hashmap_iter_init(dir_re_head, &iter);
+ while ((head_ent = hashmap_iter_next(&iter))) {
+ merge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);
+ if (merge_ent &&
+ !head_ent->non_unique_new_dir &&
+ !merge_ent->non_unique_new_dir &&
+ !strbuf_cmp(&head_ent->new_dir, &merge_ent->new_dir)) {
+ /* 1. Renamed identically; remove it from both sides */
+ string_list_append(&remove_from_head,
+ head_ent->dir)->util = head_ent;
+ strbuf_release(&head_ent->new_dir);
+ string_list_append(&remove_from_merge,
+ merge_ent->dir)->util = merge_ent;
+ strbuf_release(&merge_ent->new_dir);
+ } else if (tree_has_path(head, head_ent->dir)) {
+ /* 2. This wasn't a directory rename after all */
+ string_list_append(&remove_from_head,
+ head_ent->dir)->util = head_ent;
+ strbuf_release(&head_ent->new_dir);
+ }
+ }
+
+ remove_hashmap_entries(dir_re_head, &remove_from_head);
+ remove_hashmap_entries(dir_re_merge, &remove_from_merge);
+
+ hashmap_iter_init(dir_re_merge, &iter);
+ while ((merge_ent = hashmap_iter_next(&iter))) {
+ head_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);
+ if (tree_has_path(merge, merge_ent->dir)) {
+ /* 2. This wasn't a directory rename after all */
+ string_list_append(&remove_from_merge,
+ merge_ent->dir)->util = merge_ent;
+ } else if (head_ent &&
+ !head_ent->non_unique_new_dir &&
+ !merge_ent->non_unique_new_dir) {
+ /* 3. rename/rename(1to2) */
+ /*
+ * We can assume it's not rename/rename(1to1) because
+ * that was case (1), already checked above. So we
+ * know that head_ent->new_dir and merge_ent->new_dir
+ * are different strings.
+ */
+ output(o, 1, _("CONFLICT (rename/rename): "
+ "Rename directory %s->%s in %s. "
+ "Rename directory %s->%s in %s"),
+ head_ent->dir, head_ent->new_dir.buf, o->branch1,
+ head_ent->dir, merge_ent->new_dir.buf, o->branch2);
+ string_list_append(&remove_from_head,
+ head_ent->dir)->util = head_ent;
+ strbuf_release(&head_ent->new_dir);
+ string_list_append(&remove_from_merge,
+ merge_ent->dir)->util = merge_ent;
+ strbuf_release(&merge_ent->new_dir);
+ }
+ }
+
+ remove_hashmap_entries(dir_re_head, &remove_from_head);
+ remove_hashmap_entries(dir_re_merge, &remove_from_merge);
+}
+
+static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs,
+ struct tree *tree)
+{
+ struct hashmap *dir_renames;
+ struct hashmap_iter iter;
+ struct dir_rename_entry *entry;
+ int i;
+
+ /*
+ * Typically, we think of a directory rename as all files from a
+ * certain directory being moved to a target directory. However,
+ * what if someone first moved two files from the original
+ * directory in one commit, and then renamed the directory
+ * somewhere else in a later commit? At merge time, we just know
+ * that files from the original directory went to two different
+ * places, and that the bulk of them ended up in the same place.
+ * We want each directory rename to represent where the bulk of the
+ * files from that directory end up; this function exists to find
+ * where the bulk of the files went.