summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--Documentation/CodingGuidelines34
-rw-r--r--Documentation/Makefile2
-rw-r--r--Documentation/RelNotes/1.8.4.5.txt13
-rw-r--r--Documentation/RelNotes/1.8.5.1.txt9
-rw-r--r--Documentation/RelNotes/1.8.5.2.txt20
-rw-r--r--Documentation/RelNotes/1.8.5.3.txt27
-rw-r--r--Documentation/RelNotes/1.9.txt314
-rw-r--r--Documentation/SubmittingPatches11
-rw-r--r--Documentation/config.txt8
-rw-r--r--Documentation/diff-config.txt5
-rw-r--r--Documentation/diff-options.txt3
-rw-r--r--Documentation/fetch-options.txt26
-rw-r--r--Documentation/git-cat-file.txt12
-rw-r--r--Documentation/git-cherry.txt143
-rw-r--r--Documentation/git-fetch-pack.txt15
-rw-r--r--Documentation/git-fetch.txt17
-rw-r--r--Documentation/git-filter-branch.txt33
-rw-r--r--Documentation/git-for-each-ref.txt14
-rw-r--r--Documentation/git-log.txt51
-rw-r--r--Documentation/git-lost-found.txt74
-rw-r--r--Documentation/git-merge-base.txt38
-rw-r--r--Documentation/git-mv.txt12
-rw-r--r--Documentation/git-pack-objects.txt3
-rw-r--r--Documentation/git-peek-remote.txt43
-rw-r--r--Documentation/git-push.txt9
-rw-r--r--Documentation/git-rebase.txt10
-rw-r--r--Documentation/git-replace.txt19
-rw-r--r--Documentation/git-repo-config.txt23
-rw-r--r--Documentation/git-rev-parse.txt22
-rw-r--r--Documentation/git-rm.txt9
-rw-r--r--Documentation/git-tar-tree.txt82
-rw-r--r--Documentation/git.txt17
-rw-r--r--Documentation/gitcli.txt16
-rw-r--r--Documentation/gitignore.txt19
-rw-r--r--Documentation/gitmodules.txt2
-rw-r--r--Documentation/gitweb.conf.txt37
-rw-r--r--Documentation/glossary-content.txt40
-rw-r--r--Documentation/merge-strategies.txt8
-rw-r--r--Documentation/rev-list-options.txt258
-rw-r--r--Documentation/technical/api-builtin.txt4
-rw-r--r--Documentation/technical/api-parse-options.txt6
-rw-r--r--Documentation/technical/api-ref-iteration.txt4
-rw-r--r--Documentation/technical/api-remote.txt20
-rw-r--r--Documentation/technical/http-protocol.txt4
-rw-r--r--Documentation/technical/pack-heuristics.txt4
-rw-r--r--Documentation/technical/protocol-capabilities.txt31
-rw-r--r--Documentation/user-manual.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile22
l---------RelNotes2
-rw-r--r--abspath.c18
-rw-r--r--alias.c2
-rw-r--r--attr.c2
-rw-r--r--bisect.c4
-rw-r--r--branch.c4
-rw-r--r--builtin.h3
-rw-r--r--builtin/add.c7
-rw-r--r--builtin/apply.c12
-rw-r--r--builtin/archive.c4
-rw-r--r--builtin/blame.c11
-rw-r--r--builtin/branch.c8
-rw-r--r--builtin/cat-file.c38
-rw-r--r--builtin/checkout.c20
-rw-r--r--builtin/clean.c4
-rw-r--r--builtin/clone.c12
-rw-r--r--builtin/column.c2
-rw-r--r--builtin/commit.c23
-rw-r--r--builtin/config.c6
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff.c75
-rw-r--r--builtin/fast-export.c6
-rw-r--r--builtin/fetch-pack.c20
-rw-r--r--builtin/fetch.c356
-rw-r--r--builtin/fmt-merge-msg.c10
-rw-r--r--builtin/for-each-ref.c111
-rw-r--r--builtin/fsck.c6
-rw-r--r--builtin/gc.c2
-rw-r--r--builtin/get-tar-commit-id.c40
-rw-r--r--builtin/help.c14
-rw-r--r--builtin/index-pack.c8
-rw-r--r--builtin/init-db.c2
-rw-r--r--builtin/log.c8
-rw-r--r--builtin/ls-remote.c4
-rw-r--r--builtin/mailinfo.c16
-rw-r--r--builtin/merge-base.c175
-rw-r--r--builtin/merge-recursive.c4
-rw-r--r--builtin/merge.c12
-rw-r--r--builtin/mv.c25
-rw-r--r--builtin/name-rev.c9
-rw-r--r--builtin/notes.c2
-rw-r--r--builtin/pack-objects.c4
-rw-r--r--builtin/prune-packed.c38
-rw-r--r--builtin/prune.c42
-rw-r--r--builtin/push.c91
-rw-r--r--builtin/receive-pack.c8
-rw-r--r--builtin/reflog.c4
-rw-r--r--builtin/remote.c227
-rw-r--r--builtin/repack.c8
-rw-r--r--builtin/replace.c67
-rw-r--r--builtin/rev-parse.c67
-rw-r--r--builtin/send-pack.c8
-rw-r--r--builtin/shortlog.c6
-rw-r--r--builtin/show-branch.c23
-rw-r--r--builtin/show-ref.c6
-rw-r--r--builtin/symbolic-ref.c2
-rw-r--r--builtin/tag.c2
-rw-r--r--builtin/tar-tree.c102
-rw-r--r--builtin/unpack-objects.c2
-rw-r--r--builtin/update-ref.c10
-rw-r--r--builtin/upload-archive.c2
-rw-r--r--bundle.c32
-rw-r--r--cache.h13
-rw-r--r--command-list.txt4
-rw-r--r--commit-slab.h39
-rw-r--r--commit.c65
-rw-r--r--commit.h5
-rwxr-xr-x[-rw-r--r--]compat/vcbuild/scripts/clink.pl0
-rwxr-xr-x[-rw-r--r--]compat/vcbuild/scripts/lib.pl0
-rw-r--r--config.c35
-rw-r--r--config.mak.uname7
-rw-r--r--connect.c253
-rw-r--r--connect.h2
-rw-r--r--connected.c2
-rwxr-xr-x[-rw-r--r--]contrib/buildsystems/engine.pl0
-rwxr-xr-x[-rw-r--r--]contrib/buildsystems/generate0
-rwxr-xr-x[-rw-r--r--]contrib/buildsystems/parse.pl0
-rw-r--r--contrib/completion/git-completion.bash31
-rw-r--r--contrib/completion/git-completion.tcsh2
-rw-r--r--contrib/completion/git-completion.zsh10
-rw-r--r--contrib/credential/gnome-keyring/git-credential-gnome-keyring.c85
-rwxr-xr-xcontrib/examples/git-whatchanged.sh4
-rwxr-xr-xcontrib/gitview/gitview2
-rwxr-xr-xcontrib/hooks/post-receive-email1
-rwxr-xr-x[-rw-r--r--]contrib/hooks/pre-auto-gc-battery1
-rwxr-xr-x[-rw-r--r--]contrib/hooks/setgitperms.perl0
-rwxr-xr-x[-rw-r--r--]contrib/hooks/update-paranoid0
-rw-r--r--contrib/mw-to-git/Makefile9
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl2
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh2
-rw-r--r--contrib/mw-to-git/t/test.config2
-rw-r--r--contrib/p4import/README1
-rw-r--r--contrib/p4import/git-p4import.py365
-rw-r--r--contrib/p4import/git-p4import.txt167
-rwxr-xr-xcontrib/remote-helpers/git-remote-bzr21
-rwxr-xr-xcontrib/remote-helpers/git-remote-hg26
-rwxr-xr-xcontrib/remote-helpers/test-bzr.sh5
-rwxr-xr-xcontrib/remote-helpers/test-hg.sh109
-rw-r--r--convert.c2
-rw-r--r--csum-file.c7
-rw-r--r--csum-file.h2
-rw-r--r--daemon.c40
-rw-r--r--diff-no-index.c44
-rw-r--r--diff.c83
-rw-r--r--diff.h6
-rw-r--r--diffcore-order.c34
-rw-r--r--dir.c47
-rw-r--r--environment.c2
-rw-r--r--fast-import.c80
-rw-r--r--fetch-pack.c20
-rw-r--r--fetch-pack.h1
-rw-r--r--gettext.c19
-rwxr-xr-xgit-am.sh4
-rwxr-xr-xgit-bisect.sh2
-rw-r--r--git-compat-util.h4
-rwxr-xr-xgit-difftool--helper.sh3
-rw-r--r--git-gui/Makefile2
-rwxr-xr-xgit-gui/git-gui.sh47
-rw-r--r--git-gui/lib/blame.tcl2
-rw-r--r--git-gui/lib/choose_repository.tcl12
-rw-r--r--git-gui/lib/index.tcl2
-rw-r--r--git-gui/lib/option.tcl2
-rw-r--r--git-gui/lib/spellcheck.tcl4
-rw-r--r--git-gui/macosx/Info.plist2
-rwxr-xr-xgit-instaweb.sh2
-rwxr-xr-xgit-lost-found.sh33
-rw-r--r--git-mergetool--lib.sh3
-rwxr-xr-xgit-p4.py2
-rw-r--r--git-parse-remote.sh4
-rwxr-xr-xgit-pull.sh12
-rw-r--r--git-rebase--am.sh3
-rw-r--r--git-rebase--interactive.sh9
-rw-r--r--git-rebase--merge.sh4
-rwxr-xr-xgit-rebase.sh20
-rwxr-xr-xgit-request-pull.sh2
-rwxr-xr-xgit-send-email.perl8
-rw-r--r--git-sh-i18n.sh5
-rw-r--r--git-sh-setup.sh12
-rwxr-xr-xgit-stash.sh14
-rwxr-xr-xgit-submodule.sh34
-rw-r--r--git.c271
-rwxr-xr-xgitk-git/gitk563
-rwxr-xr-xgitweb/gitweb.perl184
-rw-r--r--help.c8
-rw-r--r--http-backend.c4
-rw-r--r--http-push.c4
-rw-r--r--http.c16
-rw-r--r--http.h1
-rw-r--r--imap-send.c10
-rw-r--r--log-tree.c16
-rw-r--r--merge-recursive.c6
-rw-r--r--notes-utils.c6
-rw-r--r--notes.c8
-rw-r--r--pack-write.c11
-rw-r--r--pack.h2
-rw-r--r--pager.c13
-rw-r--r--parse-options.c12
-rw-r--r--parse-options.h11
-rw-r--r--pathspec.c43
-rw-r--r--pathspec.h4
-rw-r--r--perl/Git/SVN/Editor.pm10
-rw-r--r--perl/Git/SVN/Log.pm1
-rw-r--r--pkt-line.c4
-rw-r--r--po/de.po16
-rw-r--r--pretty.c36
-rw-r--r--prompt.c3
-rw-r--r--refs.c75
-rw-r--r--remote-curl.c45
-rw-r--r--remote-testsvn.c10
-rw-r--r--remote.c148
-rw-r--r--remote.h10
-rw-r--r--replace_object.c3
-rw-r--r--revision.c88
-rw-r--r--revision.h8
-rw-r--r--send-pack.c6
-rw-r--r--sequencer.c8
-rw-r--r--setup.c4
-rw-r--r--sha1_file.c203
-rw-r--r--sha1_name.c22
-rw-r--r--shallow.c3
-rw-r--r--shell.c2
-rw-r--r--strbuf.c18
-rw-r--r--streaming.c2
-rw-r--r--submodule.c2
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/00compile.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/add_path_to_url.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/can_compress.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/canonicalize_url.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/collapse_dotdot.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/fatal.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/join_paths.t0
-rw-r--r--t/annotate-tests.sh21
-rw-r--r--t/gitweb-lib.sh3
-rw-r--r--t/lib-bash.sh7
-rw-r--r--t/lib-cvs.sh2
-rw-r--r--t/lib-diff-alternative.sh3
-rw-r--r--t/lib-gettext.sh3
-rw-r--r--t/lib-git-daemon.sh18
-rw-r--r--t/lib-httpd.sh44
-rw-r--r--t/lib-httpd/passwd2
-rw-r--r--t/lib-pack.sh2
-rw-r--r--t/lib-pager.sh2
-rw-r--r--t/lib-prereq-FILEMODE.sh11
-rw-r--r--t/lib-read-tree.sh54
-rw-r--r--t/lib-rebase.sh2
-rw-r--r--t/lib-terminal.sh2
-rwxr-xr-xt/perf/p4001-diff-no-index.sh22
-rw-r--r--t/perf/perf-lib.sh4
-rwxr-xr-xt/t0000-basic.sh19
-rwxr-xr-xt/t0002-gitfile.sh3
-rwxr-xr-xt/t0003-attributes.sh1
-rwxr-xr-x[-rw-r--r--]t/t0202/test.pl0
-rwxr-xr-xt/t1005-read-tree-reset.sh141
-rwxr-xr-xt/t1006-cat-file.sh62
-rwxr-xr-xt/t1013-loose-object-format.sh66
-rw-r--r--t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6bin117 -> 0 bytes
-rw-r--r--t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435bin17 -> 0 bytes
-rw-r--r--t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbdbin18 -> 0 bytes
-rw-r--r--t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99bin19 -> 0 bytes
-rw-r--r--t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752ebin10 -> 0 bytes
-rw-r--r--t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696bin181 -> 0 bytes
-rw-r--r--t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fdbin26 -> 0 bytes
-rw-r--r--t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb2
-rw-r--r--t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09bin139 -> 0 bytes
-rw-r--r--t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8bin54 -> 0 bytes
-rw-r--r--t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730bin13 -> 0 bytes
-rw-r--r--t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fabin156 -> 0 bytes
-rw-r--r--t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64fbin252 -> 0 bytes
-rw-r--r--t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832bin11 -> 0 bytes
-rw-r--r--t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8bin34 -> 0 bytes
-rw-r--r--t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391bin9 -> 0 bytes
-rw-r--r--t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a1
-rwxr-xr-xt/t1303-wacky-config.sh64
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh42
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh24
-rwxr-xr-xt/t3400-rebase.sh16
-rwxr-xr-xt/t3600-rm.sh16
-rwxr-xr-xt/t3700-add.sh19
-rwxr-xr-xt/t3701-add-interactive.sh1
-rwxr-xr-xt/t3903-stash.sh12
-rwxr-xr-xt/t4020-diff-external.sh13
-rwxr-xr-xt/t4053-diff-no-index.sh26
-rwxr-xr-xt/t4056-diff-order.sh100
-rwxr-xr-xt/t4102-apply-rename.sh1
-rwxr-xr-xt/t4116-apply-reverse.sh4
-rwxr-xr-xt/t4120-apply-popt.sh1
-rwxr-xr-xt/t4129-apply-samemode.sh1
-rwxr-xr-xt/t4205-log-pretty-formats.sh15
-rwxr-xr-xt/t5000-tar-tree.sh36
-rwxr-xr-xt/t5001-archive-attr.sh10
-rwxr-xr-xt/t5302-pack-index.sh4
-rwxr-xr-xt/t5500-fetch-pack.sh87
-rwxr-xr-xt/t5510-fetch.sh62
-rw-r--r--t/t5515/fetch.br-unconfig_--tags_.._.git1
-rw-r--r--t/t5515/fetch.master_--tags_.._.git1
-rwxr-xr-xt/t5516-fetch-push.sh75
-rwxr-xr-xt/t5525-fetch-tagopt.sh23
-rwxr-xr-xt/t5531-deep-submodule-push.sh1
-rwxr-xr-xt/t5536-fetch-conflicts.sh100
-rwxr-xr-xt/t5540-http-push.sh4
-rwxr-xr-xt/t5541-http-push.sh6
-rwxr-xr-xt/t5550-http-fetch.sh10
-rwxr-xr-xt/t5551-http-fetch.sh6
-rwxr-xr-xt/t5601-clone.sh132
-rwxr-xr-xt/t6010-merge-base.sh67
-rwxr-xr-xt/t6018-rev-list-glob.sh54
-rwxr-xr-xt/t6031-merge-recursive.sh1
-rwxr-xr-xt/t6050-replace.sh42
-rwxr-xr-xt/t6101-rev-parse-parents.sh16
-rwxr-xr-xt/t6131-pathspec-icase.sh6
-rwxr-xr-xt/t6132-pathspec-exclude.sh184
-rwxr-xr-xt/t6300-for-each-ref.sh69
-rwxr-xr-xt/t7001-mv.sh50
-rwxr-xr-xt/t7006-pager.sh12
-rwxr-xr-xt/t7406-submodule-update.sh26
-rwxr-xr-xt/t7407-submodule-foreach.sh9
-rwxr-xr-xt/t7507-commit-verbose.sh28
-rwxr-xr-x[-rw-r--r--]t/t9150/make-svk-dump0
-rwxr-xr-x[-rw-r--r--]t/t9151/make-svnmerge-dump0
-rwxr-xr-xt/t9200-git-cvsexportcommit.sh1
-rw-r--r--t/test-lib-functions.sh3
-rw-r--r--t/test-lib.sh18
-rw-r--r--tag.c10
-rw-r--r--test-line-buffer.c6
-rw-r--r--test-string-list.c2
-rw-r--r--transport-helper.c16
-rw-r--r--transport.c40
-rw-r--r--tree-walk.c83
-rw-r--r--unpack-trees.c76
-rw-r--r--upload-pack.c13
-rw-r--r--vcs-svn/fast_export.c11
-rw-r--r--wrapper.c2
-rw-r--r--wt-status.c125
-rw-r--r--wt-status.h1
344 files changed, 6038 insertions, 3615 deletions
diff --git a/.gitignore b/.gitignore
index 66199ed..b5f9def 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
/GIT-CFLAGS
/GIT-LDFLAGS
/GIT-PREFIX
+/GIT-PERL-DEFINES
/GIT-PYTHON-VARS
/GIT-SCRIPT-DEFINES
/GIT-USER-AGENT
@@ -75,7 +76,6 @@
/git-init-db
/git-instaweb
/git-log
-/git-lost-found
/git-ls-files
/git-ls-remote
/git-ls-tree
@@ -105,7 +105,6 @@
/git-pack-refs
/git-parse-remote
/git-patch-id
-/git-peek-remote
/git-prune
/git-prune-packed
/git-pull
@@ -131,7 +130,6 @@
/git-remote-testsvn
/git-repack
/git-replace
-/git-repo-config
/git-request-pull
/git-rerere
/git-reset
@@ -159,7 +157,6 @@
/git-svn
/git-symbolic-ref
/git-tag
-/git-tar-tree
/git-unpack-file
/git-unpack-objects
/git-update-index
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index a600e35..ef67b53 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -260,9 +260,11 @@ Writing Documentation:
Every user-visible change should be reflected in the documentation.
The same general rule as for code applies -- imitate the existing
- conventions. A few commented examples follow to provide reference
- when writing or modifying command usage strings and synopsis sections
- in the manual pages:
+ conventions.
+
+ A few commented examples follow to provide reference when writing or
+ modifying command usage strings and synopsis sections in the manual
+ pages:
Placeholders are spelled in lowercase and enclosed in angle brackets:
<file>
@@ -312,3 +314,29 @@ Writing Documentation:
Use 'git' (all lowercase) when talking about commands i.e. something
the user would type into a shell and use 'Git' (uppercase first letter)
when talking about the version control system and its properties.
+
+ A few commented examples follow to provide reference when writing or
+ modifying paragraphs or option/command explanations that contain options
+ or commands:
+
+ Literal examples (e.g. use of command-line options, command names, and
+ configuration variables) are typeset in monospace, and if you can use
+ `backticks around word phrases`, do so.
+ `--pretty=oneline`
+ `git rev-list`
+ `remote.pushdefault`
+
+ Word phrases enclosed in `backtick characters` are rendered literally
+ and will not be further expanded. The use of `backticks` to achieve the
+ previous rule means that literal examples should not use AsciiDoc
+ escapes.
+ Correct:
+ `--pretty=oneline`
+ Incorrect:
+ `\--pretty=oneline`
+
+ If some place in the documentation needs to typeset a command usage
+ example with inline substitutions, it is fine to use +monospaced and
+ inline substituted text+ instead of `monospaced literal text`, and with
+ the former, the part that should not get substituted must be
+ quoted/escaped.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 91a12c7..36c58fc 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -324,7 +324,7 @@ manpage-base-url.xsl: manpage-base-url.xsl.in
user-manual.xml: user-manual.txt user-manual.conf
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
- $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book -o $@+ $< && \
+ $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d article -o $@+ $< && \
mv $@+ $@
technical/api-index.txt: technical/api-index-skel.txt \
diff --git a/Documentation/RelNotes/1.8.4.5.txt b/Documentation/RelNotes/1.8.4.5.txt
new file mode 100644
index 0000000..215bd1a
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.5.txt
@@ -0,0 +1,13 @@
+Git v1.8.4.5 Release Notes
+==========================
+
+Fixes since v1.8.4.4
+--------------------
+
+ * Recent update to remote-hg that attempted to make it work better
+ with non ASCII pathnames fed Unicode strings to the underlying Hg
+ API, which was wrong.
+
+ * "git submodule init" copied "submodule.$name.update" settings from
+ .gitmodules to .git/config without making sure if the suggested
+ value was sensible.
diff --git a/Documentation/RelNotes/1.8.5.1.txt b/Documentation/RelNotes/1.8.5.1.txt
new file mode 100644
index 0000000..7236aaf
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.1.txt
@@ -0,0 +1,9 @@
+Git v1.8.5.1 Release Notes
+==========================
+
+Fixes since v1.8.5
+------------------
+
+ * "git submodule init" copied "submodule.$name.update" settings from
+ .gitmodules to .git/config without making sure if the suggested
+ value was sensible.
diff --git a/Documentation/RelNotes/1.8.5.2.txt b/Documentation/RelNotes/1.8.5.2.txt
new file mode 100644
index 0000000..3ac4984
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.2.txt
@@ -0,0 +1,20 @@
+Git v1.8.5.2 Release Notes
+==========================
+
+Fixes since v1.8.5.1
+--------------------
+
+ * "git diff -- ':(icase)makefile'" was unnecessarily rejected at the
+ command line parser.
+
+ * "git cat-file --batch-check=ok" did not check the existence of
+ the named object.
+
+ * "git am --abort" sometimes complained about not being able to write
+ a tree with an 0{40} object in it.
+
+ * Two processes creating loose objects at the same time could have
+ failed unnecessarily when the name of their new objects started
+ with the same byte value, due to a race condition.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.3.txt b/Documentation/RelNotes/1.8.5.3.txt
new file mode 100644
index 0000000..3de2dd0
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.3.txt
@@ -0,0 +1,27 @@
+Git v1.8.5.3 Release Notes
+==========================
+
+Fixes since v1.8.5.2
+--------------------
+
+ * The "--[no-]informative-errors" options to "git daemon" were parsed
+ a bit too loosely, allowing any other string after these option
+ names.
+
+ * A "gc" process running as a different user should be able to stop a
+ new "gc" process from starting.
+
+ * An earlier "clean-up" introduced an unnecessary memory leak to the
+ credential subsystem.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+
+ * "git rev-parse <revs> -- <paths>" did not implement the usual
+ disambiguation rules the commands in the "git log" family used in
+ the same way.
+
+ * "git cat-file --batch=", an admittedly useless command, did not
+ behave very well.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.9.txt b/Documentation/RelNotes/1.9.txt
new file mode 100644
index 0000000..9959257
--- /dev/null
+++ b/Documentation/RelNotes/1.9.txt
@@ -0,0 +1,314 @@
+Git v1.9 Release Notes
+======================
+
+Backward compatibility notes
+----------------------------
+
+"git submodule foreach $cmd $args" used to treat "$cmd $args" the same
+way "ssh" did, concatenating them into a single string and letting the
+shell unquote. Careless users who forget to sufficiently quote $args
+gets their argument split at $IFS whitespaces by the shell, and got
+unexpected results due to this. Starting from this release, the
+command line is passed directly to the shell, if it has an argument.
+
+Read-only support for experimental loose-object format, in which users
+could optionally choose to write in their loose objects for a short
+while between v1.4.3 to v1.5.3 era, has been dropped.
+
+The meanings of "--tags" option to "git fetch" has changed; the
+command fetches tags _in addition to_ what are fetched by the same
+command line without the option.
+
+The way "git push $there $what" interprets $what part given on the
+command line, when it does not have a colon that explicitly tells us
+what ref at the $there repository is to be updated, has been enhanced.
+
+A handful of ancient commands that have long been deprecated are
+finally gone (repo-config, tar-tree, lost-found, and peek-remote).
+
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there). In Git 2.0, the default will change to the "simple"
+semantics, which pushes:
+
+ - only the current branch to the branch with the same name, and only
+ when the current branch is set to integrate with that remote
+ branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+ are pushing to a remote that is not where you usually fetch from.
+
+Use the user preference configuration variable "push.default" to
+change this. If you are an old-timer who is used to the "matching"
+semantics, you can set the variable to "matching" to keep the
+traditional behaviour. If you want to live in the future early, you
+can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands. There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes. A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal. Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+The default prefix for "git svn" will change in Git 2.0. For a long
+time, "git svn" created its remote-tracking branches directly under
+refs/remotes, but it will place them under refs/remotes/origin/ unless
+it is told otherwise with its --prefix option.
+
+
+Updates since v1.8.5
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * The HTTP transport, when talking GSS-Negotiate, uses "100
+ Continue" response to avoid having to rewind and resend a large
+ payload, which may not be always doable.
+
+ * Various bugfixes to remote-bzr and remote-hg (in contrib/).
+
+ * The build procedure is aware of MirBSD now.
+
+
+UI, Workflows & Features
+
+ * Just like we give a reasonable default for "less" via the LESS
+ environment variable, we now specify a reasonable default for "lv"
+ via the "LV" environment variable when spawning the pager.
+
+ * Two-level configuration variable names in "branch.*" and "remote.*"
+ hierarchies, whose variables are predominantly three-level, were
+ not completed by hitting a <TAB> in bash and zsh completions.
+
+ * Fetching 'frotz' branch with "git fetch", while 'frotz/nitfol'
+ remote-tracking branch from an earlier fetch was still there, would
+ error out, primarily because the command was not told that it is
+ allowed to lose any information on our side. "git fetch --prune"
+ now can be used to remove 'frotz/nitfol' to make room to fetch and
+ store 'frotz' remote-tracking branch.
+
+ * "diff.orderfile=<file>" configuration variable can be used to
+ pretend as if the "-O<file>" option were given from the command
+ line of "git diff", etc.
+
+ * The negative pathspec syntax allows "git log -- . ':!dir'" to tell
+ us "I am interested in everything but 'dir' directory".
+
+ * "git difftool" shows how many different paths there are in total,
+ and how many of them have been shown so far, to indicate progress.
+
+ * "git push origin master" used to push our 'master' branch to update
+ the 'master' branch at the 'origin' repository. This has been
+ enhanced to use the same ref mapping "git push origin" would use to
+ determine what ref at the 'origin' to be updated with our 'master'.
+ For example, with this configuration
+
+ [remote "origin"]
+ push = refs/heads/*:refs/review/*
+
+ that would cause "git push origin" to push out our local branches
+ to corresponding refs under refs/review/ hierarchy at 'origin',
+ "git push origin master" would update 'refs/review/master' over
+ there. Alternatively, if push.default is set to 'upstream' and our
+ 'master' is set to integrate with 'topic' from the 'origin' branch,
+ running "git push origin" while on our 'master' would update their
+ 'topic' branch, and running "git push origin master" while on any
+ of our branches does the same.
+
+ * "gitweb" learned to treat ref hierarchies other than refs/heads as
+ if they are additional branch namespaces (e.g. refs/changes/ in
+ Gerrit).
+
+ * "git for-each-ref --format=..." learned a few formatting directives;
+ e.g. "%(color:red)%(HEAD)%(color:reset) %(refname:short) %(subject)".
+
+ * The command string given to "git submodule foreach" is passed
+ directly to the shell, without being eval'ed. This is a backward
+ incompatible change that may break existing users.
+
+ * "git log" and friends learned the "--exclude=<glob>" option, to
+ allow people to say "list history of all branches except those that
+ match this pattern" with "git log --exclude='*/*' --branches".
+
+ * "git rev-parse --parseopt" learned a new "--stuck-long" option to
+ help scripts parse options with an optional parameter.
+
+ * The "--tags" option to "git fetch" no longer tells the command to
+ fetch _only_ the tags. It instead fetches tags _in addition to_
+ what are fetched by the same command line without the option.
+
+
+Performance, Internal Implementation, etc.
+
+ * When parsing a 40-hex string into the object name, the string is
+ checked to see if it can be interpreted as a ref so that a warning
+ can be given for ambiguity. The code kicked in even when the
+ core.warnambiguousrefs is set to false to squelch this warning, in
+ which case the cycles spent to look at the ref namespace were an
+ expensive no-op, as the result was discarded without being used.
+
+ * The naming convention of the packfiles has been updated; it used to
+ be based on the enumeration of names of the objects that are
+ contained in the pack, but now it also depends on how the packed
+ result is represented---packing the same set of objects using
+ different settings (or delta order) would produce a pack with
+ different name.
+
+ * "git diff --no-index" mode used to unnecessarily attempt to read
+ the index when there is one.
+
+ * The deprecated parse-options macro OPT_BOOLEAN has been removed;
+ use OPT_BOOL or OPT_COUNTUP in new code.
+
+ * A few duplicate implementations of prefix/suffix string comparison
+ functions have been unified to starts_with() and ends_with().
+
+ * The new PERLLIB_EXTRA makefile variable can be used to specify
+ additional directories Perl modules (e.g. the ones necessary to run
+ git-svn) are installed on the platform when building.
+
+ * "git merge-base" learned the "--fork-point" mode, that implements
+ the same logic used in "git pull --rebase" to find a suitable fork
+ point out of the reflog entries for the remote-tracking branch the
+ work has been based on. "git rebase" has the same logic that can be
+ triggered with the "--fork-point" option.
+
+ * A third-party "receive-pack" (the responder to "git push") can
+ advertise the "no-thin" capability to tell "git push" not to use
+ the thin-pack optimization. Our receive-pack has always been
+ capable of accepting and fattening a thin-pack, and will continue
+ not to ask "git push" to use a non-thin pack.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.5
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.5 in the maintenance
+track are contained in this release (see the maintenance releases' notes
+for details).
+
+ * The implementation of 'git stash $cmd "stash@{...}"' did not quote
+ the stash argument properly and left it split at IFS whitespace.
+ (merge 2a07e43 ow/stash-with-ifs later to maint).
+
+ * The "--[no-]informative-errors" options to "git daemon" were parsed
+ a bit too loosely, allowing any other string after these option
+ names.
+ (merge 82246b7 nd/daemon-informative-errors-typofix later to maint).
+
+ * There is no reason to have a hardcoded upper limit of the number of
+ parents for an octopus merge, created via the graft mechanism, but
+ there was.
+ (merge e228c17 js/lift-parent-count-limit later to maint).
+
+ * The basic test used to leave unnecessary trash directories in the
+ t/ directory.
+ (merge 738a8be jk/test-framework-updates later to maint).
+
+ * "git merge-base --octopus" used to leave cleaning up suboptimal
+ result to the caller, but now it does the clean-up itself.
+ (merge 8f29299 bm/merge-base-octopus-dedup later to maint).
+
+ * A "gc" process running as a different user should be able to stop a
+ new "gc" process from starting, but it didn't.
+ (merge ed7eda8 km/gc-eperm later to maint).
+
+ * An earlier "clean-up" introduced an unnecessary memory leak.
+ (merge e1c1a32 jk/credential-plug-leak later to maint).
+
+ * "git add -A" (no other arguments) in a totally empty working tree
+ used to emit an error.
+ (merge 64ed07c nd/add-empty-fix later to maint).
+
+ * "git log --decorate" did not handle a tag pointed by another tag
+ nicely.
+ (merge 5e1361c bc/log-decoration later to maint).
+
+ * When we figure out how many file descriptors to allocate for
+ keeping packfiles open, a system with non-working getrlimit() could
+ cause us to die(), but because we make this call only to get a
+ rough estimate of how many is available and we do not even attempt
+ to use up all file descriptors available ourselves, it is nicer to
+ fall back to a reasonable low value rather than dying.
+ (merge 491a8de jh/rlimit-nofile-fallback later to maint).
+
+ * read_sha1_file(), that is the workhorse to read the contents given
+ an object name, honoured object replacements, but there was no
+ corresponding mechanism to sha1_object_info() that was used to
+ obtain the metainfo (e.g. type & size) about the object. This led
+ callers to weird inconsistencies.
+ (merge 663a856 cc/replace-object-info later to maint).
+
+ * "git cat-file --batch=", an admittedly useless command, did not
+ behave very well.
+ (merge 6554dfa jk/cat-file-regression-fix later to maint).
+
+ * "git rev-parse <revs> -- <paths>" did not implement the usual
+ disambiguation rules the commands in the "git log" family used in
+ the same way.
+ (merge 62f162f jk/rev-parse-double-dashes later to maint).
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+ (merge c57f628 mm/mv-file-to-no-such-dir-with-slash later to maint).
+
+ * A workaround to an old bug in glibc prior to glibc 2.17 has been
+ retired; this would remove a side effect of the workaround that
+ corrupts system error messages in non-C locales.
+
+ * SSL-related options were not passed correctly to underlying socket
+ layer in "git send-email".
+ (merge 5508f3e tr/send-email-ssl later to maint).
+
+ * "git commit -v" appends the patch to the log message before
+ editing, and then removes the patch when the editor returned
+ control. However, the patch was not stripped correctly when the
+ first modified path was a submodule.
+ (merge 1a72cfd jl/commit-v-strip-marker later to maint).
+
+ * "git fetch --depth=0" was a no-op, and was silently ignored.
+ Diagnose it as an error.
+ (merge 5594bca nd/transport-positive-depth-only later to maint).
+
+ * Remote repository URL expressed in scp-style host:path notation are
+ parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks
+ to connect to user's home directory on host at address ::1.
+ (merge a2036d7 tb/clone-ssh-with-colon-for-port later to maint).
+
+ * "git diff -- ':(icase)makefile'" was unnecessarily rejected at the
+ command line parser.
+ (merge 887c6c1 nd/magic-pathspec later to maint).
+
+ * "git cat-file --batch-check=ok" did not check the existence of
+ the named object.
+ (merge 4ef8d1d sb/sha1-loose-object-info-check-existence later to maint).
+
+ * "git am --abort" sometimes complained about not being able to write
+ a tree with an 0{40} object in it.
+ (merge 77b43ca jk/two-way-merge-corner-case-fix later to maint).
+
+ * Two processes creating loose objects at the same time could have
+ failed unnecessarily when the name of their new objects started
+ with the same byte value, due to a race condition.
+ (merge b2476a6 jh/loose-object-dirs-creation-race later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 7055576..e6d46ed 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -139,8 +139,15 @@ People on the Git mailing list need to be able to read and
comment on the changes you are submitting. It is important for
a developer to be able to "quote" your changes, using standard
e-mail tools, so that they may comment on specific portions of
-your code. For this reason, all patches should be submitted
-"inline". If your log message (including your name on the
+your code. For this reason, each patch should be submitted
+"inline" in a separate message.
+
+Multiple related patches should be grouped into their own e-mail
+thread to help readers find all parts of the series. To that end,
+send them as replies to either an additional "cover letter" message
+(see below), the first patch, or the respective preceding patch.
+
+If your log message (including your name on the
Signed-off-by line) is not writable in ASCII, make sure that
you send off a message in the correct encoding.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1a0bd0d..5f4d793 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -567,6 +567,10 @@ be passed to the shell by Git, which will translate the final
command to `LESS=FRSX less -+S`. The environment tells the command
to set the `S` option to chop long lines but the command line
resets it to the default to fold long lines.
++
+Likewise, when the `LV` environment variable is unset, Git sets it
+to `-c`. You can override this setting by exporting `LV` with
+another value or setting `core.pager` to `lv +c`.
core.whitespace::
A comma separated list of common whitespace problems to
@@ -2091,8 +2095,8 @@ remote.<name>.vcs::
remote.<name>.prune::
When set to true, fetching from this remote by default will also
- remove any remote-tracking branches which no longer exist on the
- remote (as if the `--prune` option was give on the command line).
+ remove any remote-tracking references that no longer exist on the
+ remote (as if the `--prune` option was given on the command line).
Overrides `fetch.prune` settings, if any.
remotes.<group>::
diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt
index 223b931..f07b451 100644
--- a/Documentation/diff-config.txt
+++ b/Documentation/diff-config.txt
@@ -98,6 +98,11 @@ diff.mnemonicprefix::
diff.noprefix::
If set, 'git diff' does not show any source or destination prefix.
+diff.orderfile::
+ File indicating how to order files within a diff, using
+ one shell glob pattern per line.
+ Can be overridden by the '-O' option to linkgit:git-diff[1].
+
diff.renameLimit::
The number of files to consider when performing the copy/rename
detection; equivalent to the 'git diff' option '-l'.
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index bbed2cd..9b37b2a 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -432,6 +432,9 @@ endif::git-format-patch[]
-O<orderfile>::
Output the patch in the order specified in the
<orderfile>, which has one shell glob pattern per line.
+ This overrides the `diff.orderfile` configuration variable
+ (see linkgit:git-config[1]). To cancel `diff.orderfile`,
+ use `-O/dev/null`.
ifndef::git-format-patch[]
-R::
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 54043e3..92c68c3 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -51,17 +51,20 @@ ifndef::git-pull[]
-p::
--prune::
- After fetching, remove any remote-tracking branches which
- no longer exist on the remote.
+ After fetching, remove any remote-tracking references that no
+ longer exist on the remote. Tags are not subject to pruning
+ if they are fetched only because of the default tag
+ auto-following or due to a --tags option. However, if tags
+ 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.
endif::git-pull[]
-ifdef::git-pull[]
---no-tags::
-endif::git-pull[]
ifndef::git-pull[]
-n::
---no-tags::
endif::git-pull[]
+--no-tags::
By default, tags that point at objects that are downloaded
from the remote repository are fetched and stored locally.
This option disables this automatic tag following. The default
@@ -71,11 +74,12 @@ endif::git-pull[]
ifndef::git-pull[]
-t::
--tags::
- This is a short-hand for giving `refs/tags/*:refs/tags/*`
- refspec from the command line, to ask all tags to be fetched
- and stored locally. Because this acts as an explicit
- refspec, the default refspecs (configured with the
- remote.$name.fetch variable) are overridden and not used.
+ Fetch all tags from the remote (i.e., fetch remote tags
+ `refs/tags/*` into local tags with the same name), in addition
+ to whatever else would otherwise be fetched. Using this
+ option alone does not subject tags to pruning, even if --prune
+ is used (though tags may be pruned anyway if they are also the
+ destination of an explicit refspec; see '--prune').
--recurse-submodules[=yes|on-demand|no]::
This option controls if and under what conditions new commits of
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 322f5ed..f6a16f4 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -109,6 +109,11 @@ newline. The available atoms are:
The size, in bytes, that the object takes up on disk. See the
note about on-disk sizes in the `CAVEATS` section below.
+`deltabase`::
+ If the object is stored as a delta on-disk, this expands to the
+ 40-hex sha1 of the delta base object. Otherwise, expands to the
+ null sha1 (40 zeroes). See `CAVEATS` below.
+
`rest`::
If this atom is used in the output string, input lines are split
at the first whitespace boundary. All characters before that
@@ -152,10 +157,11 @@ should be taken in drawing conclusions about which refs or objects are
responsible for disk usage. The size of a packed non-delta object may be
much larger than the size of objects which delta against it, but the
choice of which object is the base and which is the delta is arbitrary
-and is subject to change during a repack. Note also that multiple copies
-of an object may be present in the object database; in this case, it is
-undefined which copy's size will be reported.
+and is subject to change during a repack.
+Note also that multiple copies of an object may be present in the object
+database; in this case, it is undefined which copy's size or delta base
+will be reported.
GIT
---
diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt
index 2d0daae..0ea921a 100644
--- a/Documentation/git-cherry.txt
+++ b/Documentation/git-cherry.txt
@@ -3,7 +3,7 @@ git-cherry(1)
NAME
----
-git-cherry - Find commits not merged upstream
+git-cherry - Find commits yet to be applied to upstream
SYNOPSIS
--------
@@ -12,46 +12,26 @@ SYNOPSIS
DESCRIPTION
-----------
-The changeset (or "diff") of each commit between the fork-point and <head>
-is compared against each commit between the fork-point and <upstream>.
-The diffs are compared after removing any whitespace and line numbers.
+Determine whether there are commits in `<head>..<upstream>` that are
+equivalent to those in the range `<limit>..<head>`.
-Every commit that doesn't exist in the <upstream> branch
-has its id (sha1) reported, prefixed by a symbol. The ones that have
-equivalent change already
-in the <upstream> branch are prefixed with a minus (-) sign, and those
-that only exist in the <head> branch are prefixed with a plus (+) symbol:
-
- __*__*__*__*__> <upstream>
- /
- fork-point
- \__+__+__-__+__+__-__+__> <head>
-
-
-If a <limit> has been given then the commits along the <head> branch up
-to and including <limit> are not reported:
-
- __*__*__*__*__> <upstream>
- /
- fork-point
- \__*__*__<limit>__-__+__> <head>
-
-
-Because 'git cherry' compares the changeset rather than the commit id
-(sha1), you can use 'git cherry' to find out if a commit you made locally
-has been applied <upstream> under a different commit id. For example,
-this will happen if you're feeding patches <upstream> via email rather
-than pushing or pulling commits directly.
+The equivalence test is based on the diff, after removing whitespace
+and line numbers. git-cherry therefore detects when commits have been
+"copied" by means of linkgit:git-cherry-pick[1], linkgit:git-am[1] or
+linkgit:git-rebase[1].
+Outputs the SHA1 of every commit in `<limit>..<head>`, prefixed with
+`-` for commits that have an equivalent in <upstream>, and `+` for
+commits that do not.
OPTIONS
-------
-v::
- Verbose.
+ Show the commit subjects next to the SHA1s.
<upstream>::
- Upstream branch to compare against.
- Defaults to the first tracked remote branch, if available.
+ Upstream branch to search for equivalent commits.
+ Defaults to the upstream branch of HEAD.
<head>::
Working branch; defaults to HEAD.
@@ -59,6 +39,103 @@ OPTIONS
<limit>::
Do not report commits up to (and including) limit.
+EXAMPLES
+--------
+
+Patch workflows
+~~~~~~~~~~~~~~~
+
+git-cherry is frequently used in patch-based workflows (see
+linkgit:gitworkflows[7]) to determine if a series of patches has been
+applied by the upstream maintainer. In such a workflow you might
+create and send a topic branch like this:
+
+------------
+$ git checkout -b topic origin/master
+# work and create some commits
+$ git format-patch origin/master
+$ git send-email ... 00*
+------------
+
+Later, you can see whether your changes have been applied by saying
+(still on `topic`):
+
+------------
+$ git fetch # update your notion of origin/master
+$ git cherry -v
+------------
+
+Concrete example
+~~~~~~~~~~~~~~~~
+
+In a situation where topic consisted of three commits, and the
+maintainer applied two of them, the situation might look like:
+
+------------
+$ git log --graph --oneline --decorate --boundary origin/master...topic
+* 7654321 (origin/master) upstream tip commit
+[... snip some other commits ...]
+* cccc111 cherry-pick of C
+* aaaa111 cherry-pick of A
+[... snip a lot more that has happened ...]
+| * cccc000 (topic) commit C
+| * bbbb000 commit B
+| * aaaa000 commit A
+|/
+o 1234567 branch point
+------------
+
+In such cases, git-cherry shows a concise summary of what has yet to
+be applied:
+
+------------
+$ git cherry origin/master topic
+- cccc000... commit C
++ bbbb000... commit B
+- aaaa000... commit A
+------------
+
+Here, we see that the commits A and C (marked with `-`) can be
+dropped from your `topic` branch when you rebase it on top of
+`origin/master`, while the commit B (marked with `+`) still needs to
+be kept so that it will be sent to be applied to `origin/master`.
+
+
+Using a limit
+~~~~~~~~~~~~~
+
+The optional <limit> is useful in cases where your topic is based on
+other work that is not in upstream. Expanding on the previous
+example, this might look like:
+
+------------
+$ git log --graph --oneline --decorate --boundary origin/master...topic
+* 7654321 (origin/master) upstream tip commit
+[... snip some other commits ...]
+* cccc111 cherry-pick of C
+* aaaa111 cherry-pick of A
+[... snip a lot more that has happened ...]
+| * cccc000 (topic) commit C
+| * bbbb000 commit B
+| * aaaa000 commit A
+| * 0000fff (base) unpublished stuff F
+[... snip ...]
+| * 0000aaa unpublished stuff A
+|/
+o 1234567 merge-base between upstream and topic
+------------
+
+By specifying `base` as the limit, you can avoid listing commits
+between `base` and `topic`:
+
+------------
+$ git cherry origin/master topic base
+- cccc000... commit C
++ bbbb000... commit B
+- aaaa000... commit A
+------------
+
+
SEE ALSO
--------
linkgit:git-patch-id[1]
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index 444b805..93b5067 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -12,7 +12,7 @@ SYNOPSIS
'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag]
[--upload-pack=<git-upload-pack>]
[--depth=<n>] [--no-progress]
- [-v] [<host>:]<directory> [<refs>...]
+ [-v] <repository> [<refs>...]
DESCRIPTION
-----------
@@ -97,19 +97,18 @@ be in a separate packet, and the list must end with a flush packet.
-v::
Run verbosely.
-<host>::
- A remote host that houses the repository. When this
- part is specified, 'git-upload-pack' is invoked via
- ssh.
-
-<directory>::
- The repository to sync from.
+<repository>::
+ The URL to the remote repository.
<refs>...::
The remote heads to update from. This is relative to
$GIT_DIR (e.g. "HEAD", "refs/heads/master"). When
unspecified, update from all heads the remote side has.
+SEE ALSO
+--------
+linkgit:git-fetch[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index e08a028..5809aa4 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -24,19 +24,22 @@ The ref names and their object names of fetched refs are stored
in `.git/FETCH_HEAD`. This information is left for a later merge
operation done by 'git merge'.
-When <refspec> stores the fetched result in remote-tracking branches,
-the tags that point at these branches are automatically
-followed. This is done by first fetching from the remote using
-the given <refspec>s, and if the repository has objects that are
-pointed by remote tags that it does not yet have, then fetch
-those missing tags. If the other end has tags that point at
-branches you are not interested in, you will not get them.
+By default, tags are auto-followed. This means that when fetching
+from a remote, any tags on the remote that point to objects that exist
+in the local repository are fetched. The effect is to fetch tags that
+point at branches that you are interested in. This default behavior
+can be changed by using the --tags or --no-tags options, by
+configuring remote.<name>.tagopt, or by using a refspec that fetches
+tags explicitly.
'git fetch' can fetch from either a single named repository,
or from several repositories at once if <group> is given and
there is a remotes.<group> entry in the configuration file.
(See linkgit:git-config[1]).
+When no remote is specified, by default the `origin` remote will be used,
+unless there's an upstream branch configured for the current branch.
+
OPTIONS
-------
include::fetch-options.txt[]
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index e4c8e82..2eba627 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -393,7 +393,7 @@ git filter-branch --index-filter \
Checklist for Shrinking a Repository
------------------------------------
-git-filter-branch is often used to get rid of a subset of files,
+git-filter-branch can be used to get rid of a subset of files,
usually with some combination of `--index-filter` and
`--subdirectory-filter`. People expect the resulting repository to
be smaller than the original, but you need a few more steps to
@@ -429,6 +429,37 @@ warned.
(or if your git-gc is not new enough to support arguments to
`--prune`, use `git repack -ad; git prune` instead).
+Notes
+-----
+
+git-filter-branch allows you to make complex shell-scripted rewrites
+of your Git history, but you probably don't need this flexibility if
+you're simply _removing unwanted data_ like large files or passwords.
+For those operations you may want to consider
+link:http://rtyley.github.io/bfg-repo-cleaner/[The BFG Repo-Cleaner],
+a JVM-based alternative to git-filter-branch, typically at least
+10-50x faster for those use-cases, and with quite different
+characteristics:
+
+* Any particular version of a file is cleaned exactly _once_. The BFG,
+ unlike git-filter-branch, does not give you the opportunity to
+ handle a file differently based on where or when it was committed
+ within your history. This constraint gives the core performance
+ benefit of The BFG, and is well-suited to the task of cleansing bad
+ data - you don't care _where_ the bad data is, you just want it
+ _gone_.
+
+* By default The BFG takes full advantage of multi-core machines,
+ cleansing commit file-trees in parallel. git-filter-branch cleans
+ commits sequentially (ie in a single-threaded manner), though it
+ _is_ possible to write filters that include their own parallellism,
+ in the scripts executed against each commit.
+
+* The link:http://rtyley.github.io/bfg-repo-cleaner/#examples[command options]
+ are much more restrictive than git-filter branch, and dedicated just
+ to the tasks of removing unwanted data- e.g:
+ `--strip-blobs-bigger-than 1M`.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index f2e08d1..94f5c46 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -91,7 +91,19 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
from the displayed ref. Respects `:short` in the same way as
- `refname` above.
+ `refname` above. Additionally respects `:track` to show
+ "[ahead N, behind M]" and `:trackshort` to show the terse
+ version: ">" (ahead), "<" (behind), "<>" (ahead and behind),
+ or "=" (in sync). Has no effect if the ref does not have
+ tracking information associated with it.
+
+HEAD::
+ '*' if HEAD matches current ref (the checked out branch), ' '
+ otherwise.
+
+color::
+ Change output color. Followed by `:<colorname>`, where names
+ are described in `color.branch.*`.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 34097ef..1f7bc67 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -15,9 +15,9 @@ DESCRIPTION
-----------
Shows the commit logs.
-The command takes options applicable to the 'git rev-list'
+The command takes options applicable to the `git rev-list`
command to control what is shown and how, and options applicable to
-the 'git diff-*' commands to control how the changes
+the `git diff-*` commands to control how the changes
each commit introduces are shown.
@@ -42,29 +42,27 @@ OPTIONS
--use-mailmap::
Use mailmap file to map author and committer names and email
- to canonical real names and email addresses. See
+ addresses to canonical real names and email addresses. See
linkgit:git-shortlog[1].
--full-diff::
- Without this flag, "git log -p <path>..." shows commits that
+ Without this flag, `git log -p <path>...` shows commits that
touch the specified paths, and diffs about the same specified
paths. With this, the full diff is shown for commits that touch
the specified paths; this means that "<path>..." limits only
commits, and doesn't limit diff for those commits.
+
Note that this affects all diff-based output types, e.g. those
-produced by --stat etc.
+produced by `--stat`, etc.
--log-size::
- Before the log message print out its size in bytes. Intended
- mainly for porcelain tools consumption. If Git is unable to
- produce a valid value size is set to zero.
- Note that only message is considered, if also a diff is shown
- its size is not included.
+ Include a line ``log size <number>'' in the output for each commit,
+ where <number> is the length of that commit's message in bytes.
+ Intended to speed up tools that read log messages from `git log`
+ output by allowing them to allocate space in advance.
-L <start>,<end>:<file>::
-L :<regex>:<file>::
-
Trace the evolution of the line range given by "<start>,<end>"
(or the funcname regex <regex>) within the <file>. You may
not give any pathspec limiters. This is currently limited to
@@ -80,16 +78,16 @@ include::line-range-format.txt[]
whole history leading to the current commit). `origin..HEAD`
specifies all the commits reachable from the current commit
(i.e. `HEAD`), but not from `origin`. For a complete list of
- ways to spell <revision range>, see the "Specifying Ranges"
+ ways to spell <revision range>, see the 'Specifying Ranges'
section of linkgit:gitrevisions[7].
[\--] <path>...::
Show only commits that are enough to explain how the files
- that match the specified paths came to be. See "History
- Simplification" below for details and other simplification
+ that match the specified paths came to be. See 'History
+ Simplification' below for details and other simplification
modes.
+
-Paths may need to be prefixed with "\-- " to separate them from
+Paths may need to be prefixed with ``\-- '' to separate them from
options or the revision range, when confusion arises.
include::rev-list-options.txt[]
@@ -113,12 +111,12 @@ EXAMPLES
`git log v2.6.12.. include/scsi drivers/scsi`::
Show all commits since version 'v2.6.12' that changed any file
- in the include/scsi or drivers/scsi subdirectories
+ in the `include/scsi` or `drivers/scsi` subdirectories
`git log --since="2 weeks ago" -- gitk`::
Show the changes during the last two weeks to the file 'gitk'.
- The "--" is necessary to avoid confusion with the *branch* named
+ The ``--'' is necessary to avoid confusion with the *branch* named
'gitk'
`git log --name-status release..test`::
@@ -129,7 +127,7 @@ EXAMPLES
`git log --follow builtin/rev-list.c`::
- Shows the commits that changed builtin/rev-list.c, including
+ Shows the commits that changed `builtin/rev-list.c`, including
those commits that occurred before the file was given its
present name.
@@ -147,17 +145,18 @@ EXAMPLES
`git log -p -m --first-parent`::
Shows the history including change diffs, but only from the
- "main branch" perspective, skipping commits that come from merged
+ ``main branch'' perspective, skipping commits that come from merged
branches, and showing full diffs of changes introduced by the merges.
This makes sense only when following a strict policy of merging all
topic branches when staying on a single integration branch.
`git log -L '/int main/',/^}/:main.c`::
- Shows how the function `main()` in the file 'main.c' evolved
+ Shows how the function `main()` in the file `main.c` evolved
over time.
`git log -3`::
+
Limits the number of commits to show to 3.
DISCUSSION
@@ -172,12 +171,12 @@ See linkgit:git-config[1] for core variables and linkgit:git-diff[1]
for settings related to diff generation.
format.pretty::
- Default for the `--format` option. (See "PRETTY FORMATS" above.)
- Defaults to "medium".
+ Default for the `--format` option. (See 'Pretty Formats' above.)
+ Defaults to `medium`.
i18n.logOutputEncoding::
- Encoding to use when displaying logs. (See "Discussion", above.)
- Defaults to the value of `i18n.commitEncoding` if set, UTF-8
+ Encoding to use when displaying logs. (See 'Discussion' above.)
+ Defaults to the value of `i18n.commitEncoding` if set, and UTF-8
otherwise.
log.date::
@@ -186,7 +185,7 @@ log.date::
dates like `Sat May 8 19:35:34 2010 -0500`.
log.showroot::
- If `false`, 'git log' and related commands will not treat the
+ If `false`, `git log` and related commands will not treat the
initial commit as a big creation event. Any root commits in
`git log -p` output would be shown without a diff attached.
The default is `true`.
@@ -197,7 +196,7 @@ mailmap.*::
notes.displayRef::
Which refs, in addition to the default set by `core.notesRef`
or 'GIT_NOTES_REF', to read notes from when showing commit
- messages with the 'log' family of commands. See
+ messages with the `log` family of commands. See
linkgit:git-notes[1].
+
May be an unabbreviated ref name or a glob and may be specified
diff --git a/Documentation/git-lost-found.txt b/Documentation/git-lost-found.txt
deleted file mode 100644
index d549328..0000000
--- a/Documentation/git-lost-found.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-git-lost-found(1)
-=================
-
-NAME
-----
-git-lost-found - Recover lost refs that luckily have not yet been pruned
-
-SYNOPSIS
---------
-[verse]
-'git lost-found'
-
-DESCRIPTION
------------
-
-*NOTE*: this command is deprecated. Use linkgit:git-fsck[1] with
-the option '--lost-found' instead.
-
-Finds dangling commits and tags from the object database, and
-creates refs to them in the .git/lost-found/ directory. Commits and
-tags that dereference to commits are stored in .git/lost-found/commit,
-and other objects are stored in .git/lost-found/other.
-
-
-OUTPUT
-------
-Prints to standard output the object names and one-line descriptions
-of any commits or tags found.
-
-EXAMPLE
--------
-
-Suppose you run 'git tag -f' and mistype the tag to overwrite.
-The ref to your tag is overwritten, but until you run 'git
-prune', the tag itself is still there.
-
-------------
-$ git lost-found
-[1ef2b196d909eed523d4f3c9bf54b78cdd6843c6] GIT 0.99.9c
-...
-------------
-
-Also you can use gitk to browse how any tags found relate to each
-other.
-
-------------
-$ gitk $(cd .git/lost-found/commit && echo ??*)
-------------
-
-After making sure you know which the object is the tag you are looking
-for, you can reconnect it to your regular `refs` hierarchy by using
-the `update-ref` command.
-
-------------
-$ git cat-file -t 1ef2b196
-tag
-$ git cat-file tag 1ef2b196
-object fa41bbce8e38c67a218415de6cfa510c7e50032a
-type commit
-tag v0.99.9c
-tagger Junio C Hamano <junkio@cox.net> 1131059594 -0800
-
-GIT 0.99.9c
-
-This contains the following changes from the "master" branch, since
-...
-$ git update-ref refs/tags/not-lost-anymore 1ef2b196
-$ git rev-parse not-lost-anymore
-1ef2b196d909eed523d4f3c9bf54b78cdd6843c6
-------------
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index 87842e3..808426f 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -13,6 +13,7 @@ SYNOPSIS
'git merge-base' [-a|--all] --octopus <commit>...
'git merge-base' --is-ancestor <commit> <commit>
'git merge-base' --independent <commit>...
+'git merge-base' --fork-point <ref> [<commit>]
DESCRIPTION
-----------
@@ -24,8 +25,8 @@ that does not have any better common ancestor is a 'best common
ancestor', i.e. a 'merge base'. Note that there can be more than one
merge base for a pair of commits.
-OPERATION MODE
---------------
+OPERATION MODES
+---------------
As the most common special case, specifying only two commits on the
command line means computing the merge base between the given two commits.
@@ -56,6 +57,14 @@ from linkgit:git-show-branch[1] when used with the `--merge-base` option.
and exit with status 0 if true, or with status 1 if not.
Errors are signaled by a non-zero status that is not 1.
+--fork-point::
+ Find the point at which a branch (or any history that leads
+ to <commit>) forked from another branch (or any reference)
+ <ref>. This does not just look for the common ancestor of
+ the two commits, but also takes into account the reflog of
+ <ref> to see if the history leading to <commit> forked from
+ an earlier incarnation of the branch <ref> (see discussion
+ on this mode below).
OPTIONS
-------
@@ -137,6 +146,31 @@ In modern git, you can say this in a more direct way:
instead.
+Discussion on fork-point mode
+-----------------------------
+
+After working on the `topic` branch created with `git checkout -b
+topic origin/master`, the history of remote-tracking branch
+`origin/master` may have been rewound and rebuilt, leading to a
+history of this shape:
+
+ o---B1
+ /
+ ---o---o---B2--o---o---o---B (origin/master)
+ \
+ B3
+ \
+ Derived (topic)
+
+where `origin/master` used to point at commits B3, B2, B1 and now it
+points at B, and your `topic` branch was started on top of it back
+when `origin/master` was at B3. This mode uses the reflog of
+`origin/master` to find B3 as the fork point, so that the `topic`
+can be rebased on top of the updated `origin/master` by:
+
+ $ fork_point=$(git merge-base --fork-point origin/master topic)
+ $ git rebase --onto origin/master $fork_point topic
+
See also
--------
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index b1f7988..e453132 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -52,6 +52,18 @@ core.worktree setting to make the submodule work in the new location.
It also will attempt to update the submodule.<name>.path setting in
the linkgit:gitmodules[5] file and stage that file (unless -n is used).
+BUGS
+----
+Each time a superproject update moves a populated submodule (e.g. when
+switching between commits before and after the move) a stale submodule
+checkout will remain in the old location and an empty directory will
+appear in the new location. To populate the submodule again in the new
+location the user will have to run "git submodule update"
+afterwards. Removing the old directory is only safe when it uses a
+gitfile, as otherwise the history of the submodule will be deleted
+too. Both steps will be obsolete when recursive submodule update has
+been implemented.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index d94edcd..cdab9ed 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -51,8 +51,7 @@ base-name::
<base-name> to determine the name of the created file.
When this option is used, the two files are written in
<base-name>-<SHA-1>.{pack,idx} files. <SHA-1> is a hash
- of the sorted object names to make the resulting filename
- based on the pack content, and written to the standard
+ based on the pack content and is written to the standard
output of the command.
--stdout::
diff --git a/Documentation/git-peek-remote.txt b/Documentation/git-peek-remote.txt
deleted file mode 100644
index 87ea3fb..0000000
--- a/Documentation/git-peek-remote.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-git-peek-remote(1)
-==================
-
-NAME
-----
-git-peek-remote - List the references in a remote repository
-
-
-SYNOPSIS
---------
-[verse]
-'git peek-remote' [--upload-pack=<git-upload-pack>] [<host>:]<directory>
-
-DESCRIPTION
------------
-This command is deprecated; use 'git ls-remote' instead.
-
-OPTIONS
--------
---upload-pack=<git-upload-pack>::
- Use this to specify the path to 'git-upload-pack' on the
- remote side, if it is not found on your $PATH. Some
- installations of sshd ignores the user's environment
- setup scripts for login shells (e.g. .bash_profile) and
- your privately installed git may not be found on the system
- default $PATH. Another workaround suggested is to set
- up your $PATH in ".bashrc", but this flag is for people
- who do not want to pay the overhead for non-interactive
- shells, but prefer having a lean .bashrc file (they set most of
- the things up in .bash_profile).
-
-<host>::
- A remote host that houses the repository. When this
- part is specified, 'git-upload-pack' is invoked via
- ssh.
-
-<directory>::
- The repository to sync from.
-
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 9eec740..2b7f4f9 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -56,8 +56,13 @@ it can be any arbitrary "SHA-1 expression", such as `master~4` or
+
The <dst> tells which ref on the remote side is updated with this
push. Arbitrary expressions cannot be used here, an actual ref must
-be named. If `:`<dst> is omitted, the same ref as <src> will be
-updated.
+be named.
+If `git push [<repository>]` without any `<refspec>` argument is set to
+update some ref at the destination with `<src>` with
+`remote.<repository>.push` configuration variable, `:<dst>` part can
+be omitted---such a push will update a ref that `<src>` normally updates
+without any `<refspec>` on the command line. Otherwise, missing
+`:<dst>` means to update the same ref as the `<src>`.
+
The object referenced by <src> is used to update the <dst> reference
on the remote side. By default this is only allowed if <dst> is not
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 94e07fd..2889be6 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -324,6 +324,16 @@ fresh commits so it can be remerged successfully without needing to "revert
the reversion" (see the
link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
+--fork-point::
+--no-fork-point::
+ Use 'git merge-base --fork-point' to find a better common ancestor
+ between `upstream` and `branch` when calculating which commits have
+ have been introduced by `branch` (see linkgit:git-merge-base[1]).
++
+If no non-option arguments are given on the command line, then the default is
+`--fork-point @{u}` otherwise the `upstream` argument is interpreted literally
+unless the `--fork-point` option is specified.
+
--ignore-whitespace::
--whitespace=<option>::
These flag are passed to the 'git apply' program
diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt
index f373ab4..0a02f70 100644
--- a/Documentation/git-replace.txt
+++ b/Documentation/git-replace.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git replace' [-f] <object> <replacement>
'git replace' -d <object>...
-'git replace' -l [<pattern>]
+'git replace' [--format=<format>] [-l [<pattern>]]
DESCRIPTION
-----------
@@ -70,6 +70,23 @@ OPTIONS
Typing "git replace" without arguments, also lists all replace
refs.
+--format=<format>::
+ When listing, use the specified <format>, which can be one of
+ 'short', 'medium' and 'long'. When omitted, the format
+ defaults to 'short'.
+
+FORMATS
+-------
+
+The following format are available:
+
+* 'short':
+ <replaced sha1>
+* 'medium':
+ <replaced sha1> -> <replacement sha1>
+* 'long':
+ <replaced sha1> (<replaced type>) -> <replacement sha1> (<replacement type>)
+
CREATING REPLACEMENT OBJECTS
----------------------------
diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt
deleted file mode 100644
index 9ec115b..0000000
--- a/Documentation/git-repo-config.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-git-repo-config(1)
-==================
-
-NAME
-----
-git-repo-config - Get and set repository or global options
-
-
-SYNOPSIS
---------
-[verse]
-'git repo-config' ...
-
-
-DESCRIPTION
------------
-
-This is a synonym for linkgit:git-config[1]. Please refer to the
-documentation of that command.
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index d068a65..0d2cdcd 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -50,6 +50,10 @@ Options for --parseopt
the first non-option argument. This can be used to parse sub-commands
that take options themselves.
+--stuck-long::
+ Only meaningful in `--parseopt` mode. Output the options in their
+ long form if available, and with their arguments stuck.
+
Options for Filtering
~~~~~~~~~~~~~~~~~~~~~
@@ -173,6 +177,20 @@ shown. If the pattern does not contain a globbing character (`?`,
character (`?`, `*`, or `[`), it is turned into a prefix
match by appending `/*`.
+--exclude=<glob-pattern>::
+ Do not include refs matching '<glob-pattern>' that the next `--all`,
+ `--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
+ consider. Repetitions of this option accumulate exclusion patterns
+ up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
+ `--glob` option (other options or arguments do not clear
+ accumlated patterns).
++
+The patterns given should not begin with `refs/heads`, `refs/tags`, or
+`refs/remotes` when applied to `--branches`, `--tags`, or `--remotes`,
+respectively, and they must begin with `refs/` when applied to `--glob`
+or `--all`. If a trailing '/{asterisk}' is intended, it must be given
+explicitly.
+
--disambiguate=<prefix>::
Show every object whose name begins with the given prefix.
The <prefix> must be at least 4 hexadecimal digits long to
@@ -285,7 +303,9 @@ Each line of options has this format:
`<flags>` are of `*`, `=`, `?` or `!`.
* Use `=` if the option takes an argument.
- * Use `?` to mean that the option is optional (though its use is discouraged).
+ * Use `?` to mean that the option takes an optional argument. You
+ probably want to use the `--stuck-long` mode to be able to
+ unambiguously parse the optional argument.
* Use `*` to mean that this option should not be listed in the usage
generated for the `-h` argument. It's shown for `--help-all` as
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 9d731b4..f1efc11 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -170,6 +170,15 @@ of files and subdirectories under the `Documentation/` directory.
(i.e. you are listing the files explicitly), it
does not remove `subdir/git-foo.sh`.
+BUGS
+----
+Each time a superproject update removes a populated submodule
+(e.g. when switching between commits before and after the removal) a
+stale submodule checkout will remain in the old location. Removing the
+old directory is only safe when it uses a gitfile, as otherwise the
+history of the submodule will be deleted too. This step will be
+obsolete when recursive submodule update has been implemented.
+
SEE ALSO
--------
linkgit:git-add[1]
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
deleted file mode 100644
index f7362dc..0000000
--- a/Documentation/git-tar-tree.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-git-tar-tree(1)
-===============
-
-NAME
-----
-git-tar-tree - Create a tar archive of the files in the named tree object
-
-
-SYNOPSIS
---------
-[verse]
-'git tar-tree' [--remote=<repo>] <tree-ish> [ <base> ]
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED. Use 'git archive' with `--format=tar`
-option instead (and move the <base> argument to `--prefix=base/`).
-
-Creates a tar archive containing the tree structure for the named tree.
-When <base> is specified it is added as a leading path to the files in the
-generated tar archive.
-
-'git tar-tree' behaves differently when given a tree ID versus when given
-a commit ID or tag ID. In the first case the current time is used as
-modification time of each file in the archive. In the latter case the
-commit time as recorded in the referenced commit object is used instead.
-Additionally the commit ID is stored in a global extended pax header.
-It can be extracted using 'git get-tar-commit-id'.
-
-OPTIONS
--------
-
-<tree-ish>::
- The tree or commit to produce tar archive for. If it is
- the object name of a commit object.
-
-<base>::
- Leading path to the files in the resulting tar archive.
-
---remote=<repo>::
- Instead of making a tar archive from local repository,
- retrieve a tar archive from a remote repository.
-
-CONFIGURATION
--------------
-
-tar.umask::
- This variable can be used to restrict the permission bits of
- tar archive entries. The default is 0002, which turns off the
- world write bit. The special value "user" indicates that the
- archiving user's umask will be used instead. See umask(2) for
- details.
-
-EXAMPLES
---------
-`git tar-tree HEAD junk | (cd /var/tmp/ && tar xf -)`::
-
- Create a tar archive that contains the contents of the
- latest commit on the current branch, and extracts it in
- `/var/tmp/junk` directory.
-
-`git tar-tree v1.4.0 git-1.4.0 | gzip >git-1.4.0.tar.gz`::
-
- Create a tarball for v1.4.0 release.
-
-`git tar-tree v1.4.0^{tree} git-1.4.0 | gzip >git-1.4.0.tar.gz`::
-
- Create a tarball for v1.4.0 release, but without a
- global extended pax header.
-
-`git tar-tree --remote=example.com:git.git v1.4.0 >git-1.4.0.tar`::
-
- Get a tarball v1.4.0 from example.com.
-
-`git tar-tree HEAD:Documentation/ git-docs > git-1.4.0-docs.tar`::
-
- Put everything in the current head's Documentation/ directory
- into 'git-1.4.0-docs.tar', with the prefix 'git-docs/'.
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git.txt b/Documentation/git.txt
index b73a24a..274d816 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,14 +43,18 @@ unreleased) version of Git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.8.5/git.html[documentation for release 1.8.5]
+* link:v1.8.5.3/git.html[documentation for release 1.8.5.3]
* release notes for
+ link:RelNotes/1.8.5.3.txt[1.8.5.3],
+ link:RelNotes/1.8.5.2.txt[1.8.5.2],
+ link:RelNotes/1.8.5.1.txt[1.8.5.1],
link:RelNotes/1.8.5.txt[1.8.5].
-* link:v1.8.4.4/git.html[documentation for release 1.8.4.4]
+* link:v1.8.4.5/git.html[documentation for release 1.8.4.5]
* release notes for
+ link:RelNotes/1.8.4.5.txt[1.8.4.5],
link:RelNotes/1.8.4.4.txt[1.8.4.4],
link:RelNotes/1.8.4.3.txt[1.8.4.3],
link:RelNotes/1.8.4.2.txt[1.8.4.2],
@@ -804,6 +808,15 @@ temporary file --- it is removed when 'GIT_EXTERNAL_DIFF' exits.
+
For a path that is unmerged, 'GIT_EXTERNAL_DIFF' is called with 1
parameter, <path>.
++
+For each path 'GIT_EXTERNAL_DIFF' is called, two environment variables,
+'GIT_DIFF_PATH_COUNTER' and 'GIT_DIFF_PATH_TOTAL' are set.
+
+'GIT_DIFF_PATH_COUNTER'::
+ A 1-based counter incremented by one for every path.
+
+'GIT_DIFF_PATH_TOTAL'::
+ The total number of paths.
other
~~~~~
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 3146413..3f33ca5 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -72,23 +72,23 @@ scripting Git:
* splitting short options to separate words (prefer `git foo -a -b`
to `git foo -ab`, the latter may not even work).
- * when a command line option takes an argument, use the 'sticked' form. In
+ * when a command line option takes an argument, use the 'stuck' form. In
other words, write `git foo -oArg` instead of `git foo -o Arg` for short
options, and `git foo --long-opt=Arg` instead of `git foo --long-opt Arg`
for long options. An option that takes optional option-argument must be
- written in the 'sticked' form.
+ written in the 'stuck' form.
* when you give a revision parameter to a command, make sure the parameter is
not ambiguous with a name of a file in the work tree. E.g. do not write
`git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
if you happen to have a file called `HEAD` in the work tree.
- * many commands allow a long option "--option" to be abbreviated
+ * many commands allow a long option `--option` to be abbreviated
only to their unique prefix (e.g. if there is no other option
- whose name begins with "opt", you may be able to spell "--opt" to
- invoke the "--option" flag), but you should fully spell them out
+ whose name begins with `opt`, you may be able to spell `--opt` to
+ invoke the `--option` flag), but you should fully spell them out
when writing your scripts; later versions of Git may introduce a
- new option whose name shares the same prefix, e.g. "--optimize",
+ new option whose name shares the same prefix, e.g. `--optimize`,
to make a short prefix that used to be unique no longer unique.
@@ -149,7 +149,7 @@ prefix of a long option as if it is fully spelled out, but use this
with a caution. For example, `git commit --amen` behaves as if you
typed `git commit --amend`, but that is true only until a later version
of Git introduces another option that shares the same prefix,
-e.g `git commit --amenity" option.
+e.g. `git commit --amenity` option.
Separating argument from the option
@@ -165,7 +165,7 @@ $ git foo -o Arg
----------------------------
However, this is *NOT* allowed for switches with an optional value, where the
-'sticked' form must be used:
+'stuck' form must be used:
----------------------------
$ git describe --abbrev HEAD # correct
$ git describe --abbrev=10 HEAD # correct
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index f971960..205e80e 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -79,8 +79,10 @@ PATTERN FORMAT
- An optional prefix "`!`" which negates the pattern; any
matching file excluded by a previous pattern will become
- included again. If a negated pattern matches, this will
- override lower precedence patterns sources.
+ included again. It is not possible to re-include a file if a parent
+ directory of that file is excluded. Git doesn't list excluded
+ directories for performance reasons, so any patterns on contained
+ files have no effect, no matter where they are defined.
Put a backslash ("`\`") in front of the first "`!`" for patterns
that begin with a literal "`!`", for example, "`\!important!.txt`".
@@ -182,6 +184,19 @@ Another example:
The second .gitignore prevents Git from ignoring
`arch/foo/kernel/vmlinux.lds.S`.
+Example to exclude everything except a specific directory `foo/bar`
+(note the `/*` - without the slash, the wildcard would also exclude
+everything within `foo/bar`):
+
+--------------------------------------------------------------
+ $ cat .gitignore
+ # exclude everything except directory foo/bar
+ /*
+ !/foo
+ /foo/*
+ !/foo/bar
+--------------------------------------------------------------
+
SEE ALSO
--------
linkgit:git-rm[1],
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index f7be93f..347a9f7 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -35,6 +35,8 @@ submodule.<name>.url::
linkgit:git-clone[1] or (if it begins with ./ or ../) a location
relative to the superproject's origin repository.
+In addition, there are a number of optional keys:
+
submodule.<name>.update::
Defines what to do when the submodule is updated by the superproject.
If 'checkout' (the default), the new commit specified in the
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index e2113d9..db4154f 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -849,6 +849,43 @@ time zones in the form of "+/-HHMM", such as "+0200".
+
Project specific override is not supported.
+extra-branch-refs::
+ List of additional directories under "refs" which are going to
+ be used as branch refs. For example if you have a gerrit setup
+ where all branches under refs/heads/ are official,
+ push-after-review ones and branches under refs/sandbox/,
+ refs/wip and refs/other are user ones where permissions are
+ much wider, then you might want to set this variable as
+ follows:
++
+--------------------------------------------------------------------------------
+$feature{'extra-branch-refs'}{'default'} =
+ ['sandbox', 'wip', 'other'];
+--------------------------------------------------------------------------------
++
+This feature can be configured on per-repository basis after setting
+$feature{'extra-branch-refs'}{'override'} to true, via repository's
+`gitweb.extraBranchRefs` configuration variable, which contains a
+space separated list of refs. An example:
++
+--------------------------------------------------------------------------------
+[gitweb]
+ extraBranchRefs = sandbox wip other
+--------------------------------------------------------------------------------
++
+The gitweb.extraBranchRefs is actually a multi-valued configuration
+variable, so following example is also correct and the result is the
+same as of the snippet above:
++
+--------------------------------------------------------------------------------
+[gitweb]
+ extraBranchRefs = sandbox
+ extraBranchRefs = wip other
+--------------------------------------------------------------------------------
++
+It is an error to specify a ref that does not pass "git check-ref-format"
+scrutiny. Duplicated values are filtered.
+
EXAMPLES
--------
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index e470661..378306f 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -323,24 +323,26 @@ including Documentation/chapter_1/figure_1.jpg.
A pathspec that begins with a colon `:` has special meaning. In the
short form, the leading colon `:` is followed by zero or more "magic
signature" letters (which optionally is terminated by another colon `:`),
-and the remainder is the pattern to match against the path. The optional
-colon that terminates the "magic signature" can be omitted if the pattern
-begins with a character that cannot be a "magic signature" and is not a
-colon.
+and the remainder is the pattern to match against the path.
+The "magic signature" consists of ASCII symbols that are neither
+alphanumeric, glob, regex special charaters nor colon.
+The optional colon that terminates the "magic signature" can be
+omitted if the pattern begins with a character that does not belong to
+"magic signature" symbol set and is not a colon.
+
In the long form, the leading colon `:` is followed by a open
parenthesis `(`, a comma-separated list of zero or more "magic words",
and a close parentheses `)`, and the remainder is the pattern to match
against the path.
+
-The "magic signature" consists of an ASCII symbol that is not
-alphanumeric.
+A pathspec with only a colon means "there is no pathspec". This form
+should not be combined with other pathspec.
+
--
-top `/`;;
- The magic word `top` (mnemonic: `/`) makes the pattern match
- from the root of the working tree, even when you are running
- the command from inside a subdirectory.
+top;;
+ The magic word `top` (magic signature: `/`) makes the pattern
+ match from the root of the working tree, even when you are
+ running the command from inside a subdirectory.
literal;;
Wildcards in the pattern such as `*` or `?` are treated
@@ -362,12 +364,12 @@ full pathname may have special meaning:
- A leading "`**`" followed by a slash means match in all
directories. For example, "`**/foo`" matches file or directory
- "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar"
+ "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`"
matches file or directory "`bar`" anywhere that is directly
under directory "`foo`".
- - A trailing "/**" matches everything inside. For example,
- "abc/**" matches all files inside directory "abc", relative
+ - A trailing "`/**`" matches everything inside. For example,
+ "`abc/**`" matches all files inside directory "abc", relative
to the location of the `.gitignore` file, with infinite depth.
- A slash followed by two consecutive asterisks then a slash
@@ -377,14 +379,12 @@ full pathname may have special meaning:
- Other consecutive asterisks are considered invalid.
+
Glob magic is incompatible with literal magic.
+
+exclude;;
+ After a path matches any non-exclude pathspec, it will be run
+ through all exclude pathspec (magic signature: `!`). If it
+ matches, the path is ignored.
--
-+
-Currently only the slash `/` is recognized as the "magic signature",
-but it is envisioned that we will support more types of magic in later
-versions of Git.
-+
-A pathspec with only a colon means "there is no pathspec". This form
-should not be combined with other pathspec.
[[def_parent]]parent::
A <<def_commit_object,commit object>> contains a (possibly empty) list
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index 49a9a7d..fb6e593 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -113,3 +113,11 @@ subtree::
match the tree structure of A, instead of reading the trees at
the same level. This adjustment is also done to the common
ancestor tree.
+
+With the strategies that use 3-way merge (including the default, 'recursive'),
+if a change is made on both branches, but later reverted on one of the
+branches, that change will be present in the merged result; some people find
+this behavior confusing. It occurs because only the heads and the merge base
+are considered when performing a merge, not the individual commits. The merge
+algorithm therefore considers the reverted change as no change at all, and
+substitutes the changed version instead.
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index ec86d09..03533af 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -18,33 +18,27 @@ ordering and formatting options, such as `--reverse`.
-<number>::
-n <number>::
--max-count=<number>::
-
Limit the number of commits to output.
--skip=<number>::
-
Skip 'number' commits before starting to show the commit output.
--since=<date>::
--after=<date>::
-
Show commits more recent than a specific date.
--until=<date>::
--before=<date>::
-
Show commits older than a specific date.
ifdef::git-rev-list[]
--max-age=<timestamp>::
--min-age=<timestamp>::
-
Limit the commits output to specified time range.
endif::git-rev-list[]
--author=<pattern>::
--committer=<pattern>::
-
Limit the commits output to ones with author/committer
header lines that match the specified pattern (regular
expression). With more than one `--author=<pattern>`,
@@ -52,7 +46,6 @@ endif::git-rev-list[]
chosen (similarly for multiple `--committer=<pattern>`).
--grep-reflog=<pattern>::
-
Limit the commits output to ones with reflog entries that
match the specified pattern (regular expression). With
more than one `--grep-reflog`, commits whose reflog message
@@ -60,7 +53,6 @@ endif::git-rev-list[]
error to use this option unless `--walk-reflogs` is in use.
--grep=<pattern>::
-
Limit the commits output to ones with log message that
matches the specified pattern (regular expression). With
more than one `--grep=<pattern>`, commits whose message
@@ -71,46 +63,39 @@ When `--show-notes` is in effect, the message from the notes as
if it is part of the log message.
--all-match::
- Limit the commits output to ones that match all given --grep,
+ Limit the commits output to ones that match all given `--grep`,
instead of ones that match at least one.
-i::
--regexp-ignore-case::
-
- Match the regexp limiting patterns without regard to letters case.
+ Match the regular expression limiting patterns without regard to letter
+ case.
--basic-regexp::
-
Consider the limiting patterns to be basic regular expressions;
this is the default.
-E::
--extended-regexp::
-
Consider the limiting patterns to be extended regular expressions
instead of the default basic regular expressions.
-F::
--fixed-strings::
-
Consider the limiting patterns to be fixed strings (don't interpret
pattern as a regular expression).
--perl-regexp::
-
- Consider the limiting patterns to be Perl-compatible regexp.
+ Consider the limiting patterns to be Perl-compatible regular expressions.
Requires libpcre to be compiled in.
--remove-empty::
-
Stop when a given path disappears from the tree.
--merges::
-
Print only merge commits. This is exactly the same as `--min-parents=2`.
--no-merges::
-
Do not print commits with more than one parent. This is
exactly the same as `--max-parents=1`.
@@ -118,7 +103,6 @@ if it is part of the log message.
--max-parents=<number>::
--no-min-parents::
--no-max-parents::
-
Show only commits which have at least (or at most) that many parent
commits. In particular, `--max-parents=1` is the same as `--no-merges`,
`--min-parents=2` is the same as `--merges`. `--max-parents=0`
@@ -138,31 +122,26 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
brought in to your history by such a merge.
--not::
-
Reverses the meaning of the '{caret}' prefix (or lack thereof)
- for all following revision specifiers, up to the next '--not'.
+ for all following revision specifiers, up to the next `--not`.
--all::
-
Pretend as if all the refs in `refs/` are listed on the
command line as '<commit>'.
--branches[=<pattern>]::
-
Pretend as if all the refs in `refs/heads` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit
branches to ones matching given shell glob. If pattern lacks '?',
'{asterisk}', or '[', '/{asterisk}' at the end is implied.
--tags[=<pattern>]::
-
Pretend as if all the refs in `refs/tags` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit
tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}',
or '[', '/{asterisk}' at the end is implied.
--remotes[=<pattern>]::
-
Pretend as if all the refs in `refs/remotes` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit
remote-tracking branches to ones matching given shell glob.
@@ -174,14 +153,27 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
is automatically prepended if missing. If pattern lacks '?', '{asterisk}',
or '[', '/{asterisk}' at the end is implied.
---ignore-missing::
+--exclude=<glob-pattern>::
+ Do not include refs matching '<glob-pattern>' that the next `--all`,
+ `--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
+ consider. Repetitions of this option accumulate exclusion patterns
+ up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
+ `--glob` option (other options or arguments do not clear
+ accumlated patterns).
++
+The patterns given should not begin with `refs/heads`, `refs/tags`, or
+`refs/remotes` when applied to `--branches`, `--tags`, or `--remotes`,
+respectively, and they must begin with `refs/` when applied to `--glob`
+or `--all`. If a trailing '/{asterisk}' is intended, it must be given
+explicitly.
+
+--ignore-missing::
Upon seeing an invalid object name in the input, pretend as if
the bad input was not given.
ifndef::git-rev-list[]
--bisect::
-
Pretend as if the bad bisection ref `refs/bisect/bad`
was listed and as if it was followed by `--not` and the good
bisection refs `refs/bisect/good-*` on the command
@@ -189,7 +181,6 @@ ifndef::git-rev-list[]
endif::git-rev-list[]
--stdin::
-
In addition to the '<commit>' listed on the command
line, read them from the standard input. If a '--' separator is
seen, stop reading commits and start reading paths to limit the
@@ -197,36 +188,32 @@ endif::git-rev-list[]
ifdef::git-rev-list[]
--quiet::
-
Don't print anything to standard output. This form
is primarily meant to allow the caller to
test the exit status to see if a range of objects is fully
connected (or not). It is faster than redirecting stdout
- to /dev/null as the output does not have to be formatted.
+ to `/dev/null` as the output does not have to be formatted.
endif::git-rev-list[]
--cherry-mark::
-
Like `--cherry-pick` (see below) but mark equivalent commits
with `=` rather than omitting them, and inequivalent ones with `+`.
--cherry-pick::
-
Omit any commit that introduces the same change as
- another commit on the "other side" when the set of
+ another commit on the ``other side'' when the set of
commits are limited with symmetric difference.
+
For example, if you have two branches, `A` and `B`, a usual way
to list all commits on only one side of them is with
`--left-right` (see the example below in the description of
-the `--left-right` option). It however shows the commits that were cherry-picked
-from the other branch (for example, "3rd on b" may be cherry-picked
-from branch A). With this option, such pairs of commits are
+the `--left-right` option). However, it shows the commits that were
+cherry-picked from the other branch (for example, ``3rd on b'' may be
+cherry-picked from branch A). With this option, such pairs of commits are
excluded from the output.
--left-only::
--right-only::
-
List only commits on the respective side of a symmetric range,
i.e. only those which would be marked `<` resp. `>` by
`--left-right`.
@@ -238,7 +225,6 @@ More precisely, `--cherry-pick --right-only --no-merges` gives the exact
list.
--cherry::
-
A synonym for `--right-only --cherry-mark --no-merges`; useful to
limit the output to the commits on our side and mark those that
have been applied to the other side of a forked history with
@@ -247,30 +233,27 @@ list.
-g::
--walk-reflogs::
-
Instead of walking the commit ancestry chain, walk
reflog entries from the most recent one to older ones.
When this option is used you cannot specify commits to
exclude (that is, '{caret}commit', 'commit1..commit2',
nor 'commit1\...commit2' notations cannot be used).
+
-With '\--pretty' format other than oneline (for obvious reasons),
+With `--pretty` format other than `oneline` (for obvious reasons),
this causes the output to have two extra lines of information
taken from the reflog. By default, 'commit@\{Nth}' notation is
used in the output. When the starting commit is specified as
'commit@\{now}', output also uses 'commit@\{timestamp}' notation
-instead. Under '\--pretty=oneline', the commit message is
+instead. Under `--pretty=oneline`, the commit message is
prefixed with this information on the same line.
-This option cannot be combined with '\--reverse'.
+This option cannot be combined with `--reverse`.
See also linkgit:git-reflog[1].
--merge::
-
After a failed merge, show refs that touch files having a
conflict and don't exist on all heads to merge.
--boundary::
-
Output excluded boundary commits. Boundary commits are
prefixed with `-`.
@@ -287,11 +270,9 @@ is how to do it, as there are various strategies to simplify the history.
The following options select the commits to be shown:
<paths>::
-
Commits modifying the given <paths> are selected.
--simplify-by-decoration::
-
Commits that are referred by some branch or tag are selected.
Note that extra commits can be shown to give a meaningful history.
@@ -299,33 +280,27 @@ Note that extra commits can be shown to give a meaningful history.
The following options affect the way the simplification is performed:
Default mode::
-
Simplifies the history to the simplest history explaining the
final state of the tree. Simplest because it prunes some side
branches if the end result is the same (i.e. merging branches
with the same content)
--full-history::
-
Same as the default mode, but does not prune some history.
--dense::
-
Only the selected commits are shown, plus some to have a
meaningful history.
--sparse::
-
All commits in the simplified history are shown.
--simplify-merges::
-
- Additional option to '--full-history' to remove some needless
+ Additional option to `--full-history` to remove some needless
merges from the resulting history, as there are no selected
commits contributing to this merge.
--ancestry-path::
-
When given a range of commits to display (e.g. 'commit1..commit2'
or 'commit2 {caret}commit1'), only display commits that exist
directly on the ancestry chain between the 'commit1' and
@@ -352,36 +327,35 @@ The horizontal line of history A---Q is taken to be the first parent of
each merge. The commits are:
* `I` is the initial commit, in which `foo` exists with contents
- "asdf", and a file `quux` exists with contents "quux". Initial
+ ``asdf'', and a file `quux` exists with contents ``quux''. Initial
commits are compared to an empty tree, so `I` is !TREESAME.
-* In `A`, `foo` contains just "foo".
+* In `A`, `foo` contains just ``foo''.
* `B` contains the same change as `A`. Its merge `M` is trivial and
hence TREESAME to all parents.
-* `C` does not change `foo`, but its merge `N` changes it to "foobar",
+* `C` does not change `foo`, but its merge `N` changes it to ``foobar'',
so it is not TREESAME to any parent.
-* `D` sets `foo` to "baz". Its merge `O` combines the strings from
- `N` and `D` to "foobarbaz"; i.e., it is not TREESAME to any parent.
+* `D` sets `foo` to ``baz''. Its merge `O` combines the strings from
+ `N` and `D` to ``foobarbaz''; i.e., it is not TREESAME to any parent.
-* `E` changes `quux` to "xyzzy", and its merge `P` combines the
- strings to "quux xyzzy". `P` is TREESAME to `O`, but not to `E`.
+* `E` changes `quux` to ``xyzzy'', and its merge `P` combines the
+ strings to ``quux xyzzy''. `P` is TREESAME to `O`, but not to `E`.
* `X` is an independent root commit that added a new file `side`, and `Y`
modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and
`Q` is TREESAME to `P`, but not to `Y`.
-'rev-list' walks backwards through history, including or excluding
-commits based on whether '\--full-history' and/or parent rewriting
-(via '\--parents' or '\--children') are used. The following settings
+`rev-list` walks backwards through history, including or excluding
+commits based on whether `--full-history` and/or parent rewriting
+(via `--parents` or `--children`) are used. The following settings
are available.
Default mode::
-
Commits are included if they are not TREESAME to any parent
- (though this can be changed, see '\--sparse' below). If the
+ (though this can be changed, see `--sparse` below). If the
commit was a merge, and it was TREESAME to one parent, follow
only that parent. (Even if there are several TREESAME
parents, follow only one of them.) Otherwise, follow all
@@ -400,12 +374,11 @@ available, removed `B` from consideration entirely. `C` was
considered via `N`, but is TREESAME. Root commits are compared to an
empty tree, so `I` is !TREESAME.
+
-Parent/child relations are only visible with --parents, but that does
+Parent/child relations are only visible with `--parents`, but that does
not affect the commits selected in default mode, so we have shown the
parent lines.
--full-history without parent rewriting::
-
This mode differs from the default in one point: always follow
all parents of a merge, even if it is TREESAME to one of them.
Even if more than one side of the merge has commits that are
@@ -425,9 +398,8 @@ about the parent/child relationships between the commits, so we show
them disconnected.
--full-history with parent rewriting::
-
Ordinary commits are only included if they are !TREESAME
- (though this can be changed, see '\--sparse' below).
+ (though this can be changed, see `--sparse` below).
+
Merges are always included. However, their parent list is rewritten:
Along each parent, prune away commits that are not included
@@ -441,7 +413,7 @@ themselves. This results in
`-------------'
-----------------------------------------------------------------------
+
-Compare to '\--full-history' without rewriting above. Note that `E`
+Compare to `--full-history` without rewriting above. Note that `E`
was pruned away because it is TREESAME, but the parent list of P was
rewritten to contain `E`'s parent `I`. The same happened for `C` and
`N`, and `X`, `Y` and `Q`.
@@ -450,22 +422,19 @@ In addition to the above settings, you can change whether TREESAME
affects inclusion:
--dense::
-
Commits that are walked are included if they are not TREESAME
to any parent.
--sparse::
-
All commits that are walked are included.
+
-Note that without '\--full-history', this still simplifies merges: if
+Note that without `--full-history`, this still simplifies merges: if
one of the parents is TREESAME, we follow only that one, so the other
sides of the merge are never walked.
--simplify-merges::
-
First, build a history graph in the same way that
- '\--full-history' with parent rewriting does (see above).
+ `--full-history` with parent rewriting does (see above).
+
Then simplify each commit `C` to its replacement `C'` in the final
history according to the following rules:
@@ -484,7 +453,7 @@ history according to the following rules:
--
+
The effect of this is best shown by way of comparing to
-'\--full-history' with parent rewriting. The example turns into:
+`--full-history` with parent rewriting. The example turns into:
+
-----------------------------------------------------------------------
.-A---M---N---O
@@ -494,7 +463,7 @@ The effect of this is best shown by way of comparing to
`---------'
-----------------------------------------------------------------------
+
-Note the major differences in `N`, `P` and `Q` over '--full-history':
+Note the major differences in `N`, `P`, and `Q` over `--full-history`:
+
--
* `N`'s parent list had `I` removed, because it is an ancestor of the
@@ -511,11 +480,10 @@ Note the major differences in `N`, `P` and `Q` over '--full-history':
Finally, there is a fifth simplification mode available:
--ancestry-path::
-
Limit the displayed commits to those directly on the ancestry
- chain between the "from" and "to" commits in the given commit
- range. I.e. only display commits that are ancestor of the "to"
- commit, and descendants of the "from" commit.
+ chain between the ``from'' and ``to'' commits in the given commit
+ range. I.e. only display commits that are ancestor of the ``to''
+ commit and descendants of the ``from'' commit.
+
As an example use case, consider the following commit history:
+
@@ -530,14 +498,14 @@ As an example use case, consider the following commit history:
A regular 'D..M' computes the set of commits that are ancestors of `M`,
but excludes the ones that are ancestors of `D`. This is useful to see
what happened to the history leading to `M` since `D`, in the sense
-that "what does `M` have that did not exist in `D`". The result in this
+that ``what does `M` have that did not exist in `D`''. The result in this
example would be all the commits, except `A` and `B` (and `D` itself,
of course).
+
When we want to find out what commits in `M` are contaminated with the
bug introduced by `D` and need fixing, however, we might want to view
only the subset of 'D..M' that are actually descendants of `D`, i.e.
-excluding `C` and `K`. This is exactly what the '--ancestry-path'
+excluding `C` and `K`. This is exactly what the `--ancestry-path`
option does. Applied to the 'D..M' range, it results in:
+
-----------------------------------------------------------------------
@@ -548,7 +516,7 @@ option does. Applied to the 'D..M' range, it results in:
L--M
-----------------------------------------------------------------------
-The '\--simplify-by-decoration' option allows you to view only the
+The `--simplify-by-decoration` option allows you to view only the
big picture of the topology of the history, by omitting commits
that are not referenced by tags. Commits are marked as !TREESAME
(in other words, kept after history simplification rules described
@@ -561,50 +529,47 @@ Bisection Helpers
~~~~~~~~~~~~~~~~~
--bisect::
-
-Limit output to the one commit object which is roughly halfway between
-included and excluded commits. Note that the bad bisection ref
-`refs/bisect/bad` is added to the included commits (if it
-exists) and the good bisection refs `refs/bisect/good-*` are
-added to the excluded commits (if they exist). Thus, supposing there
-are no refs in `refs/bisect/`, if
-
+ Limit output to the one commit object which is roughly halfway between
+ included and excluded commits. Note that the bad bisection ref
+ `refs/bisect/bad` is added to the included commits (if it
+ exists) and the good bisection refs `refs/bisect/good-*` are
+ added to the excluded commits (if they exist). Thus, supposing there
+ are no refs in `refs/bisect/`, if
++
-----------------------------------------------------------------------
$ git rev-list --bisect foo ^bar ^baz
-----------------------------------------------------------------------
-
++
outputs 'midpoint', the output of the two commands
-
++
-----------------------------------------------------------------------
$ git rev-list foo ^midpoint
$ git rev-list midpoint ^bar ^baz
-----------------------------------------------------------------------
-
++
would be of roughly the same length. Finding the change which
introduces a regression is thus reduced to a binary search: repeatedly
generate and test new 'midpoint's until the commit chain is of length
one.
--bisect-vars::
-
-This calculates the same as `--bisect`, except that refs in
-`refs/bisect/` are not used, and except that this outputs
-text ready to be eval'ed by the shell. These lines will assign the
-name of the midpoint revision to the variable `bisect_rev`, and the
-expected number of commits to be tested after `bisect_rev` is tested
-to `bisect_nr`, the expected number of commits to be tested if
-`bisect_rev` turns out to be good to `bisect_good`, the expected
-number of commits to be tested if `bisect_rev` turns out to be bad to
-`bisect_bad`, and the number of commits we are bisecting right now to
-`bisect_all`.
+ This calculates the same as `--bisect`, except that refs in
+ `refs/bisect/` are not used, and except that this outputs
+ text ready to be eval'ed by the shell. These lines will assign the
+ name of the midpoint revision to the variable `bisect_rev`, and the
+ expected number of commits to be tested after `bisect_rev` is tested
+ to `bisect_nr`, the expected number of commits to be tested if
+ `bisect_rev` turns out to be good to `bisect_good`, the expected
+ number of commits to be tested if `bisect_rev` turns out to be bad to
+ `bisect_bad`, and the number of commits we are bisecting right now to
+ `bisect_all`.
--bisect-all::
-
-This outputs all the commit objects between the included and excluded
-commits, ordered by their distance to the included and excluded
-commits. Refs in `refs/bisect/` are not used. The farthest
-from them is displayed first. (This is the only one displayed by
-`--bisect`.)
+ This outputs all the commit objects between the included and excluded
+ commits, ordered by their distance to the included and excluded
+ commits. Refs in `refs/bisect/` are not used. The farthest
+ from them is displayed first. (This is the only one displayed by
+ `--bisect`.)
+
This is useful because it makes it easy to choose a good commit to
test when you want to avoid to test some of them for some reason (they
@@ -654,9 +619,8 @@ avoid showing the commits from two parallel development track mixed
together.
--reverse::
-
Output the commits in reverse order.
- Cannot be combined with '\--walk-reflogs'.
+ Cannot be combined with `--walk-reflogs`.
Object Traversal
~~~~~~~~~~~~~~~~
@@ -664,37 +628,32 @@ Object Traversal
These options are mostly targeted for packing of Git repositories.
--objects::
-
Print the object IDs of any object referenced by the listed
- commits. '--objects foo ^bar' thus means "send me
+ commits. `--objects foo ^bar` thus means ``send me
all object IDs which I need to download if I have the commit
- object 'bar', but not 'foo'".
+ object _bar_ but not _foo_''.
--objects-edge::
-
- Similar to '--objects', but also print the IDs of excluded
- commits prefixed with a "-" character. This is used by
- linkgit:git-pack-objects[1] to build "thin" pack, which records
+ Similar to `--objects`, but also print the IDs of excluded
+ commits prefixed with a ``-'' character. This is used by
+ linkgit:git-pack-objects[1] to build ``thin'' pack, which records
objects in deltified form based on objects contained in these
excluded commits to reduce network traffic.
--unpacked::
-
- Only useful with '--objects'; print the object IDs that are not
+ Only useful with `--objects`; print the object IDs that are not
in packs.
--no-walk[=(sorted|unsorted)]::
-
Only show the given commits, but do not traverse their ancestors.
This has no effect if a range is specified. If the argument
- "unsorted" is given, the commits are show in the order they were
- given on the command line. Otherwise (if "sorted" or no argument
- was given), the commits are show in reverse chronological order
+ `unsorted` is given, the commits are shown in the order they were
+ given on the command line. Otherwise (if `sorted` or no argument
+ was given), the commits are shown in reverse chronological order
by commit time.
--do-walk::
-
- Overrides a previous --no-walk.
+ Overrides a previous `--no-walk`.
Commit Formatting
~~~~~~~~~~~~~~~~~
@@ -708,26 +667,24 @@ endif::git-rev-list[]
include::pretty-options.txt[]
--relative-date::
-
Synonym for `--date=relative`.
--date=(relative|local|default|iso|rfc|short|raw)::
-
Only takes effect for dates shown in human-readable format, such
- as when using "--pretty". `log.date` config variable sets a default
- value for log command's --date option.
+ as when using `--pretty`. `log.date` config variable sets a default
+ value for the log command's `--date` option.
+
`--date=relative` shows dates relative to the current time,
-e.g. "2 hours ago".
+e.g. ``2 hours ago''.
+
`--date=local` shows timestamps in user's local time zone.
+
`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
+
`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
-format, often found in E-mail messages.
+format, often found in email messages.
+
-`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
+`--date=short` shows only the date, but not the time, in `YYYY-MM-DD` format.
+
`--date=raw` shows the date in the internal raw Git format `%s %z` format.
+
@@ -736,18 +693,15 @@ format, often found in E-mail messages.
ifdef::git-rev-list[]
--header::
-
Print the contents of the commit in raw-format; each record is
separated with a NUL character.
endif::git-rev-list[]
--parents::
-
Print also the parents of the commit (in the form "commit parent...").
Also enables parent rewriting, see 'History Simplification' below.
--children::
-
Print also the children of the commit (in the form "commit child...").
Also enables parent rewriting, see 'History Simplification' below.
@@ -757,7 +711,6 @@ ifdef::git-rev-list[]
endif::git-rev-list[]
--left-right::
-
Mark which side of a symmetric diff a commit is reachable from.
Commits from the left side are prefixed with `<` and those from
the right with `>`. If combined with `--boundary`, those
@@ -787,7 +740,6 @@ you would get an output like this:
-----------------------------------------------------------------------
--graph::
-
Draw a text-based graphical representation of the commit history
on the left hand side of the output. This may cause extra lines
to be printed in between commits, in order for the graph history
@@ -795,31 +747,29 @@ you would get an output like this:
+
This enables parent rewriting, see 'History Simplification' below.
+
-This implies the '--topo-order' option by default, but the
-'--date-order' option may also be specified.
+This implies the `--topo-order` option by default, but the
+`--date-order` option may also be specified.
ifdef::git-rev-list[]
--count::
Print a number stating how many commits would have been
listed, and suppress all other output. When used together
- with '--left-right', instead print the counts for left and
+ with `--left-right`, instead print the counts for left and
right commits, separated by a tab. When used together with
- '--cherry-mark', omit patch equivalent commits from these
+ `--cherry-mark`, omit patch equivalent commits from these
counts and print the count for equivalent commits separated
by a tab.
endif::git-rev-list[]
-
ifndef::git-rev-list[]
Diff Formatting
~~~~~~~~~~~~~~~
-Below are listed options that control the formatting of diff output.
+Listed below are options that control the formatting of diff output.
Some of them are specific to linkgit:git-rev-list[1], however other diff
options may be given. See linkgit:git-diff-files[1] for more options.
-c::
-
With this option, diff output for a merge commit
shows the differences from each of the parents to the merge result
simultaneously instead of showing pairwise diff between a parent
@@ -827,26 +777,22 @@ options may be given. See linkgit:git-diff-files[1] for more options.
which were modified from all parents.
--cc::
-
- This flag implies the '-c' option and further compresses the
+ This flag implies the `-c` option and further compresses the
patch output by omitting uninteresting hunks whose contents in
the parents have only two variants and the merge result picks
one of them without modification.
-m::
-
This flag makes the merge commits show the full diff like
regular commits; for each merge parent, a separate log entry
and diff is generated. An exception is that only diff against
- the first parent is shown when '--first-parent' option is given;
+ the first parent is shown when `--first-parent` option is given;
in that case, the output represents the changes the merge
brought _into_ the then-current branch.
-r::
-
Show recursive diffs.
-t::
-
- Show the tree objects in the diff output. This implies '-r'.
+ Show the tree objects in the diff output. This implies `-r`.
endif::git-rev-list[]
diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt
index f3c1357..e3d6e7a 100644
--- a/Documentation/technical/api-builtin.txt
+++ b/Documentation/technical/api-builtin.txt
@@ -14,8 +14,8 @@ Git:
. Add the external declaration for the function to `builtin.h`.
-. Add the command to `commands[]` table in `handle_internal_command()`,
- defined in `git.c`. The entry should look like:
+. Add the command to the `commands[]` table defined in `git.c`.
+ The entry should look like:
{ "foo", cmd_foo, <options> },
+
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 0be2b51..be50cf4 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -29,9 +29,9 @@ that allow to change the behavior of a command.
The parse-options API allows:
-* 'sticked' and 'separate form' of options with arguments.
- `-oArg` is sticked, `-o Arg` is separate form.
- `--option=Arg` is sticked, `--option Arg` is separate form.
+* 'stuck' and 'separate form' of options with arguments.
+ `-oArg` is stuck, `-o Arg` is separate form.
+ `--option=Arg` is stuck, `--option Arg` is separate form.
* Long options may be 'abbreviated', as long as the abbreviation
is unambiguous.
diff --git a/Documentation/technical/api-ref-iteration.txt b/Documentation/technical/api-ref-iteration.txt
index aa1c50f..02adfd4 100644
--- a/Documentation/technical/api-ref-iteration.txt
+++ b/Documentation/technical/api-ref-iteration.txt
@@ -50,10 +50,10 @@ submodules object database. You can do this by a code-snippet like
this:
const char *path = "path/to/submodule"
- if (!add_submodule_odb(path))
+ if (add_submodule_odb(path))
die("Error submodule '%s' not populated.", path);
-`add_submodule_odb()` will return an non-zero value on success. If you
+`add_submodule_odb()` will return zero on success. If you
do not do this you will get an error for each ref that it does not point
to a valid object.
diff --git a/Documentation/technical/api-remote.txt b/Documentation/technical/api-remote.txt
index 4be8776..5d245aa 100644
--- a/Documentation/technical/api-remote.txt
+++ b/Documentation/technical/api-remote.txt
@@ -58,16 +58,16 @@ default remote, given the current branch and configuration.
struct refspec
--------------
-A struct refspec holds the parsed interpretation of a refspec. If it
-will force updates (starts with a '+'), force is true. If it is a
-pattern (sides end with '*') pattern is true. src and dest are the two
-sides (if a pattern, only the part outside of the wildcards); if there
-is only one side, it is src, and dst is NULL; if sides exist but are
-empty (i.e., the refspec either starts or ends with ':'), the
-corresponding side is "".
-
-This parsing can be done to an array of strings to give an array of
-struct refpsecs with parse_ref_spec().
+A struct refspec holds the parsed interpretation of a refspec. If it
+will force updates (starts with a '+'), force is true. If it is a
+pattern (sides end with '*') pattern is true. src and dest are the
+two sides (including '*' characters if present); if there is only one
+side, it is src, and dst is NULL; if sides exist but are empty (i.e.,
+the refspec either starts or ends with ':'), the corresponding side is
+"".
+
+An array of strings can be parsed into an array of struct refspecs
+using parse_fetch_refspec() or parse_push_refspec().
remote_find_tracking(), given a remote and a struct refspec with
either src or dst filled out, will fill out the other such that the
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
index caf941a..d21d77d 100644
--- a/Documentation/technical/http-protocol.txt
+++ b/Documentation/technical/http-protocol.txt
@@ -307,7 +307,7 @@ Clients MUST first perform ref discovery with
S: ....ACK %s, continue
S: ....NAK
-Clients MUST NOT reuse or revalidate a cached reponse.
+Clients MUST NOT reuse or revalidate a cached response.
Servers MUST include sufficient Cache-Control headers
to prevent caching of the response.
@@ -468,7 +468,7 @@ Clients MUST first perform ref discovery with
S:
S: ....
-Clients MUST NOT reuse or revalidate a cached reponse.
+Clients MUST NOT reuse or revalidate a cached response.
Servers MUST include sufficient Cache-Control headers
to prevent caching of the response.
diff --git a/Documentation/technical/pack-heuristics.txt b/Documentation/technical/pack-heuristics.txt
index b7bd951..95a07db 100644
--- a/Documentation/technical/pack-heuristics.txt
+++ b/Documentation/technical/pack-heuristics.txt
@@ -1,5 +1,5 @@
- Concerning Git's Packing Heuristics
- ===================================
+Concerning Git's Packing Heuristics
+===================================
Oh, here's a really stupid question:
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index fd8ffa5..e3e7924 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -72,14 +72,29 @@ interleaved with S-R-Q.
thin-pack
---------
-This capability means that the server can send a 'thin' pack, a pack
-which does not contain base objects; if those base objects are available
-on client side. Client requests 'thin-pack' capability when it
-understands how to "thicken" it by adding required delta bases making
-it self-contained.
-
-Client MUST NOT request 'thin-pack' capability if it cannot turn a thin
-pack into a self-contained pack.
+A thin pack is one with deltas which reference base objects not
+contained within the pack (but are known to exist at the receiving
+end). This can reduce the network traffic significantly, but it
+requires the receiving end to know how to "thicken" these packs by
+adding the missing bases to the pack.
+
+The upload-pack server advertises 'thin-pack' when it can generate
+and send a thin pack. A client requests the 'thin-pack' capability
+when it understands how to "thicken" it, notifying the server that
+it can receive such a pack. A client MUST NOT request the
+'thin-pack' capability if it cannot turn a thin pack into a
+self-contained pack.
+
+Receive-pack, on the other hand, is assumed by default to be able to
+handle thin packs, but can ask the client not to use the feature by
+advertising the 'no-thin' capability. A client MUST NOT send a thin
+pack if the server advertises the 'no-thin' capability.
+
+The reasons for this asymmetry are historical. The receive-pack
+program did not exist until after the invention of thin packs, so
+historically the reference implementation of receive-pack always
+understood thin packs. Adding 'no-thin' later allowed receive-pack
+to disable the feature in a backwards-compatible manner.
side-band, side-band-64k
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index cbb01a1..248dcab 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1,5 +1,5 @@
Git User Manual
-_______________
+===============
Git is a fast distributed revision control system.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 99a62f3..b9532f0 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.5
+DEF_VER=v1.8.5.GIT
LF='
'
diff --git a/Makefile b/Makefile
index af847f8..b4af1e2 100644
--- a/Makefile
+++ b/Makefile
@@ -452,7 +452,6 @@ SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
-SCRIPT_SH += git-lost-found.sh
SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
@@ -587,11 +586,8 @@ BUILT_INS += git-cherry$X
BUILT_INS += git-cherry-pick$X
BUILT_INS += git-format-patch$X
BUILT_INS += git-fsck-objects$X
-BUILT_INS += git-get-tar-commit-id$X
BUILT_INS += git-init$X
BUILT_INS += git-merge-subtree$X
-BUILT_INS += git-peek-remote$X
-BUILT_INS += git-repo-config$X
BUILT_INS += git-show$X
BUILT_INS += git-stage$X
BUILT_INS += git-status$X
@@ -932,6 +928,7 @@ BUILTIN_OBJS += builtin/fmt-merge-msg.o
BUILTIN_OBJS += builtin/for-each-ref.o
BUILTIN_OBJS += builtin/fsck.o
BUILTIN_OBJS += builtin/gc.o
+BUILTIN_OBJS += builtin/get-tar-commit-id.o
BUILTIN_OBJS += builtin/grep.o
BUILTIN_OBJS += builtin/hash-object.o
BUILTIN_OBJS += builtin/help.o
@@ -983,7 +980,6 @@ BUILTIN_OBJS += builtin/show-ref.o
BUILTIN_OBJS += builtin/stripspace.o
BUILTIN_OBJS += builtin/symbolic-ref.o
BUILTIN_OBJS += builtin/tag.o
-BUILTIN_OBJS += builtin/tar-tree.o
BUILTIN_OBJS += builtin/unpack-file.o
BUILTIN_OBJS += builtin/unpack-objects.o
BUILTIN_OBJS += builtin/update-index.o
@@ -1588,6 +1584,7 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
DIFF_SQ = $(subst ','\'',$(DIFF))
+PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
LIBS = $(GITLIBS) $(EXTLIBS)
@@ -1792,9 +1789,12 @@ perl/PM.stamp: FORCE
perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
-$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
+PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ)
+$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
+ INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
+ INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
sed -e '1{' \
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
-e ' h' \
@@ -1807,6 +1807,13 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
chmod +x $@+ && \
mv $@+ $@
+GIT-PERL-DEFINES: FORCE
+ @FLAGS='$(PERL_DEFINES)'; \
+ if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
+ echo >&2 " * new perl-specific parameters"; \
+ echo "$$FLAGS" >$@; \
+ fi
+
.PHONY: gitweb
gitweb:
@@ -2494,7 +2501,8 @@ ifndef NO_TCLTK
$(MAKE) -C git-gui clean
endif
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
- $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES GIT-PYTHON-VARS
+ $(RM) GIT-USER-AGENT GIT-PREFIX
+ $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PYTHON-VARS
.PHONY: all install profile-clean clean strip
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --git a/RelNotes b/RelNotes
index 61c3b54..c300119 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.5.txt \ No newline at end of file
+Documentation/RelNotes/1.9.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index e390994..ca33558 100644
--- a/abspath.c
+++ b/abspath.c
@@ -143,7 +143,7 @@ static const char *real_path_internal(const char *path, int die_on_error)
error_out:
free(last_elem);
if (*cwd && chdir(cwd))
- die_errno ("Could not change back to '%s'", cwd);
+ die_errno("Could not change back to '%s'", cwd);
return retval;
}
@@ -215,23 +215,25 @@ const char *absolute_path(const char *path)
*/
const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
{
- static char path[PATH_MAX];
+ static struct strbuf path = STRBUF_INIT;
#ifndef GIT_WINDOWS_NATIVE
if (!pfx_len || is_absolute_path(arg))
return arg;
- memcpy(path, pfx, pfx_len);
- strcpy(path + pfx_len, arg);
+ strbuf_reset(&path);
+ strbuf_add(&path, pfx, pfx_len);
+ strbuf_addstr(&path, arg);
#else
char *p;
/* don't add prefix to absolute paths, but still replace '\' by '/' */
+ strbuf_reset(&path);
if (is_absolute_path(arg))
pfx_len = 0;
else if (pfx_len)
- memcpy(path, pfx, pfx_len);
- strcpy(path + pfx_len, arg);
- for (p = path + pfx_len; *p; p++)
+ strbuf_add(&path, pfx, pfx_len);
+ strbuf_addstr(&path, arg);
+ for (p = path.buf + pfx_len; *p; p++)
if (*p == '\\')
*p = '/';
#endif
- return path;
+ return path.buf;
}
diff --git a/alias.c b/alias.c
index 9938f03..5efc3d6 100644
--- a/alias.c
+++ b/alias.c
@@ -5,7 +5,7 @@ static char *alias_val;
static int alias_lookup_cb(const char *k, const char *v, void *cb)
{
- if (!prefixcmp(k, "alias.") && !strcmp(k + 6, alias_key)) {
+ if (starts_with(k, "alias.") && !strcmp(k + 6, alias_key)) {
if (!v)
return config_error_nonbool(k);
alias_val = xstrdup(v);
diff --git a/attr.c b/attr.c
index 0e774c6..8d13d70 100644
--- a/attr.c
+++ b/attr.c
@@ -211,7 +211,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
name = cp;
namelen = strcspn(name, blank);
if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&
- !prefixcmp(name, ATTRIBUTE_MACRO_PREFIX)) {
+ starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {
if (!macro_ok) {
fprintf(stderr, "%s not allowed: %s:%d\n",
name, src, lineno);
diff --git a/bisect.c b/bisect.c
index 1e46a4f..37200b4 100644
--- a/bisect.c
+++ b/bisect.c
@@ -406,9 +406,9 @@ static int register_ref(const char *refname, const unsigned char *sha1,
if (!strcmp(refname, "bad")) {
current_bad_sha1 = xmalloc(20);
hashcpy(current_bad_sha1, sha1);
- } else if (!prefixcmp(refname, "good-")) {
+ } else if (starts_with(refname, "good-")) {
sha1_array_append(&good_revs, sha1);
- } else if (!prefixcmp(refname, "skip-")) {
+ } else if (starts_with(refname, "skip-")) {
sha1_array_append(&skipped_revs, sha1);
}
diff --git a/branch.c b/branch.c
index 9e6c68e..723a36b 100644
--- a/branch.c
+++ b/branch.c
@@ -50,7 +50,7 @@ static int should_setup_rebase(const char *origin)
void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
{
const char *shortname = remote + 11;
- int remote_is_branch = !prefixcmp(remote, "refs/heads/");
+ int remote_is_branch = starts_with(remote, "refs/heads/");
struct strbuf key = STRBUF_INIT;
int rebasing = should_setup_rebase(origin);
@@ -272,7 +272,7 @@ void create_branch(const char *head,
break;
case 1:
/* Unique completion -- good, only if it is a real branch */
- if (prefixcmp(real_ref, "refs/heads/") &&
+ if (!starts_with(real_ref, "refs/heads/") &&
validate_remote_tracking_branch(real_ref)) {
if (explicit_tracking)
die(_(upstream_not_branch), start_name);
diff --git a/builtin.h b/builtin.h
index b56cf07..c47c110 100644
--- a/builtin.h
+++ b/builtin.h
@@ -27,6 +27,8 @@ extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
+extern int is_builtin(const char *s);
+
extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_apply(int argc, const char **argv, const char *prefix);
@@ -103,7 +105,6 @@ extern int cmd_remote(int argc, const char **argv, const char *prefix);
extern int cmd_remote_ext(int argc, const char **argv, const char *prefix);
extern int cmd_remote_fd(int argc, const char **argv, const char *prefix);
extern int cmd_repack(int argc, const char **argv, const char *prefix);
-extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
extern int cmd_rerere(int argc, const char **argv, const char *prefix);
extern int cmd_reset(int argc, const char **argv, const char *prefix);
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 226f758..2a2722f 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -540,11 +540,14 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_FROMTOP |
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
- PATHSPEC_ICASE);
+ PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE);
for (i = 0; i < pathspec.nr; i++) {
const char *path = pathspec.items[i].match;
- if (!seen[i] &&
+ if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
+ continue;
+ if (!seen[i] && path[0] &&
((pathspec.items[i].magic &
(PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
!file_exists(path))) {
diff --git a/builtin/apply.c b/builtin/apply.c
index ef32e4f..b0d0986 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1409,10 +1409,10 @@ static void recount_diff(const char *line, int size, struct fragment *fragment)
case '\\':
continue;
case '@':
- ret = size < 3 || prefixcmp(line, "@@ ");
+ ret = size < 3 || !starts_with(line, "@@ ");
break;
case 'd':
- ret = size < 5 || prefixcmp(line, "diff ");
+ ret = size < 5 || !starts_with(line, "diff ");
break;
default:
ret = -1;
@@ -1798,11 +1798,11 @@ static struct fragment *parse_binary_hunk(char **buf_p,
*status_p = 0;
- if (!prefixcmp(buffer, "delta ")) {
+ if (starts_with(buffer, "delta ")) {
patch_method = BINARY_DELTA_DEFLATED;
origlen = strtoul(buffer + 6, NULL, 10);
}
- else if (!prefixcmp(buffer, "literal ")) {
+ else if (starts_with(buffer, "literal ")) {
patch_method = BINARY_LITERAL_DEFLATED;
origlen = strtoul(buffer + 8, NULL, 10);
}
@@ -3627,12 +3627,12 @@ static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20
hunk->oldpos == 1 && hunk->oldlines == 1 &&
/* does preimage begin with the heading? */
(preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
- !prefixcmp(++preimage, heading) &&
+ starts_with(++preimage, heading) &&
/* does it record full SHA-1? */
!get_sha1_hex(preimage + sizeof(heading) - 1, sha1) &&
preimage[sizeof(heading) + 40 - 1] == '\n' &&
/* does the abbreviated name on the index line agree with it? */
- !prefixcmp(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
+ starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
return 0; /* it all looks fine */
/* we may have full object name on the index line */
diff --git a/builtin/archive.c b/builtin/archive.c
index 49178f1..a1e3b94 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -57,9 +57,9 @@ static int run_remote_archiver(int argc, const char **argv,
if (!buf)
die(_("git archive: expected ACK/NAK, got EOF"));
if (strcmp(buf, "ACK")) {
- if (!prefixcmp(buf, "NACK "))
+ if (starts_with(buf, "NACK "))
die(_("git archive: NACK %s"), buf + 5);
- if (!prefixcmp(buf, "ERR "))
+ if (starts_with(buf, "ERR "))
die(_("remote error: %s"), buf + 4);
die(_("git archive: protocol error"));
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 1407ae7..e44a6bb 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1551,8 +1551,7 @@ static void assign_blame(struct scoreboard *sb, int opt)
*/
origin_incref(suspect);
commit = suspect->commit;
- if (!commit->object.parsed)
- parse_commit(commit);
+ parse_commit(commit);
if (reverse ||
(!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age)))
@@ -1804,17 +1803,17 @@ static int prepare_lines(struct scoreboard *sb)
static int read_ancestry(const char *graft_file)
{
FILE *fp = fopen(graft_file, "r");
- char buf[1024];
+ struct strbuf buf = STRBUF_INIT;
if (!fp)
return -1;
- while (fgets(buf, sizeof(buf), fp)) {
+ while (!strbuf_getwholeline(&buf, fp, '\n')) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
- int len = strlen(buf);
- struct commit_graft *graft = read_graft_line(buf, len);
+ struct commit_graft *graft = read_graft_line(buf.buf, buf.len);
if (graft)
register_commit_graft(graft, 0);
}
fclose(fp);
+ strbuf_release(&buf);
return 0;
}
diff --git a/builtin/branch.c b/builtin/branch.c
index f157f92..b4d7716 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -81,13 +81,13 @@ static int parse_branch_color_slot(const char *var, int ofs)
static int git_branch_config(const char *var, const char *value, void *cb)
{
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "branch", &colopts);
if (!strcmp(var, "color.branch")) {
branch_use_color = git_config_colorbool(var, value);
return 0;
}
- if (!prefixcmp(var, "color.branch.")) {
+ if (starts_with(var, "color.branch.")) {
int slot = parse_branch_color_slot(var, 13);
if (slot < 0)
return 0;
@@ -502,7 +502,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,
const char *sub = _(" **** invalid ref ****");
struct commit *commit = item->commit;
- if (commit && !parse_commit(commit)) {
+ if (!parse_commit(commit)) {
pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);
sub = subject.buf;
}
@@ -868,7 +868,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!strcmp(head, "HEAD")) {
detached = 1;
} else {
- if (prefixcmp(head, "refs/heads/"))
+ if (!starts_with(head, "refs/heads/"))
die(_("HEAD not found below refs/heads!"));
head += 11;
}
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b2ca775..d5a93e0 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -118,6 +118,7 @@ struct expand_data {
unsigned long size;
unsigned long disk_size;
const char *rest;
+ unsigned char delta_base_sha1[20];
/*
* If mark_query is true, we do not expand anything, but rather
@@ -174,6 +175,11 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
data->split_on_whitespace = 1;
else if (data->rest)
strbuf_addstr(sb, data->rest);
+ } else if (is_atom("deltabase", atom, len)) {
+ if (data->mark_query)
+ data->info.delta_base_sha1 = data->delta_base_sha1;
+ else
+ strbuf_addstr(sb, sha1_to_hex(data->delta_base_sha1));
} else
die("unknown format element: %.*s", len, atom);
}
@@ -193,25 +199,28 @@ static size_t expand_format(struct strbuf *sb, const char *start, void *data)
return end - start + 1;
}
-static void print_object_or_die(int fd, const unsigned char *sha1,
- enum object_type type, unsigned long size)
+static void print_object_or_die(int fd, struct expand_data *data)
{
- if (type == OBJ_BLOB) {
+ const unsigned char *sha1 = data->sha1;
+
+ assert(data->info.typep);
+
+ if (data->type == OBJ_BLOB) {
if (stream_blob_to_fd(fd, sha1, NULL, 0) < 0)
die("unable to stream %s to stdout", sha1_to_hex(sha1));
}
else {
- enum object_type rtype;
- unsigned long rsize;
+ enum object_type type;
+ unsigned long size;
void *contents;
- contents = read_sha1_file(sha1, &rtype, &rsize);
+ contents = read_sha1_file(sha1, &type, &size);
if (!contents)
die("object %s disappeared", sha1_to_hex(sha1));
- if (rtype != type)
+ if (type != data->type)
die("object %s changed type!?", sha1_to_hex(sha1));
- if (rsize != size)
- die("object %s change size!?", sha1_to_hex(sha1));
+ if (data->info.sizep && size != data->size)
+ die("object %s changed size!?", sha1_to_hex(sha1));
write_or_die(fd, contents, size);
free(contents);
@@ -238,7 +247,7 @@ static int batch_one_object(const char *obj_name, struct batch_options *opt,
return 0;
}
- if (sha1_object_info_extended(data->sha1, &data->info) < 0) {
+ if (sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
printf("%s missing\n", obj_name);
fflush(stdout);
return 0;
@@ -250,7 +259,7 @@ static int batch_one_object(const char *obj_name, struct batch_options *opt,
strbuf_release(&buf);
if (opt->print_contents) {
- print_object_or_die(1, data->sha1, data->type, data->size);
+ print_object_or_die(1, data);
write_or_die(1, "\n", 1);
}
return 0;
@@ -275,6 +284,13 @@ static int batch_objects(struct batch_options *opt)
data.mark_query = 0;
/*
+ * If we are printing out the object, then always fill in the type,
+ * since we will want to decide whether or not to stream.
+ */
+ if (opt->print_contents)
+ data.info.typep = &data.type;
+
+ /*
* We are going to call get_sha1 on a potentially very large number of
* objects. In most large cases, these will be actual object sha1s. The
* cost to double-check that each one is not also a ref (just so we can
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 54f80bd..5df3837 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -380,8 +380,8 @@ static void show_local_changes(struct object *head,
static void describe_detached_head(const char *msg, struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
- parse_commit(commit);
- pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
+ if (!parse_commit(commit))
+ pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
fprintf(stderr, "%s %s... %s\n", msg,
find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV), sb.buf);
strbuf_release(&sb);
@@ -677,12 +677,12 @@ static int add_pending_uninteresting_ref(const char *refname,
static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
{
- parse_commit(commit);
strbuf_addstr(sb, " ");
strbuf_addstr(sb,
find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
strbuf_addch(sb, ' ');
- pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
+ if (!parse_commit(commit))
+ pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
strbuf_addch(sb, '\n');
}
@@ -781,7 +781,7 @@ static int switch_branches(const struct checkout_opts *opts,
if (!(flag & REF_ISSYMREF))
old.path = NULL;
- if (old.path && !prefixcmp(old.path, "refs/heads/"))
+ if (old.path && starts_with(old.path, "refs/heads/"))
old.name = old.path + strlen("refs/heads/");
if (!new->name) {
@@ -789,7 +789,7 @@ static int switch_branches(const struct checkout_opts *opts,
new->commit = old.commit;
if (!new->commit)
die(_("You are on a branch yet to be born"));
- parse_commit(new->commit);
+ parse_commit_or_die(new->commit);
}
ret = merge_working_tree(opts, &old, new, &writeout_error);
@@ -816,7 +816,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
return 0;
}
- if (!prefixcmp(var, "submodule."))
+ if (starts_with(var, "submodule."))
return parse_submodule_config_option(var, value);
return git_xmerge_config(var, value, NULL);
@@ -995,7 +995,7 @@ static int parse_branchname_arg(int argc, const char **argv,
/* not a commit */
*source_tree = parse_tree_indirect(rev);
} else {
- parse_commit(new->commit);
+ parse_commit_or_die(new->commit);
*source_tree = new->commit->tree;
}
@@ -1151,9 +1151,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
const char *argv0 = argv[0];
if (!argc || !strcmp(argv0, "--"))
die (_("--track needs a branch name"));
- if (!prefixcmp(argv0, "refs/"))
+ if (starts_with(argv0, "refs/"))
argv0 += 5;
- if (!prefixcmp(argv0, "remotes/"))
+ if (starts_with(argv0, "remotes/"))
argv0 += 8;
argv0 = strchr(argv0, '/');
if (!argv0 || !argv0[1])
diff --git a/builtin/clean.c b/builtin/clean.c
index 615cd57..2f26297 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -100,7 +100,7 @@ static int parse_clean_color_slot(const char *var)
static int git_clean_config(const char *var, const char *value, void *cb)
{
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "clean", &colopts);
/* honors the color.interactive* config variables which also
@@ -109,7 +109,7 @@ static int git_clean_config(const char *var, const char *value, void *cb)
clean_use_color = git_config_colorbool(var, value);
return 0;
}
- if (!prefixcmp(var, "color.interactive.")) {
+ if (starts_with(var, "color.interactive.")) {
int slot = parse_clean_color_slot(var +
strlen("color.interactive."));
if (slot < 0)
diff --git a/builtin/clone.c b/builtin/clone.c
index 71ee68b..43e772c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -514,9 +514,9 @@ static void write_followtags(const struct ref *refs, const char *msg)
{
const struct ref *ref;
for (ref = refs; ref; ref = ref->next) {
- if (prefixcmp(ref->name, "refs/tags/"))
+ if (!starts_with(ref->name, "refs/tags/"))
continue;
- if (!suffixcmp(ref->name, "^{}"))
+ if (ends_with(ref->name, "^{}"))
continue;
if (!has_sha1_file(ref->old_sha1))
continue;
@@ -584,7 +584,7 @@ static void update_remote_refs(const struct ref *refs,
static void update_head(const struct ref *our, const struct ref *remote,
const char *msg)
{
- if (our && !prefixcmp(our->name, "refs/heads/")) {
+ if (our && starts_with(our->name, "refs/heads/")) {
/* Local default branch link */
create_symref("HEAD", our->name, NULL);
if (!option_bare) {
@@ -631,7 +631,7 @@ static int checkout(void)
if (advice_detached_head)
detach_advice(sha1_to_hex(sha1));
} else {
- if (prefixcmp(head, "refs/heads/"))
+ if (!starts_with(head, "refs/heads/"))
die(_("HEAD not found below refs/heads!"));
}
free(head);
@@ -809,6 +809,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_local > 0 && !is_local)
warning(_("--local is ignored"));
+ /* no need to be strict, transport_set_option() will validate it again */
+ if (option_depth && atoi(option_depth) < 1)
+ die(_("depth %s is not a positive number"), option_depth);
+
if (argc == 2)
dir = xstrdup(argv[1]);
else
diff --git a/builtin/column.c b/builtin/column.c
index e125a55..7581852 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -34,7 +34,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)
};
/* This one is special and must be the first one */
- if (argc > 1 && !prefixcmp(argv[1], "--command=")) {
+ if (argc > 1 && starts_with(argv[1], "--command=")) {
command = argv[1] + 10;
git_config(column_config, (void *)command);
} else
diff --git a/builtin/commit.c b/builtin/commit.c
index 6ab4605..3767478 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -733,7 +733,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
eol = nl - sb.buf;
else
eol = sb.len;
- if (!prefixcmp(sb.buf + previous, "\nConflicts:\n")) {
+ if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
ignore_footer = sb.len - previous;
break;
}
@@ -904,7 +904,7 @@ static int rest_is_empty(struct strbuf *sb, int start)
eol = sb->len;
if (strlen(sign_off_header) <= eol - i &&
- !prefixcmp(sb->buf + i, sign_off_header)) {
+ starts_with(sb->buf + i, sign_off_header)) {
i = eol;
continue;
}
@@ -1183,7 +1183,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
{
struct wt_status *s = cb;
- if (!prefixcmp(k, "column."))
+ if (starts_with(k, "column."))
return git_column_config(k, v, "status", &s->colopts);
if (!strcmp(k, "status.submodulesummary")) {
int is_bool;
@@ -1211,7 +1211,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
s->display_comment_prefix = git_config_bool(k, v);
return 0;
}
- if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
+ if (starts_with(k, "status.color.") || starts_with(k, "color.status.")) {
int slot = parse_status_slot(k, 13);
if (slot < 0)
return 0;
@@ -1338,7 +1338,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
commit = lookup_commit(sha1);
if (!commit)
die(_("couldn't look up newly created commit"));
- if (!commit || parse_commit(commit))
+ if (parse_commit(commit))
die(_("could not parse newly created commit"));
strbuf_addstr(&format, "format:%h] %s");
@@ -1377,7 +1377,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL);
printf("[%s%s ",
- !prefixcmp(head, "refs/heads/") ?
+ starts_with(head, "refs/heads/") ?
head + 11 :
!strcmp(head, "HEAD") ?
_("detached HEAD") :
@@ -1505,7 +1505,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct strbuf sb = STRBUF_INIT;
struct strbuf author_ident = STRBUF_INIT;
const char *index_file, *reflog_msg;
- char *nl, *p;
+ char *nl;
unsigned char sha1[20];
struct ref_lock *ref_lock;
struct commit_list *parents = NULL, **pptr = &parents;
@@ -1525,7 +1525,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
current_head = NULL;
else {
current_head = lookup_commit_or_die(sha1, "HEAD");
- if (!current_head || parse_commit(current_head))
+ if (parse_commit(current_head))
die(_("could not parse HEAD commit"));
}
argc = parse_and_validate_options(argc, argv, builtin_commit_options,
@@ -1601,11 +1601,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
/* Truncate the message just before the diff, if any. */
- if (verbose) {
- p = strstr(sb.buf, "\ndiff --git ");
- if (p != NULL)
- strbuf_setlen(&sb, p - sb.buf + 1);
- }
+ if (verbose)
+ wt_status_truncate_message_at_cut_line(&sb);
if (cleanup_mode != CLEANUP_NONE)
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
diff --git a/builtin/config.c b/builtin/config.c
index 20e89fe..92ebf23 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -671,9 +671,3 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return 0;
}
-
-int cmd_repo_config(int argc, const char **argv, const char *prefix)
-{
- fprintf(stderr, "WARNING: git repo-config is deprecated in favor of git config.\n");
- return cmd_config(argc, argv, prefix);
-}
diff --git a/builtin/describe.c b/builtin/describe.c
index 6f62109..7db43da 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -141,7 +141,7 @@ static void add_to_known_names(const char *path,
static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
- int is_tag = !prefixcmp(path, "refs/tags/");
+ int is_tag = starts_with(path, "refs/tags/");
unsigned char peeled[20];
int is_annotated, prio;
diff --git a/builtin/diff.c b/builtin/diff.c
index adb93a9..0f247d2 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -16,6 +16,9 @@
#include "submodule.h"
#include "sha1-array.h"
+#define DIFF_NO_INDEX_EXPLICIT 1
+#define DIFF_NO_INDEX_IMPLICIT 2
+
struct blobinfo {
unsigned char sha1[20];
const char *name;
@@ -64,15 +67,18 @@ static void stuff_change(struct diff_options *opt,
static int builtin_diff_b_f(struct rev_info *revs,
int argc, const char **argv,
- struct blobinfo *blob,
- const char *path)
+ struct blobinfo *blob)
{
/* Blob vs file in the working tree*/
struct stat st;
+ const char *path;
if (argc > 1)
usage(builtin_diff_usage);
+ GUARD_PATHSPEC(&revs->prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
+ path = revs->prune_data.items[0].match;
+
if (lstat(path, &st))
die_errno(_("failed to stat '%s'"), path);
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
@@ -255,9 +261,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
struct rev_info rev;
struct object_array ent = OBJECT_ARRAY_INIT;
int blobs = 0, paths = 0;
- const char *path = NULL;
struct blobinfo blob[2];
- int nongit;
+ int nongit = 0, no_index = 0;
int result = 0;
/*
@@ -283,14 +288,59 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
* Other cases are errors.
*/
- prefix = setup_git_directory_gently(&nongit);
- gitmodules_config();
+ /* Were we asked to do --no-index explicitly? */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ i++;
+ break;
+ }
+ if (!strcmp(argv[i], "--no-index"))
+ no_index = DIFF_NO_INDEX_EXPLICIT;
+ if (argv[i][0] != '-')
+ break;
+ }
+
+ if (!no_index)
+ prefix = setup_git_directory_gently(&nongit);
+
+ /*
+ * Treat git diff with at least one path outside of the
+ * repo the same as if the command would have been executed
+ * outside of a git repository. In this case it behaves
+ * the same way as "git diff --no-index <a> <b>", which acts
+ * as a colourful "diff" replacement.
+ */
+ if (nongit || ((argc == i + 2) &&
+ (!path_inside_repo(prefix, argv[i]) ||
+ !path_inside_repo(prefix, argv[i + 1]))))
+ no_index = DIFF_NO_INDEX_IMPLICIT;
+
+ if (!no_index)
+ gitmodules_config();
git_config(git_diff_ui_config, NULL);
init_revisions(&rev, prefix);
- /* If this is a no-index diff, just run it and exit there. */
- diff_no_index(&rev, argc, argv, nongit, prefix);
+ if (no_index && argc != i + 2) {
+ if (no_index == DIFF_NO_INDEX_IMPLICIT) {
+ /*
+ * There was no --no-index and there were not two
+ * paths. It is possible that the user intended
+ * to do an inside-repository operation.
+ */
+ fprintf(stderr, "Not a git repository\n");
+ fprintf(stderr,
+ "To compare two paths outside a working tree:\n");
+ }
+ /* Give the usage message for non-repository usage and exit. */
+ usagef("git diff %s <path> <path>",
+ no_index == DIFF_NO_INDEX_EXPLICIT ?
+ "--no-index" : "[--no-index]");
+
+ }
+ if (no_index)
+ /* If this is a no-index diff, just run it and exit there. */
+ diff_no_index(&rev, argc, argv, prefix);
/* Otherwise, we are doing the usual "git" diff */
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
@@ -366,13 +416,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
die(_("unhandled object '%s' given."), name);
}
}
- if (rev.prune_data.nr) {
- /* builtin_diff_b_f() */
- GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
- if (!path)
- path = rev.prune_data.items[0].match;
+ if (rev.prune_data.nr)
paths += rev.prune_data.nr;
- }
/*
* Now, do the arguments look reasonable?
@@ -385,7 +430,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
case 1:
if (paths != 1)
usage(builtin_diff_usage);
- result = builtin_diff_b_f(&rev, argc, argv, blob, path);
+ result = builtin_diff_b_f(&rev, argc, argv, blob);
break;
case 2:
if (paths)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 78250ea..b8d8a3a 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -287,7 +287,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
- parse_commit(commit);
+ parse_commit_or_die(commit);
author = strstr(commit->buffer, "\nauthor ");
if (!author)
die ("Could not find author in commit %s",
@@ -308,7 +308,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
if (commit->parents &&
get_object_mark(&commit->parents->item->object) != 0 &&
!full_tree) {
- parse_commit(commit->parents->item);
+ parse_commit_or_die(commit->parents->item);
diff_tree_sha1(commit->parents->item->tree->object.sha1,
commit->tree->object.sha1, "", &rev->diffopt);
}
@@ -476,7 +476,7 @@ static void handle_tag(const char *name, struct tag *tag)
}
}
- if (!prefixcmp(name, "refs/tags/"))
+ if (starts_with(name, "refs/tags/"))
name += 10;
printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
name, tagged_mark,
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 81fae38..1262b40 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -8,7 +8,7 @@
static const char fetch_pack_usage[] =
"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
-"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
+"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
const char *name, int namelen)
@@ -57,11 +57,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc && *argv[i] == '-'; i++) {
const char *arg = argv[i];
- if (!prefixcmp(arg, "--upload-pack=")) {
+ if (starts_with(arg, "--upload-pack=")) {
args.uploadpack = arg + 14;
continue;
}
- if (!prefixcmp(arg, "--exec=")) {
+ if (starts_with(arg, "--exec=")) {
args.uploadpack = arg + 7;
continue;
}
@@ -90,11 +90,15 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.stdin_refs = 1;
continue;
}
+ if (!strcmp("--diag-url", arg)) {
+ args.diag_url = 1;
+ continue;
+ }
if (!strcmp("-v", arg)) {
args.verbose = 1;
continue;
}
- if (!prefixcmp(arg, "--depth=")) {
+ if (starts_with(arg, "--depth=")) {
args.depth = strtol(arg + 8, NULL, 0);
continue;
}
@@ -163,10 +167,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
fd[0] = 0;
fd[1] = 1;
} else {
+ int flags = args.verbose ? CONNECT_VERBOSE : 0;
+ if (args.diag_url)
+ flags |= CONNECT_DIAG_URL;
conn = git_connect(fd, dest, args.uploadpack,
- args.verbose ? CONNECT_VERBOSE : 0);
+ flags);
+ if (!conn)
+ return args.diag_url ? 0 : 1;
}
-
get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
diff --git a/builtin/fetch.c b/builtin/fetch.c
index d2e4fc0..025bc3e 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -44,6 +44,7 @@ static struct transport *gtransport;
static struct transport *gsecondary;
static const char *submodule_prefix = "";
static const char *recurse_submodules_default;
+static int shown_url = 0;
static int option_parse_recurse_submodules(const struct option *opt,
const char *arg, int unset)
@@ -162,48 +163,156 @@ static void add_merge_config(struct ref **head,
}
}
+static int add_existing(const char *refname, const unsigned char *sha1,
+ int flag, void *cbdata)
+{
+ struct string_list *list = (struct string_list *)cbdata;
+ struct string_list_item *item = string_list_insert(list, refname);
+ item->util = xmalloc(20);
+ hashcpy(item->util, sha1);
+ return 0;
+}
+
+static int will_fetch(struct ref **head, const unsigned char *sha1)
+{
+ struct ref *rm = *head;
+ while (rm) {
+ if (!hashcmp(rm->old_sha1, sha1))
+ return 1;
+ rm = rm->next;
+ }
+ return 0;
+}
+
static void find_non_local_tags(struct transport *transport,
struct ref **head,
- struct ref ***tail);
+ struct ref ***tail)
+{
+ struct string_list existing_refs = STRING_LIST_INIT_DUP;
+ struct string_list remote_refs = STRING_LIST_INIT_NODUP;
+ const struct ref *ref;
+ struct string_list_item *item = NULL;
+
+ for_each_ref(add_existing, &existing_refs);
+ for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
+ if (!starts_with(ref->name, "refs/tags/"))
+ continue;
+
+ /*
+ * The peeled ref always follows the matching base
+ * ref, so if we see a peeled ref that we don't want
+ * to fetch then we can mark the ref entry in the list
+ * as one to ignore by setting util to NULL.
+ */
+ if (ends_with(ref->name, "^{}")) {
+ if (item && !has_sha1_file(ref->old_sha1) &&
+ !will_fetch(head, ref->old_sha1) &&
+ !has_sha1_file(item->util) &&
+ !will_fetch(head, item->util))
+ item->util = NULL;
+ item = NULL;
+ continue;
+ }
+
+ /*
+ * If item is non-NULL here, then we previously saw a
+ * ref not followed by a peeled reference, so we need
+ * to check if it is a lightweight tag that we want to
+ * fetch.
+ */
+ if (item && !has_sha1_file(item->util) &&
+ !will_fetch(head, item->util))
+ item->util = NULL;
+
+ item = NULL;
+
+ /* skip duplicates and refs that we already have */
+ if (string_list_has_string(&remote_refs, ref->name) ||
+ string_list_has_string(&existing_refs, ref->name))
+ continue;
+
+ item = string_list_insert(&remote_refs, ref->name);
+ item->util = (void *)ref->old_sha1;
+ }
+ string_list_clear(&existing_refs, 1);
+
+ /*
+ * We may have a final lightweight tag that needs to be
+ * checked to see if it needs fetching.
+ */
+ if (item && !has_sha1_file(item->util) &&
+ !will_fetch(head, item->util))
+ item->util = NULL;
+
+ /*
+ * For all the tags in the remote_refs string list,
+ * add them to the list of refs to be fetched
+ */
+ for_each_string_list_item(item, &remote_refs) {
+ /* Unless we have already decided to ignore this item... */
+ if (item->util)
+ {
+ struct ref *rm = alloc_ref(item->string);
+ rm->peer_ref = alloc_ref(item->string);
+ hashcpy(rm->old_sha1, item->util);
+ **tail = rm;
+ *tail = &rm->next;
+ }
+ }
+
+ string_list_clear(&remote_refs, 0);
+}
static struct ref *get_ref_map(struct transport *transport,
- struct refspec *refs, int ref_count, int tags,
- int *autotags)
+ struct refspec *refspecs, int refspec_count,
+ int tags, int *autotags)
{
int i;
struct ref *rm;
struct ref *ref_map = NULL;
struct ref **tail = &ref_map;
- const struct ref *remote_refs = transport_get_remote_refs(transport);
+ /* opportunistically-updated references: */
+ struct ref *orefs = NULL, **oref_tail = &orefs;
- if (ref_count || tags == TAGS_SET) {
- struct ref **old_tail;
+ const struct ref *remote_refs = transport_get_remote_refs(transport);
- for (i = 0; i < ref_count; i++) {
- get_fetch_map(remote_refs, &refs[i], &tail, 0);
- if (refs[i].dst && refs[i].dst[0])
+ if (refspec_count) {
+ for (i = 0; i < refspec_count; i++) {
+ get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
+ if (refspecs[i].dst && refspecs[i].dst[0])
*autotags = 1;
}
- /* Merge everything on the command line, but not --tags */
+ /* Merge everything on the command line (but not --tags) */
for (rm = ref_map; rm; rm = rm->next)
rm->fetch_head_status = FETCH_HEAD_MERGE;
- if (tags == TAGS_SET)
- get_fetch_map(remote_refs, tag_refspec, &tail, 0);
/*
- * For any refs that we happen to be fetching via command-line
- * arguments, take the opportunity to update their configured
- * counterparts. However, we do not want to mention these
- * entries in FETCH_HEAD at all, as they would simply be
- * duplicates of existing entries.
+ * For any refs that we happen to be fetching via
+ * command-line arguments, the destination ref might
+ * have been missing or have been different than the
+ * remote-tracking ref that would be derived from the
+ * configured refspec. In these cases, we want to
+ * take the opportunity to update their configured
+ * remote-tracking reference. However, we do not want
+ * to mention these entries in FETCH_HEAD at all, as
+ * they would simply be duplicates of existing
+ * entries, so we set them FETCH_HEAD_IGNORE below.
+ *
+ * We compute these entries now, based only on the
+ * refspecs specified on the command line. But we add
+ * them to the list following the refspecs resulting
+ * from the tags option so that one of the latter,
+ * which has FETCH_HEAD_NOT_FOR_MERGE, is not removed
+ * by ref_remove_duplicates() in favor of one of these
+ * opportunistic entries with FETCH_HEAD_IGNORE.
*/
- old_tail = tail;
for (i = 0; i < transport->remote->fetch_refspec_nr; i++)
get_fetch_map(ref_map, &transport->remote->fetch[i],
- &tail, 1);
- for (rm = *old_tail; rm; rm = rm->next)
- rm->fetch_head_status = FETCH_HEAD_IGNORE;
+ &oref_tail, 1);
+
+ if (tags == TAGS_SET)
+ get_fetch_map(remote_refs, tag_refspec, &tail, 0);
} else {
/* Use the defaults */
struct remote *remote = transport->remote;
@@ -240,11 +349,21 @@ static struct ref *get_ref_map(struct transport *transport,
tail = &ref_map->next;
}
}
- if (tags == TAGS_DEFAULT && *autotags)
+
+ if (tags == TAGS_SET)
+ /* also fetch all tags */
+ get_fetch_map(remote_refs, tag_refspec, &tail, 0);
+ else if (tags == TAGS_DEFAULT && *autotags)
find_non_local_tags(transport, &ref_map, &tail);
- ref_remove_duplicates(ref_map);
- return ref_map;
+ /* Now append any refs to be updated opportunistically: */
+ *tail = orefs;
+ for (rm = orefs; rm; rm = rm->next) {
+ rm->fetch_head_status = FETCH_HEAD_IGNORE;
+ tail = &rm->next;
+ }
+
+ return ref_remove_duplicates(ref_map);
}
#define STORE_REF_ERROR_OTHER 1
@@ -315,7 +434,7 @@ static int update_local_ref(struct ref *ref,
}
if (!is_null_sha1(ref->old_sha1) &&
- !prefixcmp(ref->name, "refs/tags/")) {
+ starts_with(ref->name, "refs/tags/")) {
int r;
r = s_update_ref("updating tag", ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
@@ -338,10 +457,10 @@ static int update_local_ref(struct ref *ref,
* more likely to follow a standard layout.
*/
const char *name = remote_ref ? remote_ref->name : "";
- if (!prefixcmp(name, "refs/tags/")) {
+ if (starts_with(name, "refs/tags/")) {
msg = "storing tag";
what = _("[new tag]");
- } else if (!prefixcmp(name, "refs/heads/")) {
+ } else if (starts_with(name, "refs/heads/")) {
msg = "storing head";
what = _("[new branch]");
} else {
@@ -421,7 +540,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
{
FILE *fp;
struct commit *commit;
- int url_len, i, shown_url = 0, rc = 0;
+ int url_len, i, rc = 0;
struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
@@ -482,15 +601,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
kind = "";
what = "";
}
- else if (!prefixcmp(rm->name, "refs/heads/")) {
+ else if (starts_with(rm->name, "refs/heads/")) {
kind = "branch";
what = rm->name + 11;
}
- else if (!prefixcmp(rm->name, "refs/tags/")) {
+ else if (starts_with(rm->name, "refs/tags/")) {
kind = "tag";
what = rm->name + 10;
}
- else if (!prefixcmp(rm->name, "refs/remotes/")) {
+ else if (starts_with(rm->name, "refs/remotes/")) {
kind = "remote-tracking branch";
what = rm->name + 13;
}
@@ -601,17 +720,36 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
return ret;
}
-static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
+static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
+ const char *raw_url)
{
- int result = 0;
+ int url_len, i, result = 0;
struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
+ char *url;
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
: _(" (%s has become dangling)");
+ if (raw_url)
+ url = transport_anonymize_url(raw_url);
+ else
+ url = xstrdup("foreign");
+
+ url_len = strlen(url);
+ for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
+ ;
+
+ url_len = i + 1;
+ if (4 < i && !strncmp(".git", url + i - 3, 4))
+ url_len = i - 3;
+
for (ref = stale_refs; ref; ref = ref->next) {
if (!dry_run)
result |= delete_ref(ref->name, NULL, 0);
+ if (verbosity >= 0 && !shown_url) {
+ fprintf(stderr, _("From %.*s\n"), url_len, url);
+ shown_url = 1;
+ }
if (verbosity >= 0) {
fprintf(stderr, " x %-*s %-*s -> %s\n",
TRANSPORT_SUMMARY(_("[deleted]")),
@@ -619,110 +757,11 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
}
+ free(url);
free_refs(stale_refs);
return result;
}
-static int add_existing(const char *refname, const unsigned char *sha1,
- int flag, void *cbdata)
-{
- struct string_list *list = (struct string_list *)cbdata;
- struct string_list_item *item = string_list_insert(list, refname);
- item->util = xmalloc(20);
- hashcpy(item->util, sha1);
- return 0;
-}
-
-static int will_fetch(struct ref **head, const unsigned char *sha1)
-{
- struct ref *rm = *head;
- while (rm) {
- if (!hashcmp(rm->old_sha1, sha1))
- return 1;
- rm = rm->next;
- }
- return 0;
-}
-
-static void find_non_local_tags(struct transport *transport,
- struct ref **head,
- struct ref ***tail)
-{
- struct string_list existing_refs = STRING_LIST_INIT_DUP;
- struct string_list remote_refs = STRING_LIST_INIT_NODUP;
- const struct ref *ref;
- struct string_list_item *item = NULL;
-
- for_each_ref(add_existing, &existing_refs);
- for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
- if (prefixcmp(ref->name, "refs/tags/"))
- continue;
-
- /*
- * The peeled ref always follows the matching base
- * ref, so if we see a peeled ref that we don't want
- * to fetch then we can mark the ref entry in the list
- * as one to ignore by setting util to NULL.
- */
- if (!suffixcmp(ref->name, "^{}")) {
- if (item && !has_sha1_file(ref->old_sha1) &&
- !will_fetch(head, ref->old_sha1) &&
- !has_sha1_file(item->util) &&
- !will_fetch(head, item->util))
- item->util = NULL;
- item = NULL;
- continue;
- }
-
- /*
- * If item is non-NULL here, then we previously saw a
- * ref not followed by a peeled reference, so we need
- * to check if it is a lightweight tag that we want to
- * fetch.
- */
- if (item && !has_sha1_file(item->util) &&
- !will_fetch(head, item->util))
- item->util = NULL;
-
- item = NULL;
-
- /* skip duplicates and refs that we already have */
- if (string_list_has_string(&remote_refs, ref->name) ||
- string_list_has_string(&existing_refs, ref->name))
- continue;
-
- item = string_list_insert(&remote_refs, ref->name);
- item->util = (void *)ref->old_sha1;
- }
- string_list_clear(&existing_refs, 1);
-
- /*
- * We may have a final lightweight tag that needs to be
- * checked to see if it needs fetching.
- */
- if (item && !has_sha1_file(item->util) &&
- !will_fetch(head, item->util))
- item->util = NULL;
-
- /*
- * For all the tags in the remote_refs string list,
- * add them to the list of refs to be fetched
- */
- for_each_string_list_item(item, &remote_refs) {
- /* Unless we have already decided to ignore this item... */
- if (item->util)
- {
- struct ref *rm = alloc_ref(item->string);
- rm->peer_ref = alloc_ref(item->string);
- hashcpy(rm->old_sha1, item->util);
- **tail = rm;
- *tail = &rm->next;
- }
- }
-
- string_list_clear(&remote_refs, 0);
-}
-
static void check_not_current_branch(struct ref *ref_map)
{
struct branch *current_branch = branch_get(NULL);
@@ -837,39 +876,26 @@ static int do_fetch(struct transport *transport,
if (tags == TAGS_DEFAULT && autotags)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
- if (fetch_refs(transport, ref_map)) {
- free_refs(ref_map);
- retcode = 1;
- goto cleanup;
- }
if (prune) {
/*
- * If --tags was specified, pretend that the user gave us
- * the canonical tags refspec
+ * We only prune based on refspecs specified
+ * explicitly (via command line or configuration); we
+ * don't care whether --tags was specified.
*/
- if (tags == TAGS_SET) {
- const char *tags_str = "refs/tags/*:refs/tags/*";
- struct refspec *tags_refspec, *refspec;
-
- /* Copy the refspec and add the tags to it */
- refspec = xcalloc(ref_count + 1, sizeof(struct refspec));
- tags_refspec = parse_fetch_refspec(1, &tags_str);
- memcpy(refspec, refs, ref_count * sizeof(struct refspec));
- memcpy(&refspec[ref_count], tags_refspec, sizeof(struct refspec));
- ref_count++;
-
- prune_refs(refspec, ref_count, ref_map);
-
- ref_count--;
- /* The rest of the strings belong to fetch_one */
- free_refspec(1, tags_refspec);
- free(refspec);
- } else if (ref_count) {
- prune_refs(refs, ref_count, ref_map);
+ if (ref_count) {
+ prune_refs(refs, ref_count, ref_map, transport->url);
} else {
- prune_refs(transport->remote->fetch, transport->remote->fetch_refspec_nr, ref_map);
+ prune_refs(transport->remote->fetch,
+ transport->remote->fetch_refspec_nr,
+ ref_map,
+ transport->url);
}
}
+ if (fetch_refs(transport, ref_map)) {
+ free_refs(ref_map);
+ retcode = 1;
+ goto cleanup;
+ }
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
@@ -905,7 +931,7 @@ static int get_remote_group(const char *key, const char *value, void *priv)
{
struct remote_group_data *g = priv;
- if (!prefixcmp(key, "remotes.") &&
+ if (starts_with(key, "remotes.") &&
!strcmp(key + 8, g->name)) {
/* split list by white space */
int space = strcspn(value, " \t\n");
@@ -943,8 +969,8 @@ static void add_options_to_argv(struct argv_array *argv)
{
if (dry_run)
argv_array_push(argv, "--dry-run");
- if (prune > 0)
- argv_array_push(argv, "--prune");
+ if (prune != -1)
+ argv_array_push(argv, prune ? "--prune" : "--no-prune");
if (update_head_ok)
argv_array_push(argv, "--update-head-ok");
if (force)
@@ -1088,6 +1114,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
}
+ /* no need to be strict, transport_set_option() will validate it again */
+ if (depth && atoi(depth) < 1)
+ die(_("depth %s is not a positive number"), depth);
+
if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
if (recurse_submodules_default) {
int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 1c04070..3906eda 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -109,7 +109,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
if (len < 43 || line[40] != '\t')
return 1;
- if (!prefixcmp(line + 41, "not-for-merge"))
+ if (starts_with(line + 41, "not-for-merge"))
return 0;
if (line[41] != '\t')
@@ -155,16 +155,16 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
if (pulling_head) {
origin = src;
src_data->head_status |= 1;
- } else if (!prefixcmp(line, "branch ")) {
+ } else if (starts_with(line, "branch ")) {
origin_data->is_local_branch = 1;
origin = line + 7;
string_list_append(&src_data->branch, origin);
src_data->head_status |= 2;
- } else if (!prefixcmp(line, "tag ")) {
+ } else if (starts_with(line, "tag ")) {
origin = line;
string_list_append(&src_data->tag, origin + 4);
src_data->head_status |= 2;
- } else if (!prefixcmp(line, "remote-tracking branch ")) {
+ } else if (starts_with(line, "remote-tracking branch ")) {
origin = line + strlen("remote-tracking branch ");
string_list_append(&src_data->r_branch, origin);
src_data->head_status |= 2;
@@ -605,7 +605,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
resolve_refdup("HEAD", head_sha1, 1, NULL);
if (!current_branch)
die("No current branch");
- if (!prefixcmp(current_branch, "refs/heads/"))
+ if (starts_with(current_branch, "refs/heads/"))
current_branch += 11;
find_merge_parents(&merge_parents, in, head_sha1);
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index d096051..51798b4 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -9,6 +9,7 @@
#include "quote.h"
#include "parse-options.h"
#include "remote.h"
+#include "color.h"
/* Quoting styles */
#define QUOTE_NONE 0
@@ -75,6 +76,8 @@ static struct {
{ "upstream" },
{ "symref" },
{ "flag" },
+ { "HEAD" },
+ { "color" },
};
/*
@@ -89,7 +92,8 @@ static struct {
*/
static const char **used_atom;
static cmp_type *used_atom_type;
-static int used_atom_cnt, sort_atom_limit, need_tagged, need_symref;
+static int used_atom_cnt, need_tagged, need_symref;
+static int need_color_reset_at_eol;
/*
* Used to parse format string and sort specifiers
@@ -176,13 +180,21 @@ static const char *find_next(const char *cp)
static int verify_format(const char *format)
{
const char *cp, *sp;
+ static const char color_reset[] = "color:reset";
+
+ need_color_reset_at_eol = 0;
for (cp = format; *cp && (sp = find_next(cp)); ) {
const char *ep = strchr(sp, ')');
+ int at;
+
if (!ep)
return error("malformed format string %s", sp);
/* sp points at "%(" and ep points at the closing ")" */
- parse_atom(sp + 2, ep);
+ at = parse_atom(sp + 2, ep);
cp = ep + 1;
+
+ if (!memcmp(used_atom[at], "color:", 6))
+ need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset);
}
return 0;
}
@@ -441,7 +453,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
if (name[wholen] != 0 &&
strcmp(name + wholen, "name") &&
strcmp(name + wholen, "email") &&
- prefixcmp(name + wholen, "date"))
+ !starts_with(name + wholen, "date"))
continue;
if (!wholine)
wholine = find_wholine(who, wholen, buf, sz);
@@ -453,7 +465,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
v->s = copy_name(wholine);
else if (!strcmp(name + wholen, "email"))
v->s = copy_email(wholine);
- else if (!prefixcmp(name + wholen, "date"))
+ else if (starts_with(name + wholen, "date"))
grab_date(wholine, v, name);
}
@@ -475,7 +487,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
if (deref)
name++;
- if (!prefixcmp(name, "creatordate"))
+ if (starts_with(name, "creatordate"))
grab_date(wholine, v, name);
else if (!strcmp(name, "creator"))
v->s = copy_line(wholine);
@@ -649,20 +661,20 @@ static void populate_value(struct refinfo *ref)
int deref = 0;
const char *refname;
const char *formatp;
+ struct branch *branch = NULL;
if (*name == '*') {
deref = 1;
name++;
}
- if (!prefixcmp(name, "refname"))
+ if (starts_with(name, "refname"))
refname = ref->refname;
- else if (!prefixcmp(name, "symref"))
+ else if (starts_with(name, "symref"))
refname = ref->symref ? ref->symref : "";
- else if (!prefixcmp(name, "upstream")) {
- struct branch *branch;
+ else if (starts_with(name, "upstream")) {
/* only local branches may have an upstream */
- if (prefixcmp(ref->refname, "refs/heads/"))
+ if (!starts_with(ref->refname, "refs/heads/"))
continue;
branch = branch_get(ref->refname + 11);
@@ -670,8 +682,13 @@ static void populate_value(struct refinfo *ref)
!branch->merge[0]->dst)
continue;
refname = branch->merge[0]->dst;
- }
- else if (!strcmp(name, "flag")) {
+ } else if (starts_with(name, "color:")) {
+ char color[COLOR_MAXLEN] = "";
+
+ color_parse(name + 6, "--format", color);
+ v->s = xstrdup(color);
+ continue;
+ } else if (!strcmp(name, "flag")) {
char buf[256], *cp = buf;
if (ref->flag & REF_ISSYMREF)
cp = copy_advance(cp, ",symref");
@@ -684,20 +701,62 @@ static void populate_value(struct refinfo *ref)
v->s = xstrdup(buf + 1);
}
continue;
- }
- else if (!deref && grab_objectname(name, ref->objectname, v))
+ } else if (!deref && grab_objectname(name, ref->objectname, v)) {
continue;
- else
+ } else if (!strcmp(name, "HEAD")) {
+ const char *head;
+ unsigned char sha1[20];
+
+ head = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
+ if (!strcmp(ref->refname, head))
+ v->s = "*";
+ else
+ v->s = " ";
+ continue;
+ } else
continue;
formatp = strchr(name, ':');
- /* look for "short" refname format */
if (formatp) {
+ int num_ours, num_theirs;
+
formatp++;
if (!strcmp(formatp, "short"))
refname = shorten_unambiguous_ref(refname,
warn_ambiguous_refs);
- else
+ else if (!strcmp(formatp, "track") &&
+ starts_with(name, "upstream")) {
+ char buf[40];
+
+ stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (!num_ours && !num_theirs)
+ v->s = "";
+ else if (!num_ours) {
+ sprintf(buf, "[behind %d]", num_theirs);
+ v->s = xstrdup(buf);
+ } else if (!num_theirs) {
+ sprintf(buf, "[ahead %d]", num_ours);
+ v->s = xstrdup(buf);
+ } else {
+ sprintf(buf, "[ahead %d, behind %d]",
+ num_ours, num_theirs);
+ v->s = xstrdup(buf);
+ }
+ continue;
+ } else if (!strcmp(formatp, "trackshort") &&
+ starts_with(name, "upstream")) {
+ assert(branch);
+ stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (!num_ours && !num_theirs)
+ v->s = "=";
+ else if (!num_ours)
+ v->s = "<";
+ else if (!num_theirs)
+ v->s = ">";
+ else
+ v->s = "<>";
+ continue;
+ } else
die("unknown %.*s format %s",
(int)(formatp - name), name, formatp);
}
@@ -875,11 +934,9 @@ static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs
qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);
}
-static void print_value(struct refinfo *ref, int atom, int quote_style)
+static void print_value(struct atom_value *v, int quote_style)
{
- struct atom_value *v;
struct strbuf sb = STRBUF_INIT;
- get_value(ref, atom, &v);
switch (quote_style) {
case QUOTE_NONE:
fputs(v->s, stdout);
@@ -946,15 +1003,26 @@ static void show_ref(struct refinfo *info, const char *format, int quote_style)
const char *cp, *sp, *ep;
for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
+ struct atom_value *atomv;
+
ep = strchr(sp, ')');
if (cp < sp)
emit(cp, sp);
- print_value(info, parse_atom(sp + 2, ep), quote_style);
+ get_value(info, parse_atom(sp + 2, ep), &atomv);
+ print_value(atomv, quote_style);
}
if (*cp) {
sp = cp + strlen(cp);
emit(cp, sp);
}
+ if (need_color_reset_at_eol) {
+ struct atom_value resetv;
+ char color[COLOR_MAXLEN] = "";
+
+ color_parse("reset", "--format", color);
+ resetv.s = color;
+ print_value(&resetv, quote_style);
+ }
putchar('\n');
}
@@ -1037,7 +1105,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
if (!sort)
sort = default_sort();
- sort_atom_limit = used_atom_cnt;
/* for warn_ambiguous_refs */
git_config(git_default_config, NULL);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 97ce678..1affdd5 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -442,7 +442,7 @@ static void fsck_dir(int i, char *path)
add_sha1_list(sha1, DIRENT_SORT_HINT(de));
continue;
}
- if (!prefixcmp(de->d_name, "tmp_obj_"))
+ if (starts_with(de->d_name, "tmp_obj_"))
continue;
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
}
@@ -484,7 +484,7 @@ static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, in
static int is_branch(const char *refname)
{
- return !strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/");
+ return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
}
static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
@@ -566,7 +566,7 @@ static int fsck_head_link(void)
if (!strcmp(head_points_at, "HEAD"))
/* detached HEAD */
null_is_error = 1;
- else if (prefixcmp(head_points_at, "refs/heads/"))
+ else if (!starts_with(head_points_at, "refs/heads/"))
return error("HEAD points to something strange (%s)",
head_points_at);
if (is_null_sha1(head_sha1)) {
diff --git a/builtin/gc.c b/builtin/gc.c
index cec8ecd..c19545d 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -223,7 +223,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
time(NULL) - st.st_mtime <= 12 * 3600 &&
fscanf(fp, "%"PRIuMAX" %127c", &pid, locking_host) == 2 &&
/* be gentle to concurrent "gc" on remote hosts */
- (strcmp(locking_host, my_host) || !kill(pid, 0));
+ (strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
if (fp != NULL)
fclose(fp);
if (should_exit) {
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
new file mode 100644
index 0000000..aa72596
--- /dev/null
+++ b/builtin/get-tar-commit-id.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005, 2006 Rene Scharfe
+ */
+#include "cache.h"
+#include "commit.h"
+#include "tar.h"
+#include "builtin.h"
+#include "quote.h"
+
+static const char builtin_get_tar_commit_id_usage[] =
+"git get-tar-commit-id < <tarfile>";
+
+/* ustar header + extended global header content */
+#define RECORDSIZE (512)
+#define HEADERSIZE (2 * RECORDSIZE)
+
+int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
+{
+ char buffer[HEADERSIZE];
+ struct ustar_header *header = (struct ustar_header *)buffer;
+ char *content = buffer + RECORDSIZE;
+ ssize_t n;
+
+ if (argc != 1)
+ usage(builtin_get_tar_commit_id_usage);
+
+ n = read_in_full(0, buffer, HEADERSIZE);
+ if (n < HEADERSIZE)
+ die("git get-tar-commit-id: read error");
+ if (header->typeflag[0] != 'g')
+ return 1;
+ if (memcmp(content, "52 comment=", 11))
+ return 1;
+
+ n = write_in_full(1, content + 11, 41);
+ if (n < 41)
+ die_errno("git get-tar-commit-id: write error");
+
+ return 0;
+}
diff --git a/builtin/help.c b/builtin/help.c
index f1e236b..1fdefeb 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -100,7 +100,7 @@ static int check_emacsclient_version(void)
*/
finish_command(&ec_process);
- if (prefixcmp(buffer.buf, "emacsclient")) {
+ if (!starts_with(buffer.buf, "emacsclient")) {
strbuf_release(&buffer);
return error(_("Failed to parse emacsclient version."));
}
@@ -258,7 +258,7 @@ static int add_man_viewer_info(const char *var, const char *value)
static int git_help_config(const char *var, const char *value, void *cb)
{
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "help", &colopts);
if (!strcmp(var, "help.format")) {
if (!value)
@@ -278,7 +278,7 @@ static int git_help_config(const char *var, const char *value, void *cb)
add_man_viewer(value);
return 0;
}
- if (!prefixcmp(var, "man."))
+ if (starts_with(var, "man."))
return add_man_viewer_info(var, value);
return git_default_config(var, value, cb);
@@ -288,6 +288,10 @@ static struct cmdnames main_cmds, other_cmds;
static int is_git_command(const char *s)
{
+ if (is_builtin(s))
+ return 1;
+
+ load_command_list("git-", &main_cmds, &other_cmds);
return is_in_cmdlist(&main_cmds, s) ||
is_in_cmdlist(&other_cmds, s);
}
@@ -306,7 +310,7 @@ static const char *cmd_to_page(const char *git_cmd)
{
if (!git_cmd)
return "git";
- else if (!prefixcmp(git_cmd, "git"))
+ else if (starts_with(git_cmd, "git"))
return git_cmd;
else if (is_git_command(git_cmd))
return prepend("git-", git_cmd);
@@ -449,7 +453,6 @@ int cmd_help(int argc, const char **argv, const char *prefix)
int nongit;
const char *alias;
enum help_format parsed_help_format;
- load_command_list("git-", &main_cmds, &other_cmds);
argc = parse_options(argc, argv, prefix, builtin_help_options,
builtin_help_usage, 0);
@@ -458,6 +461,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)
if (show_all) {
git_config(git_help_config, NULL);
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
+ load_command_list("git-", &main_cmds, &other_cmds);
list_commands(colopts, &main_cmds, &other_cmds);
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 9e9eb4b..2f37a38 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1534,9 +1534,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
stat_only = 1;
} else if (!strcmp(arg, "--keep")) {
keep_msg = "";
- } else if (!prefixcmp(arg, "--keep=")) {
+ } else if (starts_with(arg, "--keep=")) {
keep_msg = arg + 7;
- } else if (!prefixcmp(arg, "--threads=")) {
+ } else if (starts_with(arg, "--threads=")) {
char *end;
nr_threads = strtoul(arg+10, &end, 0);
if (!arg[10] || *end || nr_threads < 0)
@@ -1547,7 +1547,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
"ignoring %s"), arg);
nr_threads = 1;
#endif
- } else if (!prefixcmp(arg, "--pack_header=")) {
+ } else if (starts_with(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;
@@ -1566,7 +1566,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (index_name || (i+1) >= argc)
usage(index_pack_usage);
index_name = argv[++i];
- } else if (!prefixcmp(arg, "--index-version=")) {
+ } else if (starts_with(arg, "--index-version=")) {
char *c;
opts.version = strtoul(arg + 16, &c, 10);
if (opts.version > 2)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 78aa387..b3f03cf 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -266,7 +266,7 @@ static int create_default_files(const char *template_path)
/* allow template config file to override the default */
if (log_all_ref_updates == -1)
git_config_set("core.logallrefupdates", "true");
- if (prefixcmp(git_dir, work_tree) ||
+ if (!starts_with(git_dir, work_tree) ||
strcmp(git_dir + strlen(work_tree), "/.git")) {
git_config_set("core.worktree", work_tree);
}
diff --git a/builtin/log.c b/builtin/log.c
index b708517..b97373d 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -391,7 +391,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
default_show_root = git_config_bool(var, value);
return 0;
}
- if (!prefixcmp(var, "color.decorate."))
+ if (starts_with(var, "color.decorate."))
return parse_decorate_color_config(var, 15, value);
if (!strcmp(var, "log.mailmap")) {
use_mailmap_config = git_config_bool(var, value);
@@ -477,7 +477,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
int new_offset = offset + 1;
while (new_offset < size && buf[new_offset++] != '\n')
; /* do nothing */
- if (!prefixcmp(buf + offset, "tagger "))
+ if (starts_with(buf + offset, "tagger "))
show_tagger(buf + offset + 7,
new_offset - offset - 7, rev);
offset = new_offset;
@@ -882,7 +882,7 @@ static char *find_branch_name(struct rev_info *rev)
ref = rev->cmdline.rev[positive].name;
tip_sha1 = rev->cmdline.rev[positive].item->sha1;
if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
- !prefixcmp(full_ref, "refs/heads/") &&
+ starts_with(full_ref, "refs/heads/") &&
!hashcmp(tip_sha1, branch_sha1))
branch = xstrdup(full_ref + strlen("refs/heads/"));
free(full_ref);
@@ -1388,7 +1388,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
unsigned char sha1[20];
const char *ref;
ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
- if (ref && !prefixcmp(ref, "refs/heads/"))
+ if (ref && starts_with(ref, "refs/heads/"))
branch_name = xstrdup(ref + strlen("refs/heads/"));
else
branch_name = xstrdup(""); /* no branch */
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 25e83cf..39e5144 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -50,11 +50,11 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
if (*arg == '-') {
- if (!prefixcmp(arg, "--upload-pack=")) {
+ if (starts_with(arg, "--upload-pack=")) {
uploadpack = arg + 14;
continue;
}
- if (!prefixcmp(arg, "--exec=")) {
+ if (starts_with(arg, "--exec=")) {
uploadpack = arg + 7;
continue;
}
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 24a772d..2c3cd8e 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -328,11 +328,11 @@ static int check_header(const struct strbuf *line,
}
/* for inbody stuff */
- if (!prefixcmp(line->buf, ">From") && isspace(line->buf[5])) {
+ if (starts_with(line->buf, ">From") && isspace(line->buf[5])) {
ret = 1; /* Should this return 0? */
goto check_header_out;
}
- if (!prefixcmp(line->buf, "[PATCH]") && isspace(line->buf[7])) {
+ if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
for (i = 0; header[i]; i++) {
if (!memcmp("Subject", header[i], 7)) {
handle_header(&hdr_data[i], line);
@@ -361,7 +361,7 @@ static int is_rfc2822_header(const struct strbuf *line)
char *cp = line->buf;
/* Count mbox From headers as headers */
- if (!prefixcmp(cp, "From ") || !prefixcmp(cp, ">From "))
+ if (starts_with(cp, "From ") || starts_with(cp, ">From "))
return 1;
while ((ch = *cp++)) {
@@ -671,11 +671,11 @@ static inline int patchbreak(const struct strbuf *line)
size_t i;
/* Beginning of a "diff -" header? */
- if (!prefixcmp(line->buf, "diff -"))
+ if (starts_with(line->buf, "diff -"))
return 1;
/* CVS "Index: " line? */
- if (!prefixcmp(line->buf, "Index: "))
+ if (starts_with(line->buf, "Index: "))
return 1;
/*
@@ -685,7 +685,7 @@ static inline int patchbreak(const struct strbuf *line)
if (line->len < 4)
return 0;
- if (!prefixcmp(line->buf, "---")) {
+ if (starts_with(line->buf, "---")) {
/* space followed by a filename? */
if (line->buf[3] == ' ' && !isspace(line->buf[4]))
return 1;
@@ -986,7 +986,7 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)
static int git_mailinfo_config(const char *var, const char *value, void *unused)
{
- if (prefixcmp(var, "mailinfo."))
+ if (!starts_with(var, "mailinfo."))
return git_default_config(var, value, unused);
if (!strcmp(var, "mailinfo.scissors")) {
use_scissors = git_config_bool(var, value);
@@ -1020,7 +1020,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
metainfo_charset = def_charset;
else if (!strcmp(argv[1], "-n"))
metainfo_charset = NULL;
- else if (!prefixcmp(argv[1], "--encoding="))
+ else if (starts_with(argv[1], "--encoding="))
metainfo_charset = argv[1] + 11;
else if (!strcmp(argv[1], "--scissors"))
use_scissors = 1;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index e88eb93..0ecde8d 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -1,6 +1,9 @@
#include "builtin.h"
#include "cache.h"
#include "commit.h"
+#include "refs.h"
+#include "diff.h"
+#include "revision.h"
#include "parse-options.h"
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
@@ -27,6 +30,7 @@ static const char * const merge_base_usage[] = {
N_("git merge-base [-a|--all] --octopus <commit>..."),
N_("git merge-base --independent <commit>..."),
N_("git merge-base --is-ancestor <commit> <commit>"),
+ N_("git merge-base --fork-point <ref> [<commit>]"),
NULL
};
@@ -44,19 +48,36 @@ static struct commit *get_commit_reference(const char *arg)
return r;
}
-static int handle_octopus(int count, const char **args, int reduce, int show_all)
+static int handle_independent(int count, const char **args)
{
struct commit_list *revs = NULL;
struct commit_list *result;
int i;
- if (reduce)
- show_all = 1;
+ for (i = count - 1; i >= 0; i--)
+ commit_list_insert(get_commit_reference(args[i]), &revs);
+
+ result = reduce_heads(revs);
+ if (!result)
+ return 1;
+
+ while (result) {
+ printf("%s\n", sha1_to_hex(result->item->object.sha1));
+ result = result->next;
+ }
+ return 0;
+}
+
+static int handle_octopus(int count, const char **args, int show_all)
+{
+ struct commit_list *revs = NULL;
+ struct commit_list *result;
+ int i;
for (i = count - 1; i >= 0; i--)
commit_list_insert(get_commit_reference(args[i]), &revs);
- result = reduce ? reduce_heads(revs) : get_octopus_merge_bases(revs);
+ result = reduce_heads(get_octopus_merge_bases(revs));
if (!result)
return 1;
@@ -85,37 +106,151 @@ static int handle_is_ancestor(int argc, const char **argv)
return 1;
}
+struct rev_collect {
+ struct commit **commit;
+ int nr;
+ int alloc;
+ unsigned int initial : 1;
+};
+
+static void add_one_commit(unsigned char *sha1, struct rev_collect *revs)
+{
+ struct commit *commit;
+
+ if (is_null_sha1(sha1))
+ return;
+
+ commit = lookup_commit(sha1);
+ if (!commit ||
+ (commit->object.flags & TMP_MARK) ||
+ parse_commit(commit))
+ return;
+
+ ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
+ revs->commit[revs->nr++] = commit;
+ commit->object.flags |= TMP_MARK;
+}
+
+static int collect_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ const char *ident, unsigned long timestamp,
+ int tz, const char *message, void *cbdata)
+{
+ struct rev_collect *revs = cbdata;
+
+ if (revs->initial) {
+ revs->initial = 0;
+ add_one_commit(osha1, revs);
+ }
+ add_one_commit(nsha1, revs);
+ return 0;
+}
+
+static int handle_fork_point(int argc, const char **argv)
+{
+ unsigned char sha1[20];
+ char *refname;
+ const char *commitname;
+ struct rev_collect revs;
+ struct commit *derived;
+ struct commit_list *bases;
+ int i, ret = 0;
+
+ switch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) {
+ case 0:
+ die("No such ref: '%s'", argv[0]);
+ case 1:
+ break; /* good */
+ default:
+ die("Ambiguous refname: '%s'", argv[0]);
+ }
+
+ commitname = (argc == 2) ? argv[1] : "HEAD";
+ if (get_sha1(commitname, sha1))
+ die("Not a valid object name: '%s'", commitname);
+
+ derived = lookup_commit_reference(sha1);
+ memset(&revs, 0, sizeof(revs));
+ revs.initial = 1;
+ for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
+
+ for (i = 0; i < revs.nr; i++)
+ revs.commit[i]->object.flags &= ~TMP_MARK;
+
+ bases = get_merge_bases_many(derived, revs.nr, revs.commit, 0);
+
+ /*
+ * There should be one and only one merge base, when we found
+ * a common ancestor among reflog entries.
+ */
+ if (!bases || bases->next) {
+ ret = 1;
+ goto cleanup_return;
+ }
+
+ /* And the found one must be one of the reflog entries */
+ for (i = 0; i < revs.nr; i++)
+ if (&bases->item->object == &revs.commit[i]->object)
+ break; /* found */
+ if (revs.nr <= i) {
+ ret = 1; /* not found */
+ goto cleanup_return;
+ }
+
+ printf("%s\n", sha1_to_hex(bases->item->object.sha1));
+
+cleanup_return:
+ free_commit_list(bases);
+ return ret;
+}
+
int cmd_merge_base(int argc, const char **argv, const char *prefix)
{
struct commit **rev;
int rev_nr = 0;
int show_all = 0;
- int octopus = 0;
- int reduce = 0;
- int is_ancestor = 0;
+ int cmdmode = 0;
struct option options[] = {
OPT_BOOL('a', "all", &show_all, N_("output all common ancestors")),
- OPT_BOOL(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")),
- OPT_BOOL(0, "independent", &reduce, N_("list revs not reachable from others")),
- OPT_BOOL(0, "is-ancestor", &is_ancestor,
- N_("is the first one ancestor of the other?")),
+ OPT_CMDMODE(0, "octopus", &cmdmode,
+ N_("find ancestors for a single n-way merge"), 'o'),
+ OPT_CMDMODE(0, "independent", &cmdmode,
+ N_("list revs not reachable from others"), 'r'),
+ OPT_CMDMODE(0, "is-ancestor", &cmdmode,
+ N_("is the first one ancestor of the other?"), 'a'),
+ OPT_CMDMODE(0, "fork-point", &cmdmode,
+ N_("find where <commit> forked from reflog of <ref>"), 'f'),
OPT_END()
};
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
- if (!octopus && !reduce && argc < 2)
- usage_with_options(merge_base_usage, options);
- if (is_ancestor && (show_all || octopus || reduce))
- die("--is-ancestor cannot be used with other options");
- if (is_ancestor)
+
+ if (cmdmode == 'a') {
+ if (argc < 2)
+ usage_with_options(merge_base_usage, options);
+ if (show_all)
+ die("--is-ancestor cannot be used with --all");
return handle_is_ancestor(argc, argv);
- if (reduce && (show_all || octopus))
- die("--independent cannot be used with other options");
+ }
- if (octopus || reduce)
- return handle_octopus(argc, argv, reduce, show_all);
+ if (cmdmode == 'r' && show_all)
+ die("--independent cannot be used with --all");
+
+ if (cmdmode == 'o')
+ return handle_octopus(argc, argv, show_all);
+
+ if (cmdmode == 'r')
+ return handle_independent(argc, argv);
+
+ if (cmdmode == 'f') {
+ if (argc < 1 || 2 < argc)
+ usage_with_options(merge_base_usage, options);
+ return handle_fork_point(argc, argv);
+ }
+
+ if (argc < 2)
+ usage_with_options(merge_base_usage, options);
rev = xmalloc(argc * sizeof(*rev));
while (argc-- > 0)
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 3a64f5d..a90f28f 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -29,7 +29,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
struct commit *result;
init_merge_options(&o);
- if (argv[0] && !suffixcmp(argv[0], "-subtree"))
+ if (argv[0] && ends_with(argv[0], "-subtree"))
o.subtree_shift = "";
if (argc < 4)
@@ -38,7 +38,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; ++i) {
const char *arg = argv[i];
- if (!prefixcmp(arg, "--")) {
+ if (starts_with(arg, "--")) {
if (!arg[2])
break;
if (parse_merge_opt(&o, arg + 2))
diff --git a/builtin/merge.c b/builtin/merge.c
index 41fb66d..4941a6c 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -446,17 +446,17 @@ static void merge_name(const char *remote, struct strbuf *msg)
die(_("'%s' does not point to a commit"), remote);
if (dwim_ref(remote, strlen(remote), branch_head, &found_ref) > 0) {
- if (!prefixcmp(found_ref, "refs/heads/")) {
+ if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
}
- if (!prefixcmp(found_ref, "refs/tags/")) {
+ if (starts_with(found_ref, "refs/tags/")) {
strbuf_addf(msg, "%s\t\ttag '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
}
- if (!prefixcmp(found_ref, "refs/remotes/")) {
+ if (starts_with(found_ref, "refs/remotes/")) {
strbuf_addf(msg, "%s\t\tremote-tracking branch '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
@@ -570,8 +570,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
{
int status;
- if (branch && !prefixcmp(k, "branch.") &&
- !prefixcmp(k + 7, branch) &&
+ if (branch && starts_with(k, "branch.") &&
+ starts_with(k + 7, branch) &&
!strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
free(branch_mergeoptions);
branch_mergeoptions = xstrdup(v);
@@ -1106,7 +1106,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* current branch.
*/
branch = branch_to_free = resolve_refdup("HEAD", head_sha1, 0, &flag);
- if (branch && !prefixcmp(branch, "refs/heads/"))
+ if (branch && starts_with(branch, "refs/heads/"))
branch += 11;
if (!branch || is_null_sha1(head_sha1))
head_commit = NULL;
diff --git a/builtin/mv.c b/builtin/mv.c
index 2e0e61b..21c46d1 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -16,9 +16,12 @@ static const char * const builtin_mv_usage[] = {
NULL
};
+#define DUP_BASENAME 1
+#define KEEP_TRAILING_SLASH 2
+
static const char **internal_copy_pathspec(const char *prefix,
const char **pathspec,
- int count, int base_name)
+ int count, unsigned flags)
{
int i;
const char **result = xmalloc((count + 1) * sizeof(const char *));
@@ -27,11 +30,12 @@ static const char **internal_copy_pathspec(const char *prefix,
for (i = 0; i < count; i++) {
int length = strlen(result[i]);
int to_copy = length;
- while (to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
+ while (!(flags & KEEP_TRAILING_SLASH) &&
+ to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
to_copy--;
- if (to_copy != length || base_name) {
+ if (to_copy != length || flags & DUP_BASENAME) {
char *it = xmemdupz(result[i], to_copy);
- if (base_name) {
+ if (flags & DUP_BASENAME) {
result[i] = xstrdup(basename(it));
free(it);
} else
@@ -87,16 +91,21 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
source = internal_copy_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
- dest_path = internal_copy_pathspec(prefix, argv + argc, 1, 0);
+ /*
+ * Keep trailing slash, needed to let
+ * "git mv file no-such-dir/" error out.
+ */
+ dest_path = internal_copy_pathspec(prefix, argv + argc, 1,
+ KEEP_TRAILING_SLASH);
submodule_gitfile = xcalloc(argc, sizeof(char *));
if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
else if (!lstat(dest_path[0], &st) &&
S_ISDIR(st.st_mode)) {
dest_path[0] = add_slash(dest_path[0]);
- destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
} else {
if (argc != 1)
die("destination '%s' is not a directory", dest_path[0]);
@@ -205,6 +214,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
} else if (string_list_has_string(&src_for_dst, dst))
bad = _("multiple sources for the same target");
+ else if (is_dir_sep(dst[strlen(dst) - 1]))
+ bad = _("destination directory does not exist");
else
string_list_insert(&src_for_dst, dst);
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 20fcf8c..0b21d7e 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -27,8 +27,7 @@ static void name_rev(struct commit *commit,
struct commit_list *parents;
int parent_number = 1;
- if (!commit->object.parsed)
- parse_commit(commit);
+ parse_commit(commit);
if (commit->date < cutoff)
return;
@@ -101,9 +100,9 @@ static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
{
if (shorten_unambiguous)
refname = shorten_unambiguous_ref(refname, 0);
- else if (!prefixcmp(refname, "refs/heads/"))
+ else if (starts_with(refname, "refs/heads/"))
refname = refname + 11;
- else if (!prefixcmp(refname, "refs/"))
+ else if (starts_with(refname, "refs/"))
refname = refname + 5;
return refname;
}
@@ -149,7 +148,7 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
int can_abbreviate_output = data->tags_only && data->name_only;
int deref = 0;
- if (data->tags_only && prefixcmp(path, "refs/tags/"))
+ if (data->tags_only && !starts_with(path, "refs/tags/"))
return 0;
if (data->ref_filter) {
diff --git a/builtin/notes.c b/builtin/notes.c
index d459e23..2b24d05 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -347,7 +347,7 @@ static struct notes_tree *init_notes_check(const char *subcommand)
init_notes(NULL, NULL, NULL, 0);
t = &default_notes_tree;
- if (prefixcmp(t->ref, "refs/notes/"))
+ if (!starts_with(t->ref, "refs/notes/"))
die("Refusing to %s notes in %s (outside of refs/notes/)",
subcommand, t->ref);
return t;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 36273dd..541667f 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -737,8 +737,6 @@ static void write_pack_file(void)
f = create_tmp_packfile(&pack_tmp_name);
offset = write_pack_header(f, nr_remaining);
- if (!offset)
- die_errno("unable to write pack header");
nr_written = 0;
for (; i < nr_objects; i++) {
struct object_entry *e = write_order[i];
@@ -2032,7 +2030,7 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo
{
unsigned char peeled[20];
- if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
+ if (starts_with(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, peeled) && /* peelable? */
locate_object_entry(peeled)) /* object packed? */
add_object_entry(sha1, OBJ_TAG, NULL, 0);
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index fa6ce42..fcf5fb6 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -10,58 +10,62 @@ static const char * const prune_packed_usage[] = {
static struct progress *progress;
-static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
+static void prune_dir(int i, DIR *dir, struct strbuf *pathname, int opts)
{
struct dirent *de;
char hex[40];
+ int top_len = pathname->len;
sprintf(hex, "%02x", i);
while ((de = readdir(dir)) != NULL) {
unsigned char sha1[20];
if (strlen(de->d_name) != 38)
continue;
- memcpy(hex+2, de->d_name, 38);
+ memcpy(hex + 2, de->d_name, 38);
if (get_sha1_hex(hex, sha1))
continue;
if (!has_sha1_pack(sha1))
continue;
- memcpy(pathname + len, de->d_name, 38);
+
+ strbuf_add(pathname, de->d_name, 38);
if (opts & PRUNE_PACKED_DRY_RUN)
- printf("rm -f %s\n", pathname);
+ printf("rm -f %s\n", pathname->buf);
else
- unlink_or_warn(pathname);
+ unlink_or_warn(pathname->buf);
display_progress(progress, i + 1);
+ strbuf_setlen(pathname, top_len);
}
}
void prune_packed_objects(int opts)
{
int i;
- static char pathname[PATH_MAX];
const char *dir = get_object_directory();
- int len = strlen(dir);
+ struct strbuf pathname = STRBUF_INIT;
+ int top_len;
+ strbuf_addstr(&pathname, dir);
if (opts & PRUNE_PACKED_VERBOSE)
progress = start_progress_delay("Removing duplicate objects",
256, 95, 2);
- if (len > PATH_MAX - 42)
- die("impossible object directory");
- memcpy(pathname, dir, len);
- if (len && pathname[len-1] != '/')
- pathname[len++] = '/';
+ if (pathname.len && pathname.buf[pathname.len - 1] != '/')
+ strbuf_addch(&pathname, '/');
+
+ top_len = pathname.len;
for (i = 0; i < 256; i++) {
DIR *d;
display_progress(progress, i + 1);
- sprintf(pathname + len, "%02x/", i);
- d = opendir(pathname);
+ strbuf_setlen(&pathname, top_len);
+ strbuf_addf(&pathname, "%02x/", i);
+ d = opendir(pathname.buf);
if (!d)
continue;
- prune_dir(i, d, pathname, len + 3, opts);
+ prune_dir(i, d, &pathname, opts);
closedir(d);
- pathname[len + 2] = '\0';
- rmdir(pathname);
+ strbuf_setlen(&pathname, top_len + 2);
+ rmdir(pathname.buf);
}
stop_progress(&progress);
}
diff --git a/builtin/prune.c b/builtin/prune.c
index 2214040..de43b26 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -17,9 +17,8 @@ static int verbose;
static unsigned long expire;
static int show_progress = -1;
-static int prune_tmp_object(const char *path, const char *filename)
+static int prune_tmp_file(const char *fullpath)
{
- const char *fullpath = mkpath("%s/%s", path, filename);
struct stat st;
if (lstat(fullpath, &st))
return error("Could not stat '%s'", fullpath);
@@ -32,9 +31,8 @@ static int prune_tmp_object(const char *path, const char *filename)
return 0;
}
-static int prune_object(char *path, const char *filename, const unsigned char *sha1)
+static int prune_object(const char *fullpath, const unsigned char *sha1)
{
- const char *fullpath = mkpath("%s/%s", path, filename);
struct stat st;
if (lstat(fullpath, &st))
return error("Could not stat '%s'", fullpath);
@@ -50,9 +48,10 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
return 0;
}
-static int prune_dir(int i, char *path)
+static int prune_dir(int i, struct strbuf *path)
{
- DIR *dir = opendir(path);
+ size_t baselen = path->len;
+ DIR *dir = opendir(path->buf);
struct dirent *de;
if (!dir)
@@ -77,28 +76,39 @@ static int prune_dir(int i, char *path)
if (lookup_object(sha1))
continue;
- prune_object(path, de->d_name, sha1);
+ strbuf_addf(path, "/%s", de->d_name);
+ prune_object(path->buf, sha1);
+ strbuf_setlen(path, baselen);
continue;
}
- if (!prefixcmp(de->d_name, "tmp_obj_")) {
- prune_tmp_object(path, de->d_name);
+ if (starts_with(de->d_name, "tmp_obj_")) {
+ strbuf_addf(path, "/%s", de->d_name);
+ prune_tmp_file(path->buf);
+ strbuf_setlen(path, baselen);
continue;
}
- fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
+ fprintf(stderr, "bad sha1 file: %s/%s\n", path->buf, de->d_name);
}
closedir(dir);
if (!show_only)
- rmdir(path);
+ rmdir(path->buf);
return 0;
}
static void prune_object_dir(const char *path)
{
+ struct strbuf buf = STRBUF_INIT;
+ size_t baselen;
int i;
+
+ strbuf_addstr(&buf, path);
+ strbuf_addch(&buf, '/');
+ baselen = buf.len;
+
for (i = 0; i < 256; i++) {
- static char dir[4096];
- sprintf(dir, "%s/%02x", path, i);
- prune_dir(i, dir);
+ strbuf_addf(&buf, "%02x", i);
+ prune_dir(i, &buf);
+ strbuf_setlen(&buf, baselen);
}
}
@@ -119,8 +129,8 @@ static void remove_temporary_files(const char *path)
return;
}
while ((de = readdir(dir)) != NULL)
- if (!prefixcmp(de->d_name, "tmp_"))
- prune_tmp_object(path, de->d_name);
+ if (starts_with(de->d_name, "tmp_"))
+ prune_tmp_file(mkpath("%s/%s", path, de->d_name));
closedir(dir);
}
diff --git a/builtin/push.c b/builtin/push.c
index 7b1b66c..0e50ddb 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -35,35 +35,75 @@ static void add_refspec(const char *ref)
refspec[refspec_nr-1] = ref;
}
-static void set_refspecs(const char **refs, int nr)
+static const char *map_refspec(const char *ref,
+ struct remote *remote, struct ref *local_refs)
{
+ struct ref *matched = NULL;
+
+ /* Does "ref" uniquely name our ref? */
+ if (count_refspec_match(ref, local_refs, &matched) != 1)
+ return ref;
+
+ if (remote->push) {
+ struct refspec query;
+ memset(&query, 0, sizeof(struct refspec));
+ query.src = matched->name;
+ if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
+ query.dst) {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf, "%s%s:%s",
+ query.force ? "+" : "",
+ query.src, query.dst);
+ return strbuf_detach(&buf, NULL);
+ }
+ }
+
+ if (push_default == PUSH_DEFAULT_UPSTREAM &&
+ !prefixcmp(matched->name, "refs/heads/")) {
+ struct branch *branch = branch_get(matched->name + 11);
+ if (branch->merge_nr == 1 && branch->merge[0]->src) {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf, "%s:%s",
+ ref, branch->merge[0]->src);
+ return strbuf_detach(&buf, NULL);
+ }
+ }
+
+ return ref;
+}
+
+static void set_refspecs(const char **refs, int nr, const char *repo)
+{
+ struct remote *remote = NULL;
+ struct ref *local_refs = NULL;
int i;
+
for (i = 0; i < nr; i++) {
const char *ref = refs[i];
if (!strcmp("tag", ref)) {
- char *tag;
- int len;
+ struct strbuf tagref = STRBUF_INIT;
if (nr <= ++i)
die(_("tag shorthand without <tag>"));
- len = strlen(refs[i]) + 11;
- if (deleterefs) {
- tag = xmalloc(len+1);
- strcpy(tag, ":refs/tags/");
- } else {
- tag = xmalloc(len);
- strcpy(tag, "refs/tags/");
+ ref = refs[i];
+ if (deleterefs)
+ strbuf_addf(&tagref, ":refs/tags/%s", ref);
+ else
+ strbuf_addf(&tagref, "refs/tags/%s", ref);
+ ref = strbuf_detach(&tagref, NULL);
+ } else if (deleterefs) {
+ struct strbuf delref = STRBUF_INIT;
+ if (strchr(ref, ':'))
+ die(_("--delete only accepts plain target ref names"));
+ strbuf_addf(&delref, ":%s", ref);
+ ref = strbuf_detach(&delref, NULL);
+ } else if (!strchr(ref, ':')) {
+ if (!remote) {
+ /* lazily grab remote and local_refs */
+ remote = remote_get(repo);
+ local_refs = get_local_heads();
}
- strcat(tag, refs[i]);
- ref = tag;
- } else if (deleterefs && !strchr(ref, ':')) {
- char *delref;
- int len = strlen(ref)+1;
- delref = xmalloc(len+1);
- strcpy(delref, ":");
- strcat(delref, ref);
- ref = delref;
- } else if (deleterefs)
- die(_("--delete only accepts plain target ref names"));
+ ref = map_refspec(ref, remote, local_refs);
+ }
add_refspec(ref);
}
}
@@ -174,6 +214,13 @@ N_("push.default is unset; its implicit value is changing in\n"
"\n"
" git config --global push.default simple\n"
"\n"
+ "When push.default is set to 'matching', git will push local branches\n"
+ "to the remote branches that already exist with the same name.\n"
+ "\n"
+ "In Git 2.0, Git will default to the more conservative 'simple'\n"
+ "behavior, which only pushes the current branch to the corresponding\n"
+ "remote branch that 'git pull' uses to update the current branch.\n"
+ "\n"
"See 'git help config' and search for 'push.default' for further information.\n"
"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
"'current' instead of 'simple' if you sometimes use older versions of Git)");
@@ -494,7 +541,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
if (argc > 0) {
repo = argv[0];
- set_refspecs(argv + 1, argc - 1);
+ set_refspecs(argv + 1, argc - 1, repo);
}
rc = do_push(repo, flags);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index bc4f5dc..85bba35 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -478,7 +478,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
struct ref_lock *lock;
/* only refs/... are allowed */
- if (prefixcmp(name, "refs/") || check_refname_format(name + 5, 0)) {
+ if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
rp_error("refusing to create funny ref '%s' remotely", name);
return "funny refname";
}
@@ -509,7 +509,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
- if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
+ if (deny_deletes && starts_with(name, "refs/heads/")) {
rp_error("denying ref deletion for %s", name);
return "deletion prohibited";
}
@@ -533,7 +533,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
!is_null_sha1(old_sha1) &&
- !prefixcmp(name, "refs/heads/")) {
+ starts_with(name, "refs/heads/")) {
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
@@ -853,7 +853,7 @@ static struct command *read_head_info(struct sha1_array *shallow)
if (!line)
break;
- if (len == 48 && !prefixcmp(line, "shallow ")) {
+ if (len == 48 && starts_with(line, "shallow ")) {
if (get_sha1_hex(line + 8, old_sha1))
die("protocol error: expected shallow sha, got '%s'", line + 8);
sha1_array_append(shallow, old_sha1);
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 6eb24c8..852cff6 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -610,12 +610,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
cb.dry_run = 1;
- else if (!prefixcmp(arg, "--expire=")) {
+ else if (starts_with(arg, "--expire=")) {
if (parse_expiry_date(arg + 9, &cb.expire_total))
die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_TOTAL;
}
- else if (!prefixcmp(arg, "--expire-unreachable=")) {
+ else if (starts_with(arg, "--expire-unreachable=")) {
if (parse_expiry_date(arg + 21, &cb.expire_unreachable))
die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_UNREACH;
diff --git a/builtin/remote.c b/builtin/remote.c
index 4e14891..b3ab4cf 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -6,6 +6,7 @@
#include "strbuf.h"
#include "run-command.h"
#include "refs.h"
+#include "argv-array.h"
static const char * const builtin_remote_usage[] = {
N_("git remote [-v | --verbose]"),
@@ -77,17 +78,6 @@ static const char * const builtin_remote_seturl_usage[] = {
static int verbose;
-static int show_all(void);
-static int prune_remote(const char *remote, int dry_run);
-
-static inline int postfixcmp(const char *string, const char *postfix)
-{
- int len1 = strlen(string), len2 = strlen(postfix);
- if (len1 < len2)
- return 1;
- return strcmp(string + len1 - len2, postfix);
-}
-
static int fetch_remote(const char *name)
{
const char *argv[] = { "fetch", name, NULL, NULL };
@@ -269,7 +259,7 @@ static const char *abbrev_ref(const char *name, const char *prefix)
static int config_read_branches(const char *key, const char *value, void *cb)
{
- if (!prefixcmp(key, "branch.")) {
+ if (starts_with(key, "branch.")) {
const char *orig_key = key;
char *name;
struct string_list_item *item;
@@ -277,13 +267,13 @@ static int config_read_branches(const char *key, const char *value, void *cb)
enum { REMOTE, MERGE, REBASE } type;
key += 7;
- if (!postfixcmp(key, ".remote")) {
+ if (ends_with(key, ".remote")) {
name = xstrndup(key, strlen(key) - 7);
type = REMOTE;
- } else if (!postfixcmp(key, ".merge")) {
+ } else if (ends_with(key, ".merge")) {
name = xstrndup(key, strlen(key) - 6);
type = MERGE;
- } else if (!postfixcmp(key, ".rebase")) {
+ } else if (ends_with(key, ".rebase")) {
name = xstrndup(key, strlen(key) - 7);
type = REBASE;
} else
@@ -309,8 +299,13 @@ static int config_read_branches(const char *key, const char *value, void *cb)
space = strchr(value, ' ');
}
string_list_append(&info->merge, xstrdup(value));
- } else
- info->rebase = git_config_bool(orig_key, value);
+ } else {
+ int v = git_config_maybe_bool(orig_key, value);
+ if (v >= 0)
+ info->rebase = v;
+ else if (!strcmp(value, "preserve"))
+ info->rebase = 1;
+ }
}
return 0;
}
@@ -534,9 +529,9 @@ static int add_branch_for_removal(const char *refname,
}
/* don't delete non-remote-tracking refs */
- if (prefixcmp(refname, "refs/remotes/")) {
+ if (!starts_with(refname, "refs/remotes/")) {
/* advise user how to delete local branches */
- if (!prefixcmp(refname, "refs/heads/"))
+ if (starts_with(refname, "refs/heads/"))
string_list_append(branches->skipped,
abbrev_branch(refname));
/* silently skip over other non-remote refs */
@@ -571,7 +566,7 @@ static int read_remote_branches(const char *refname,
const char *symref;
strbuf_addf(&buf, "refs/remotes/%s/", rename->old);
- if (!prefixcmp(refname, buf.buf)) {
+ if (starts_with(refname, buf.buf)) {
item = string_list_append(rename->remote_branches, xstrdup(refname));
symref = resolve_ref_unsafe(refname, orig_sha1, 1, &flag);
if (flag & REF_ISSYMREF)
@@ -1084,6 +1079,64 @@ static int show_push_info_item(struct string_list_item *item, void *cb_data)
return 0;
}
+static int get_one_entry(struct remote *remote, void *priv)
+{
+ struct string_list *list = priv;
+ struct strbuf url_buf = STRBUF_INIT;
+ const char **url;
+ int i, url_nr;
+
+ if (remote->url_nr > 0) {
+ strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
+ string_list_append(list, remote->name)->util =
+ strbuf_detach(&url_buf, NULL);
+ } else
+ string_list_append(list, remote->name)->util = NULL;
+ if (remote->pushurl_nr) {
+ url = remote->pushurl;
+ url_nr = remote->pushurl_nr;
+ } else {
+ url = remote->url;
+ url_nr = remote->url_nr;
+ }
+ for (i = 0; i < url_nr; i++)
+ {
+ strbuf_addf(&url_buf, "%s (push)", url[i]);
+ string_list_append(list, remote->name)->util =
+ strbuf_detach(&url_buf, NULL);
+ }
+
+ return 0;
+}
+
+static int show_all(void)
+{
+ struct string_list list = STRING_LIST_INIT_NODUP;
+ int result;
+
+ list.strdup_strings = 1;
+ result = for_each_remote(get_one_entry, &list);
+
+ if (!result) {
+ int i;
+
+ sort_string_list(&list);
+ for (i = 0; i < list.nr; i++) {
+ struct string_list_item *item = list.items + i;
+ if (verbose)
+ printf("%s\t%s\n", item->string,
+ item->util ? (const char *)item->util : "");
+ else {
+ if (i && !strcmp((item - 1)->string, item->string))
+ continue;
+ printf("%s\n", item->string);
+ }
+ }
+ }
+ string_list_clear(&list, 1);
+ return result;
+}
+
static int show(int argc, const char **argv)
{
int no_query = 0, result = 0, query_flag = 0;
@@ -1246,26 +1299,6 @@ static int set_head(int argc, const char **argv)
return result;
}
-static int prune(int argc, const char **argv)
-{
- int dry_run = 0, result = 0;
- struct option options[] = {
- OPT__DRY_RUN(&dry_run, N_("dry run")),
- OPT_END()
- };
-
- argc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage,
- 0);
-
- if (argc < 1)
- usage_with_options(builtin_remote_prune_usage, options);
-
- for (; argc; argc--, argv++)
- result |= prune_remote(*argv, dry_run);
-
- return result;
-}
-
static int prune_remote(const char *remote, int dry_run)
{
int result = 0, i;
@@ -1304,6 +1337,26 @@ static int prune_remote(const char *remote, int dry_run)
return result;
}
+static int prune(int argc, const char **argv)
+{
+ int dry_run = 0, result = 0;
+ struct option options[] = {
+ OPT__DRY_RUN(&dry_run, N_("dry run")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage,
+ 0);
+
+ if (argc < 1)
+ usage_with_options(builtin_remote_prune_usage, options);
+
+ for (; argc; argc--, argv++)
+ result |= prune_remote(*argv, dry_run);
+
+ return result;
+}
+
static int get_remote_default(const char *key, const char *value, void *priv)
{
if (strcmp(key, "remotes.default") == 0) {
@@ -1315,42 +1368,42 @@ static int get_remote_default(const char *key, const char *value, void *priv)
static int update(int argc, const char **argv)
{
- int i, prune = 0;
+ int i, prune = -1;
struct option options[] = {
OPT_BOOL('p', "prune", &prune,
N_("prune remotes after fetching")),
OPT_END()
};
- const char **fetch_argv;
- int fetch_argc = 0;
+ struct argv_array fetch_argv = ARGV_ARRAY_INIT;
int default_defined = 0;
-
- fetch_argv = xmalloc(sizeof(char *) * (argc+5));
+ int retval;
argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
PARSE_OPT_KEEP_ARGV0);
- fetch_argv[fetch_argc++] = "fetch";
+ argv_array_push(&fetch_argv, "fetch");
- if (prune)
- fetch_argv[fetch_argc++] = "--prune";
+ if (prune != -1)
+ argv_array_push(&fetch_argv, prune ? "--prune" : "--no-prune");
if (verbose)
- fetch_argv[fetch_argc++] = "-v";
- fetch_argv[fetch_argc++] = "--multiple";
+ argv_array_push(&fetch_argv, "-v");
+ argv_array_push(&fetch_argv, "--multiple");
if (argc < 2)
- fetch_argv[fetch_argc++] = "default";
+ argv_array_push(&fetch_argv, "default");
for (i = 1; i < argc; i++)
- fetch_argv[fetch_argc++] = argv[i];
+ argv_array_push(&fetch_argv, argv[i]);
- if (strcmp(fetch_argv[fetch_argc-1], "default") == 0) {
+ if (strcmp(fetch_argv.argv[fetch_argv.argc-1], "default") == 0) {
git_config(get_remote_default, &default_defined);
- if (!default_defined)
- fetch_argv[fetch_argc-1] = "--all";
+ if (!default_defined) {
+ argv_array_pop(&fetch_argv);
+ argv_array_push(&fetch_argv, "--all");
+ }
}
- fetch_argv[fetch_argc] = NULL;
-
- return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
+ retval = run_command_v_opt(fetch_argv.argv, RUN_GIT_CMD);
+ argv_array_clear(&fetch_argv);
+ return retval;
}
static int remove_all_fetch_refspecs(const char *remote, const char *key)
@@ -1505,64 +1558,6 @@ static int set_url(int argc, const char **argv)
return 0;
}
-static int get_one_entry(struct remote *remote, void *priv)
-{
- struct string_list *list = priv;
- struct strbuf url_buf = STRBUF_INIT;
- const char **url;
- int i, url_nr;
-
- if (remote->url_nr > 0) {
- strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
- string_list_append(list, remote->name)->util =
- strbuf_detach(&url_buf, NULL);
- } else
- string_list_append(list, remote->name)->util = NULL;
- if (remote->pushurl_nr) {
- url = remote->pushurl;
- url_nr = remote->pushurl_nr;
- } else {
- url = remote->url;
- url_nr = remote->url_nr;
- }
- for (i = 0; i < url_nr; i++)
- {
- strbuf_addf(&url_buf, "%s (push)", url[i]);
- string_list_append(list, remote->name)->util =
- strbuf_detach(&url_buf, NULL);
- }
-
- return 0;
-}
-
-static int show_all(void)
-{
- struct string_list list = STRING_LIST_INIT_NODUP;
- int result;
-
- list.strdup_strings = 1;
- result = for_each_remote(get_one_entry, &list);
-
- if (!result) {
- int i;
-
- sort_string_list(&list);
- for (i = 0; i < list.nr; i++) {
- struct string_list_item *item = list.items + i;
- if (verbose)
- printf("%s\t%s\n", item->string,
- item->util ? (const char *)item->util : "");
- else {
- if (i && !strcmp((item - 1)->string, item->string))
- continue;
- printf("%s\n", item->string);
- }
- }
- }
- string_list_clear(&list, 1);
- return result;
-}
-
int cmd_remote(int argc, const char **argv, const char *prefix)
{
struct option options[] = {
diff --git a/builtin/repack.c b/builtin/repack.c
index a0ff5c7..ba66c6e 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -78,7 +78,7 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
return;
while ((e = readdir(dir)) != NULL) {
- if (suffixcmp(e->d_name, ".pack"))
+ if (!ends_with(e->d_name, ".pack"))
continue;
len = strlen(e->d_name) - strlen(".pack");
@@ -123,7 +123,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct string_list rollback = STRING_LIST_INIT_NODUP;
struct string_list existing_packs = STRING_LIST_INIT_DUP;
struct strbuf line = STRBUF_INIT;
- int nr_packs, ext, ret, failed;
+ int ext, ret, failed;
FILE *out;
/* variables to be filled by option parsing */
@@ -233,13 +233,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (ret)
return ret;
- nr_packs = 0;
out = xfdopen(cmd.out, "r");
while (strbuf_getline(&line, out, '\n') != EOF) {
if (line.len != 40)
die("repack: Expecting 40 character sha1 lines only from pack-objects.");
string_list_append(&names, line.buf);
- nr_packs++;
}
fclose(out);
ret = finish_command(&cmd);
@@ -247,7 +245,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
return ret;
argv_array_clear(&cmd_args);
- if (!nr_packs && !quiet)
+ if (!names.nr && !quiet)
printf("Nothing new to pack.\n");
/*
diff --git a/builtin/replace.c b/builtin/replace.c
index b1bd3ef..2336325 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -16,27 +16,69 @@
static const char * const git_replace_usage[] = {
N_("git replace [-f] <object> <replacement>"),
N_("git replace -d <object>..."),
- N_("git replace -l [<pattern>]"),
+ N_("git replace [--format=<format>] [-l [<pattern>]]"),
NULL
};
+enum replace_format {
+ REPLACE_FORMAT_SHORT,
+ REPLACE_FORMAT_MEDIUM,
+ REPLACE_FORMAT_LONG
+};
+
+struct show_data {
+ const char *pattern;
+ enum replace_format format;
+};
+
static int show_reference(const char *refname, const unsigned char *sha1,
int flag, void *cb_data)
{
- const char *pattern = cb_data;
+ struct show_data *data = cb_data;
- if (!fnmatch(pattern, refname, 0))
- printf("%s\n", refname);
+ if (!fnmatch(data->pattern, refname, 0)) {
+ if (data->format == REPLACE_FORMAT_SHORT)
+ printf("%s\n", refname);
+ else if (data->format == REPLACE_FORMAT_MEDIUM)
+ printf("%s -> %s\n", refname, sha1_to_hex(sha1));
+ else { /* data->format == REPLACE_FORMAT_LONG */
+ unsigned char object[20];
+ enum object_type obj_type, repl_type;
+
+ if (get_sha1(refname, object))
+ return error("Failed to resolve '%s' as a valid ref.", refname);
+
+ obj_type = sha1_object_info(object, NULL);
+ repl_type = sha1_object_info(sha1, NULL);
+
+ printf("%s (%s) -> %s (%s)\n", refname, typename(obj_type),
+ sha1_to_hex(sha1), typename(repl_type));
+ }
+ }
return 0;
}
-static int list_replace_refs(const char *pattern)
+static int list_replace_refs(const char *pattern, const char *format)
{
+ struct show_data data;
+
if (pattern == NULL)
pattern = "*";
+ data.pattern = pattern;
- for_each_replace_ref(show_reference, (void *) pattern);
+ if (format == NULL || *format == '\0' || !strcmp(format, "short"))
+ data.format = REPLACE_FORMAT_SHORT;
+ else if (!strcmp(format, "medium"))
+ data.format = REPLACE_FORMAT_MEDIUM;
+ else if (!strcmp(format, "long"))
+ data.format = REPLACE_FORMAT_LONG;
+ else
+ die("invalid replace format '%s'\n"
+ "valid formats are 'short', 'medium' and 'long'\n",
+ format);
+
+ for_each_replace_ref(show_reference, (void *) &data);
return 0;
}
@@ -127,19 +169,27 @@ static int replace_object(const char *object_ref, const char *replace_ref,
int cmd_replace(int argc, const char **argv, const char *prefix)
{
int list = 0, delete = 0, force = 0;
+ const char *format = NULL;
struct option options[] = {
OPT_BOOL('l', "list", &list, N_("list replace refs")),
OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
+ OPT_STRING(0, "format", &format, N_("format"), N_("use this format")),
OPT_END()
};
+ read_replace_refs = 0;
+
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
if (list && delete)
usage_msg_opt("-l and -d cannot be used together",
git_replace_usage, options);
+ if (format && delete)
+ usage_msg_opt("--format and -d cannot be used together",
+ git_replace_usage, options);
+
if (force && (list || delete))
usage_msg_opt("-f cannot be used with -d or -l",
git_replace_usage, options);
@@ -157,6 +207,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
if (argc != 2)
usage_msg_opt("bad number of arguments",
git_replace_usage, options);
+ if (format)
+ usage_msg_opt("--format cannot be used when not listing",
+ git_replace_usage, options);
return replace_object(argv[0], argv[1], force);
}
@@ -168,5 +221,5 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
usage_msg_opt("-f needs some arguments",
git_replace_usage, options);
- return list_replace_refs(argv[0]);
+ return list_replace_refs(argv[0], format);
}
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index c76b89d..aaeb611 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -9,6 +9,8 @@
#include "quote.h"
#include "builtin.h"
#include "parse-options.h"
+#include "diff.h"
+#include "revision.h"
#define DO_REVS 1
#define DO_NOREV 2
@@ -30,6 +32,9 @@ static int abbrev_ref;
static int abbrev_ref_strict;
static int output_sq;
+static int stuck_long;
+static struct string_list *ref_excludes;
+
/*
* Some arguments are relevant "revision" arguments,
* others are about output format or other details.
@@ -185,6 +190,8 @@ static int show_default(void)
static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
+ if (ref_excluded(ref_excludes, refname))
+ return 0;
show_rev(NORMAL, sha1, refname);
return 0;
}
@@ -279,6 +286,7 @@ static int try_difference(const char *arg)
exclude = n;
}
}
+ *dotdot = '.';
return 1;
}
*dotdot = '.';
@@ -302,8 +310,10 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
- if (get_sha1_committish(arg, sha1))
+ if (get_sha1_committish(arg, sha1)) {
+ *dotdot = '^';
return 0;
+ }
if (!parents_only)
show_rev(NORMAL, sha1, arg);
@@ -312,6 +322,7 @@ static int try_parent_shorthands(const char *arg)
show_rev(parents_only ? NORMAL : REVERSED,
parents->item->object.sha1, arg);
+ *dotdot = '^';
return 1;
}
@@ -320,12 +331,15 @@ static int parseopt_dump(const struct option *o, const char *arg, int unset)
struct strbuf *parsed = o->value;
if (unset)
strbuf_addf(parsed, " --no-%s", o->long_name);
- else if (o->short_name)
+ else if (o->short_name && (o->long_name == NULL || !stuck_long))
strbuf_addf(parsed, " -%c", o->short_name);
else
strbuf_addf(parsed, " --%s", o->long_name);
if (arg) {
- strbuf_addch(parsed, ' ');
+ if (!stuck_long)
+ strbuf_addch(parsed, ' ');
+ else if (o->long_name)
+ strbuf_addch(parsed, '=');
sq_quote_buf(parsed, arg);
}
return 0;
@@ -351,6 +365,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
N_("stop parsing after the "
"first non-option argument")),
+ OPT_BOOL(0, "stuck-long", &stuck_long,
+ N_("output in stuck long form")),
OPT_END(),
};
@@ -476,6 +492,7 @@ N_("git rev-parse --parseopt [options] -- [<args>...]\n"
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
{
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
+ int has_dashdash = 0;
int output_prefix = 0;
unsigned char sha1[20];
const char *name = NULL;
@@ -489,6 +506,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (argc > 1 && !strcmp("-h", argv[1]))
usage(builtin_rev_parse_usage);
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ has_dashdash = 1;
+ break;
+ }
+ }
+
prefix = setup_git_directory();
git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) {
@@ -508,7 +532,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
continue;
}
- if (!prefixcmp(arg, "-n")) {
+ if (starts_with(arg, "-n")) {
if ((filter & DO_FLAGS) && (filter & DO_REVS))
show(arg);
continue;
@@ -560,7 +584,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--short") ||
- !prefixcmp(arg, "--short=")) {
+ starts_with(arg, "--short=")) {
filter &= ~(DO_FLAGS|DO_NOREV);
verify = 1;
abbrev = DEFAULT_ABBREV;
@@ -588,7 +612,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
symbolic = SHOW_SYMBOLIC_FULL;
continue;
}
- if (!prefixcmp(arg, "--abbrev-ref") &&
+ if (starts_with(arg, "--abbrev-ref") &&
(!arg[12] || arg[12] == '=')) {
abbrev_ref = 1;
abbrev_ref_strict = warn_ambiguous_refs;
@@ -606,7 +630,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_ref(show_reference, NULL);
continue;
}
- if (!prefixcmp(arg, "--disambiguate=")) {
+ if (starts_with(arg, "--disambiguate=")) {
for_each_abbrev(arg + 15, show_abbrev, NULL);
continue;
}
@@ -615,35 +639,46 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_ref_in("refs/bisect/good", anti_reference, NULL);
continue;
}
- if (!prefixcmp(arg, "--branches=")) {
+ if (starts_with(arg, "--branches=")) {
for_each_glob_ref_in(show_reference, arg + 11,
"refs/heads/", NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
if (!strcmp(arg, "--branches")) {
for_each_branch_ref(show_reference, NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
- if (!prefixcmp(arg, "--tags=")) {
+ if (starts_with(arg, "--tags=")) {
for_each_glob_ref_in(show_reference, arg + 7,
"refs/tags/", NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
if (!strcmp(arg, "--tags")) {
for_each_tag_ref(show_reference, NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
- if (!prefixcmp(arg, "--glob=")) {
+ if (starts_with(arg, "--glob=")) {
for_each_glob_ref(show_reference, arg + 7, NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
- if (!prefixcmp(arg, "--remotes=")) {
+ if (starts_with(arg, "--remotes=")) {
for_each_glob_ref_in(show_reference, arg + 10,
"refs/remotes/", NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
if (!strcmp(arg, "--remotes")) {
for_each_remote_ref(show_reference, NULL);
+ clear_ref_exclusion(&ref_excludes);
+ continue;
+ }
+ if (starts_with(arg, "--exclude=")) {
+ add_ref_exclusion(&ref_excludes, arg + 10);
continue;
}
if (!strcmp(arg, "--local-env-vars")) {
@@ -724,19 +759,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "false");
continue;
}
- if (!prefixcmp(arg, "--since=")) {
+ if (starts_with(arg, "--since=")) {
show_datestring("--max-age=", arg+8);
continue;
}
- if (!prefixcmp(arg, "--after=")) {
+ if (starts_with(arg, "--after=")) {
show_datestring("--max-age=", arg+8);
continue;
}
- if (!prefixcmp(arg, "--before=")) {
+ if (starts_with(arg, "--before=")) {
show_datestring("--min-age=", arg+9);
continue;
}
- if (!prefixcmp(arg, "--until=")) {
+ if (starts_with(arg, "--until=")) {
show_datestring("--min-age=", arg+8);
continue;
}
@@ -765,6 +800,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (verify)
die_no_single_rev(quiet);
+ if (has_dashdash)
+ die("bad revision '%s'", arg);
as_is = 1;
if (!show_file(arg, output_prefix))
continue;
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index cc25744..f420b74 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -117,15 +117,15 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
const char *arg = *argv;
if (*arg == '-') {
- if (!prefixcmp(arg, "--receive-pack=")) {
+ if (starts_with(arg, "--receive-pack=")) {
receivepack = arg + 15;
continue;
}
- if (!prefixcmp(arg, "--exec=")) {
+ if (starts_with(arg, "--exec=")) {
receivepack = arg + 7;
continue;
}
- if (!prefixcmp(arg, "--remote=")) {
+ if (starts_with(arg, "--remote=")) {
remote_name = arg + 9;
continue;
}
@@ -183,7 +183,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
exit(1);
continue;
}
- if (!prefixcmp(arg, "--" CAS_OPT_NAME "=")) {
+ if (starts_with(arg, "--" CAS_OPT_NAME "=")) {
if (parse_push_cas_option(&cas,
strchr(arg, '=') + 1, 0) < 0)
exit(1);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index c226f76..4b7e536 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -65,7 +65,7 @@ static void insert_one_record(struct shortlog *log,
eol = strchr(oneline, '\n');
if (!eol)
eol = oneline + strlen(oneline);
- if (!prefixcmp(oneline, "[PATCH")) {
+ if (starts_with(oneline, "[PATCH")) {
char *eob = strchr(oneline, ']');
if (eob && (!eol || eob < eol))
oneline = eob + 1;
@@ -95,7 +95,7 @@ static void read_from_stdin(struct shortlog *log)
while (fgets(author, sizeof(author), stdin) != NULL) {
if (!(author[0] == 'A' || author[0] == 'a') ||
- prefixcmp(author + 1, "uthor: "))
+ !starts_with(author + 1, "uthor: "))
continue;
while (fgets(oneline, sizeof(oneline), stdin) &&
oneline[0] != '\n')
@@ -123,7 +123,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
else
eol++;
- if (!prefixcmp(buffer, "author "))
+ if (starts_with(buffer, "author "))
author = buffer + 7;
buffer = eol;
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 001f29c..d9217ce 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -227,8 +227,7 @@ static void join_revs(struct commit_list **list_p,
parents = parents->next;
if ((this_flag & flags) == flags)
continue;
- if (!p->object.parsed)
- parse_commit(p);
+ parse_commit(p);
if (mark_seen(p, seen_p) && !still_interesting)
extra--;
p->object.flags |= flags;
@@ -285,7 +284,7 @@ static void show_one_commit(struct commit *commit, int no_name)
pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
pretty_str = pretty.buf;
}
- if (!prefixcmp(pretty_str, "[PATCH] "))
+ if (starts_with(pretty_str, "[PATCH] "))
pretty_str += 8;
if (!no_name) {
@@ -396,7 +395,7 @@ static int append_head_ref(const char *refname, const unsigned char *sha1, int f
{
unsigned char tmp[20];
int ofs = 11;
- if (prefixcmp(refname, "refs/heads/"))
+ if (!starts_with(refname, "refs/heads/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
@@ -410,7 +409,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
{
unsigned char tmp[20];
int ofs = 13;
- if (prefixcmp(refname, "refs/remotes/"))
+ if (!starts_with(refname, "refs/remotes/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
@@ -422,7 +421,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- if (prefixcmp(refname, "refs/tags/"))
+ if (!starts_with(refname, "refs/tags/"))
return 0;
return append_ref(refname + 5, sha1, 0);
}
@@ -453,9 +452,9 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
return 0;
if (fnmatch(match_ref_pattern, tail, 0))
return 0;
- if (!prefixcmp(refname, "refs/heads/"))
+ if (starts_with(refname, "refs/heads/"))
return append_head_ref(refname, sha1, flag, cb_data);
- if (!prefixcmp(refname, "refs/tags/"))
+ if (starts_with(refname, "refs/tags/"))
return append_tag_ref(refname, sha1, flag, cb_data);
return append_ref(refname, sha1, 0);
}
@@ -480,11 +479,11 @@ static int rev_is_head(char *head, int headlen, char *name,
if ((!head[0]) ||
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
return 0;
- if (!prefixcmp(head, "refs/heads/"))
+ if (starts_with(head, "refs/heads/"))
head += 11;
- if (!prefixcmp(name, "refs/heads/"))
+ if (starts_with(name, "refs/heads/"))
name += 11;
- else if (!prefixcmp(name, "heads/"))
+ else if (starts_with(name, "heads/"))
name += 6;
return !strcmp(head, name);
}
@@ -813,7 +812,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
has_head++;
}
if (!has_head) {
- int offset = !prefixcmp(head, "refs/heads/") ? 11 : 0;
+ int offset = starts_with(head, "refs/heads/") ? 11 : 0;
append_one_rev(head + offset);
}
}
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 9f3f5e3..5ba1f30 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -37,8 +37,8 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
if (tags_only || heads_only) {
int match;
- match = heads_only && !prefixcmp(refname, "refs/heads/");
- match |= tags_only && !prefixcmp(refname, "refs/tags/");
+ match = heads_only && starts_with(refname, "refs/heads/");
+ match |= tags_only && starts_with(refname, "refs/tags/");
if (!match)
return 0;
}
@@ -210,7 +210,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
while (*pattern) {
unsigned char sha1[20];
- if (!prefixcmp(*pattern, "refs/") &&
+ if (starts_with(*pattern, "refs/") &&
!read_ref(*pattern, sha1)) {
if (!quiet)
show_one(*pattern, sha1);
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 71286b4..b6a711d 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -65,7 +65,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
break;
case 2:
if (!strcmp(argv[0], "HEAD") &&
- prefixcmp(argv[1], "refs/"))
+ !starts_with(argv[1], "refs/"))
die("Refusing to point HEAD outside of refs/");
create_symref(argv[0], argv[1], msg);
break;
diff --git a/builtin/tag.c b/builtin/tag.c
index ea55f1d..74d3780 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -259,7 +259,7 @@ static int git_tag_config(const char *var, const char *value, void *cb)
int status = git_gpg_config(var, value, cb);
if (status)
return status;
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "tag", &colopts);
return git_default_config(var, value, cb);
}
diff --git a/builtin/tar-tree.c b/builtin/tar-tree.c
deleted file mode 100644
index ba3ffe6..0000000
--- a/builtin/tar-tree.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2005, 2006 Rene Scharfe
- */
-#include "cache.h"
-#include "commit.h"
-#include "tar.h"
-#include "builtin.h"
-#include "quote.h"
-
-static const char tar_tree_usage[] =
-"git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
-"*** Note that this command is now deprecated; use \"git archive\" instead.";
-
-static const char builtin_get_tar_commit_id_usage[] =
-"git get-tar-commit-id < <tarfile>";
-
-int cmd_tar_tree(int argc, const char **argv, const char *prefix)
-{
- /*
- * "git tar-tree" is now a wrapper around "git archive --format=tar"
- *
- * $0 --remote=<repo> arg... ==>
- * git archive --format=tar --remote=<repo> arg...
- * $0 tree-ish ==>
- * git archive --format=tar tree-ish
- * $0 tree-ish basedir ==>
- * git archive --format-tar --prefix=basedir tree-ish
- */
- const char **nargv = xcalloc(sizeof(*nargv), argc + 3);
- struct strbuf sb = STRBUF_INIT;
- char *basedir_arg;
- int nargc = 0;
-
- nargv[nargc++] = "archive";
- nargv[nargc++] = "--format=tar";
-
- if (2 <= argc && !prefixcmp(argv[1], "--remote=")) {
- nargv[nargc++] = argv[1];
- argv++;
- argc--;
- }
-
- /*
- * Because it's just a compatibility wrapper, tar-tree supports only
- * the old behaviour of reading attributes from the work tree.
- */
- nargv[nargc++] = "--worktree-attributes";
-
- switch (argc) {
- default:
- usage(tar_tree_usage);
- break;
- case 3:
- /* base-path */
- basedir_arg = xmalloc(strlen(argv[2]) + 11);
- sprintf(basedir_arg, "--prefix=%s/", argv[2]);
- nargv[nargc++] = basedir_arg;
- /* fallthru */
- case 2:
- /* tree-ish */
- nargv[nargc++] = argv[1];
- }
- nargv[nargc] = NULL;
-
- fprintf(stderr,
- "*** \"git tar-tree\" is now deprecated.\n"
- "*** Running \"git archive\" instead.\n***");
- sq_quote_argv(&sb, nargv, 0);
- strbuf_addch(&sb, '\n');
- fputs(sb.buf, stderr);
- strbuf_release(&sb);
- return cmd_archive(nargc, nargv, prefix);
-}
-
-/* ustar header + extended global header content */
-#define RECORDSIZE (512)
-#define HEADERSIZE (2 * RECORDSIZE)
-
-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
-{
- char buffer[HEADERSIZE];
- struct ustar_header *header = (struct ustar_header *)buffer;
- char *content = buffer + RECORDSIZE;
- ssize_t n;
-
- if (argc != 1)
- usage(builtin_get_tar_commit_id_usage);
-
- n = read_in_full(0, buffer, HEADERSIZE);
- if (n < HEADERSIZE)
- die("git get-tar-commit-id: read error");
- if (header->typeflag[0] != 'g')
- return 1;
- if (memcmp(content, "52 comment=", 11))
- return 1;
-
- n = write_in_full(1, content + 11, 41);
- if (n < 41)
- die_errno("git get-tar-commit-id: write error");
-
- return 0;
-}
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 2217d7b..62ff673 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -523,7 +523,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
strict = 1;
continue;
}
- if (!prefixcmp(arg, "--pack_header=")) {
+ if (starts_with(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 702e90d..1292cfe 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -229,15 +229,15 @@ static void update_refs_stdin(void)
die("empty command in input");
else if (isspace(*cmd.buf))
die("whitespace before command: %s", cmd.buf);
- else if (!prefixcmp(cmd.buf, "update "))
+ else if (starts_with(cmd.buf, "update "))
parse_cmd_update(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "create "))
+ else if (starts_with(cmd.buf, "create "))
parse_cmd_create(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "delete "))
+ else if (starts_with(cmd.buf, "delete "))
parse_cmd_delete(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "verify "))
+ else if (starts_with(cmd.buf, "verify "))
parse_cmd_verify(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "option "))
+ else if (starts_with(cmd.buf, "option "))
parse_cmd_option(cmd.buf + 7);
else
die("unknown command: %s", cmd.buf);
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index af2da35..32ab94c 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -37,7 +37,7 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
if (sent_argv.argc > MAX_ARGS)
die("Too many options (>%d)", MAX_ARGS - 1);
- if (prefixcmp(buf, arg_cmd))
+ if (!starts_with(buf, arg_cmd))
die("'argument' token or flush expected");
argv_array_push(&sent_argv, buf + strlen(arg_cmd));
}
diff --git a/bundle.c b/bundle.c
index 3d64311..e99065c 100644
--- a/bundle.c
+++ b/bundle.c
@@ -7,6 +7,7 @@
#include "list-objects.h"
#include "run-command.h"
#include "refs.h"
+#include "argv-array.h"
static const char bundle_signature[] = "# v2 git bundle\n";
@@ -234,13 +235,13 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)
}
int create_bundle(struct bundle_header *header, const char *path,
- int argc, const char **argv)
+ int argc, const char **argv)
{
static struct lock_file lock;
int bundle_fd = -1;
int bundle_to_stdout;
- const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
- const char **argv_pack = xmalloc(6 * sizeof(const char *));
+ struct argv_array argv_boundary = ARGV_ARRAY_INIT;
+ struct argv_array argv_pack = ARGV_ARRAY_INIT;
int i, ref_count = 0;
struct strbuf buf = STRBUF_INIT;
struct rev_info revs;
@@ -262,13 +263,14 @@ int create_bundle(struct bundle_header *header, const char *path,
init_revisions(&revs, NULL);
/* write prerequisites */
- memcpy(argv_boundary + 3, argv + 1, argc * sizeof(const char *));
- argv_boundary[0] = "rev-list";
- argv_boundary[1] = "--boundary";
- argv_boundary[2] = "--pretty=oneline";
- argv_boundary[argc + 2] = NULL;
+ argv_array_pushl(&argv_boundary,
+ "rev-list", "--boundary", "--pretty=oneline",
+ NULL);
+ for (i = 1; i < argc; i++)
+ argv_array_push(&argv_boundary, argv[i]);
+
memset(&rls, 0, sizeof(rls));
- rls.argv = argv_boundary;
+ rls.argv = argv_boundary.argv;
rls.out = -1;
rls.git_cmd = 1;
if (start_command(&rls))
@@ -383,14 +385,12 @@ int create_bundle(struct bundle_header *header, const char *path,
write_or_die(bundle_fd, "\n", 1);
/* write pack */
- argv_pack[0] = "pack-objects";
- argv_pack[1] = "--all-progress-implied";
- argv_pack[2] = "--stdout";
- argv_pack[3] = "--thin";
- argv_pack[4] = "--delta-base-offset";
- argv_pack[5] = NULL;
+ argv_array_pushl(&argv_pack,
+ "pack-objects", "--all-progress-implied",
+ "--stdout", "--thin", "--delta-base-offset",
+ NULL);
memset(&rls, 0, sizeof(rls));
- rls.argv = argv_pack;
+ rls.argv = argv_pack.argv;
rls.in = -1;
rls.out = bundle_fd;
rls.git_cmd = 1;
diff --git a/cache.h b/cache.h
index 8b13287..c9efe88 100644
--- a/cache.h
+++ b/cache.h
@@ -761,11 +761,11 @@ int daemon_avoid_alias(const char *path);
int offset_1st_component(const char *path);
/* object replacement */
-#define READ_SHA1_FILE_REPLACE 1
+#define LOOKUP_REPLACE_OBJECT 1
extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
{
- return read_sha1_file_extended(sha1, type, size, READ_SHA1_FILE_REPLACE);
+ return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
}
extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
static inline const unsigned char *lookup_replace_object(const unsigned char *sha1)
@@ -774,6 +774,12 @@ static inline const unsigned char *lookup_replace_object(const unsigned char *sh
return sha1;
return do_lookup_replace_object(sha1);
}
+static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
+{
+ if (!(flag & LOOKUP_REPLACE_OBJECT))
+ return sha1;
+ return lookup_replace_object(sha1);
+}
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *);
@@ -1075,6 +1081,7 @@ struct object_info {
enum object_type *typep;
unsigned long *sizep;
unsigned long *disk_sizep;
+ unsigned char *delta_base_sha1;
/* Response */
enum {
@@ -1099,7 +1106,7 @@ struct object_info {
} packed;
} u;
};
-extern int sha1_object_info_extended(const unsigned char *, struct object_info *);
+extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
/* Dumb servers support */
extern int update_server_info(int);
diff --git a/command-list.txt b/command-list.txt
index 08b04e2..cf36c3d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -64,7 +64,6 @@ git-init mainporcelain common
git-instaweb ancillaryinterrogators
gitk mainporcelain
git-log mainporcelain common
-git-lost-found ancillarymanipulators deprecated
git-ls-files plumbinginterrogators
git-ls-remote plumbinginterrogators
git-ls-tree plumbinginterrogators
@@ -88,7 +87,6 @@ git-pack-redundant plumbinginterrogators
git-pack-refs ancillarymanipulators
git-parse-remote synchelpers
git-patch-id purehelpers
-git-peek-remote purehelpers deprecated
git-prune ancillarymanipulators
git-prune-packed plumbingmanipulators
git-pull mainporcelain common
@@ -102,7 +100,6 @@ git-relink ancillarymanipulators
git-remote ancillarymanipulators
git-repack ancillarymanipulators
git-replace ancillarymanipulators
-git-repo-config ancillarymanipulators deprecated
git-request-pull foreignscminterface
git-rerere ancillaryinterrogators
git-reset mainporcelain common
@@ -127,7 +124,6 @@ git-submodule mainporcelain
git-svn foreignscminterface
git-symbolic-ref plumbingmanipulators
git-tag mainporcelain common
-git-tar-tree plumbinginterrogators deprecated
git-unpack-file plumbinginterrogators
git-unpack-objects plumbingmanipulators
git-update-index plumbingmanipulators
diff --git a/commit-slab.h b/commit-slab.h
index d4c8286..cc114b5 100644
--- a/commit-slab.h
+++ b/commit-slab.h
@@ -22,8 +22,17 @@
*
* Initializes the indegree slab that associates an array of integers
* to each commit. 'stride' specifies how big each array is. The slab
- * that id initialied by the variant without "_with_stride" associates
+ * that is initialized by the variant without "_with_stride" associates
* each commit with an array of one integer.
+ *
+ * - void clear_indegree(struct indegree *);
+ *
+ * Empties the slab. The slab can be reused with the same stride
+ * without calling init_indegree() again or can be reconfigured to a
+ * different stride by calling init_indegree_with_stride().
+ *
+ * Call this function before the slab falls out of scope to avoid
+ * leaking memory.
*/
/* allocate ~512kB at once, allowing for malloc overhead */
@@ -31,6 +40,8 @@
#define COMMIT_SLAB_SIZE (512*1024-32)
#endif
+#define MAYBE_UNUSED __attribute__((__unused__))
+
#define define_commit_slab(slabname, elemtype) \
\
struct slabname { \
@@ -41,8 +52,8 @@ struct slabname { \
}; \
static int stat_ ##slabname## realloc; \
\
-static void init_ ##slabname## _with_stride(struct slabname *s, \
- unsigned stride) \
+static MAYBE_UNUSED void init_ ##slabname## _with_stride(struct slabname *s, \
+ unsigned stride) \
{ \
unsigned int elem_size; \
if (!stride) \
@@ -54,12 +65,12 @@ static void init_ ##slabname## _with_stride(struct slabname *s, \
s->slab = NULL; \
} \
\
-static void init_ ##slabname(struct slabname *s) \
+static MAYBE_UNUSED void init_ ##slabname(struct slabname *s) \
{ \
init_ ##slabname## _with_stride(s, 1); \
} \
\
-static void clear_ ##slabname(struct slabname *s) \
+static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s) \
{ \
int i; \
for (i = 0; i < s->slab_count; i++) \
@@ -69,8 +80,8 @@ static void clear_ ##slabname(struct slabname *s) \
s->slab = NULL; \
} \
\
-static elemtype *slabname## _at(struct slabname *s, \
- const struct commit *c) \
+static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
+ const struct commit *c) \
{ \
int nth_slab, nth_slot; \
\
@@ -80,7 +91,7 @@ static elemtype *slabname## _at(struct slabname *s, \
if (s->slab_count <= nth_slab) { \
int i; \
s->slab = xrealloc(s->slab, \
- (nth_slab + 1) * sizeof(s->slab)); \
+ (nth_slab + 1) * sizeof(*s->slab)); \
stat_ ##slabname## realloc++; \
for (i = s->slab_count; i <= nth_slab; i++) \
s->slab[i] = NULL; \
@@ -94,4 +105,16 @@ static elemtype *slabname## _at(struct slabname *s, \
\
static int stat_ ##slabname## realloc
+/*
+ * Note that this seemingly redundant second declaration is required
+ * to allow a terminating semicolon, which makes instantiations look
+ * like function declarations. I.e., the expansion of
+ *
+ * define_commit_slab(indegree, int);
+ *
+ * ends in 'static int stat_indegreerealloc;'. This would otherwise
+ * be a syntax error according (at least) to ISO C. It's hard to
+ * catch because GCC silently parses it by default.
+ */
+
#endif /* COMMIT_SLAB_H */
diff --git a/commit.c b/commit.c
index de16a3c..6bf4fe0 100644
--- a/commit.c
+++ b/commit.c
@@ -79,7 +79,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
if (get_sha1_committish(name, sha1))
return NULL;
commit = lookup_commit_reference(sha1);
- if (!commit || parse_commit(commit))
+ if (parse_commit(commit))
return NULL;
return commit;
}
@@ -196,19 +196,19 @@ bad_graft_data:
static int read_graft_file(const char *graft_file)
{
FILE *fp = fopen(graft_file, "r");
- char buf[1024];
+ struct strbuf buf = STRBUF_INIT;
if (!fp)
return -1;
- while (fgets(buf, sizeof(buf), fp)) {
+ while (!strbuf_getwholeline(&buf, fp, '\n')) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
- int len = strlen(buf);
- struct commit_graft *graft = read_graft_line(buf, len);
+ struct commit_graft *graft = read_graft_line(buf.buf, buf.len);
if (!graft)
continue;
if (register_commit_graft(graft, 1))
- error("duplicate graft data: %s", buf);
+ error("duplicate graft data: %s", buf.buf);
}
fclose(fp);
+ strbuf_release(&buf);
return 0;
}
@@ -341,6 +341,13 @@ int parse_commit(struct commit *item)
return ret;
}
+void parse_commit_or_die(struct commit *item)
+{
+ if (parse_commit(item))
+ die("unable to parse commit %s",
+ item ? sha1_to_hex(item->object.sha1) : "(null)");
+}
+
int find_commit_subject(const char *commit_buffer, const char **subject)
{
const char *eol;
@@ -559,7 +566,7 @@ static void record_author_date(struct author_date_slab *author_date,
buf;
buf = line_end + 1) {
line_end = strchrnul(buf, '\n');
- if (prefixcmp(buf, "author ")) {
+ if (!starts_with(buf, "author ")) {
if (!line_end[0] || line_end[1] == '\n')
return; /* end of header */
continue;
@@ -834,26 +841,26 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
struct commit_list *get_octopus_merge_bases(struct commit_list *in)
{
struct commit_list *i, *j, *k, *ret = NULL;
- struct commit_list **pptr = &ret;
- for (i = in; i; i = i->next) {
- if (!ret)
- pptr = &commit_list_insert(i->item, pptr)->next;
- else {
- struct commit_list *new = NULL, *end = NULL;
-
- for (j = ret; j; j = j->next) {
- struct commit_list *bases;
- bases = get_merge_bases(i->item, j->item, 1);
- if (!new)
- new = bases;
- else
- end->next = bases;
- for (k = bases; k; k = k->next)
- end = k;
- }
- ret = new;
+ if (!in)
+ return ret;
+
+ commit_list_insert(in->item, &ret);
+
+ for (i = in->next; i; i = i->next) {
+ struct commit_list *new = NULL, *end = NULL;
+
+ for (j = ret; j; j = j->next) {
+ struct commit_list *bases;
+ bases = get_merge_bases(i->item, j->item, 1);
+ if (!new)
+ new = bases;
+ else
+ end->next = bases;
+ for (k = bases; k; k = k->next)
+ end = k;
}
+ ret = new;
}
return ret;
}
@@ -1106,7 +1113,7 @@ int parse_signed_commit(const unsigned char *sha1,
next = next ? next + 1 : tail;
if (in_signature && line[0] == ' ')
sig = line + 1;
- else if (!prefixcmp(line, gpg_sig_header) &&
+ else if (starts_with(line, gpg_sig_header) &&
line[gpg_sig_header_len] == ' ')
sig = line + gpg_sig_header_len + 1;
if (sig) {
@@ -1186,7 +1193,7 @@ static void parse_gpg_output(struct signature_check *sigc)
for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
const char *found, *next;
- if (!prefixcmp(buf, sigcheck_gpg_status[i].check + 1)) {
+ if (starts_with(buf, sigcheck_gpg_status[i].check + 1)) {
/* At the very beginning of the buffer */
found = buf + strlen(sigcheck_gpg_status[i].check + 1);
} else {
@@ -1349,7 +1356,7 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
}
}
-int commit_tree(const struct strbuf *msg, unsigned char *tree,
+int commit_tree(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit)
{
@@ -1478,7 +1485,7 @@ static const char commit_utf8_warn[] =
"You may want to amend it after fixing the message, or set the config\n"
"variable i18n.commitencoding to the encoding your project uses.\n";
-int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
+int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *extra)
diff --git a/commit.h b/commit.h
index 2a20b10..16d9c43 100644
--- a/commit.h
+++ b/commit.h
@@ -49,6 +49,7 @@ struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_n
int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size);
int parse_commit(struct commit *item);
+void parse_commit_or_die(struct commit *item);
/* Find beginning and length of commit subject. */
int find_commit_subject(const char *commit_buffer, const char **subject);
@@ -260,11 +261,11 @@ struct commit_extra_header {
extern void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail);
-extern int commit_tree(const struct strbuf *msg, unsigned char *tree,
+extern int commit_tree(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit);
-extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
+extern int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *);
diff --git a/compat/vcbuild/scripts/clink.pl b/compat/vcbuild/scripts/clink.pl
index 4374771..4374771 100644..100755
--- a/compat/vcbuild/scripts/clink.pl
+++ b/compat/vcbuild/scripts/clink.pl
diff --git a/compat/vcbuild/scripts/lib.pl b/compat/vcbuild/scripts/lib.pl
index d8054e4..d8054e4 100644..100755
--- a/compat/vcbuild/scripts/lib.pl
+++ b/compat/vcbuild/scripts/lib.pl
diff --git a/config.c b/config.c
index e1d66a1..d969a5a 100644
--- a/config.c
+++ b/config.c
@@ -969,25 +969,25 @@ static int git_default_mailmap_config(const char *var, const char *value)
int git_default_config(const char *var, const char *value, void *dummy)
{
- if (!prefixcmp(var, "core."))
+ if (starts_with(var, "core."))
return git_default_core_config(var, value);
- if (!prefixcmp(var, "user."))
+ if (starts_with(var, "user."))
return git_ident_config(var, value, dummy);
- if (!prefixcmp(var, "i18n."))
+ if (starts_with(var, "i18n."))
return git_default_i18n_config(var, value);
- if (!prefixcmp(var, "branch."))
+ if (starts_with(var, "branch."))
return git_default_branch_config(var, value);
- if (!prefixcmp(var, "push."))
+ if (starts_with(var, "push."))
return git_default_push_config(var, value);
- if (!prefixcmp(var, "mailmap."))
+ if (starts_with(var, "mailmap."))
return git_default_mailmap_config(var, value);
- if (!prefixcmp(var, "advice."))
+ if (starts_with(var, "advice."))
return git_default_advice_config(var, value);
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
@@ -1210,15 +1210,14 @@ int git_config(config_fn_t fn, void *data)
* Find all the stuff for git_config_set() below.
*/
-#define MAX_MATCHES 512
-
static struct {
int baselen;
char *key;
int do_not_match;
regex_t *value_regex;
int multi_replace;
- size_t offset[MAX_MATCHES];
+ size_t *offset;
+ unsigned int offset_alloc;
enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
int seen;
} store;
@@ -1241,11 +1240,11 @@ static int store_aux(const char *key, const char *value, void *cb)
if (matches(key, value)) {
if (store.seen == 1 && store.multi_replace == 0) {
warning("%s has multiple values", key);
- } else if (store.seen >= MAX_MATCHES) {
- error("too many matches for %s", key);
- return 1;
}
+ ALLOC_GROW(store.offset, store.seen + 1,
+ store.offset_alloc);
+
store.offset[store.seen] = cf->do_ftell(cf);
store.seen++;
}
@@ -1273,11 +1272,15 @@ static int store_aux(const char *key, const char *value, void *cb)
* Do not increment matches: this is no match, but we
* just made sure we are in the desired section.
*/
+ ALLOC_GROW(store.offset, store.seen + 1,
+ store.offset_alloc);
store.offset[store.seen] = cf->do_ftell(cf);
/* fallthru */
case SECTION_END_SEEN:
case START:
if (matches(key, value)) {
+ ALLOC_GROW(store.offset, store.seen + 1,
+ store.offset_alloc);
store.offset[store.seen] = cf->do_ftell(cf);
store.state = KEY_SEEN;
store.seen++;
@@ -1285,6 +1288,9 @@ static int store_aux(const char *key, const char *value, void *cb)
if (strrchr(key, '.') - key == store.baselen &&
!strncmp(key, store.key, store.baselen)) {
store.state = SECTION_SEEN;
+ ALLOC_GROW(store.offset,
+ store.seen + 1,
+ store.offset_alloc);
store.offset[store.seen] = cf->do_ftell(cf);
}
}
@@ -1583,6 +1589,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
}
}
+ ALLOC_GROW(store.offset, 1, store.offset_alloc);
store.offset[0] = 0;
store.state = START;
store.seen = 0;
@@ -1872,7 +1879,7 @@ int parse_config_key(const char *var,
const char *dot;
/* Does it start with "section." ? */
- if (prefixcmp(var, section) || var[section_len] != '.')
+ if (!starts_with(var, section) || var[section_len] != '.')
return -1;
/*
diff --git a/config.mak.uname b/config.mak.uname
index 82d549e..7d31fad 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -198,6 +198,13 @@ ifeq ($(uname_S),OpenBSD)
BASIC_LDFLAGS += -L/usr/local/lib
HAVE_PATHS_H = YesPlease
endif
+ifeq ($(uname_S),MirBSD)
+ NO_STRCASESTR = YesPlease
+ NO_MEMMEM = YesPlease
+ USE_ST_TIMESPEC = YesPlease
+ NEEDS_LIBICONV = YesPlease
+ HAVE_PATHS_H = YesPlease
+endif
ifeq ($(uname_S),NetBSD)
ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
NEEDS_LIBICONV = YesPlease
diff --git a/connect.c b/connect.c
index efadd3c..4150412 100644
--- a/connect.c
+++ b/connect.c
@@ -140,10 +140,10 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
if (!len)
break;
- if (len > 4 && !prefixcmp(buffer, "ERR "))
+ if (len > 4 && starts_with(buffer, "ERR "))
die("remote error: %s", buffer + 4);
- if (len == 48 && !prefixcmp(buffer, "shallow ")) {
+ if (len == 48 && starts_with(buffer, "shallow ")) {
if (get_sha1_hex(buffer + 8, old_sha1))
die("protocol error: expected shallow sha-1, got '%s'", buffer + 8);
if (!shallow_points)
@@ -236,10 +236,34 @@ int server_supports(const char *feature)
enum protocol {
PROTO_LOCAL = 1,
+ PROTO_FILE,
PROTO_SSH,
PROTO_GIT
};
+int url_is_local_not_ssh(const char *url)
+{
+ const char *colon = strchr(url, ':');
+ const char *slash = strchr(url, '/');
+ return !colon || (slash && slash < colon) ||
+ has_dos_drive_prefix(url);
+}
+
+static const char *prot_name(enum protocol protocol)
+{
+ switch (protocol) {
+ case PROTO_LOCAL:
+ case PROTO_FILE:
+ return "file";
+ case PROTO_SSH:
+ return "ssh";
+ case PROTO_GIT:
+ return "git";
+ default:
+ return "unkown protocol";
+ }
+}
+
static enum protocol get_protocol(const char *name)
{
if (!strcmp(name, "ssh"))
@@ -251,7 +275,7 @@ static enum protocol get_protocol(const char *name)
if (!strcmp(name, "ssh+git"))
return PROTO_SSH;
if (!strcmp(name, "file"))
- return PROTO_LOCAL;
+ return PROTO_FILE;
die("I don't handle protocol '%s'", name);
}
@@ -531,55 +555,31 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
return proxy;
}
-#define MAX_CMD_LEN 1024
-
-static char *get_port(char *host)
+static const char *get_port_numeric(const char *p)
{
char *end;
- char *p = strchr(host, ':');
-
if (p) {
long port = strtol(p + 1, &end, 10);
if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) {
- *p = '\0';
- return p+1;
+ return p;
}
}
return NULL;
}
-static struct child_process no_fork;
-
/*
- * This returns a dummy child_process if the transport protocol does not
- * need fork(2), or a struct child_process object if it does. Once done,
- * finish the connection with finish_connect() with the value returned from
- * this function (it is safe to call finish_connect() with NULL to support
- * the former case).
- *
- * If it returns, the connect is successful; it just dies on errors (this
- * will hopefully be changed in a libification effort, to return NULL when
- * the connection failed).
+ * Extract protocol and relevant parts from the specified connection URL.
+ * The caller must free() the returned strings.
*/
-struct child_process *git_connect(int fd[2], const char *url_orig,
- const char *prog, int flags)
+static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
+ char **ret_path)
{
char *url;
char *host, *path;
char *end;
- int c;
- struct child_process *conn = &no_fork;
+ int separator = '/';
enum protocol protocol = PROTO_LOCAL;
- int free_path = 0;
- char *port = NULL;
- const char **arg;
- struct strbuf cmd;
-
- /* Without this we cannot rely on waitpid() to tell
- * what happened to our children.
- */
- signal(SIGCHLD, SIG_DFL);
if (is_url(url_orig))
url = url_decode(url_orig);
@@ -591,40 +591,33 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
*host = '\0';
protocol = get_protocol(url);
host += 3;
- c = '/';
} else {
host = url;
- c = ':';
+ if (!url_is_local_not_ssh(url)) {
+ protocol = PROTO_SSH;
+ separator = ':';
+ }
}
/*
- * Don't do destructive transforms with git:// as that
- * protocol code does '[]' unwrapping of its own.
+ * Don't do destructive transforms as protocol code does
+ * '[]' unwrapping in get_host_and_port()
*/
if (host[0] == '[') {
end = strchr(host + 1, ']');
if (end) {
- if (protocol != PROTO_GIT) {
- *end = 0;
- host++;
- }
end++;
} else
end = host;
} else
end = host;
- path = strchr(end, c);
- if (path && !has_dos_drive_prefix(end)) {
- if (c == ':') {
- if (host != url || path < strchrnul(host, '/')) {
- protocol = PROTO_SSH;
- *path++ = '\0';
- } else /* '/' in the host part, assume local path */
- path = end;
- }
- } else
+ if (protocol == PROTO_LOCAL)
path = end;
+ else if (protocol == PROTO_FILE && has_dos_drive_prefix(end))
+ path = end; /* "file://$(pwd)" may be "file://C:/projects/repo" */
+ else
+ path = strchr(end, separator);
if (!path || !*path)
die("No path specified. See 'man git-pull' for valid url syntax");
@@ -633,33 +626,67 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
* null-terminate hostname and point path to ~ for URL's like this:
* ssh://host.xz/~user/repo
*/
- if (protocol != PROTO_LOCAL && host != url) {
- char *ptr = path;
+
+ end = path; /* Need to \0 terminate host here */
+ if (separator == ':')
+ path++; /* path starts after ':' */
+ if (protocol == PROTO_GIT || protocol == PROTO_SSH) {
if (path[1] == '~')
path++;
- else {
- path = xstrdup(ptr);
- free_path = 1;
- }
-
- *ptr = '\0';
}
- /*
- * Add support for ssh port: ssh://host.xy:<port>/...
+ path = xstrdup(path);
+ *end = '\0';
+
+ *ret_host = xstrdup(host);
+ *ret_path = path;
+ free(url);
+ return protocol;
+}
+
+static struct child_process no_fork;
+
+/*
+ * This returns a dummy child_process if the transport protocol does not
+ * need fork(2), or a struct child_process object if it does. Once done,
+ * finish the connection with finish_connect() with the value returned from
+ * this function (it is safe to call finish_connect() with NULL to support
+ * the former case).
+ *
+ * If it returns, the connect is successful; it just dies on errors (this
+ * will hopefully be changed in a libification effort, to return NULL when
+ * the connection failed).
+ */
+struct child_process *git_connect(int fd[2], const char *url,
+ const char *prog, int flags)
+{
+ char *hostandport, *path;
+ struct child_process *conn = &no_fork;
+ enum protocol protocol;
+ const char **arg;
+ struct strbuf cmd = STRBUF_INIT;
+
+ /* Without this we cannot rely on waitpid() to tell
+ * what happened to our children.
*/
- if (protocol == PROTO_SSH && host != url)
- port = get_port(end);
+ signal(SIGCHLD, SIG_DFL);
- if (protocol == PROTO_GIT) {
+ protocol = parse_connect_url(url, &hostandport, &path);
+ if (flags & CONNECT_DIAG_URL) {
+ printf("Diag: url=%s\n", url ? url : "NULL");
+ printf("Diag: protocol=%s\n", prot_name(protocol));
+ printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
+ printf("Diag: path=%s\n", path ? path : "NULL");
+ conn = NULL;
+ } else if (protocol == PROTO_GIT) {
/* These underlying connection commands die() if they
* cannot connect.
*/
- char *target_host = xstrdup(host);
- if (git_use_proxy(host))
- conn = git_proxy_connect(fd, host);
+ char *target_host = xstrdup(hostandport);
+ if (git_use_proxy(hostandport))
+ conn = git_proxy_connect(fd, hostandport);
else
- git_tcp_connect(fd, host, flags);
+ git_tcp_connect(fd, hostandport, flags);
/*
* Separate original protocol components prog and path
* from extended host header with a NUL byte.
@@ -672,55 +699,51 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
prog, path, 0,
target_host, 0);
free(target_host);
- free(url);
- if (free_path)
- free(path);
- return conn;
- }
-
- conn = xcalloc(1, sizeof(*conn));
-
- strbuf_init(&cmd, MAX_CMD_LEN);
- strbuf_addstr(&cmd, prog);
- strbuf_addch(&cmd, ' ');
- sq_quote_buf(&cmd, path);
- if (cmd.len >= MAX_CMD_LEN)
- die("command line too long");
-
- conn->in = conn->out = -1;
- conn->argv = arg = xcalloc(7, sizeof(*arg));
- if (protocol == PROTO_SSH) {
- const char *ssh = getenv("GIT_SSH");
- int putty = ssh && strcasestr(ssh, "plink");
- if (!ssh) ssh = "ssh";
-
- *arg++ = ssh;
- if (putty && !strcasestr(ssh, "tortoiseplink"))
- *arg++ = "-batch";
- if (port) {
- /* P is for PuTTY, p is for OpenSSH */
- *arg++ = putty ? "-P" : "-p";
- *arg++ = port;
+ } else {
+ conn = xcalloc(1, sizeof(*conn));
+
+ strbuf_addstr(&cmd, prog);
+ strbuf_addch(&cmd, ' ');
+ sq_quote_buf(&cmd, path);
+
+ conn->in = conn->out = -1;
+ conn->argv = arg = xcalloc(7, sizeof(*arg));
+ if (protocol == PROTO_SSH) {
+ const char *ssh = getenv("GIT_SSH");
+ int putty = ssh && strcasestr(ssh, "plink");
+ char *ssh_host = hostandport;
+ const char *port = NULL;
+ get_host_and_port(&ssh_host, &port);
+ port = get_port_numeric(port);
+
+ if (!ssh) ssh = "ssh";
+
+ *arg++ = ssh;
+ if (putty && !strcasestr(ssh, "tortoiseplink"))
+ *arg++ = "-batch";
+ if (port) {
+ /* P is for PuTTY, p is for OpenSSH */
+ *arg++ = putty ? "-P" : "-p";
+ *arg++ = port;
+ }
+ *arg++ = ssh_host;
+ } else {
+ /* remove repo-local variables from the environment */
+ conn->env = local_repo_env;
+ conn->use_shell = 1;
}
- *arg++ = host;
- }
- else {
- /* remove repo-local variables from the environment */
- conn->env = local_repo_env;
- conn->use_shell = 1;
- }
- *arg++ = cmd.buf;
- *arg = NULL;
+ *arg++ = cmd.buf;
+ *arg = NULL;
- if (start_command(conn))
- die("unable to fork");
+ if (start_command(conn))
+ die("unable to fork");
- fd[0] = conn->out; /* read from child's stdout */
- fd[1] = conn->in; /* write to child's stdin */
- strbuf_release(&cmd);
- free(url);
- if (free_path)
- free(path);
+ fd[0] = conn->out; /* read from child's stdout */
+ fd[1] = conn->in; /* write to child's stdin */
+ strbuf_release(&cmd);
+ }
+ free(hostandport);
+ free(path);
return conn;
}
diff --git a/connect.h b/connect.h
index 64fb7db..c41a685 100644
--- a/connect.h
+++ b/connect.h
@@ -2,11 +2,13 @@
#define CONNECT_H
#define CONNECT_VERBOSE (1u << 0)
+#define CONNECT_DIAG_URL (1u << 1)
extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
extern int finish_connect(struct child_process *conn);
extern int git_connection_is_socket(struct child_process *conn);
extern int server_supports(const char *feature);
extern int parse_feature_request(const char *features, const char *feature);
extern const char *server_feature_value(const char *feature, int *len_ret);
+extern int url_is_local_not_ssh(const char *url);
#endif
diff --git a/connected.c b/connected.c
index 427389d..be0253e 100644
--- a/connected.c
+++ b/connected.c
@@ -38,7 +38,7 @@ static int check_everything_connected_real(sha1_iterate_fn fn,
if (transport && transport->smart_options &&
transport->smart_options->self_contained_and_connected &&
transport->pack_lockfile &&
- !suffixcmp(transport->pack_lockfile, ".keep")) {
+ ends_with(transport->pack_lockfile, ".keep")) {
struct strbuf idx_file = STRBUF_INIT;
strbuf_addstr(&idx_file, transport->pack_lockfile);
strbuf_setlen(&idx_file, idx_file.len - 5); /* ".keep" */
diff --git a/contrib/buildsystems/engine.pl b/contrib/buildsystems/engine.pl
index 23da787..23da787 100644..100755
--- a/contrib/buildsystems/engine.pl
+++ b/contrib/buildsystems/engine.pl
diff --git a/contrib/buildsystems/generate b/contrib/buildsystems/generate
index bc10f25..bc10f25 100644..100755
--- a/contrib/buildsystems/generate
+++ b/contrib/buildsystems/generate
diff --git a/contrib/buildsystems/parse.pl b/contrib/buildsystems/parse.pl
index c9656ec..c9656ec 100644..100755
--- a/contrib/buildsystems/parse.pl
+++ b/contrib/buildsystems/parse.pl
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index dba3c15..8aaf214 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1,5 +1,3 @@
-#!bash
-#
# bash/zsh completion support for core Git.
#
# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
@@ -180,9 +178,9 @@ _get_comp_words_by_ref ()
}
fi
-__gitcompadd ()
+__gitcompappend ()
{
- local i=0
+ local i=${#COMPREPLY[@]}
for x in $1; do
if [[ "$x" == "$3"* ]]; then
COMPREPLY[i++]="$2$x$4"
@@ -190,6 +188,12 @@ __gitcompadd ()
done
}
+__gitcompadd ()
+{
+ COMPREPLY=()
+ __gitcompappend "$@"
+}
+
# Generates completion reply, appending a space to possible completion words,
# if necessary.
# It accepts 1 to 4 arguments:
@@ -220,6 +224,14 @@ __gitcomp ()
esac
}
+# Variation of __gitcomp_nl () that appends to the existing list of
+# completion candidates, COMPREPLY.
+__gitcomp_nl_append ()
+{
+ local IFS=$'\n'
+ __gitcompappend "$1" "${2-}" "${3-$cur}" "${4- }"
+}
+
# Generates completion reply from newline-separated possible completion words
# by appending a space to all of them.
# It accepts 1 to 4 arguments:
@@ -231,8 +243,8 @@ __gitcomp ()
# appended.
__gitcomp_nl ()
{
- local IFS=$'\n'
- __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }"
+ COMPREPLY=()
+ __gitcomp_nl_append "$@"
}
# Generates completion reply with compgen from newline-separated possible
@@ -673,7 +685,6 @@ __git_list_porcelain_commands ()
index-pack) : plumbing;;
init-db) : deprecated;;
local-fetch) : plumbing;;
- lost-found) : infrequent;;
ls-files) : plumbing;;
ls-remote) : plumbing;;
ls-tree) : plumbing;;
@@ -687,14 +698,12 @@ __git_list_porcelain_commands ()
pack-refs) : plumbing;;
parse-remote) : plumbing;;
patch-id) : plumbing;;
- peek-remote) : plumbing;;
prune) : plumbing;;
prune-packed) : plumbing;;
quiltimport) : import;;
read-tree) : plumbing;;
receive-pack) : plumbing;;
remote-*) : transport;;
- repo-config) : deprecated;;
rerere) : plumbing;;
rev-list) : plumbing;;
rev-parse) : plumbing;;
@@ -707,7 +716,6 @@ __git_list_porcelain_commands ()
ssh-*) : transport;;
stripspace) : plumbing;;
symbolic-ref) : plumbing;;
- tar-tree) : deprecated;;
unpack-file) : plumbing;;
unpack-objects) : plumbing;;
update-index) : plumbing;;
@@ -1833,6 +1841,7 @@ _git_config ()
branch.*)
local pfx="${cur%.*}." cur_="${cur#*.}"
__gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "."
+ __gitcomp_nl_append $'autosetupmerge\nautosetuprebase\n' "$pfx" "$cur_"
return
;;
guitool.*.*)
@@ -1875,6 +1884,7 @@ _git_config ()
remote.*)
local pfx="${cur%.*}." cur_="${cur#*.}"
__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
+ __gitcomp_nl_append "pushdefault" "$pfx" "$cur_"
return
;;
url.*.*)
@@ -1997,6 +2007,7 @@ _git_config ()
fetch.unpackLimit
format.attach
format.cc
+ format.coverLetter
format.headers
format.numbered
format.pretty
diff --git a/contrib/completion/git-completion.tcsh b/contrib/completion/git-completion.tcsh
index eaacaf0..6104a42 100644
--- a/contrib/completion/git-completion.tcsh
+++ b/contrib/completion/git-completion.tcsh
@@ -1,5 +1,3 @@
-#!tcsh
-#
# tcsh completion support for core Git.
#
# Copyright (C) 2012 Marc Khouzam <marc.khouzam@gmail.com>
diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index fac5e71..6b77968 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -30,10 +30,10 @@ if [ -z "$script" ]; then
local -a locations
local e
locations=(
+ $(dirname ${funcsourcetrace[1]%:*})/git-completion.bash
'/etc/bash_completion.d/git' # fedora, old debian
'/usr/share/bash-completion/completions/git' # arch, ubuntu, new debian
'/usr/share/bash-completion/git' # gentoo
- $(dirname ${funcsourcetrace[1]%:*})/git-completion.bash
)
for e in $locations; do
test -f $e && script="$e" && break
@@ -76,6 +76,14 @@ __gitcomp_nl ()
compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0
}
+__gitcomp_nl_append ()
+{
+ emulate -L zsh
+
+ local IFS=$'\n'
+ compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0
+}
+
__gitcomp_file ()
{
emulate -L zsh
diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
index 635c96b..2a317fc 100644
--- a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
+++ b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
@@ -60,7 +60,7 @@
#define gnome_keyring_memory_free gnome_keyring_free_password
#define gnome_keyring_memory_strdup g_strdup
-static const char* gnome_keyring_result_to_message(GnomeKeyringResult result)
+static const char *gnome_keyring_result_to_message(GnomeKeyringResult result)
{
switch (result) {
case GNOME_KEYRING_RESULT_OK:
@@ -95,9 +95,9 @@ static const char* gnome_keyring_result_to_message(GnomeKeyringResult result)
static void gnome_keyring_done_cb(GnomeKeyringResult result, gpointer user_data)
{
- gpointer *data = (gpointer*) user_data;
- int *done = (int*) data[0];
- GnomeKeyringResult *r = (GnomeKeyringResult*) data[1];
+ gpointer *data = (gpointer *)user_data;
+ int *done = (int *)data[0];
+ GnomeKeyringResult *r = (GnomeKeyringResult *)data[1];
*r = result;
*done = 1;
@@ -130,34 +130,30 @@ static GnomeKeyringResult gnome_keyring_item_delete_sync(const char *keyring, gu
/*
* This credential struct and API is simplified from git's credential.{h,c}
*/
-struct credential
-{
- char *protocol;
- char *host;
+struct credential {
+ char *protocol;
+ char *host;
unsigned short port;
- char *path;
- char *username;
- char *password;
+ char *path;
+ char *username;
+ char *password;
};
-#define CREDENTIAL_INIT \
- { NULL,NULL,0,NULL,NULL,NULL }
+#define CREDENTIAL_INIT { NULL, NULL, 0, NULL, NULL, NULL }
-typedef int (*credential_op_cb)(struct credential*);
+typedef int (*credential_op_cb)(struct credential *);
-struct credential_operation
-{
- char *name;
+struct credential_operation {
+ char *name;
credential_op_cb op;
};
-#define CREDENTIAL_OP_END \
- { NULL,NULL }
+#define CREDENTIAL_OP_END { NULL, NULL }
/* ----------------- GNOME Keyring functions ----------------- */
/* create a special keyring option string, if path is given */
-static char* keyring_object(struct credential *c)
+static char *keyring_object(struct credential *c)
{
if (!c->path)
return NULL;
@@ -170,7 +166,7 @@ static char* keyring_object(struct credential *c)
static int keyring_get(struct credential *c)
{
- char* object = NULL;
+ char *object = NULL;
GList *entries;
GnomeKeyringNetworkPasswordData *password_data;
GnomeKeyringResult result;
@@ -204,7 +200,7 @@ static int keyring_get(struct credential *c)
}
/* pick the first one from the list */
- password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+ password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
gnome_keyring_memory_free(c->password);
c->password = gnome_keyring_memory_strdup(password_data->password);
@@ -221,7 +217,7 @@ static int keyring_get(struct credential *c)
static int keyring_store(struct credential *c)
{
guint32 item_id;
- char *object = NULL;
+ char *object = NULL;
GnomeKeyringResult result;
/*
@@ -262,7 +258,7 @@ static int keyring_store(struct credential *c)
static int keyring_erase(struct credential *c)
{
- char *object = NULL;
+ char *object = NULL;
GList *entries;
GnomeKeyringNetworkPasswordData *password_data;
GnomeKeyringResult result;
@@ -298,22 +294,20 @@ static int keyring_erase(struct credential *c)
if (result == GNOME_KEYRING_RESULT_CANCELLED)
return EXIT_SUCCESS;
- if (result != GNOME_KEYRING_RESULT_OK)
- {
+ if (result != GNOME_KEYRING_RESULT_OK) {
g_critical("%s", gnome_keyring_result_to_message(result));
return EXIT_FAILURE;
}
/* pick the first one from the list (delete all matches?) */
- password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+ password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
result = gnome_keyring_item_delete_sync(
password_data->keyring, password_data->item_id);
gnome_keyring_network_password_list_free(entries);
- if (result != GNOME_KEYRING_RESULT_OK)
- {
+ if (result != GNOME_KEYRING_RESULT_OK) {
g_critical("%s", gnome_keyring_result_to_message(result));
return EXIT_FAILURE;
}
@@ -325,9 +319,8 @@ static int keyring_erase(struct credential *c)
* Table with helper operation callbacks, used by generic
* credential helper main function.
*/
-static struct credential_operation const credential_helper_ops[] =
-{
- { "get", keyring_get },
+static struct credential_operation const credential_helper_ops[] = {
+ { "get", keyring_get },
{ "store", keyring_store },
{ "erase", keyring_erase },
CREDENTIAL_OP_END
@@ -353,24 +346,23 @@ static void credential_clear(struct credential *c)
static int credential_read(struct credential *c)
{
- char *buf;
+ char *buf;
size_t line_len;
- char *key;
- char *value;
+ char *key;
+ char *value;
key = buf = gnome_keyring_memory_alloc(1024);
- while (fgets(buf, 1024, stdin))
- {
+ while (fgets(buf, 1024, stdin)) {
line_len = strlen(buf);
if (line_len && buf[line_len-1] == '\n')
- buf[--line_len]='\0';
+ buf[--line_len] = '\0';
if (!line_len)
break;
- value = strchr(buf,'=');
+ value = strchr(buf, '=');
if (!value) {
g_warning("invalid credential line: %s", key);
gnome_keyring_memory_free(buf);
@@ -384,7 +376,7 @@ static int credential_read(struct credential *c)
} else if (!strcmp(key, "host")) {
g_free(c->host);
c->host = g_strdup(value);
- value = strrchr(c->host,':');
+ value = strrchr(c->host, ':');
if (value) {
*value++ = '\0';
c->port = atoi(value);
@@ -398,7 +390,8 @@ static int credential_read(struct credential *c)
} else if (!strcmp(key, "password")) {
gnome_keyring_memory_free(c->password);
c->password = gnome_keyring_memory_strdup(value);
- while (*value) *value++ = '\0';
+ while (*value)
+ *value++ = '\0';
}
/*
* Ignore other lines; we don't know what they mean, but
@@ -429,16 +422,16 @@ static void credential_write(const struct credential *c)
static void usage(const char *name)
{
struct credential_operation const *try_op = credential_helper_ops;
- const char *basename = strrchr(name,'/');
+ const char *basename = strrchr(name, '/');
basename = (basename) ? basename + 1 : name;
fprintf(stderr, "usage: %s <", basename);
while (try_op->name) {
- fprintf(stderr,"%s",(try_op++)->name);
+ fprintf(stderr, "%s", (try_op++)->name);
if (try_op->name)
- fprintf(stderr,"%s","|");
+ fprintf(stderr, "%s", "|");
}
- fprintf(stderr,"%s",">\n");
+ fprintf(stderr, "%s", ">\n");
}
int main(int argc, char *argv[])
@@ -446,7 +439,7 @@ int main(int argc, char *argv[])
int ret = EXIT_SUCCESS;
struct credential_operation const *try_op = credential_helper_ops;
- struct credential cred = CREDENTIAL_INIT;
+ struct credential cred = CREDENTIAL_INIT;
if (!argv[1]) {
usage(argv[0]);
diff --git a/contrib/examples/git-whatchanged.sh b/contrib/examples/git-whatchanged.sh
index 1fb9feb..2edbdc6 100755
--- a/contrib/examples/git-whatchanged.sh
+++ b/contrib/examples/git-whatchanged.sh
@@ -9,12 +9,12 @@ case "$0" in
*whatchanged)
count=
test -z "$diff_tree_flags" &&
- diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
+ diff_tree_flags=$(git config --get whatchanged.difftree)
diff_tree_default_flags='-c -M --abbrev' ;;
*show)
count=-n1
test -z "$diff_tree_flags" &&
- diff_tree_flags=$(git-repo-config --get show.difftree)
+ diff_tree_flags=$(git config --get show.difftree)
diff_tree_default_flags='--cc --always' ;;
esac
test -z "$diff_tree_flags" &&
diff --git a/contrib/gitview/gitview b/contrib/gitview/gitview
index 4c99dfb..4e23c65 100755
--- a/contrib/gitview/gitview
+++ b/contrib/gitview/gitview
@@ -1205,7 +1205,7 @@ class GitView(object):
#The first parent always continue on the same line
try:
- # check we alreay have the value
+ # check we already have the value
tmp_node_pos = self.nodepos[commit.parent_sha1[0]]
except KeyError:
self.colours[commit.parent_sha1[0]] = colour
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 8ee410f..8747b84 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -22,7 +22,6 @@
# For example, on debian the hook is stored in
# /usr/share/git-core/contrib/hooks/post-receive-email:
#
-# chmod a+x post-receive-email
# cd /path/to/your/repository.git
# ln -sf /usr/share/git-core/contrib/hooks/post-receive-email hooks/post-receive
#
diff --git a/contrib/hooks/pre-auto-gc-battery b/contrib/hooks/pre-auto-gc-battery
index 1f914c9..9d0c2d1 100644..100755
--- a/contrib/hooks/pre-auto-gc-battery
+++ b/contrib/hooks/pre-auto-gc-battery
@@ -13,7 +13,6 @@
# For example, if the hook is stored in
# /usr/share/git-core/contrib/hooks/pre-auto-gc-battery:
#
-# chmod a+x pre-auto-gc-battery
# cd /path/to/your/repository.git
# ln -sf /usr/share/git-core/contrib/hooks/pre-auto-gc-battery \
# hooks/pre-auto-gc
diff --git a/contrib/hooks/setgitperms.perl b/contrib/hooks/setgitperms.perl
index 2770a1b..2770a1b 100644..100755
--- a/contrib/hooks/setgitperms.perl
+++ b/contrib/hooks/setgitperms.perl
diff --git a/contrib/hooks/update-paranoid b/contrib/hooks/update-paranoid
index d18b317..d18b317 100644..100755
--- a/contrib/hooks/update-paranoid
+++ b/contrib/hooks/update-paranoid
diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile
index f206f96..a4b6f7a 100644
--- a/contrib/mw-to-git/Makefile
+++ b/contrib/mw-to-git/Makefile
@@ -18,9 +18,13 @@ SCRIPT_PERL+=git-mw.perl
GIT_ROOT_DIR=../..
HERE=contrib/mw-to-git/
+INSTALL = install
+
SCRIPT_PERL_FULL=$(patsubst %,$(HERE)/%,$(SCRIPT_PERL))
INSTLIBDIR=$(shell $(MAKE) -C $(GIT_ROOT_DIR)/perl \
-s --no-print-directory instlibdir)
+DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
+INSTLIBDIR_SQ = $(subst ','\'',$(INSTLIBDIR))
all: build
@@ -30,7 +34,9 @@ test: all
check: perlcritic test
install_pm:
- install $(GIT_MEDIAWIKI_PM) $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(INSTLIBDIR_SQ)/Git'
+ $(INSTALL) -m 644 $(GIT_MEDIAWIKI_PM) \
+ '$(DESTDIR_SQ)$(INSTLIBDIR_SQ)/$(GIT_MEDIAWIKI_PM)'
build:
$(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL="$(SCRIPT_PERL_FULL)" \
@@ -43,7 +49,6 @@ install: install_pm
clean:
$(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL="$(SCRIPT_PERL_FULL)" \
clean-perl-script
- rm $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
perlcritic:
perlcritic -5 $(SCRIPT_PERL)
diff --git a/contrib/mw-to-git/git-remote-mediawiki.perl b/contrib/mw-to-git/git-remote-mediawiki.perl
index 476e0a2..3f8d993 100755
--- a/contrib/mw-to-git/git-remote-mediawiki.perl
+++ b/contrib/mw-to-git/git-remote-mediawiki.perl
@@ -1315,7 +1315,7 @@ sub get_mw_namespace_id {
# Store "notANameSpace" as special value for inexisting namespaces
my $store_id = ($id || 'notANameSpace');
- # Store explicitely requested namespaces on disk
+ # Store explicitly requested namespaces on disk
if (!exists $cached_mw_namespace_id{$name}) {
run_git(qq(config --add remote.${remotename}.namespaceCache "${name}:${store_id}"));
$cached_mw_namespace_id{$name} = 1;
diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh
index ca6860f..3372b2a 100755
--- a/contrib/mw-to-git/t/test-gitmw-lib.sh
+++ b/contrib/mw-to-git/t/test-gitmw-lib.sh
@@ -91,7 +91,7 @@ test_diff_directories () {
# Check that <dir> contains exactly <N> files
test_contains_N_files () {
if test `ls -- "$1" | wc -l` -ne "$2"; then
- echo "directory $1 sould contain $2 files"
+ echo "directory $1 should contain $2 files"
echo "it contains these files:"
ls "$1"
false
diff --git a/contrib/mw-to-git/t/test.config b/contrib/mw-to-git/t/test.config
index 4cfebe9..5ba0684 100644
--- a/contrib/mw-to-git/t/test.config
+++ b/contrib/mw-to-git/t/test.config
@@ -12,7 +12,7 @@ SERVER_ADDR=localhost
TMP=/tmp
DB_FILE=wikidb.sqlite
-# If LIGHTTPD is not set to true, the script will use the defaut
+# If LIGHTTPD is not set to true, the script will use the default
# web server running in WIKI_DIR_INST.
WIKI_DIR_INST=/var/www
diff --git a/contrib/p4import/README b/contrib/p4import/README
deleted file mode 100644
index b9892b6..0000000
--- a/contrib/p4import/README
+++ /dev/null
@@ -1 +0,0 @@
-Please see contrib/fast-import/git-p4 for a better Perforce importer.
diff --git a/contrib/p4import/git-p4import.py b/contrib/p4import/git-p4import.py
deleted file mode 100644
index 593d6a0..0000000
--- a/contrib/p4import/git-p4import.py
+++ /dev/null
@@ -1,365 +0,0 @@
-#!/usr/bin/env python
-#
-# This tool is copyright (c) 2006, Sean Estabrooks.
-# It is released under the Gnu Public License, version 2.
-#
-# Import Perforce branches into Git repositories.
-# Checking out the files is done by calling the standard p4
-# client which you must have properly configured yourself
-#
-
-import marshal
-import os
-import sys
-import time
-import getopt
-
-if sys.hexversion < 0x02020000:
- # The behavior of the marshal module changed significantly in 2.2
- sys.stderr.write("git-p4import.py: requires Python 2.2 or later.\n")
- sys.exit(1)
-
-from signal import signal, \
- SIGPIPE, SIGINT, SIG_DFL, \
- default_int_handler
-
-signal(SIGPIPE, SIG_DFL)
-s = signal(SIGINT, SIG_DFL)
-if s != default_int_handler:
- signal(SIGINT, s)
-
-def die(msg, *args):
- for a in args:
- msg = "%s %s" % (msg, a)
- print "git-p4import fatal error:", msg
- sys.exit(1)
-
-def usage():
- print "USAGE: git-p4import [-q|-v] [--authors=<file>] [-t <timezone>] [//p4repo/path <branch>]"
- sys.exit(1)
-
-verbosity = 1
-logfile = "/dev/null"
-ignore_warnings = False
-stitch = 0
-tagall = True
-
-def report(level, msg, *args):
- global verbosity
- global logfile
- for a in args:
- msg = "%s %s" % (msg, a)
- fd = open(logfile, "a")
- fd.writelines(msg)
- fd.close()
- if level <= verbosity:
- print msg
-
-class p4_command:
- def __init__(self, _repopath):
- try:
- global logfile
- self.userlist = {}
- if _repopath[-1] == '/':
- self.repopath = _repopath[:-1]
- else:
- self.repopath = _repopath
- if self.repopath[-4:] != "/...":
- self.repopath= "%s/..." % self.repopath
- f=os.popen('p4 -V 2>>%s'%logfile, 'rb')
- a = f.readlines()
- if f.close():
- raise
- except:
- die("Could not find the \"p4\" command")
-
- def p4(self, cmd, *args):
- global logfile
- cmd = "%s %s" % (cmd, ' '.join(args))
- report(2, "P4:", cmd)
- f=os.popen('p4 -G %s 2>>%s' % (cmd,logfile), 'rb')
- list = []
- while 1:
- try:
- list.append(marshal.load(f))
- except EOFError:
- break
- self.ret = f.close()
- return list
-
- def sync(self, id, force=False, trick=False, test=False):
- if force:
- ret = self.p4("sync -f %s@%s"%(self.repopath, id))[0]
- elif trick:
- ret = self.p4("sync -k %s@%s"%(self.repopath, id))[0]
- elif test:
- ret = self.p4("sync -n %s@%s"%(self.repopath, id))[0]
- else:
- ret = self.p4("sync %s@%s"%(self.repopath, id))[0]
- if ret['code'] == "error":
- data = ret['data'].upper()
- if data.find('VIEW') > 0:
- die("Perforce reports %s is not in client view"% self.repopath)
- elif data.find('UP-TO-DATE') < 0:
- die("Could not sync files from perforce", self.repopath)
-
- def changes(self, since=0):
- try:
- list = []
- for rec in self.p4("changes %s@%s,#head" % (self.repopath, since+1)):
- list.append(rec['change'])
- list.reverse()
- return list
- except:
- return []
-
- def authors(self, filename):
- f=open(filename)
- for l in f.readlines():
- self.userlist[l[:l.find('=')].rstrip()] = \
- (l[l.find('=')+1:l.find('<')].rstrip(),l[l.find('<')+1:l.find('>')])
- f.close()
- for f,e in self.userlist.items():
- report(2, f, ":", e[0], " <", e[1], ">")
-
- def _get_user(self, id):
- if not self.userlist.has_key(id):
- try:
- user = self.p4("users", id)[0]
- self.userlist[id] = (user['FullName'], user['Email'])
- except:
- self.userlist[id] = (id, "")
- return self.userlist[id]
-
- def _format_date(self, ticks):
- symbol='+'
- name = time.tzname[0]
- offset = time.timezone
- if ticks[8]:
- name = time.tzname[1]
- offset = time.altzone
- if offset < 0:
- offset *= -1
- symbol = '-'
- localo = "%s%02d%02d %s" % (symbol, offset / 3600, offset % 3600, name)
- tickso = time.strftime("%a %b %d %H:%M:%S %Y", ticks)
- return "%s %s" % (tickso, localo)
-
- def where(self):
- try:
- return self.p4("where %s" % self.repopath)[-1]['path']
- except:
- return ""
-
- def describe(self, num):
- desc = self.p4("describe -s", num)[0]
- self.msg = desc['desc']
- self.author, self.email = self._get_user(desc['user'])
- self.date = self._format_date(time.localtime(long(desc['time'])))
- return self
-
-class git_command:
- def __init__(self):
- try:
- self.version = self.git("--version")[0][12:].rstrip()
- except:
- die("Could not find the \"git\" command")
- try:
- self.gitdir = self.get_single("rev-parse --git-dir")
- report(2, "gdir:", self.gitdir)
- except:
- die("Not a git repository... did you forget to \"git init\" ?")
- try:
- self.cdup = self.get_single("rev-parse --show-cdup")
- if self.cdup != "":
- os.chdir(self.cdup)
- self.topdir = os.getcwd()
- report(2, "topdir:", self.topdir)
- except:
- die("Could not find top git directory")
-
- def git(self, cmd):
- global logfile
- report(2, "GIT:", cmd)
- f=os.popen('git %s 2>>%s' % (cmd,logfile), 'rb')
- r=f.readlines()
- self.ret = f.close()
- return r
-
- def get_single(self, cmd):
- return self.git(cmd)[0].rstrip()
-
- def current_branch(self):
- try:
- testit = self.git("rev-parse --verify HEAD")[0]
- return self.git("symbolic-ref HEAD")[0][11:].rstrip()
- except:
- return None
-
- def get_config(self, variable):
- try:
- return self.git("config --get %s" % variable)[0].rstrip()
- except:
- return None
-
- def set_config(self, variable, value):
- try:
- self.git("config %s %s"%(variable, value) )
- except:
- die("Could not set %s to " % variable, value)
-
- def make_tag(self, name, head):
- self.git("tag -f %s %s"%(name,head))
-
- def top_change(self, branch):
- try:
- a=self.get_single("name-rev --tags refs/heads/%s" % branch)
- loc = a.find(' tags/') + 6
- if a[loc:loc+3] != "p4/":
- raise
- return int(a[loc+3:][:-2])
- except:
- return 0
-
- def update_index(self):
- self.git("ls-files -m -d -o -z | git update-index --add --remove -z --stdin")
-
- def checkout(self, branch):
- self.git("checkout %s" % branch)
-
- def repoint_head(self, branch):
- self.git("symbolic-ref HEAD refs/heads/%s" % branch)
-
- def remove_files(self):
- self.git("ls-files | xargs rm")
-
- def clean_directories(self):
- self.git("clean -d")
-
- def fresh_branch(self, branch):
- report(1, "Creating new branch", branch)
- self.git("ls-files | xargs rm")
- os.remove(".git/index")
- self.repoint_head(branch)
- self.git("clean -d")
-
- def basedir(self):
- return self.topdir
-
- def commit(self, author, email, date, msg, id):
- self.update_index()
- fd=open(".msg", "w")
- fd.writelines(msg)
- fd.close()
- try:
- current = self.get_single("rev-parse --verify HEAD")
- head = "-p HEAD"
- except:
- current = ""
- head = ""
- tree = self.get_single("write-tree")
- for r,l in [('DATE',date),('NAME',author),('EMAIL',email)]:
- os.environ['GIT_AUTHOR_%s'%r] = l
- os.environ['GIT_COMMITTER_%s'%r] = l
- commit = self.get_single("commit-tree %s %s < .msg" % (tree,head))
- os.remove(".msg")
- self.make_tag("p4/%s"%id, commit)
- self.git("update-ref HEAD %s %s" % (commit, current) )
-
-try:
- opts, args = getopt.getopt(sys.argv[1:], "qhvt:",
- ["authors=","help","stitch=","timezone=","log=","ignore","notags"])
-except getopt.GetoptError:
- usage()
-
-for o, a in opts:
- if o == "-q":
- verbosity = 0
- if o == "-v":
- verbosity += 1
- if o in ("--log"):
- logfile = a
- if o in ("--notags"):
- tagall = False
- if o in ("-h", "--help"):
- usage()
- if o in ("--ignore"):
- ignore_warnings = True
-
-git = git_command()
-branch=git.current_branch()
-
-for o, a in opts:
- if o in ("-t", "--timezone"):
- git.set_config("perforce.timezone", a)
- if o in ("--stitch"):
- git.set_config("perforce.%s.path" % branch, a)
- stitch = 1
-
-if len(args) == 2:
- branch = args[1]
- git.checkout(branch)
- if branch == git.current_branch():
- die("Branch %s already exists!" % branch)
- report(1, "Setting perforce to ", args[0])
- git.set_config("perforce.%s.path" % branch, args[0])
-elif len(args) != 0:
- die("You must specify the perforce //depot/path and git branch")
-
-p4path = git.get_config("perforce.%s.path" % branch)
-if p4path == None:
- die("Do not know Perforce //depot/path for git branch", branch)
-
-p4 = p4_command(p4path)
-
-for o, a in opts:
- if o in ("-a", "--authors"):
- p4.authors(a)
-
-localdir = git.basedir()
-if p4.where()[:len(localdir)] != localdir:
- report(1, "**WARNING** Appears p4 client is misconfigured")
- report(1, " for sync from %s to %s" % (p4.repopath, localdir))
- if ignore_warnings != True:
- die("Reconfigure or use \"--ignore\" on command line")
-
-if stitch == 0:
- top = git.top_change(branch)
-else:
- top = 0
-changes = p4.changes(top)
-count = len(changes)
-if count == 0:
- report(1, "Already up to date...")
- sys.exit(0)
-
-ptz = git.get_config("perforce.timezone")
-if ptz:
- report(1, "Setting timezone to", ptz)
- os.environ['TZ'] = ptz
- time.tzset()
-
-if stitch == 1:
- git.remove_files()
- git.clean_directories()
- p4.sync(changes[0], force=True)
-elif top == 0 and branch != git.current_branch():
- p4.sync(changes[0], test=True)
- report(1, "Creating new initial commit");
- git.fresh_branch(branch)
- p4.sync(changes[0], force=True)
-else:
- p4.sync(changes[0], trick=True)
-
-report(1, "processing %s changes from p4 (%s) to git (%s)" % (count, p4.repopath, branch))
-for id in changes:
- report(1, "Importing changeset", id)
- change = p4.describe(id)
- p4.sync(id)
- if tagall :
- git.commit(change.author, change.email, change.date, change.msg, id)
- else:
- git.commit(change.author, change.email, change.date, change.msg, "import")
- if stitch == 1:
- git.clean_directories()
- stitch = 0
diff --git a/contrib/p4import/git-p4import.txt b/contrib/p4import/git-p4import.txt
deleted file mode 100644
index 9967587..0000000
--- a/contrib/p4import/git-p4import.txt
+++ /dev/null
@@ -1,167 +0,0 @@
-git-p4import(1)
-===============
-
-NAME
-----
-git-p4import - Import a Perforce repository into git
-
-
-SYNOPSIS
---------
-[verse]
-`git-p4import` [-q|-v] [--notags] [--authors <file>] [-t <timezone>]
- <//p4repo/path> <branch>
-`git-p4import` --stitch <//p4repo/path>
-`git-p4import`
-
-
-DESCRIPTION
------------
-Import a Perforce repository into an existing git repository. When
-a <//p4repo/path> and <branch> are specified a new branch with the
-given name will be created and the initial import will begin.
-
-Once the initial import is complete you can do an incremental import
-of new commits from the Perforce repository. You do this by checking
-out the appropriate git branch and then running `git-p4import` without
-any options.
-
-The standard p4 client is used to communicate with the Perforce
-repository; it must be configured correctly in order for `git-p4import`
-to operate (see below).
-
-
-OPTIONS
--------
--q::
- Do not display any progress information.
-
--v::
- Give extra progress information.
-
-\--authors::
- Specify an authors file containing a mapping of Perforce user
- ids to full names and email addresses (see Notes below).
-
-\--notags::
- Do not create a tag for each imported commit.
-
-\--stitch::
- Import the contents of the given perforce branch into the
- currently checked out git branch.
-
-\--log::
- Store debugging information in the specified file.
-
--t::
- Specify that the remote repository is in the specified timezone.
- Timezone must be in the format "US/Pacific" or "Europe/London"
- etc. You only need to specify this once, it will be saved in
- the git config file for the repository.
-
-<//p4repo/path>::
- The Perforce path that will be imported into the specified branch.
-
-<branch>::
- The new branch that will be created to hold the Perforce imports.
-
-
-P4 Client
----------
-You must make the `p4` client command available in your $PATH and
-configure it to communicate with the target Perforce repository.
-Typically this means you must set the "$P4PORT" and "$P4CLIENT"
-environment variables.
-
-You must also configure a `p4` client "view" which maps the Perforce
-branch into the top level of your git repository, for example:
-
-------------
-Client: myhost
-
-Root: /home/sean/import
-
-Options: noallwrite clobber nocompress unlocked modtime rmdir
-
-View:
- //public/jam/... //myhost/jam/...
-------------
-
-With the above `p4` client setup, you could import the "jam"
-perforce branch into a branch named "jammy", like so:
-
-------------
-$ mkdir -p /home/sean/import/jam
-$ cd /home/sean/import/jam
-$ git init
-$ git p4import //public/jam jammy
-------------
-
-
-Multiple Branches
------------------
-Note that by creating multiple "views" you can use `git-p4import`
-to import additional branches into the same git repository.
-However, the `p4` client has a limitation in that it silently
-ignores all but the last "view" that maps into the same local
-directory. So the following will *not* work:
-
-------------
-View:
- //public/jam/... //myhost/jam/...
- //public/other/... //myhost/jam/...
- //public/guest/... //myhost/jam/...
-------------
-
-If you want more than one Perforce branch to be imported into the
-same directory you must employ a workaround. A simple option is
-to adjust your `p4` client before each import to only include a
-single view.
-
-Another option is to create multiple symlinks locally which all
-point to the same directory in your git repository and then use
-one per "view" instead of listing the actual directory.
-
-
-Tags
-----
-A git tag of the form p4/xx is created for every change imported from
-the Perforce repository where xx is the Perforce changeset number.
-Therefore after the import you can use git to access any commit by its
-Perforce number, e.g. git show p4/327.
-
-The tag associated with the HEAD commit is also how `git-p4import`
-determines if there are new changes to incrementally import from the
-Perforce repository.
-
-If you import from a repository with many thousands of changes
-you will have an equal number of p4/xxxx git tags. Git tags can
-be expensive in terms of disk space and repository operations.
-If you don't need to perform further incremental imports, you
-may delete the tags.
-
-
-Notes
------
-You can interrupt the import (e.g. ctrl-c) at any time and restart it
-without worry.
-
-Author information is automatically determined by querying the
-Perforce "users" table using the id associated with each change.
-However, if you want to manually supply these mappings you can do
-so with the "--authors" option. It accepts a file containing a list
-of mappings with each line containing one mapping in the format:
-
-------------
- perforce_id = Full Name <email@address.com>
-------------
-
-
-Author
-------
-Written by Sean Estabrooks <seanlkml@sympatico.ca>
-
-
-GIT
----
-Part of the gitlink:git[7] suite
diff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr
index 054161a..332aba7 100755
--- a/contrib/remote-helpers/git-remote-bzr
+++ b/contrib/remote-helpers/git-remote-bzr
@@ -44,8 +44,8 @@ import StringIO
import atexit, shutil, hashlib, urlparse, subprocess
NAME_RE = re.compile('^([^<>]+)')
-AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
-EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)')
+AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
+EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)')
RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)')
def die(msg, *args):
@@ -193,8 +193,7 @@ def fixup_user(user):
else:
m = EMAIL_RE.match(user)
if m:
- name = m.group(1)
- mail = m.group(2)
+ mail = m.group(1)
else:
m = NAME_RE.match(user)
if m:
@@ -884,6 +883,16 @@ def main(args):
global branches, peers
global transports
+ marks = None
+ is_tmp = False
+ gitdir = os.environ.get('GIT_DIR', None)
+
+ if len(args) < 3:
+ die('Not enough arguments.')
+
+ if not gitdir:
+ die('GIT_DIR not set')
+
alias = args[1]
url = args[2]
@@ -892,7 +901,6 @@ def main(args):
blob_marks = {}
parsed_refs = {}
files_cache = {}
- marks = None
branches = {}
peers = {}
transports = []
@@ -900,11 +908,8 @@ def main(args):
if alias[5:] == url:
is_tmp = True
alias = hashlib.sha1(alias).hexdigest()
- else:
- is_tmp = False
prefix = 'refs/bzr/%s' % alias
- gitdir = os.environ['GIT_DIR']
dirname = os.path.join(gitdir, 'bzr', alias)
if not is_tmp:
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index c6026b9..eb89ef6 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -51,8 +51,8 @@ import time as ptime
#
NAME_RE = re.compile('^([^<>]+)')
-AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
-EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)')
+AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
+EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)')
AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$')
RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
@@ -316,8 +316,7 @@ def fixup_user_git(user):
else:
m = EMAIL_RE.match(user)
if m:
- name = m.group(1)
- mail = m.group(2)
+ mail = m.group(1)
else:
m = NAME_RE.match(user)
if m:
@@ -416,6 +415,9 @@ def get_repo(url, alias):
local_path = os.path.join(dirname, 'clone')
if not os.path.exists(local_path):
hg.share(myui, shared_path, local_path, update=False)
+ else:
+ # make sure the shared path is always up-to-date
+ util.writefile(os.path.join(local_path, '.hg', 'sharedpath'), hg_path)
repo = hg.repository(myui, local_path)
try:
@@ -538,7 +540,7 @@ def export_ref(repo, name, kind, head):
print "commit %s" % ref
print "mark :%d" % (note_mark)
- print "committer remote-hg <> %s" % (ptime.strftime('%s %z'))
+ print "committer remote-hg <> %d %s" % (ptime.time(), gittz(ptime.timezone))
desc = "Notes for %s\n" % (name)
print "data %d" % (len(desc))
print desc
@@ -1165,6 +1167,16 @@ def main(args):
global dry_run
global notes, alias
+ marks = None
+ is_tmp = False
+ gitdir = os.environ.get('GIT_DIR', None)
+
+ if len(args) < 3:
+ die('Not enough arguments.')
+
+ if not gitdir:
+ die('GIT_DIR not set')
+
alias = args[1]
url = args[2]
peer = None
@@ -1185,16 +1197,12 @@ def main(args):
if alias[4:] == url:
is_tmp = True
alias = hashlib.sha1(alias).hexdigest()
- else:
- is_tmp = False
- gitdir = os.environ['GIT_DIR']
dirname = os.path.join(gitdir, 'hg', alias)
branches = {}
bmarks = {}
blob_marks = {}
parsed_refs = {}
- marks = None
parsed_tags = {}
filenodes = {}
fake_bmark = None
diff --git a/contrib/remote-helpers/test-bzr.sh b/contrib/remote-helpers/test-bzr.sh
index 5c50251..1e53ff9 100755
--- a/contrib/remote-helpers/test-bzr.sh
+++ b/contrib/remote-helpers/test-bzr.sh
@@ -5,7 +5,8 @@
test_description='Test remote-bzr'
-. ./test-lib.sh
+test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=${0%/*}/../../t
+. "$TEST_DIRECTORY"/test-lib.sh
if ! test_have_prereq PYTHON
then
@@ -378,7 +379,7 @@ test_expect_success 'export utf-8 authors' '
git add content &&
git commit -m one &&
git remote add bzr "bzr::../bzrrepo" &&
- git push bzr
+ git push bzr master
) &&
(
diff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh
index 72f745d..5d128a5 100755
--- a/contrib/remote-helpers/test-hg.sh
+++ b/contrib/remote-helpers/test-hg.sh
@@ -8,7 +8,8 @@
test_description='Test remote-hg'
-. ./test-lib.sh
+test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=${0%/*}/../../t
+. "$TEST_DIRECTORY"/test-lib.sh
if ! test_have_prereq PYTHON
then
@@ -53,14 +54,14 @@ check_bookmark () {
}
check_push () {
- local expected_ret=$1 ret=0 ref_ret=0 IFS=':'
+ expected_ret=$1 ret=0 ref_ret=0
shift
git push origin "$@" 2>error
ret=$?
cat error
- while read branch kind
+ while IFS=':' read branch kind
do
case "$kind" in
'new')
@@ -82,7 +83,7 @@ check_push () {
test $ref_ret -ne 0 && echo "match for '$branch' failed" && break
done
- if test $expected_ret -ne $ret -o $ref_ret -ne 0
+ if test $expected_ret -ne $ret || test $ref_ret -ne 0
then
return 1
fi
@@ -205,16 +206,17 @@ test_expect_success 'authors' '
>../expected &&
author_test alpha "" "H G Wells <wells@example.com>" &&
- author_test beta "test" "test <unknown>" &&
- author_test beta "test <test@example.com> (comment)" "test <test@example.com>" &&
- author_test gamma "<test@example.com>" "Unknown <test@example.com>" &&
- author_test delta "name<test@example.com>" "name <test@example.com>" &&
- author_test epsilon "name <test@example.com" "name <test@example.com>" &&
- author_test zeta " test " "test <unknown>" &&
- author_test eta "test < test@example.com >" "test <test@example.com>" &&
- author_test theta "test >test@example.com>" "test <test@example.com>" &&
- author_test iota "test < test <at> example <dot> com>" "test <unknown>" &&
- author_test kappa "test@example.com" "Unknown <test@example.com>"
+ author_test beta "beta" "beta <unknown>" &&
+ author_test gamma "gamma <test@example.com> (comment)" "gamma <test@example.com>" &&
+ author_test delta "<delta@example.com>" "Unknown <delta@example.com>" &&
+ author_test epsilon "epsilon<test@example.com>" "epsilon <test@example.com>" &&
+ author_test zeta "zeta <test@example.com" "zeta <test@example.com>" &&
+ author_test eta " eta " "eta <unknown>" &&
+ author_test theta "theta < test@example.com >" "theta <test@example.com>" &&
+ author_test iota "iota >test@example.com>" "iota <test@example.com>" &&
+ author_test kappa "kappa < test <at> example <dot> com>" "kappa <unknown>" &&
+ author_test lambda "lambda@example.com" "Unknown <lambda@example.com>" &&
+ author_test mu "mu.mu@example.com" "Unknown <mu.mu@example.com>"
) &&
git clone "hg::hgrepo" gitrepo &&
@@ -335,6 +337,17 @@ test_expect_success 'remote cloning' '
check gitrepo HEAD zero
'
+test_expect_success 'moving remote clone' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ mv gitrepo gitrepo2 &&
+ cd gitrepo2 &&
+ git fetch
+ )
+'
+
test_expect_success 'remote update bookmark' '
test_when_finished "rm -rf gitrepo*" &&
@@ -442,6 +455,74 @@ test_expect_success 'remote new bookmark multiple branch head' '
# cleanup previous stuff
rm -rf hgrepo
+test_expect_success 'fetch special filenames' '
+ test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
+
+ LC_ALL=en_US.UTF-8
+ export LC_ALL
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+
+ echo test >> "æ rø" &&
+ hg add "æ rø" &&
+ echo test >> "ø~?" &&
+ hg add "ø~?" &&
+ hg commit -m add-utf-8 &&
+ echo test >> "æ rø" &&
+ hg commit -m test-utf-8 &&
+ hg rm "ø~?" &&
+ hg mv "æ rø" "ø~?" &&
+ hg commit -m hg-mv-utf-8
+ ) &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ git -c core.quotepath=false ls-files > ../actual
+ ) &&
+ echo "ø~?" > expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'push special filenames' '
+ test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
+
+ mkdir -p tmp && cd tmp &&
+
+ LC_ALL=en_US.UTF-8
+ export LC_ALL
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+
+ echo one >> content &&
+ hg add content &&
+ hg commit -m one
+ ) &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+
+ echo test >> "æ rø" &&
+ git add "æ rø" &&
+ git commit -m utf-8 &&
+
+ git push
+ ) &&
+
+ (cd hgrepo &&
+ hg update &&
+ hg manifest > ../actual
+ ) &&
+
+ printf "content\næ rø\n" > expected &&
+ test_cmp expected actual
+'
+
setup_big_push () {
(
hg init hgrepo &&
diff --git a/convert.c b/convert.c
index 11a95fc..ab80b72 100644
--- a/convert.c
+++ b/convert.c
@@ -1121,7 +1121,7 @@ static int is_foreign_ident(const char *str)
{
int i;
- if (prefixcmp(str, "$Id: "))
+ if (!starts_with(str, "$Id: "))
return 0;
for (i = 5; str[i]; i++) {
if (isspace(str[i]) && str[i+1] != '$')
diff --git a/csum-file.c b/csum-file.c
index 53f5375..b00b215 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, void *buf, unsigned int count)
+static void flush(struct sha1file *f, const void *buf, unsigned int count)
{
if (0 <= f->check_fd && count) {
unsigned char check_buffer[8192];
@@ -86,13 +86,13 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
return fd;
}
-int sha1write(struct sha1file *f, void *buf, unsigned int count)
+void sha1write(struct sha1file *f, const void *buf, unsigned int count)
{
while (count) {
unsigned offset = f->offset;
unsigned left = sizeof(f->buffer) - offset;
unsigned nr = count > left ? left : count;
- void *data;
+ const void *data;
if (f->do_crc)
f->crc32 = crc32(f->crc32, buf, nr);
@@ -116,7 +116,6 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count)
}
f->offset = offset;
}
- return 0;
}
struct sha1file *sha1fd(int fd, const char *name)
diff --git a/csum-file.h b/csum-file.h
index 3b540bd..bb543d5 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -34,7 +34,7 @@ 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 int sha1write(struct sha1file *, void *, 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 *);
diff --git a/daemon.c b/daemon.c
index 34916c5..503e039 100644
--- a/daemon.c
+++ b/daemon.c
@@ -235,7 +235,7 @@ static int service_enabled;
static int git_daemon_config(const char *var, const char *value, void *cb)
{
- if (!prefixcmp(var, "daemon.") &&
+ if (starts_with(var, "daemon.") &&
!strcmp(var + 7, service_looking_at->config_name)) {
service_enabled = git_config_bool(var, value);
return 0;
@@ -633,7 +633,7 @@ static int execute(void)
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
struct daemon_service *s = &(daemon_service[i]);
int namelen = strlen(s->name);
- if (!prefixcmp(line, "git-") &&
+ if (starts_with(line, "git-") &&
!strncmp(s->name, line + 4, namelen) &&
line[namelen + 4] == ' ') {
/*
@@ -1165,11 +1165,11 @@ int main(int argc, char **argv)
for (i = 1; i < argc; i++) {
char *arg = argv[i];
- if (!prefixcmp(arg, "--listen=")) {
+ if (starts_with(arg, "--listen=")) {
string_list_append(&listen_addr, xstrdup_tolower(arg + 9));
continue;
}
- if (!prefixcmp(arg, "--port=")) {
+ if (starts_with(arg, "--port=")) {
char *end;
unsigned long n;
n = strtoul(arg+7, &end, 0);
@@ -1199,19 +1199,19 @@ int main(int argc, char **argv)
export_all_trees = 1;
continue;
}
- if (!prefixcmp(arg, "--access-hook=")) {
+ if (starts_with(arg, "--access-hook=")) {
access_hook = arg + 14;
continue;
}
- if (!prefixcmp(arg, "--timeout=")) {
+ if (starts_with(arg, "--timeout=")) {
timeout = atoi(arg+10);
continue;
}
- if (!prefixcmp(arg, "--init-timeout=")) {
+ if (starts_with(arg, "--init-timeout=")) {
init_timeout = atoi(arg+15);
continue;
}
- if (!prefixcmp(arg, "--max-connections=")) {
+ if (starts_with(arg, "--max-connections=")) {
max_connections = atoi(arg+18);
if (max_connections < 0)
max_connections = 0; /* unlimited */
@@ -1221,7 +1221,7 @@ int main(int argc, char **argv)
strict_paths = 1;
continue;
}
- if (!prefixcmp(arg, "--base-path=")) {
+ if (starts_with(arg, "--base-path=")) {
base_path = arg+12;
continue;
}
@@ -1229,7 +1229,7 @@ int main(int argc, char **argv)
base_path_relaxed = 1;
continue;
}
- if (!prefixcmp(arg, "--interpolated-path=")) {
+ if (starts_with(arg, "--interpolated-path=")) {
interpolated_path = arg+20;
continue;
}
@@ -1241,11 +1241,11 @@ int main(int argc, char **argv)
user_path = "";
continue;
}
- if (!prefixcmp(arg, "--user-path=")) {
+ if (starts_with(arg, "--user-path=")) {
user_path = arg + 12;
continue;
}
- if (!prefixcmp(arg, "--pid-file=")) {
+ if (starts_with(arg, "--pid-file=")) {
pid_file = arg + 11;
continue;
}
@@ -1254,35 +1254,35 @@ int main(int argc, char **argv)
log_syslog = 1;
continue;
}
- if (!prefixcmp(arg, "--user=")) {
+ if (starts_with(arg, "--user=")) {
user_name = arg + 7;
continue;
}
- if (!prefixcmp(arg, "--group=")) {
+ if (starts_with(arg, "--group=")) {
group_name = arg + 8;
continue;
}
- if (!prefixcmp(arg, "--enable=")) {
+ if (starts_with(arg, "--enable=")) {
enable_service(arg + 9, 1);
continue;
}
- if (!prefixcmp(arg, "--disable=")) {
+ if (starts_with(arg, "--disable=")) {
enable_service(arg + 10, 0);
continue;
}
- if (!prefixcmp(arg, "--allow-override=")) {
+ if (starts_with(arg, "--allow-override=")) {
make_service_overridable(arg + 17, 1);
continue;
}
- if (!prefixcmp(arg, "--forbid-override=")) {
+ if (starts_with(arg, "--forbid-override=")) {
make_service_overridable(arg + 18, 0);
continue;
}
- if (!prefixcmp(arg, "--informative-errors")) {
+ if (!strcmp(arg, "--informative-errors")) {
informative_errors = 1;
continue;
}
- if (!prefixcmp(arg, "--no-informative-errors")) {
+ if (!strcmp(arg, "--no-informative-errors")) {
informative_errors = 0;
continue;
}
diff --git a/diff-no-index.c b/diff-no-index.c
index 00a8eef..33e5982 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -183,54 +183,12 @@ static int queue_diff(struct diff_options *o,
void diff_no_index(struct rev_info *revs,
int argc, const char **argv,
- int nongit, const char *prefix)
+ const char *prefix)
{
int i, prefixlen;
- int no_index = 0;
unsigned deprecated_show_diff_q_option_used = 0;
const char *paths[2];
- /* Were we asked to do --no-index explicitly? */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "--")) {
- i++;
- break;
- }
- if (!strcmp(argv[i], "--no-index"))
- no_index = 1;
- if (argv[i][0] != '-')
- break;
- }
-
- if (!no_index && !nongit) {
- /*
- * Inside a git repository, without --no-index. Only
- * when a path outside the repository is given,
- * e.g. "git diff /var/tmp/[12]", or "git diff
- * Makefile /var/tmp/Makefile", allow it to be used as
- * a colourful "diff" replacement.
- */
- if ((argc != i + 2) ||
- (path_inside_repo(prefix, argv[i]) &&
- path_inside_repo(prefix, argv[i+1])))
- return;
- }
- if (argc != i + 2) {
- if (!no_index) {
- /*
- * There was no --no-index and there were not two
- * paths. It is possible that the user intended
- * to do an inside-repository operation.
- */
- fprintf(stderr, "Not a git repository\n");
- fprintf(stderr,
- "To compare two paths outside a working tree:\n");
- }
- /* Give the usage message for non-repository usage and exit. */
- usagef("git diff %s <path> <path>",
- no_index ? "--no-index" : "[--no-index]");
- }
-
diff_setup(&revs->diffopt);
for (i = 1; i < argc - 2; ) {
int j;
diff --git a/diff.c b/diff.c
index e34bf97..6b4cd0e 100644
--- a/diff.c
+++ b/diff.c
@@ -30,6 +30,7 @@ static int diff_use_color_default = -1;
static int diff_context_default = 3;
static const char *diff_word_regex_cfg;
static const char *external_diff_cmd_cfg;
+static const char *diff_order_file_cfg;
int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static int diff_no_prefix;
@@ -201,6 +202,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
return git_config_string(&external_diff_cmd_cfg, var, value);
if (!strcmp(var, "diff.wordregex"))
return git_config_string(&diff_word_regex_cfg, var, value);
+ if (!strcmp(var, "diff.orderfile"))
+ return git_config_pathname(&diff_order_file_cfg, var, value);
if (!strcmp(var, "diff.ignoresubmodules"))
handle_ignore_submodules_arg(&default_diff_options, value);
@@ -235,7 +238,7 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
if (userdiff_config(var, value) < 0)
return -1;
- if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
+ if (starts_with(var, "diff.color.") || starts_with(var, "color.diff.")) {
int slot = parse_diff_color_slot(var, 11);
if (slot < 0)
return 0;
@@ -264,7 +267,7 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
return 0;
}
- if (!prefixcmp(var, "submodule."))
+ if (starts_with(var, "submodule."))
return parse_submodule_config_option(var, value);
return git_default_config(var, value, cb);
@@ -1215,7 +1218,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
diff_words_append(line, len,
&ecbdata->diff_words->plus);
return;
- } else if (!prefixcmp(line, "\\ ")) {
+ } else if (starts_with(line, "\\ ")) {
/*
* Eat the "no newline at eof" marker as if we
* saw a "+" or "-" line with nothing on it,
@@ -2387,9 +2390,9 @@ static void builtin_diff(const char *name_a,
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
if (!diffopts)
;
- else if (!prefixcmp(diffopts, "--unified="))
+ else if (starts_with(diffopts, "--unified="))
xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
- else if (!prefixcmp(diffopts, "-u"))
+ else if (starts_with(diffopts, "-u"))
xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
if (o->word_diff)
init_diff_words_data(&ecbdata, o, one, two);
@@ -2899,11 +2902,16 @@ static void run_external_diff(const char *pgm,
struct diff_filespec *one,
struct diff_filespec *two,
const char *xfrm_msg,
- int complete_rewrite)
+ int complete_rewrite,
+ struct diff_options *o)
{
const char *spawn_arg[10];
int retval;
const char **arg = &spawn_arg[0];
+ struct diff_queue_struct *q = &diff_queued_diff;
+ const char *env[3] = { NULL };
+ char env_counter[50];
+ char env_total[50];
if (one && two) {
struct diff_tempfile *temp_one, *temp_two;
@@ -2928,7 +2936,14 @@ static void run_external_diff(const char *pgm,
}
*arg = NULL;
fflush(NULL);
- retval = run_command_v_opt(spawn_arg, RUN_USING_SHELL);
+
+ env[0] = env_counter;
+ snprintf(env_counter, sizeof(env_counter), "GIT_DIFF_PATH_COUNTER=%d",
+ ++o->diff_path_counter);
+ env[1] = env_total;
+ snprintf(env_total, sizeof(env_total), "GIT_DIFF_PATH_TOTAL=%d", q->nr);
+
+ retval = run_command_v_opt_cd_env(spawn_arg, RUN_USING_SHELL, NULL, env);
remove_tempfile();
if (retval) {
fprintf(stderr, "external diff died, stopping at %s.\n", name);
@@ -3042,7 +3057,7 @@ static void run_diff_cmd(const char *pgm,
if (pgm) {
run_external_diff(pgm, name, other, one, two, xfrm_msg,
- complete_rewrite);
+ complete_rewrite, o);
return;
}
if (one && two)
@@ -3207,6 +3222,8 @@ void diff_setup(struct diff_options *options)
options->detect_rename = diff_detect_rename_default;
options->xdl_opts |= diff_algorithm;
+ options->orderfile = diff_order_file_cfg;
+
if (diff_no_prefix) {
options->a_prefix = options->b_prefix = "";
} else if (!diff_mnemonic_prefix) {
@@ -3317,6 +3334,8 @@ void diff_setup_done(struct diff_options *options)
options->output_format = DIFF_FORMAT_NO_OUTPUT;
DIFF_OPT_SET(options, EXIT_WITH_STATUS);
}
+
+ options->diff_path_counter = 0;
}
static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
@@ -3391,10 +3410,10 @@ int parse_long_opt(const char *opt, const char **argv,
if (arg[0] != '-' || arg[1] != '-')
return 0;
arg += strlen("--");
- if (prefixcmp(arg, opt))
+ if (!starts_with(arg, opt))
return 0;
arg += strlen(opt);
- if (*arg == '=') { /* sticked form: --option=value */
+ if (*arg == '=') { /* stuck form: --option=value */
*optarg = arg + 1;
return 1;
}
@@ -3422,7 +3441,7 @@ static int stat_opt(struct diff_options *options, const char **av)
switch (*arg) {
case '-':
- if (!prefixcmp(arg, "-width")) {
+ if (starts_with(arg, "-width")) {
arg += strlen("-width");
if (*arg == '=')
width = strtoul(arg + 1, &end, 10);
@@ -3432,7 +3451,7 @@ static int stat_opt(struct diff_options *options, const char **av)
width = strtoul(av[1], &end, 10);
argcount = 2;
}
- } else if (!prefixcmp(arg, "-name-width")) {
+ } else if (starts_with(arg, "-name-width")) {
arg += strlen("-name-width");
if (*arg == '=')
name_width = strtoul(arg + 1, &end, 10);
@@ -3442,7 +3461,7 @@ static int stat_opt(struct diff_options *options, const char **av)
name_width = strtoul(av[1], &end, 10);
argcount = 2;
}
- } else if (!prefixcmp(arg, "-graph-width")) {
+ } else if (starts_with(arg, "-graph-width")) {
arg += strlen("-graph-width");
if (*arg == '=')
graph_width = strtoul(arg + 1, &end, 10);
@@ -3452,7 +3471,7 @@ static int stat_opt(struct diff_options *options, const char **av)
graph_width = strtoul(av[1], &end, 10);
argcount = 2;
}
- } else if (!prefixcmp(arg, "-count")) {
+ } else if (starts_with(arg, "-count")) {
arg += strlen("-count");
if (*arg == '=')
count = strtoul(arg + 1, &end, 10);
@@ -3614,15 +3633,15 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->output_format |= DIFF_FORMAT_SHORTSTAT;
else if (!strcmp(arg, "-X") || !strcmp(arg, "--dirstat"))
return parse_dirstat_opt(options, "");
- else if (!prefixcmp(arg, "-X"))
+ else if (starts_with(arg, "-X"))
return parse_dirstat_opt(options, arg + 2);
- else if (!prefixcmp(arg, "--dirstat="))
+ else if (starts_with(arg, "--dirstat="))
return parse_dirstat_opt(options, arg + 10);
else if (!strcmp(arg, "--cumulative"))
return parse_dirstat_opt(options, "cumulative");
else if (!strcmp(arg, "--dirstat-by-file"))
return parse_dirstat_opt(options, "files");
- else if (!prefixcmp(arg, "--dirstat-by-file=")) {
+ else if (starts_with(arg, "--dirstat-by-file=")) {
parse_dirstat_opt(options, "files");
return parse_dirstat_opt(options, arg + 18);
}
@@ -3639,17 +3658,17 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->output_format |= DIFF_FORMAT_NAME_STATUS;
else if (!strcmp(arg, "-s") || !strcmp(arg, "--no-patch"))
options->output_format |= DIFF_FORMAT_NO_OUTPUT;
- else if (!prefixcmp(arg, "--stat"))
+ else if (starts_with(arg, "--stat"))
/* --stat, --stat-width, --stat-name-width, or --stat-count */
return stat_opt(options, av);
/* renames options */
- else if (!prefixcmp(arg, "-B") || !prefixcmp(arg, "--break-rewrites=") ||
+ else if (starts_with(arg, "-B") || starts_with(arg, "--break-rewrites=") ||
!strcmp(arg, "--break-rewrites")) {
if ((options->break_opt = diff_scoreopt_parse(arg)) == -1)
return error("invalid argument to -B: %s", arg+2);
}
- else if (!prefixcmp(arg, "-M") || !prefixcmp(arg, "--find-renames=") ||
+ else if (starts_with(arg, "-M") || starts_with(arg, "--find-renames=") ||
!strcmp(arg, "--find-renames")) {
if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
return error("invalid argument to -M: %s", arg+2);
@@ -3658,7 +3677,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
else if (!strcmp(arg, "-D") || !strcmp(arg, "--irreversible-delete")) {
options->irreversible_delete = 1;
}
- else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--find-copies=") ||
+ else if (starts_with(arg, "-C") || starts_with(arg, "--find-copies=") ||
!strcmp(arg, "--find-copies")) {
if (options->detect_rename == DIFF_DETECT_COPY)
DIFF_OPT_SET(options, FIND_COPIES_HARDER);
@@ -3674,7 +3693,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_OPT_CLR(options, RENAME_EMPTY);
else if (!strcmp(arg, "--relative"))
DIFF_OPT_SET(options, RELATIVE_NAME);
- else if (!prefixcmp(arg, "--relative=")) {
+ else if (starts_with(arg, "--relative=")) {
DIFF_OPT_SET(options, RELATIVE_NAME);
options->prefix = arg + 11;
}
@@ -3727,7 +3746,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_OPT_CLR(options, FOLLOW_RENAMES);
else if (!strcmp(arg, "--color"))
options->use_color = 1;
- else if (!prefixcmp(arg, "--color=")) {
+ else if (starts_with(arg, "--color=")) {
int value = git_config_colorbool(NULL, arg+8);
if (value < 0)
return error("option `color' expects \"always\", \"auto\", or \"never\"");
@@ -3739,7 +3758,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->use_color = 1;
options->word_diff = DIFF_WORDS_COLOR;
}
- else if (!prefixcmp(arg, "--color-words=")) {
+ else if (starts_with(arg, "--color-words=")) {
options->use_color = 1;
options->word_diff = DIFF_WORDS_COLOR;
options->word_regex = arg + 14;
@@ -3748,7 +3767,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
if (options->word_diff == DIFF_WORDS_NONE)
options->word_diff = DIFF_WORDS_PLAIN;
}
- else if (!prefixcmp(arg, "--word-diff=")) {
+ else if (starts_with(arg, "--word-diff=")) {
const char *type = arg + 12;
if (!strcmp(type, "plain"))
options->word_diff = DIFF_WORDS_PLAIN;
@@ -3784,12 +3803,12 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
else if (!strcmp(arg, "--ignore-submodules")) {
DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
handle_ignore_submodules_arg(options, "all");
- } else if (!prefixcmp(arg, "--ignore-submodules=")) {
+ } else if (starts_with(arg, "--ignore-submodules=")) {
DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
handle_ignore_submodules_arg(options, arg + 20);
} else if (!strcmp(arg, "--submodule"))
DIFF_OPT_SET(options, SUBMODULE_LOG);
- else if (!prefixcmp(arg, "--submodule="))
+ else if (starts_with(arg, "--submodule="))
return parse_submodule_opt(options, arg + 12);
/* misc options */
@@ -3825,7 +3844,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
}
else if (!strcmp(arg, "--abbrev"))
options->abbrev = DEFAULT_ABBREV;
- else if (!prefixcmp(arg, "--abbrev=")) {
+ else if (starts_with(arg, "--abbrev=")) {
options->abbrev = strtoul(arg + 9, NULL, 10);
if (options->abbrev < MINIMUM_ABBREV)
options->abbrev = MINIMUM_ABBREV;
@@ -3907,15 +3926,15 @@ static int diff_scoreopt_parse(const char *opt)
cmd = *opt++;
if (cmd == '-') {
/* convert the long-form arguments into short-form versions */
- if (!prefixcmp(opt, "break-rewrites")) {
+ if (starts_with(opt, "break-rewrites")) {
opt += strlen("break-rewrites");
if (*opt == 0 || *opt++ == '=')
cmd = 'B';
- } else if (!prefixcmp(opt, "find-copies")) {
+ } else if (starts_with(opt, "find-copies")) {
opt += strlen("find-copies");
if (*opt == 0 || *opt++ == '=')
cmd = 'C';
- } else if (!prefixcmp(opt, "find-renames")) {
+ } else if (starts_with(opt, "find-renames")) {
opt += strlen("find-renames");
if (*opt == 0 || *opt++ == '=')
cmd = 'M';
@@ -4325,7 +4344,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
int new_len;
/* Ignore line numbers when computing the SHA1 of the patch */
- if (!prefixcmp(line, "@@ -"))
+ if (starts_with(line, "@@ -"))
return;
new_len = remove_space(line, len);
diff --git a/diff.h b/diff.h
index e342325..ce123fa 100644
--- a/diff.h
+++ b/diff.h
@@ -164,6 +164,8 @@ struct diff_options {
diff_prefix_fn_t output_prefix;
int output_prefix_length;
void *output_prefix_data;
+
+ int diff_path_counter;
};
enum color_diff {
@@ -244,7 +246,7 @@ extern struct diff_filepair *diff_unmerge(struct diff_options *, const char *pat
#define DIFF_SETUP_USE_SIZE_CACHE 4
/*
- * Poor man's alternative to parse-option, to allow both sticked form
+ * Poor man's alternative to parse-option, to allow both stuck form
* (--option=value) and separate form (--option value).
*/
extern int parse_long_opt(const char *opt, const char **argv,
@@ -330,7 +332,7 @@ extern int diff_flush_patch_id(struct diff_options *, unsigned char *);
extern int diff_result_code(struct diff_options *, int);
-extern void diff_no_index(struct rev_info *, int, const char **, int, const char *);
+extern void diff_no_index(struct rev_info *, int, const char **, const char *);
extern int index_differs_from(const char *def, int diff_flags);
diff --git a/diffcore-order.c b/diffcore-order.c
index 23e9385..fe7f1f4 100644
--- a/diffcore-order.c
+++ b/diffcore-order.c
@@ -10,28 +10,21 @@ static int order_cnt;
static void prepare_order(const char *orderfile)
{
- int fd, cnt, pass;
+ int cnt, pass;
+ struct strbuf sb = STRBUF_INIT;
void *map;
char *cp, *endp;
- struct stat st;
- size_t sz;
+ ssize_t sz;
if (order)
return;
- fd = open(orderfile, O_RDONLY);
- if (fd < 0)
- return;
- if (fstat(fd, &st)) {
- close(fd);
- return;
- }
- sz = xsize_t(st.st_size);
- map = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
- close(fd);
- if (map == MAP_FAILED)
- return;
+ sz = strbuf_read_file(&sb, orderfile, 0);
+ if (sz < 0)
+ die_errno(_("failed to read orderfile '%s'"), orderfile);
+ map = strbuf_detach(&sb, NULL);
endp = (char *) map + sz;
+
for (pass = 0; pass < 2; pass++) {
cnt = 0;
cp = map;
@@ -73,15 +66,16 @@ struct pair_order {
static int match_order(const char *path)
{
int i;
- char p[PATH_MAX];
+ static struct strbuf p = STRBUF_INIT;
for (i = 0; i < order_cnt; i++) {
- strcpy(p, path);
- while (p[0]) {
+ strbuf_reset(&p);
+ strbuf_addstr(&p, path);
+ while (p.buf[0]) {
char *cp;
- if (!fnmatch(order[i], p, 0))
+ if (!fnmatch(order[i], p.buf, 0))
return i;
- cp = strrchr(p, '/');
+ cp = strrchr(p.buf, '/');
if (!cp)
break;
*cp = 0;
diff --git a/dir.c b/dir.c
index 23b6de4..d10a63f 100644
--- a/dir.c
+++ b/dir.c
@@ -126,10 +126,13 @@ static size_t common_prefix_len(const struct pathspec *pathspec)
PATHSPEC_MAXDEPTH |
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
- PATHSPEC_ICASE);
+ PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE);
for (n = 0; n < pathspec->nr; n++) {
size_t i = 0, len = 0, item_len;
+ if (pathspec->items[n].magic & PATHSPEC_EXCLUDE)
+ continue;
if (pathspec->items[n].magic & PATHSPEC_ICASE)
item_len = pathspec->items[n].prefix;
else
@@ -279,9 +282,10 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
* pathspec did not match any names, which could indicate that the
* user mistyped the nth pathspec.
*/
-int match_pathspec_depth(const struct pathspec *ps,
- const char *name, int namelen,
- int prefix, char *seen)
+static int match_pathspec_depth_1(const struct pathspec *ps,
+ const char *name, int namelen,
+ int prefix, char *seen,
+ int exclude)
{
int i, retval = 0;
@@ -290,7 +294,8 @@ int match_pathspec_depth(const struct pathspec *ps,
PATHSPEC_MAXDEPTH |
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
- PATHSPEC_ICASE);
+ PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE);
if (!ps->nr) {
if (!ps->recursive ||
@@ -309,8 +314,19 @@ int match_pathspec_depth(const struct pathspec *ps,
for (i = ps->nr - 1; i >= 0; i--) {
int how;
+
+ if ((!exclude && ps->items[i].magic & PATHSPEC_EXCLUDE) ||
+ ( exclude && !(ps->items[i].magic & PATHSPEC_EXCLUDE)))
+ continue;
+
if (seen && seen[i] == MATCHED_EXACTLY)
continue;
+ /*
+ * Make exclude patterns optional and never report
+ * "pathspec ':(exclude)foo' matches no files"
+ */
+ if (seen && ps->items[i].magic & PATHSPEC_EXCLUDE)
+ seen[i] = MATCHED_FNMATCH;
how = match_pathspec_item(ps->items+i, prefix, name, namelen);
if (ps->recursive &&
(ps->magic & PATHSPEC_MAXDEPTH) &&
@@ -334,6 +350,18 @@ int match_pathspec_depth(const struct pathspec *ps,
return retval;
}
+int match_pathspec_depth(const struct pathspec *ps,
+ const char *name, int namelen,
+ int prefix, char *seen)
+{
+ int positive, negative;
+ positive = match_pathspec_depth_1(ps, name, namelen, prefix, seen, 0);
+ if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)
+ return positive;
+ negative = match_pathspec_depth_1(ps, name, namelen, prefix, seen, 1);
+ return negative ? 0 : positive;
+}
+
/*
* Return the length of the "simple" part of a path match limiter.
*/
@@ -1375,11 +1403,18 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
PATHSPEC_MAXDEPTH |
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
- PATHSPEC_ICASE);
+ PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE);
if (has_symlink_leading_path(path, len))
return dir->nr;
+ /*
+ * exclude patterns are treated like positive ones in
+ * create_simplify. Usually exclude patterns should be a
+ * subset of positive ones, which has no impacts on
+ * create_simplify().
+ */
simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
if (!len || treat_leading_path(dir, path, len, simplify))
read_directory_recursive(dir, path, len, 0, simplify);
diff --git a/environment.c b/environment.c
index b73b39d..4a3437d 100644
--- a/environment.c
+++ b/environment.c
@@ -177,7 +177,7 @@ const char *get_git_namespace(void)
const char *strip_namespace(const char *namespaced_ref)
{
- if (prefixcmp(namespaced_ref, get_git_namespace()) != 0)
+ if (!starts_with(namespaced_ref, get_git_namespace()))
return NULL;
return namespaced_ref + namespace_len;
}
diff --git a/fast-import.c b/fast-import.c
index f4d9969..4fd18a3 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1877,8 +1877,8 @@ static int read_next_command(void)
return EOF;
if (!seen_data_command
- && prefixcmp(command_buf.buf, "feature ")
- && prefixcmp(command_buf.buf, "option ")) {
+ && !starts_with(command_buf.buf, "feature ")
+ && !starts_with(command_buf.buf, "option ")) {
parse_argv();
}
@@ -1898,7 +1898,7 @@ static int read_next_command(void)
rc->prev->next = rc;
cmd_tail = rc;
}
- if (!prefixcmp(command_buf.buf, "cat-blob ")) {
+ if (starts_with(command_buf.buf, "cat-blob ")) {
parse_cat_blob();
continue;
}
@@ -1917,7 +1917,7 @@ static void skip_optional_lf(void)
static void parse_mark(void)
{
- if (!prefixcmp(command_buf.buf, "mark :")) {
+ if (starts_with(command_buf.buf, "mark :")) {
next_mark = strtoumax(command_buf.buf + 6, NULL, 10);
read_next_command();
}
@@ -1929,10 +1929,10 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
{
strbuf_reset(sb);
- if (prefixcmp(command_buf.buf, "data "))
+ if (!starts_with(command_buf.buf, "data "))
die("Expected 'data n' command, found: %s", command_buf.buf);
- if (!prefixcmp(command_buf.buf + 5, "<<")) {
+ if (starts_with(command_buf.buf + 5, "<<")) {
char *term = xstrdup(command_buf.buf + 5 + 2);
size_t term_len = command_buf.len - 5 - 2;
@@ -2306,7 +2306,7 @@ static void file_change_m(struct branch *b)
if (*p == ':') {
oe = find_mark(parse_mark_ref_space(&p));
hashcpy(sha1, oe->idx.sha1);
- } else if (!prefixcmp(p, "inline ")) {
+ } else if (starts_with(p, "inline ")) {
inline_data = 1;
oe = NULL; /* not used with inline_data, but makes gcc happy */
p += strlen("inline"); /* advance to space */
@@ -2479,7 +2479,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
if (*p == ':') {
oe = find_mark(parse_mark_ref_space(&p));
hashcpy(sha1, oe->idx.sha1);
- } else if (!prefixcmp(p, "inline ")) {
+ } else if (starts_with(p, "inline ")) {
inline_data = 1;
oe = NULL; /* not used with inline_data, but makes gcc happy */
p += strlen("inline"); /* advance to space */
@@ -2590,7 +2590,7 @@ static int parse_from(struct branch *b)
const char *from;
struct branch *s;
- if (prefixcmp(command_buf.buf, "from "))
+ if (!starts_with(command_buf.buf, "from "))
return 0;
if (b->branch_tree.tree) {
@@ -2636,7 +2636,7 @@ static struct hash_list *parse_merge(unsigned int *count)
struct branch *s;
*count = 0;
- while (!prefixcmp(command_buf.buf, "merge ")) {
+ while (starts_with(command_buf.buf, "merge ")) {
from = strchr(command_buf.buf, ' ') + 1;
n = xmalloc(sizeof(*n));
s = lookup_branch(from);
@@ -2687,11 +2687,11 @@ static void parse_new_commit(void)
read_next_command();
parse_mark();
- if (!prefixcmp(command_buf.buf, "author ")) {
+ if (starts_with(command_buf.buf, "author ")) {
author = parse_ident(command_buf.buf + 7);
read_next_command();
}
- if (!prefixcmp(command_buf.buf, "committer ")) {
+ if (starts_with(command_buf.buf, "committer ")) {
committer = parse_ident(command_buf.buf + 10);
read_next_command();
}
@@ -2712,19 +2712,19 @@ static void parse_new_commit(void)
/* file_change* */
while (command_buf.len > 0) {
- if (!prefixcmp(command_buf.buf, "M "))
+ if (starts_with(command_buf.buf, "M "))
file_change_m(b);
- else if (!prefixcmp(command_buf.buf, "D "))
+ else if (starts_with(command_buf.buf, "D "))
file_change_d(b);
- else if (!prefixcmp(command_buf.buf, "R "))
+ else if (starts_with(command_buf.buf, "R "))
file_change_cr(b, 1);
- else if (!prefixcmp(command_buf.buf, "C "))
+ else if (starts_with(command_buf.buf, "C "))
file_change_cr(b, 0);
- else if (!prefixcmp(command_buf.buf, "N "))
+ else if (starts_with(command_buf.buf, "N "))
note_change_n(b, &prev_fanout);
else if (!strcmp("deleteall", command_buf.buf))
file_change_deleteall(b);
- else if (!prefixcmp(command_buf.buf, "ls "))
+ else if (starts_with(command_buf.buf, "ls "))
parse_ls(b);
else {
unread_command_buf = 1;
@@ -2793,7 +2793,7 @@ static void parse_new_tag(void)
read_next_command();
/* from ... */
- if (prefixcmp(command_buf.buf, "from "))
+ if (!starts_with(command_buf.buf, "from "))
die("Expected from command, got %s", command_buf.buf);
from = strchr(command_buf.buf, ' ') + 1;
s = lookup_branch(from);
@@ -2821,7 +2821,7 @@ static void parse_new_tag(void)
read_next_command();
/* tagger ... */
- if (!prefixcmp(command_buf.buf, "tagger ")) {
+ if (starts_with(command_buf.buf, "tagger ")) {
tagger = parse_ident(command_buf.buf + 7);
read_next_command();
} else
@@ -3209,7 +3209,7 @@ static void option_export_pack_edges(const char *edges)
static int parse_one_option(const char *option)
{
- if (!prefixcmp(option, "max-pack-size=")) {
+ if (starts_with(option, "max-pack-size=")) {
unsigned long v;
if (!git_parse_ulong(option + 14, &v))
return 0;
@@ -3221,20 +3221,20 @@ static int parse_one_option(const char *option)
v = 1024 * 1024;
}
max_packsize = v;
- } else if (!prefixcmp(option, "big-file-threshold=")) {
+ } else if (starts_with(option, "big-file-threshold=")) {
unsigned long v;
if (!git_parse_ulong(option + 19, &v))
return 0;
big_file_threshold = v;
- } else if (!prefixcmp(option, "depth=")) {
+ } else if (starts_with(option, "depth=")) {
option_depth(option + 6);
- } else if (!prefixcmp(option, "active-branches=")) {
+ } else if (starts_with(option, "active-branches=")) {
option_active_branches(option + 16);
- } else if (!prefixcmp(option, "export-pack-edges=")) {
+ } else if (starts_with(option, "export-pack-edges=")) {
option_export_pack_edges(option + 18);
- } else if (!prefixcmp(option, "quiet")) {
+ } else if (starts_with(option, "quiet")) {
show_stats = 0;
- } else if (!prefixcmp(option, "stats")) {
+ } else if (starts_with(option, "stats")) {
show_stats = 1;
} else {
return 0;
@@ -3245,14 +3245,14 @@ static int parse_one_option(const char *option)
static int parse_one_feature(const char *feature, int from_stream)
{
- if (!prefixcmp(feature, "date-format=")) {
+ if (starts_with(feature, "date-format=")) {
option_date_format(feature + 12);
- } else if (!prefixcmp(feature, "import-marks=")) {
+ } else if (starts_with(feature, "import-marks=")) {
option_import_marks(feature + 13, from_stream, 0);
- } else if (!prefixcmp(feature, "import-marks-if-exists=")) {
+ } else if (starts_with(feature, "import-marks-if-exists=")) {
option_import_marks(feature + strlen("import-marks-if-exists="),
from_stream, 1);
- } else if (!prefixcmp(feature, "export-marks=")) {
+ } else if (starts_with(feature, "export-marks=")) {
option_export_marks(feature + 13);
} else if (!strcmp(feature, "cat-blob")) {
; /* Don't die - this feature is supported */
@@ -3350,7 +3350,7 @@ static void parse_argv(void)
if (parse_one_feature(a + 2, 0))
continue;
- if (!prefixcmp(a + 2, "cat-blob-fd=")) {
+ if (starts_with(a + 2, "cat-blob-fd=")) {
option_cat_blob_fd(a + 2 + strlen("cat-blob-fd="));
continue;
}
@@ -3404,25 +3404,25 @@ int main(int argc, char **argv)
while (read_next_command() != EOF) {
if (!strcmp("blob", command_buf.buf))
parse_new_blob();
- else if (!prefixcmp(command_buf.buf, "ls "))
+ else if (starts_with(command_buf.buf, "ls "))
parse_ls(NULL);
- else if (!prefixcmp(command_buf.buf, "commit "))
+ else if (starts_with(command_buf.buf, "commit "))
parse_new_commit();
- else if (!prefixcmp(command_buf.buf, "tag "))
+ else if (starts_with(command_buf.buf, "tag "))
parse_new_tag();
- else if (!prefixcmp(command_buf.buf, "reset "))
+ else if (starts_with(command_buf.buf, "reset "))
parse_reset_branch();
else if (!strcmp("checkpoint", command_buf.buf))
parse_checkpoint();
else if (!strcmp("done", command_buf.buf))
break;
- else if (!prefixcmp(command_buf.buf, "progress "))
+ else if (starts_with(command_buf.buf, "progress "))
parse_progress();
- else if (!prefixcmp(command_buf.buf, "feature "))
+ else if (starts_with(command_buf.buf, "feature "))
parse_feature();
- else if (!prefixcmp(command_buf.buf, "option git "))
+ else if (starts_with(command_buf.buf, "option git "))
parse_option();
- else if (!prefixcmp(command_buf.buf, "option "))
+ else if (starts_with(command_buf.buf, "option "))
/* ignore non-git options*/;
else
die("Unsupported command: %s", command_buf.buf);
diff --git a/fetch-pack.c b/fetch-pack.c
index 9bc29cf..d52de74 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -48,9 +48,8 @@ static void rev_list_push(struct commit *commit, int mark)
if (!(commit->object.flags & mark)) {
commit->object.flags |= mark;
- if (!(commit->object.parsed))
- if (parse_commit(commit))
- return;
+ if (parse_commit(commit))
+ return;
prio_queue_put(&rev_list, commit);
@@ -129,8 +128,7 @@ static const unsigned char *get_rev(void)
return NULL;
commit = prio_queue_get(&rev_list);
- if (!commit->object.parsed)
- parse_commit(commit);
+ parse_commit(commit);
parents = commit->parents;
commit->object.flags |= POPPED;
@@ -177,9 +175,9 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
*/
char *line;
while ((line = packet_read_line(fd, NULL))) {
- if (!prefixcmp(line, "shallow "))
+ if (starts_with(line, "shallow "))
continue;
- if (!prefixcmp(line, "unshallow "))
+ if (starts_with(line, "unshallow "))
continue;
die("git fetch-pack: expected shallow list");
}
@@ -195,7 +193,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)
die("git fetch-pack: expected ACK/NAK, got EOF");
if (!strcmp(line, "NAK"))
return NAK;
- if (!prefixcmp(line, "ACK ")) {
+ if (starts_with(line, "ACK ")) {
if (!get_sha1_hex(line+4, result_sha1)) {
if (len < 45)
return ACK;
@@ -324,13 +322,13 @@ static int find_common(struct fetch_pack_args *args,
send_request(args, fd[1], &req_buf);
while ((line = packet_read_line(fd[0], NULL))) {
- if (!prefixcmp(line, "shallow ")) {
+ if (starts_with(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
register_shallow(sha1);
continue;
}
- if (!prefixcmp(line, "unshallow ")) {
+ if (starts_with(line, "unshallow ")) {
if (get_sha1_hex(line + 10, sha1))
die("invalid unshallow line: %s", line);
if (!lookup_object(sha1))
@@ -524,7 +522,7 @@ static void filter_refs(struct fetch_pack_args *args,
}
if (!keep && args->fetch_all &&
- (!args->depth || prefixcmp(ref->name, "refs/tags/")))
+ (!args->depth || !starts_with(ref->name, "refs/tags/")))
keep = 1;
if (keep) {
diff --git a/fetch-pack.h b/fetch-pack.h
index ada02f5..bb7fd76 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -16,6 +16,7 @@ struct fetch_pack_args {
unsigned use_thin_pack:1;
unsigned fetch_all:1;
unsigned stdin_refs:1;
+ unsigned diag_url:1;
unsigned verbose:1;
unsigned no_progress:1;
unsigned include_tag:1;
diff --git a/gettext.c b/gettext.c
index 71e9545..8b2da46 100644
--- a/gettext.c
+++ b/gettext.c
@@ -29,6 +29,17 @@ int use_gettext_poison(void)
#endif
#ifndef NO_GETTEXT
+static int test_vsnprintf(const char *fmt, ...)
+{
+ char buf[26];
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
static const char *charset;
static void init_gettext_charset(const char *domain)
{
@@ -99,9 +110,7 @@ static void init_gettext_charset(const char *domain)
$ LANGUAGE= LANG=de_DE.utf8 ./test
test: Kein passendes Ger?t gefunden
- In the long term we should probably see about getting that
- vsnprintf bug in glibc fixed, and audit our code so it won't
- fall apart under a non-C locale.
+ The vsnprintf bug has been fixed since glibc 2.17.
Then we could simply set LC_CTYPE from the environment, which would
make things like the external perror(3) messages work.
@@ -115,7 +124,9 @@ static void init_gettext_charset(const char *domain)
setlocale(LC_CTYPE, "");
charset = locale_charset();
bind_textdomain_codeset(domain, charset);
- setlocale(LC_CTYPE, "C");
+ /* the string is taken from v0.99.6~1 */
+ if (test_vsnprintf("%.*s", 13, "David_K\345gedal") < 0)
+ setlocale(LC_CTYPE, "C");
}
void git_setup_gettext(void)
diff --git a/git-am.sh b/git-am.sh
index 7ea40fe..bbea430 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -302,7 +302,7 @@ split_patches () {
# not starting with Author, From or Date is the
# subject, and the body starts with the next nonempty
# line not starting with Author, From or Date
- perl -ne 'BEGIN { $subject = 0 }
+ @@PERL@@ -ne 'BEGIN { $subject = 0 }
if ($subject > 1) { print ; }
elsif (/^\s+$/) { next ; }
elsif (/^Author:/) { s/Author/From/ ; print ;}
@@ -334,7 +334,7 @@ split_patches () {
# Since we cannot guarantee that the commit message is in
# git-friendly format, we put no Subject: line and just consume
# all of the message as the body
- LANG=C LC_ALL=C perl -M'POSIX qw(strftime)' -ne 'BEGIN { $subject = 0 }
+ LANG=C LC_ALL=C @@PERL@@ -M'POSIX qw(strftime)' -ne 'BEGIN { $subject = 0 }
if ($subject) { print ; }
elsif (/^\# User /) { s/\# User/From:/ ; print ; }
elsif (/^\# Date /) {
diff --git a/git-bisect.sh b/git-bisect.sh
index 9f064b6..73b4c14 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -137,7 +137,7 @@ bisect_start() {
# cogito usage, and cogito users should understand
# it relates to cg-seek.
[ -s "$GIT_DIR/head-name" ] &&
- die "$(gettext "won't bisect on seeked tree")"
+ die "$(gettext "won't bisect on cg-seek'ed tree")"
start_head="${head#refs/heads/}"
;;
*)
diff --git a/git-compat-util.h b/git-compat-util.h
index 7776f12..cbd86c3 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -75,7 +75,7 @@
# endif
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
!defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
- !defined(__TANDEM) && !defined(__QNX__)
+ !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__)
#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
#endif
@@ -350,7 +350,9 @@ extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_lis
extern void set_error_routine(void (*routine)(const char *err, va_list params));
extern void set_die_is_recursing_routine(int (*routine)(void));
+extern int starts_with(const char *str, const char *prefix);
extern int prefixcmp(const char *str, const char *prefix);
+extern int ends_with(const char *str, const char *suffix);
extern int suffixcmp(const char *str, const char *suffix);
static inline const char *skip_prefix(const char *str, const char *prefix)
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
index b00ed95..7ef36b9 100755
--- a/git-difftool--helper.sh
+++ b/git-difftool--helper.sh
@@ -40,7 +40,8 @@ launch_merge_tool () {
# the user with the real $MERGED name before launching $merge_tool.
if should_prompt
then
- printf "\nViewing: '%s'\n" "$MERGED"
+ printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
+ "$GIT_DIFF_PATH_TOTAL" "$MERGED"
if use_ext_cmd
then
printf "Launch '%s' [Y/n]: " \
diff --git a/git-gui/Makefile b/git-gui/Makefile
index e9c2bc3..cde8b2e 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -4,7 +4,7 @@ all::
#
# Define NO_MSGFMT if you do not have msgfmt from the GNU gettext
# package and want to use our rough pure Tcl po->msg translator.
-# TCL_PATH must be vaild for this to work.
+# TCL_PATH must be valid for this to work.
#
GIT-VERSION-FILE: FORCE
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 153f85d..db46ac5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -894,6 +894,7 @@ set default_config(gui.textconv) true
set default_config(gui.pruneduringfetch) false
set default_config(gui.trustmtime) false
set default_config(gui.fastcopyblame) false
+set default_config(gui.maxrecentrepo) 10
set default_config(gui.copyblamethreshold) 40
set default_config(gui.blamehistoryctx) 7
set default_config(gui.diffcontext) 5
@@ -912,6 +913,7 @@ set font_descs {
{fontdiff font_diff {mc "Diff/Console Font"}}
}
set default_config(gui.stageuntracked) ask
+set default_config(gui.displayuntracked) true
######################################################################
##
@@ -1282,7 +1284,11 @@ apply_config
# v1.7.0 introduced --show-toplevel to return the canonical work-tree
if {[package vsatisfies $_git_version 1.7.0]} {
- set _gitworktree [git rev-parse --show-toplevel]
+ if { [is_Cygwin] } {
+ catch {set _gitworktree [exec cygpath --windows [git rev-parse --show-toplevel]]}
+ } else {
+ set _gitworktree [git rev-parse --show-toplevel]
+ }
} else {
# try to set work tree from environment, core.worktree or use
# cdup to obtain a relative path to the top of the worktree. If
@@ -1550,18 +1556,23 @@ proc rescan_stage2 {fd after} {
set buf_rdf {}
set buf_rlo {}
- set rescan_active 3
+ set rescan_active 2
ui_status [mc "Scanning for modified files ..."]
set fd_di [git_read diff-index --cached -z [PARENT]]
set fd_df [git_read diff-files -z]
- set fd_lo [eval git_read ls-files --others -z $ls_others]
fconfigure $fd_di -blocking 0 -translation binary -encoding binary
fconfigure $fd_df -blocking 0 -translation binary -encoding binary
- fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
+
fileevent $fd_di readable [list read_diff_index $fd_di $after]
fileevent $fd_df readable [list read_diff_files $fd_df $after]
- fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
+
+ if {[is_config_true gui.displayuntracked]} {
+ set fd_lo [eval git_read ls-files --others -z $ls_others]
+ fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
+ fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
+ incr rescan_active
+ }
}
proc load_message {file {encoding {}}} {
@@ -2654,6 +2665,16 @@ if {![is_bare]} {
.mbar.repository add command \
-label [mc "Explore Working Copy"] \
-command {do_explore}
+}
+
+if {[is_Windows]} {
+ .mbar.repository add command \
+ -label [mc "Git Bash"] \
+ -command {eval exec [auto_execok start] \
+ [list "Git Bash" bash --login -l &]}
+}
+
+if {[is_Windows] || ![is_bare]} {
.mbar.repository add separator
}
@@ -3203,13 +3224,19 @@ unset i
# -- Diff and Commit Area
#
-${NS}::frame .vpane.lower -height 300 -width 400
+${NS}::panedwindow .vpane.lower -orient vertical
${NS}::frame .vpane.lower.commarea
-${NS}::frame .vpane.lower.diff -relief sunken -borderwidth 1
-pack .vpane.lower.diff -fill both -expand 1
-pack .vpane.lower.commarea -side bottom -fill x
+${NS}::frame .vpane.lower.diff -relief sunken -borderwidth 1 -height 500
+.vpane.lower add .vpane.lower.diff
+.vpane.lower add .vpane.lower.commarea
.vpane add .vpane.lower
-if {!$use_ttk} {.vpane paneconfigure .vpane.lower -sticky nsew}
+if {$use_ttk} {
+ .vpane.lower pane .vpane.lower.diff -weight 1
+ .vpane.lower pane .vpane.lower.commarea -weight 0
+} else {
+ .vpane.lower paneconfigure .vpane.lower.diff -stretch always
+ .vpane.lower paneconfigure .vpane.lower.commarea -stretch never
+}
# -- Commit Area Buttons
#
diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl
index 324f774..b1d15f4 100644
--- a/git-gui/lib/blame.tcl
+++ b/git-gui/lib/blame.tcl
@@ -5,7 +5,7 @@ class blame {
image create photo ::blame::img_back_arrow -data {R0lGODlhGAAYAIUAAPwCBEzKXFTSZIz+nGzmhGzqfGTidIT+nEzGXHTqhGzmfGzifFzadETCVES+VARWDFzWbHzyjAReDGTadFTOZDSyRDyyTCymPARaFGTedFzSbDy2TCyqRCyqPARaDAyCHES6VDy6VCyiPAR6HCSeNByWLARyFARiDARqFGTifARiFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAYABgAAAajQIBwSCwaj8ikcsk0BppJwRPqHEypQwHBis0WDAdEFyBIKBaMAKLBdjQeSkFBYTBAIvgEoS6JmhUTEwIUDQ4VFhcMGEhyCgoZExoUaxsWHB0THkgfAXUGAhoBDSAVFR0XBnCbDRmgog0hpSIiDJpJIyEQhBUcJCIlwA22SSYVogknEg8eD82qSigdDSknY0IqJQXPYxIl1dZCGNvWw+Dm510GQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7}
-# Persistant data (survives loads)
+# Persistent data (survives loads)
#
field history {}; # viewer history: {commit path}
field header ; # array commit,key -> header field
diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl
index ee58981..3c10bc6 100644
--- a/git-gui/lib/choose_repository.tcl
+++ b/git-gui/lib/choose_repository.tcl
@@ -24,6 +24,10 @@ field sorted_recent ; # recent repositories (sorted)
constructor pick {} {
global M1T M1B use_ttk NS
+ if {[set maxrecent [get_config gui.maxrecentrepo]] eq {}} {
+ set maxrecent 10
+ }
+
make_dialog top w
wm title $top [mc "Git Gui"]
@@ -148,7 +152,7 @@ constructor pick {} {
-background [get_bg_color $w_body.recentlabel] \
-wrap none \
-width 50 \
- -height 10
+ -height $maxrecent
$w_recentlist tag conf link \
-foreground blue \
-underline 1
@@ -264,7 +268,11 @@ proc _append_recentrepos {path} {
git config --global --add gui.recentrepo $path
load_config 1
- while {[llength $recent] > 10} {
+ if {[set maxrecent [get_config gui.maxrecentrepo]] eq {}} {
+ set maxrecent 10
+ }
+
+ while {[llength $recent] > $maxrecent} {
_unset_recentrepo [lindex $recent 0]
set recent [lrange $recent 1 end]
}
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdd..74a81a7 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -414,7 +414,7 @@ proc revert_helper {txt paths} {
# such distinction is needed in some languages. Previously, the
# code used "Revert changes in" for both, but that can't work
# in languages where 'in' must be combined with word from
- # rest of string (in diffrent way for both cases of course).
+ # rest of string (in different way for both cases of course).
#
# FIXME: Unfortunately, even that isn't enough in some languages
# as they have quite complex plural-form rules. Unfortunately,
diff --git a/git-gui/lib/option.tcl b/git-gui/lib/option.tcl
index 0cf1da1..23c9ae7 100644
--- a/git-gui/lib/option.tcl
+++ b/git-gui/lib/option.tcl
@@ -150,6 +150,7 @@ proc do_options {} {
{b gui.matchtrackingbranch {mc "Match Tracking Branches"}}
{b gui.textconv {mc "Use Textconv For Diffs and Blames"}}
{b gui.fastcopyblame {mc "Blame Copy Only On Changed Files"}}
+ {i-0..100 gui.maxrecentrepo {mc "Maximum Length of Recent Repositories List"}}
{i-20..200 gui.copyblamethreshold {mc "Minimum Letters To Blame Copy On"}}
{i-0..300 gui.blamehistoryctx {mc "Blame History Context Radius (days)"}}
{i-1..99 gui.diffcontext {mc "Number of Diff Context Lines"}}
@@ -159,6 +160,7 @@ proc do_options {} {
{c gui.encoding {mc "Default File Contents Encoding"}}
{b gui.warndetachedcommit {mc "Warn before committing to a detached head"}}
{s gui.stageuntracked {mc "Staging of untracked files"} {list "yes" "no" "ask"}}
+ {b gui.displayuntracked {mc "Show untracked files"}}
} {
set type [lindex $option 0]
set name [lindex $option 1]
diff --git a/git-gui/lib/spellcheck.tcl b/git-gui/lib/spellcheck.tcl
index e612030..538d61c 100644
--- a/git-gui/lib/spellcheck.tcl
+++ b/git-gui/lib/spellcheck.tcl
@@ -14,7 +14,7 @@ field w_menu ; # context menu for the widget
field s_menuidx 0 ; # last index of insertion into $w_menu
field s_i {} ; # timer registration for _run callbacks
-field s_clear 0 ; # did we erase mispelled tags yet?
+field s_clear 0 ; # did we erase misspelled tags yet?
field s_seen [list] ; # lines last seen from $w_text in _run
field s_checked [list] ; # lines already checked
field s_pending [list] ; # [$line $data] sent to ispell/aspell
@@ -259,7 +259,7 @@ method _run {} {
if {$n == $cur_line
&& ![regexp {^\W$} [$w_text get $cur_pos insert]]} {
- # If the current word is mispelled remove the tag
+ # If the current word is misspelled remove the tag
# but force a spellcheck later.
#
set tags [$w_text tag names $cur_pos]
diff --git a/git-gui/macosx/Info.plist b/git-gui/macosx/Info.plist
index b3bf15f..1ade121 100644
--- a/git-gui/macosx/Info.plist
+++ b/git-gui/macosx/Info.plist
@@ -24,5 +24,7 @@
<string>GITg</string>
<key>CFBundleVersion</key>
<string>@@GITGUI_VERSION@@</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
</dict>
</plist>
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 01a1b05..e93a238 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -581,7 +581,7 @@ EOF
gitweb_conf() {
cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF
-#!/usr/bin/perl
+#!@@PERL@@
our \$projectroot = "$(dirname "$fqgitdir")";
our \$git_temp = "$fqgitdir/gitweb/tmp";
our \$projects_list = \$projectroot;
diff --git a/git-lost-found.sh b/git-lost-found.sh
deleted file mode 100755
index 0b3e8c7..0000000
--- a/git-lost-found.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/sh
-
-USAGE=''
-SUBDIRECTORY_OK='Yes'
-OPTIONS_SPEC=
-. git-sh-setup
-
-echo "WARNING: '$0' is deprecated in favor of 'git fsck --lost-found'" >&2
-
-if [ "$#" != "0" ]
-then
- usage
-fi
-
-laf="$GIT_DIR/lost-found"
-rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
-
-git fsck --full --no-reflogs |
-while read dangling type sha1
-do
- case "$dangling" in
- dangling)
- if git rev-parse -q --verify "$sha1^0" >/dev/null
- then
- dir="$laf/commit"
- git show-branch "$sha1"
- else
- dir="$laf/other"
- fi
- echo "$sha1" >"$dir/$sha1"
- ;;
- esac
-done
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index a280f49..c45a020 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-# git-mergetool--lib is a library for common merge tool functions
+# git-mergetool--lib is a shell library for common merge tool functions
: ${MERGE_TOOLS_DIR=$(git --exec-path)/mergetools}
diff --git a/git-p4.py b/git-p4.py
index 06a3cc6..5ea8bb8 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -1311,7 +1311,7 @@ class P4Submit(Command, P4UserMap):
else:
die("unknown modifier %s for %s" % (modifier, path))
- diffcmd = "git format-patch -k --stdout \"%s^\"..\"%s\"" % (id, id)
+ diffcmd = "git diff-tree -p \"%s\"" % (id)
patchcmd = diffcmd + " | git apply "
tryPatchCmd = patchcmd + "--check -"
applyPatchCmd = patchcmd + "--check --apply -"
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 0e87e09..55fe8d5 100644
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -1,4 +1,6 @@
-#!/bin/sh
+# This is a shell library to calculate the remote repository and
+# upstream branch that should be pulled by "git pull" from the current
+# branch.
# git-ls-remote could be called from outside a git managed repository;
# this would fail in that case and would issue an error message.
diff --git a/git-pull.sh b/git-pull.sh
index b946fd9..0a5aa2c 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -172,7 +172,7 @@ error_on_no_merge_candidates () {
do
case "$opt" in
-t|--t|--ta|--tag|--tags)
- echo "Fetching tags only, you probably meant:"
+ echo "It doesn't make sense to pull all tags; you probably meant:"
echo " git fetch --tags"
exit 1
esac
@@ -229,15 +229,7 @@ test true = "$rebase" && {
test -n "$curr_branch" &&
. git-parse-remote &&
remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" &&
- oldremoteref="$(git rev-parse -q --verify "$remoteref")" &&
- for reflog in $(git rev-list -g $remoteref 2>/dev/null)
- do
- if test "$reflog" = "$(git merge-base $reflog $curr_branch)"
- then
- oldremoteref="$reflog"
- break
- fi
- done
+ oldremoteref=$(git merge-base --fork-point "$remoteref" $curr_branch 2>/dev/null)
}
orig_head=$(git rev-parse -q --verify HEAD)
git fetch $verbosity $progress $dry_run $recurse_submodules --update-head-ok "$@" || exit 1
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index 34e3102..a4f683a 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+# This shell script fragment is sourced by git-rebase to implement
+# its default, fast, patch-based, non-interactive mode.
#
# Copyright (c) 2010 Junio C Hamano.
#
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 3c6bed9..43c19e0 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -1,11 +1,8 @@
-#!/bin/sh
+# This shell script fragment is sourced by git-rebase to implement
+# its interactive mode. "git rebase --interactive" makes it easy
+# to fix up commits in the middle of a series and rearrange commits.
#
# Copyright (c) 2006 Johannes E. Schindelin
-
-# SHORT DESCRIPTION
-#
-# This script makes it easy to fix up commits in the middle of a series,
-# and rearrange commits.
#
# The original idea comes from Eric W. Biederman, in
# http://article.gmane.org/gmane.comp.version-control.git/22407
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index 16d1817..e7d96de 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -1,4 +1,6 @@
-#!/bin/sh
+# This shell script fragment is sourced by git-rebase to implement
+# its merge-based non-interactive mode that copes well with renamed
+# files.
#
# Copyright (c) 2010 Junio C Hamano.
#
diff --git a/git-rebase.sh b/git-rebase.sh
index 226752f..8a3efa2 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -14,6 +14,7 @@ git-rebase --continue | --abort | --skip | --edit-todo
v,verbose! display a diffstat of what changed upstream
q,quiet! be quiet. implies --no-stat
autostash! automatically stash/stash pop before and after
+fork-point use 'merge-base --fork-point' to refine upstream
onto=! rebase onto given branch instead of upstream
p,preserve-merges! try to recreate merges instead of ignoring them
s,strategy=! use the given merge strategy
@@ -66,6 +67,7 @@ verbose=
diffstat=
test "$(git config --bool rebase.stat)" = true && diffstat=t
autostash="$(git config --bool rebase.autostash || echo false)"
+fork_point=auto
git_am_opt=
rebase_root=
force_rebase=
@@ -260,6 +262,12 @@ do
--no-autosquash)
autosquash=
;;
+ --fork-point)
+ fork_point=t
+ ;;
+ --no-fork-point)
+ fork_point=
+ ;;
-M|-m)
do_merge=t
;;
@@ -437,6 +445,8 @@ then
error_on_missing_default_upstream "rebase" "rebase" \
"against" "git rebase <branch>"
fi
+
+ test "$fork_point" = auto && fork_point=t
;;
*) upstream_name="$1"
shift
@@ -522,6 +532,16 @@ case "$#" in
;;
esac
+if test "$fork_point" = t
+then
+ new_upstream=$(git merge-base --fork-point "$upstream_name" \
+ "${switch_to:-HEAD}")
+ if test -n "$new_upstream"
+ then
+ upstream=$new_upstream
+ fi
+fi
+
if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
then
stash_sha1=$(git stash create "autostash") ||
diff --git a/git-request-pull.sh b/git-request-pull.sh
index ebf1269..fe21d5d 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -106,7 +106,7 @@ find_matching_ref='
}
'
-ref=$(git ls-remote "$url" | perl -e "$find_matching_ref" "$head" "$headrev" "$tag_name")
+ref=$(git ls-remote "$url" | @@PERL@@ -e "$find_matching_ref" "$head" "$headrev" "$tag_name")
url=$(git ls-remote --get-url "$url")
diff --git a/git-send-email.perl b/git-send-email.perl
index 3782c3b..2016d9c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -291,7 +291,7 @@ my $rc = GetOptions("h" => \$help,
"smtp-pass:s" => \$smtp_authpass,
"smtp-ssl" => sub { $smtp_encryption = 'ssl' },
"smtp-encryption=s" => \$smtp_encryption,
- "smtp-ssl-cert-path" => \$smtp_ssl_cert_path,
+ "smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
"smtp-debug:i" => \$debug_net_smtp,
"smtp-domain:s" => \$smtp_domain,
"identity=s" => \$identity,
@@ -1214,10 +1214,14 @@ X-Mailer: git-send-email $gitversion
$smtp_server_port ||= 465; # ssmtp
require Net::SMTP::SSL;
$smtp_domain ||= maildomain();
+ require IO::Socket::SSL;
+ # Net::SMTP::SSL->new() does not forward any SSL options
+ IO::Socket::SSL::set_client_defaults(
+ ssl_verify_params());
$smtp ||= Net::SMTP::SSL->new($smtp_server,
Hello => $smtp_domain,
Port => $smtp_server_port,
- ssl_verify_params());
+ Debug => $debug_net_smtp);
}
else {
require Net::SMTP;
diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh
index 6a27f68..e6c3116 100644
--- a/git-sh-i18n.sh
+++ b/git-sh-i18n.sh
@@ -1,9 +1,8 @@
-#!/bin/sh
+# This shell library is Git's interface to gettext.sh. See po/README
+# for usage instructions.
#
# Copyright (c) 2010 Ævar Arnfjörð Bjarmason
#
-# This is Git's interface to gettext.sh. See po/README for usage
-# instructions.
# Export the TEXTDOMAIN* data that we need for Git
TEXTDOMAIN=git
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index ebfe8f7..fffa3c7 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -1,9 +1,6 @@
-#!/bin/sh
-#
-# This is included in commands that either have to be run from the toplevel
-# of the repository, or with GIT_DIR environment variable properly.
-# If the GIT_DIR does not look like the right correct git-repository,
-# it dies.
+# This shell scriplet is meant to be included by other shell scripts
+# to set up some variables pointing at the normal git directories and
+# a few helper shell functions.
# Having this variable in your environment would break scripts because
# you would cause "cd" to be taken to unexpected places. If you
@@ -162,7 +159,8 @@ git_pager() {
GIT_PAGER=cat
fi
: ${LESS=-FRSX}
- export LESS
+ : ${LV=-c}
+ export LESS LV
eval "$GIT_PAGER" '"$@"'
}
diff --git a/git-stash.sh b/git-stash.sh
index 1e541a2..f0a94ab 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -358,7 +358,7 @@ parse_flags_and_rev()
i_tree=
u_tree=
- REV=$(git rev-parse --no-flags --symbolic "$@") || exit 1
+ REV=$(git rev-parse --no-flags --symbolic --sq "$@") || exit 1
FLAGS=
for opt
@@ -376,7 +376,7 @@ parse_flags_and_rev()
esac
done
- set -- $REV
+ eval set -- $REV
case $# in
0)
@@ -391,13 +391,13 @@ parse_flags_and_rev()
;;
esac
- REV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null) || {
+ REV=$(git rev-parse --quiet --symbolic --verify "$1" 2>/dev/null) || {
reference="$1"
die "$(eval_gettext "\$reference is not valid reference")"
}
- i_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null) &&
- set -- $(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null) &&
+ i_commit=$(git rev-parse --quiet --verify "$REV^2" 2>/dev/null) &&
+ set -- $(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null) &&
s=$1 &&
w_commit=$1 &&
b_commit=$2 &&
@@ -408,8 +408,8 @@ parse_flags_and_rev()
test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
IS_STASH_REF=t
- u_commit=$(git rev-parse --quiet --verify $REV^3 2>/dev/null) &&
- u_tree=$(git rev-parse $REV^3: 2>/dev/null)
+ u_commit=$(git rev-parse --quiet --verify "$REV^3" 2>/dev/null) &&
+ u_tree=$(git rev-parse "$REV^3:" 2>/dev/null)
}
is_stash_like()
diff --git a/git-submodule.sh b/git-submodule.sh
index 896f1c9..2677f2e 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -156,7 +156,7 @@ module_list()
git ls-files -z --error-unmatch --stage -- "$@" ||
echo "unmatched pathspec exists"
) |
- perl -e '
+ @@PERL@@ -e '
my %unmerged = ();
my ($null_sha1) = ("0" x 40);
my @out = ();
@@ -545,7 +545,12 @@ cmd_foreach()
sm_path=$(relative_path "$sm_path") &&
# we make $path available to scripts ...
path=$sm_path &&
- eval "$@" &&
+ if test $# -eq 1
+ then
+ eval "$1"
+ else
+ "$@"
+ fi &&
if test -n "$recursive"
then
cmd_foreach "--recursive" "$@"
@@ -612,11 +617,21 @@ cmd_init()
fi
# Copy "update" setting when it is not set yet
- upd="$(git config -f .gitmodules submodule."$name".update)"
- test -z "$upd" ||
- test -n "$(git config submodule."$name".update)" ||
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
+ if upd="$(git config -f .gitmodules submodule."$name".update)" &&
+ test -n "$upd" &&
+ test -z "$(git config submodule."$name".update)"
+ then
+ case "$upd" in
+ rebase | merge | none)
+ ;; # known modes of updating
+ *)
+ echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
+ upd=none
+ ;;
+ esac
+ git config submodule."$name".update "$upd" ||
+ die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
+ fi
done
}
@@ -706,7 +721,6 @@ cmd_deinit()
cmd_update()
{
# parse $args after "submodule ... update".
- orig_flags=
while test $# -ne 0
do
case "$1" in
@@ -731,7 +745,6 @@ cmd_update()
--reference)
case "$2" in '') usage ;; esac
reference="--reference=$2"
- orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
shift
;;
--reference=*)
@@ -765,7 +778,6 @@ cmd_update()
break
;;
esac
- orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
shift
done
@@ -909,7 +921,7 @@ Maybe you want to use 'update --init'?")"
prefix="$prefix$sm_path/"
clear_local_git_env
cd "$sm_path" &&
- eval cmd_update "$orig_flags"
+ eval cmd_update
)
res=$?
if test $res -gt 0
diff --git a/git.c b/git.c
index 179c4f6..7cf2953 100644
--- a/git.c
+++ b/git.c
@@ -54,7 +54,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
/*
* Check remaining flags.
*/
- if (!prefixcmp(cmd, "--exec-path")) {
+ if (starts_with(cmd, "--exec-path")) {
cmd += 11;
if (*cmd == '=')
git_set_argv_exec_path(cmd + 1);
@@ -92,7 +92,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
- } else if (!prefixcmp(cmd, "--git-dir=")) {
+ } else if (starts_with(cmd, "--git-dir=")) {
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
if (envchanged)
*envchanged = 1;
@@ -106,7 +106,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
- } else if (!prefixcmp(cmd, "--namespace=")) {
+ } else if (starts_with(cmd, "--namespace=")) {
setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1);
if (envchanged)
*envchanged = 1;
@@ -120,7 +120,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
- } else if (!prefixcmp(cmd, "--work-tree=")) {
+ } else if (starts_with(cmd, "--work-tree=")) {
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
if (envchanged)
*envchanged = 1;
@@ -332,127 +332,136 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
return 0;
}
-static void handle_internal_command(int argc, const char **argv)
+static struct cmd_struct commands[] = {
+ { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
+ { "annotate", cmd_annotate, RUN_SETUP },
+ { "apply", cmd_apply, RUN_SETUP_GENTLY },
+ { "archive", cmd_archive },
+ { "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+ { "blame", cmd_blame, RUN_SETUP },
+ { "branch", cmd_branch, RUN_SETUP },
+ { "bundle", cmd_bundle, RUN_SETUP_GENTLY },
+ { "cat-file", cmd_cat_file, RUN_SETUP },
+ { "check-attr", cmd_check_attr, RUN_SETUP },
+ { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
+ { "check-mailmap", cmd_check_mailmap, RUN_SETUP },
+ { "check-ref-format", cmd_check_ref_format },
+ { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
+ { "checkout-index", cmd_checkout_index,
+ RUN_SETUP | NEED_WORK_TREE},
+ { "cherry", cmd_cherry, RUN_SETUP },
+ { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+ { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
+ { "clone", cmd_clone },
+ { "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 },
+ { "count-objects", cmd_count_objects, RUN_SETUP },
+ { "credential", cmd_credential, RUN_SETUP_GENTLY },
+ { "describe", cmd_describe, RUN_SETUP },
+ { "diff", cmd_diff },
+ { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
+ { "diff-index", cmd_diff_index, RUN_SETUP },
+ { "diff-tree", cmd_diff_tree, RUN_SETUP },
+ { "fast-export", cmd_fast_export, RUN_SETUP },
+ { "fetch", cmd_fetch, RUN_SETUP },
+ { "fetch-pack", cmd_fetch_pack, RUN_SETUP },
+ { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
+ { "for-each-ref", cmd_for_each_ref, RUN_SETUP },
+ { "format-patch", cmd_format_patch, RUN_SETUP },
+ { "fsck", cmd_fsck, RUN_SETUP },
+ { "fsck-objects", cmd_fsck, RUN_SETUP },
+ { "gc", cmd_gc, RUN_SETUP },
+ { "get-tar-commit-id", cmd_get_tar_commit_id },
+ { "grep", cmd_grep, RUN_SETUP_GENTLY },
+ { "hash-object", cmd_hash_object },
+ { "help", cmd_help },
+ { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
+ { "init", cmd_init_db },
+ { "init-db", cmd_init_db },
+ { "log", cmd_log, RUN_SETUP },
+ { "ls-files", cmd_ls_files, RUN_SETUP },
+ { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
+ { "ls-tree", cmd_ls_tree, RUN_SETUP },
+ { "mailinfo", cmd_mailinfo },
+ { "mailsplit", cmd_mailsplit },
+ { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
+ { "merge-base", cmd_merge_base, RUN_SETUP },
+ { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
+ { "merge-index", cmd_merge_index, RUN_SETUP },
+ { "merge-ours", cmd_merge_ours, RUN_SETUP },
+ { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
+ { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
+ { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
+ { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
+ { "merge-tree", cmd_merge_tree, RUN_SETUP },
+ { "mktag", cmd_mktag, RUN_SETUP },
+ { "mktree", cmd_mktree, RUN_SETUP },
+ { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
+ { "name-rev", cmd_name_rev, RUN_SETUP },
+ { "notes", cmd_notes, RUN_SETUP },
+ { "pack-objects", cmd_pack_objects, RUN_SETUP },
+ { "pack-redundant", cmd_pack_redundant, RUN_SETUP },
+ { "pack-refs", cmd_pack_refs, RUN_SETUP },
+ { "patch-id", cmd_patch_id },
+ { "pickaxe", cmd_blame, RUN_SETUP },
+ { "prune", cmd_prune, RUN_SETUP },
+ { "prune-packed", cmd_prune_packed, RUN_SETUP },
+ { "push", cmd_push, RUN_SETUP },
+ { "read-tree", cmd_read_tree, RUN_SETUP },
+ { "receive-pack", cmd_receive_pack },
+ { "reflog", cmd_reflog, RUN_SETUP },
+ { "remote", cmd_remote, RUN_SETUP },
+ { "remote-ext", cmd_remote_ext },
+ { "remote-fd", cmd_remote_fd },
+ { "repack", cmd_repack, RUN_SETUP },
+ { "replace", cmd_replace, RUN_SETUP },
+ { "rerere", cmd_rerere, RUN_SETUP },
+ { "reset", cmd_reset, RUN_SETUP },
+ { "rev-list", cmd_rev_list, RUN_SETUP },
+ { "rev-parse", cmd_rev_parse },
+ { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
+ { "rm", cmd_rm, RUN_SETUP },
+ { "send-pack", cmd_send_pack, RUN_SETUP },
+ { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
+ { "show", cmd_show, RUN_SETUP },
+ { "show-branch", cmd_show_branch, RUN_SETUP },
+ { "show-ref", cmd_show_ref, RUN_SETUP },
+ { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
+ { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
+ { "stripspace", cmd_stripspace },
+ { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
+ { "tag", cmd_tag, RUN_SETUP },
+ { "unpack-file", cmd_unpack_file, RUN_SETUP },
+ { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
+ { "update-index", cmd_update_index, RUN_SETUP },
+ { "update-ref", cmd_update_ref, RUN_SETUP },
+ { "update-server-info", cmd_update_server_info, RUN_SETUP },
+ { "upload-archive", cmd_upload_archive },
+ { "upload-archive--writer", cmd_upload_archive_writer },
+ { "var", cmd_var, RUN_SETUP_GENTLY },
+ { "verify-pack", cmd_verify_pack },
+ { "verify-tag", cmd_verify_tag, RUN_SETUP },
+ { "version", cmd_version },
+ { "whatchanged", cmd_whatchanged, RUN_SETUP },
+ { "write-tree", cmd_write_tree, RUN_SETUP },
+};
+
+int is_builtin(const char *s)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ struct cmd_struct *p = commands+i;
+ if (!strcmp(s, p->cmd))
+ return 1;
+ }
+ return 0;
+}
+
+static void handle_builtin(int argc, const char **argv)
{
const char *cmd = argv[0];
- static struct cmd_struct commands[] = {
- { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
- { "annotate", cmd_annotate, RUN_SETUP },
- { "apply", cmd_apply, RUN_SETUP_GENTLY },
- { "archive", cmd_archive },
- { "bisect--helper", cmd_bisect__helper, RUN_SETUP },
- { "blame", cmd_blame, RUN_SETUP },
- { "branch", cmd_branch, RUN_SETUP },
- { "bundle", cmd_bundle, RUN_SETUP_GENTLY },
- { "cat-file", cmd_cat_file, RUN_SETUP },
- { "check-attr", cmd_check_attr, RUN_SETUP },
- { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
- { "check-mailmap", cmd_check_mailmap, RUN_SETUP },
- { "check-ref-format", cmd_check_ref_format },
- { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
- { "checkout-index", cmd_checkout_index,
- RUN_SETUP | NEED_WORK_TREE},
- { "cherry", cmd_cherry, RUN_SETUP },
- { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
- { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
- { "clone", cmd_clone },
- { "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 },
- { "count-objects", cmd_count_objects, RUN_SETUP },
- { "credential", cmd_credential, RUN_SETUP_GENTLY },
- { "describe", cmd_describe, RUN_SETUP },
- { "diff", cmd_diff },
- { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
- { "diff-index", cmd_diff_index, RUN_SETUP },
- { "diff-tree", cmd_diff_tree, RUN_SETUP },
- { "fast-export", cmd_fast_export, RUN_SETUP },
- { "fetch", cmd_fetch, RUN_SETUP },
- { "fetch-pack", cmd_fetch_pack, RUN_SETUP },
- { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
- { "for-each-ref", cmd_for_each_ref, RUN_SETUP },
- { "format-patch", cmd_format_patch, RUN_SETUP },
- { "fsck", cmd_fsck, RUN_SETUP },
- { "fsck-objects", cmd_fsck, RUN_SETUP },
- { "gc", cmd_gc, RUN_SETUP },
- { "get-tar-commit-id", cmd_get_tar_commit_id },
- { "grep", cmd_grep, RUN_SETUP_GENTLY },
- { "hash-object", cmd_hash_object },
- { "help", cmd_help },
- { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
- { "init", cmd_init_db },
- { "init-db", cmd_init_db },
- { "log", cmd_log, RUN_SETUP },
- { "ls-files", cmd_ls_files, RUN_SETUP },
- { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
- { "ls-tree", cmd_ls_tree, RUN_SETUP },
- { "mailinfo", cmd_mailinfo },
- { "mailsplit", cmd_mailsplit },
- { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
- { "merge-base", cmd_merge_base, RUN_SETUP },
- { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
- { "merge-index", cmd_merge_index, RUN_SETUP },
- { "merge-ours", cmd_merge_ours, RUN_SETUP },
- { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
- { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
- { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
- { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
- { "merge-tree", cmd_merge_tree, RUN_SETUP },
- { "mktag", cmd_mktag, RUN_SETUP },
- { "mktree", cmd_mktree, RUN_SETUP },
- { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
- { "name-rev", cmd_name_rev, RUN_SETUP },
- { "notes", cmd_notes, RUN_SETUP },
- { "pack-objects", cmd_pack_objects, RUN_SETUP },
- { "pack-redundant", cmd_pack_redundant, RUN_SETUP },
- { "pack-refs", cmd_pack_refs, RUN_SETUP },
- { "patch-id", cmd_patch_id },
- { "peek-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
- { "pickaxe", cmd_blame, RUN_SETUP },
- { "prune", cmd_prune, RUN_SETUP },
- { "prune-packed", cmd_prune_packed, RUN_SETUP },
- { "push", cmd_push, RUN_SETUP },
- { "read-tree", cmd_read_tree, RUN_SETUP },
- { "receive-pack", cmd_receive_pack },
- { "reflog", cmd_reflog, RUN_SETUP },
- { "remote", cmd_remote, RUN_SETUP },
- { "remote-ext", cmd_remote_ext },
- { "remote-fd", cmd_remote_fd },
- { "repack", cmd_repack, RUN_SETUP },
- { "replace", cmd_replace, RUN_SETUP },
- { "repo-config", cmd_repo_config, RUN_SETUP_GENTLY },
- { "rerere", cmd_rerere, RUN_SETUP },
- { "reset", cmd_reset, RUN_SETUP },
- { "rev-list", cmd_rev_list, RUN_SETUP },
- { "rev-parse", cmd_rev_parse },
- { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
- { "rm", cmd_rm, RUN_SETUP },
- { "send-pack", cmd_send_pack, RUN_SETUP },
- { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
- { "show", cmd_show, RUN_SETUP },
- { "show-branch", cmd_show_branch, RUN_SETUP },
- { "show-ref", cmd_show_ref, RUN_SETUP },
- { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
- { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
- { "stripspace", cmd_stripspace },
- { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
- { "tag", cmd_tag, RUN_SETUP },
- { "tar-tree", cmd_tar_tree },
- { "unpack-file", cmd_unpack_file, RUN_SETUP },
- { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
- { "update-index", cmd_update_index, RUN_SETUP },
- { "update-ref", cmd_update_ref, RUN_SETUP },
- { "update-server-info", cmd_update_server_info, RUN_SETUP },
- { "upload-archive", cmd_upload_archive },
- { "upload-archive--writer", cmd_upload_archive_writer },
- { "var", cmd_var, RUN_SETUP_GENTLY },
- { "verify-pack", cmd_verify_pack },
- { "verify-tag", cmd_verify_tag, RUN_SETUP },
- { "version", cmd_version },
- { "whatchanged", cmd_whatchanged, RUN_SETUP },
- { "write-tree", cmd_write_tree, RUN_SETUP },
- };
int i;
static const char ext[] = STRIP_EXTENSION;
@@ -520,8 +529,8 @@ static int run_argv(int *argcp, const char ***argv)
int done_alias = 0;
while (1) {
- /* See if it's an internal command */
- handle_internal_command(*argcp, *argv);
+ /* See if it's a builtin */
+ handle_builtin(*argcp, *argv);
/* .. then try the external ones */
execv_dashed_external(*argv);
@@ -566,14 +575,14 @@ int main(int argc, char **av)
* - cannot execute it externally (since it would just do
* the same thing over again)
*
- * So we just directly call the internal command handler, and
- * die if that one cannot handle it.
+ * So we just directly call the builtin handler, and die if
+ * that one cannot handle it.
*/
- if (!prefixcmp(cmd, "git-")) {
+ if (starts_with(cmd, "git-")) {
cmd += 4;
argv[0] = cmd;
- handle_internal_command(argc, argv);
- die("cannot handle %s internally", cmd);
+ handle_builtin(argc, argv);
+ die("cannot handle %s as a builtin", cmd);
}
/* Look for flags.. */
@@ -581,7 +590,7 @@ int main(int argc, char **av)
argc--;
handle_options(&argv, &argc, NULL);
if (argc > 0) {
- if (!prefixcmp(argv[0], "--"))
+ if (starts_with(argv[0], "--"))
argv[0] += 2;
} else {
/* The user didn't specify a command; give them help */
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 5cd00d8..33c3a6c 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -156,10 +156,12 @@ proc unmerged_files {files} {
proc parseviewargs {n arglist} {
global vdatemode vmergeonly vflags vdflags vrevs vfiltered vorigargs env
+ global vinlinediff
global worddiff git_version
set vdatemode($n) 0
set vmergeonly($n) 0
+ set vinlinediff($n) 0
set glflags {}
set diffargs {}
set nextisval 0
@@ -227,12 +229,20 @@ proc parseviewargs {n arglist} {
"--until=*" - "--before=*" - "--max-age=*" - "--min-age=*" -
"--author=*" - "--committer=*" - "--grep=*" - "-[iE]" -
"--remove-empty" - "--first-parent" - "--cherry-pick" -
- "-S*" - "--pickaxe-all" - "--pickaxe-regex" -
+ "-S*" - "-G*" - "--pickaxe-all" - "--pickaxe-regex" -
"--simplify-by-decoration" {
# These mean that we get a subset of the commits
set filtered 1
lappend glflags $arg
}
+ "-L*" {
+ # Line-log with 'stuck' argument (unstuck form is
+ # not supported)
+ set filtered 1
+ set vinlinediff($n) 1
+ set allknown 0
+ lappend glflags $arg
+ }
"-n" {
# This appears to be the only one that has a value as a
# separate word following it
@@ -1704,8 +1714,17 @@ proc parsecommit {id contents listed} {
set comment $newcomment
}
set hasnote [string first "\nNotes:\n" $contents]
+ set diff ""
+ # If there is diff output shown in the git-log stream, split it
+ # out. But get rid of the empty line that always precedes the
+ # diff.
+ set i [string first "\n\ndiff" $comment]
+ if {$i >= 0} {
+ set diff [string range $comment $i+1 end]
+ set comment [string range $comment 0 $i-1]
+ }
set commitinfo($id) [list $headline $auname $audate \
- $comname $comdate $comment $hasnote]
+ $comname $comdate $comment $hasnote $diff]
}
proc getcommit {id} {
@@ -2385,6 +2404,7 @@ proc makewindow {} {
$ctext tag conf found -back $foundbgcolor
$ctext tag conf currentsearchhit -back $currentsearchhitbgcolor
$ctext tag conf wwrap -wrap word
+ $ctext tag conf bold -font textfontbold
.pwbottom add .bleft
if {!$use_ttk} {
@@ -6387,6 +6407,25 @@ proc bindline {t id} {
$canv bind $t <Button-1> "lineclick %x %y $id 1"
}
+proc graph_pane_width {} {
+ global use_ttk
+
+ if {$use_ttk} {
+ set g [.tf.histframe.pwclist sashpos 0]
+ } else {
+ set g [.tf.histframe.pwclist sash coord 0]
+ }
+ return [lindex $g 0]
+}
+
+proc totalwidth {l font extra} {
+ set tot 0
+ foreach str $l {
+ set tot [expr {$tot + [font measure $font $str] + $extra}]
+ }
+ return $tot
+}
+
proc drawtags {id x xt y1} {
global idtags idheads idotherrefs mainhead
global linespc lthickness
@@ -6398,9 +6437,27 @@ proc drawtags {id x xt y1} {
set marks {}
set ntags 0
set nheads 0
+ set singletag 0
+ set maxtags 3
+ set maxtagpct 25
+ set maxwidth [expr {[graph_pane_width] * $maxtagpct / 100}]
+ set delta [expr {int(0.5 * ($linespc - $lthickness))}]
+ set extra [expr {$delta + $lthickness + $linespc}]
+
if {[info exists idtags($id)]} {
set marks $idtags($id)
set ntags [llength $marks]
+ if {$ntags > $maxtags ||
+ [totalwidth $marks mainfont $extra] > $maxwidth} {
+ # show just a single "n tags..." tag
+ set singletag 1
+ if {$ntags == 1} {
+ set marks [list "tag..."]
+ } else {
+ set marks [list [format "%d tags..." $ntags]]
+ }
+ set ntags 1
+ }
}
if {[info exists idheads($id)]} {
set marks [concat $marks $idheads($id)]
@@ -6413,7 +6470,6 @@ proc drawtags {id x xt y1} {
return $xt
}
- set delta [expr {int(0.5 * ($linespc - $lthickness))}]
set yt [expr {$y1 - 0.5 * $linespc}]
set yb [expr {$yt + $linespc - 1}]
set xvals {}
@@ -6428,7 +6484,7 @@ proc drawtags {id x xt y1} {
}
lappend xvals $xt
lappend wvals $wid
- set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
+ set xt [expr {$xt + $wid + $extra}]
}
set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
-width $lthickness -fill $reflinecolor -tags tag.$id]
@@ -6444,7 +6500,12 @@ proc drawtags {id x xt y1} {
$xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
-width 1 -outline $tagoutlinecolor -fill $tagbgcolor \
-tags tag.$id]
- $canv bind $t <1> [list showtag $tag_quoted 1]
+ if {$singletag} {
+ set tagclick [list showtags $id 1]
+ } else {
+ set tagclick [list showtag $tag_quoted 1]
+ }
+ $canv bind $t <1> $tagclick
set rowtextx([rowofcommit $id]) [expr {$xr + $linespc}]
} else {
# draw a head or other ref
@@ -6471,7 +6532,7 @@ proc drawtags {id x xt y1} {
set t [$canv create text $xl $y1 -anchor w -text $tag -fill $headfgcolor \
-font $font -tags [list tag.$id text]]
if {$ntags >= 0} {
- $canv bind $t <1> [list showtag $tag_quoted 1]
+ $canv bind $t <1> $tagclick
} elseif {$nheads >= 0} {
$canv bind $t $ctxbut [list headmenu %X %Y $id $tag_quoted]
}
@@ -7080,6 +7141,7 @@ proc selectline {l isnew {desired_loc {}}} {
global cmitmode showneartags allcommits
global targetrow targetid lastscrollrows
global autoselect autosellen jump_to_here
+ global vinlinediff
catch {unset pending_select}
$canv delete hover
@@ -7221,6 +7283,8 @@ proc selectline {l isnew {desired_loc {}}} {
init_flist [mc "Comments"]
if {$cmitmode eq "tree"} {
gettree $id
+ } elseif {$vinlinediff($curview) == 1} {
+ showinlinediff $id
} elseif {[llength $olds] <= 1} {
startdiff $id
} else {
@@ -7557,6 +7621,39 @@ proc startdiff {ids} {
}
}
+proc showinlinediff {ids} {
+ global commitinfo commitdata ctext
+ global treediffs
+
+ set info $commitinfo($ids)
+ set diff [lindex $info 7]
+ set difflines [split $diff "\n"]
+
+ initblobdiffvars
+ set treediff {}
+
+ set inhdr 0
+ foreach line $difflines {
+ if {![string compare -length 5 "diff " $line]} {
+ set inhdr 1
+ } elseif {$inhdr && ![string compare -length 4 "+++ " $line]} {
+ # offset also accounts for the b/ prefix
+ lappend treediff [string range $line 6 end]
+ set inhdr 0
+ }
+ }
+
+ set treediffs($ids) $treediff
+ add_flist $treediff
+
+ $ctext conf -state normal
+ foreach line $difflines {
+ parseblobdiffline $ids $line
+ }
+ maybe_scroll_ctext 1
+ $ctext conf -state disabled
+}
+
# If the filename (name) is under any of the passed filter paths
# then return true to include the file in the listing.
proc path_filter {filter name} {
@@ -7710,15 +7807,25 @@ proc changeworddiff {name ix op} {
reselectline
}
+proc initblobdiffvars {} {
+ global diffencoding targetline diffnparents
+ global diffinhdr currdiffsubmod diffseehere
+ set targetline {}
+ set diffnparents 0
+ set diffinhdr 0
+ set diffencoding [get_path_encoding {}]
+ set currdiffsubmod ""
+ set diffseehere -1
+}
+
proc getblobdiffs {ids} {
global blobdifffd diffids env
- global diffinhdr treediffs
+ global treediffs
global diffcontext
global ignorespace
global worddiff
global limitdiffs vfilelimit curview
- global diffencoding targetline diffnparents
- global git_version currdiffsubmod
+ global git_version
set textconv {}
if {[package vcompare $git_version "1.6.1"] >= 0} {
@@ -7742,13 +7849,9 @@ proc getblobdiffs {ids} {
error_popup [mc "Error getting diffs: %s" $err]
return
}
- set targetline {}
- set diffnparents 0
- set diffinhdr 0
- set diffencoding [get_path_encoding {}]
fconfigure $bdf -blocking 0 -encoding binary -eofchar {}
set blobdifffd($ids) $bdf
- set currdiffsubmod ""
+ initblobdiffvars
filerun $bdf [list getblobdiffline $bdf $diffids]
}
@@ -7814,13 +7917,17 @@ proc makediffhdr {fname ids} {
set diffline 0
}
+proc blobdiffmaybeseehere {ateof} {
+ global diffseehere
+ if {$diffseehere >= 0} {
+ mark_ctext_line [lindex [split $diffseehere .] 0]
+ }
+ maybe_scroll_ctext ateof
+}
+
proc getblobdiffline {bdf ids} {
- global diffids blobdifffd ctext curdiffstart
- global diffnexthead diffnextnote difffilestart
- global ctext_file_names ctext_file_lines
- global diffinhdr treediffs mergemax diffnparents
- global diffencoding jump_to_here targetline diffline currdiffsubmod
- global worddiff
+ global diffids blobdifffd
+ global ctext
set nr 0
$ctext conf -state normal
@@ -7829,212 +7936,220 @@ proc getblobdiffline {bdf ids} {
catch {close $bdf}
return 0
}
- if {![string compare -length 5 "diff " $line]} {
- if {![regexp {^diff (--cc|--git) } $line m type]} {
- set line [encoding convertfrom $line]
- $ctext insert end "$line\n" hunksep
- continue
+ parseblobdiffline $ids $line
+ }
+ $ctext conf -state disabled
+ blobdiffmaybeseehere [eof $bdf]
+ if {[eof $bdf]} {
+ catch {close $bdf}
+ return 0
+ }
+ return [expr {$nr >= 1000? 2: 1}]
+}
+
+proc parseblobdiffline {ids line} {
+ global ctext curdiffstart
+ global diffnexthead diffnextnote difffilestart
+ global ctext_file_names ctext_file_lines
+ global diffinhdr treediffs mergemax diffnparents
+ global diffencoding jump_to_here targetline diffline currdiffsubmod
+ global worddiff diffseehere
+
+ if {![string compare -length 5 "diff " $line]} {
+ if {![regexp {^diff (--cc|--git) } $line m type]} {
+ set line [encoding convertfrom $line]
+ $ctext insert end "$line\n" hunksep
+ continue
+ }
+ # start of a new file
+ set diffinhdr 1
+ $ctext insert end "\n"
+ set curdiffstart [$ctext index "end - 1c"]
+ lappend ctext_file_names ""
+ lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
+ $ctext insert end "\n" filesep
+
+ if {$type eq "--cc"} {
+ # start of a new file in a merge diff
+ set fname [string range $line 10 end]
+ if {[lsearch -exact $treediffs($ids) $fname] < 0} {
+ lappend treediffs($ids) $fname
+ add_flist [list $fname]
}
- # start of a new file
- set diffinhdr 1
- $ctext insert end "\n"
- set curdiffstart [$ctext index "end - 1c"]
- lappend ctext_file_names ""
- lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
- $ctext insert end "\n" filesep
-
- if {$type eq "--cc"} {
- # start of a new file in a merge diff
- set fname [string range $line 10 end]
- if {[lsearch -exact $treediffs($ids) $fname] < 0} {
- lappend treediffs($ids) $fname
- add_flist [list $fname]
- }
+ } else {
+ set line [string range $line 11 end]
+ # If the name hasn't changed the length will be odd,
+ # the middle char will be a space, and the two bits either
+ # side will be a/name and b/name, or "a/name" and "b/name".
+ # If the name has changed we'll get "rename from" and
+ # "rename to" or "copy from" and "copy to" lines following
+ # this, and we'll use them to get the filenames.
+ # This complexity is necessary because spaces in the
+ # filename(s) don't get escaped.
+ set l [string length $line]
+ set i [expr {$l / 2}]
+ if {!(($l & 1) && [string index $line $i] eq " " &&
+ [string range $line 2 [expr {$i - 1}]] eq \
+ [string range $line [expr {$i + 3}] end])} {
+ return
+ }
+ # unescape if quoted and chop off the a/ from the front
+ if {[string index $line 0] eq "\""} {
+ set fname [string range [lindex $line 0] 2 end]
} else {
- set line [string range $line 11 end]
- # If the name hasn't changed the length will be odd,
- # the middle char will be a space, and the two bits either
- # side will be a/name and b/name, or "a/name" and "b/name".
- # If the name has changed we'll get "rename from" and
- # "rename to" or "copy from" and "copy to" lines following
- # this, and we'll use them to get the filenames.
- # This complexity is necessary because spaces in the
- # filename(s) don't get escaped.
- set l [string length $line]
- set i [expr {$l / 2}]
- if {!(($l & 1) && [string index $line $i] eq " " &&
- [string range $line 2 [expr {$i - 1}]] eq \
- [string range $line [expr {$i + 3}] end])} {
- continue
- }
- # unescape if quoted and chop off the a/ from the front
- if {[string index $line 0] eq "\""} {
- set fname [string range [lindex $line 0] 2 end]
- } else {
- set fname [string range $line 2 [expr {$i - 1}]]
- }
+ set fname [string range $line 2 [expr {$i - 1}]]
}
- makediffhdr $fname $ids
+ }
+ makediffhdr $fname $ids
+
+ } elseif {![string compare -length 16 "* Unmerged path " $line]} {
+ set fname [encoding convertfrom [string range $line 16 end]]
+ $ctext insert end "\n"
+ set curdiffstart [$ctext index "end - 1c"]
+ lappend ctext_file_names $fname
+ lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
+ $ctext insert end "$line\n" filesep
+ set i [lsearch -exact $treediffs($ids) $fname]
+ if {$i >= 0} {
+ setinlist difffilestart $i $curdiffstart
+ }
- } elseif {![string compare -length 16 "* Unmerged path " $line]} {
- set fname [encoding convertfrom [string range $line 16 end]]
- $ctext insert end "\n"
- set curdiffstart [$ctext index "end - 1c"]
- lappend ctext_file_names $fname
- lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
+ } elseif {![string compare -length 2 "@@" $line]} {
+ regexp {^@@+} $line ats
+ set line [encoding convertfrom $diffencoding $line]
+ $ctext insert end "$line\n" hunksep
+ if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
+ set diffline $nl
+ }
+ set diffnparents [expr {[string length $ats] - 1}]
+ set diffinhdr 0
+
+ } elseif {![string compare -length 10 "Submodule " $line]} {
+ # start of a new submodule
+ if {[regexp -indices "\[0-9a-f\]+\\.\\." $line nameend]} {
+ set fname [string range $line 10 [expr [lindex $nameend 0] - 2]]
+ } else {
+ set fname [string range $line 10 [expr [string first "contains " $line] - 2]]
+ }
+ if {$currdiffsubmod != $fname} {
+ $ctext insert end "\n"; # Add newline after commit message
+ }
+ set curdiffstart [$ctext index "end - 1c"]
+ lappend ctext_file_names ""
+ if {$currdiffsubmod != $fname} {
+ lappend ctext_file_lines $fname
+ makediffhdr $fname $ids
+ set currdiffsubmod $fname
+ $ctext insert end "\n$line\n" filesep
+ } else {
$ctext insert end "$line\n" filesep
+ }
+ } elseif {![string compare -length 3 " >" $line]} {
+ set $currdiffsubmod ""
+ set line [encoding convertfrom $diffencoding $line]
+ $ctext insert end "$line\n" dresult
+ } elseif {![string compare -length 3 " <" $line]} {
+ set $currdiffsubmod ""
+ set line [encoding convertfrom $diffencoding $line]
+ $ctext insert end "$line\n" d0
+ } elseif {$diffinhdr} {
+ if {![string compare -length 12 "rename from " $line]} {
+ set fname [string range $line [expr 6 + [string first " from " $line] ] end]
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ set fname [encoding convertfrom $fname]
set i [lsearch -exact $treediffs($ids) $fname]
if {$i >= 0} {
setinlist difffilestart $i $curdiffstart
}
-
- } elseif {![string compare -length 2 "@@" $line]} {
- regexp {^@@+} $line ats
- set line [encoding convertfrom $diffencoding $line]
- $ctext insert end "$line\n" hunksep
- if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
- set diffline $nl
+ } elseif {![string compare -length 10 $line "rename to "] ||
+ ![string compare -length 8 $line "copy to "]} {
+ set fname [string range $line [expr 4 + [string first " to " $line] ] end]
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
}
- set diffnparents [expr {[string length $ats] - 1}]
+ makediffhdr $fname $ids
+ } elseif {[string compare -length 3 $line "---"] == 0} {
+ # do nothing
+ return
+ } elseif {[string compare -length 3 $line "+++"] == 0} {
set diffinhdr 0
+ return
+ }
+ $ctext insert end "$line\n" filesep
- } elseif {![string compare -length 10 "Submodule " $line]} {
- # start of a new submodule
- if {[regexp -indices "\[0-9a-f\]+\\.\\." $line nameend]} {
- set fname [string range $line 10 [expr [lindex $nameend 0] - 2]]
- } else {
- set fname [string range $line 10 [expr [string first "contains " $line] - 2]]
- }
- if {$currdiffsubmod != $fname} {
- $ctext insert end "\n"; # Add newline after commit message
- }
- set curdiffstart [$ctext index "end - 1c"]
- lappend ctext_file_names ""
- if {$currdiffsubmod != $fname} {
- lappend ctext_file_lines $fname
- makediffhdr $fname $ids
- set currdiffsubmod $fname
- $ctext insert end "\n$line\n" filesep
- } else {
- $ctext insert end "$line\n" filesep
- }
- } elseif {![string compare -length 3 " >" $line]} {
- set $currdiffsubmod ""
- set line [encoding convertfrom $diffencoding $line]
- $ctext insert end "$line\n" dresult
- } elseif {![string compare -length 3 " <" $line]} {
- set $currdiffsubmod ""
- set line [encoding convertfrom $diffencoding $line]
- $ctext insert end "$line\n" d0
- } elseif {$diffinhdr} {
- if {![string compare -length 12 "rename from " $line]} {
- set fname [string range $line [expr 6 + [string first " from " $line] ] end]
- if {[string index $fname 0] eq "\""} {
- set fname [lindex $fname 0]
- }
- set fname [encoding convertfrom $fname]
- set i [lsearch -exact $treediffs($ids) $fname]
- if {$i >= 0} {
- setinlist difffilestart $i $curdiffstart
+ } else {
+ set line [string map {\x1A ^Z} \
+ [encoding convertfrom $diffencoding $line]]
+ # parse the prefix - one ' ', '-' or '+' for each parent
+ set prefix [string range $line 0 [expr {$diffnparents - 1}]]
+ set tag [expr {$diffnparents > 1? "m": "d"}]
+ set dowords [expr {$worddiff ne [mc "Line diff"] && $diffnparents == 1}]
+ set words_pre_markup ""
+ set words_post_markup ""
+ if {[string trim $prefix " -+"] eq {}} {
+ # prefix only has " ", "-" and "+" in it: normal diff line
+ set num [string first "-" $prefix]
+ if {$dowords} {
+ set line [string range $line 1 end]
+ }
+ if {$num >= 0} {
+ # removed line, first parent with line is $num
+ if {$num >= $mergemax} {
+ set num "max"
}
- } elseif {![string compare -length 10 $line "rename to "] ||
- ![string compare -length 8 $line "copy to "]} {
- set fname [string range $line [expr 4 + [string first " to " $line] ] end]
- if {[string index $fname 0] eq "\""} {
- set fname [lindex $fname 0]
+ if {$dowords && $worddiff eq [mc "Markup words"]} {
+ $ctext insert end "\[-$line-\]" $tag$num
+ } else {
+ $ctext insert end "$line" $tag$num
}
- makediffhdr $fname $ids
- } elseif {[string compare -length 3 $line "---"] == 0} {
- # do nothing
- continue
- } elseif {[string compare -length 3 $line "+++"] == 0} {
- set diffinhdr 0
- continue
- }
- $ctext insert end "$line\n" filesep
-
- } else {
- set line [string map {\x1A ^Z} \
- [encoding convertfrom $diffencoding $line]]
- # parse the prefix - one ' ', '-' or '+' for each parent
- set prefix [string range $line 0 [expr {$diffnparents - 1}]]
- set tag [expr {$diffnparents > 1? "m": "d"}]
- set dowords [expr {$worddiff ne [mc "Line diff"] && $diffnparents == 1}]
- set words_pre_markup ""
- set words_post_markup ""
- if {[string trim $prefix " -+"] eq {}} {
- # prefix only has " ", "-" and "+" in it: normal diff line
- set num [string first "-" $prefix]
- if {$dowords} {
- set line [string range $line 1 end]
+ if {!$dowords} {
+ $ctext insert end "\n" $tag$num
}
- if {$num >= 0} {
- # removed line, first parent with line is $num
- if {$num >= $mergemax} {
- set num "max"
- }
- if {$dowords && $worddiff eq [mc "Markup words"]} {
- $ctext insert end "\[-$line-\]" $tag$num
- } else {
- $ctext insert end "$line" $tag$num
- }
- if {!$dowords} {
- $ctext insert end "\n" $tag$num
- }
- } else {
- set tags {}
- if {[string first "+" $prefix] >= 0} {
- # added line
- lappend tags ${tag}result
- if {$diffnparents > 1} {
- set num [string first " " $prefix]
- if {$num >= 0} {
- if {$num >= $mergemax} {
- set num "max"
- }
- lappend tags m$num
+ } else {
+ set tags {}
+ if {[string first "+" $prefix] >= 0} {
+ # added line
+ lappend tags ${tag}result
+ if {$diffnparents > 1} {
+ set num [string first " " $prefix]
+ if {$num >= 0} {
+ if {$num >= $mergemax} {
+ set num "max"
}
+ lappend tags m$num
}
- set words_pre_markup "{+"
- set words_post_markup "+}"
}
- if {$targetline ne {}} {
- if {$diffline == $targetline} {
- set seehere [$ctext index "end - 1 chars"]
- set targetline {}
- } else {
- incr diffline
- }
- }
- if {$dowords && $worddiff eq [mc "Markup words"]} {
- $ctext insert end "$words_pre_markup$line$words_post_markup" $tags
+ set words_pre_markup "{+"
+ set words_post_markup "+}"
+ }
+ if {$targetline ne {}} {
+ if {$diffline == $targetline} {
+ set diffseehere [$ctext index "end - 1 chars"]
+ set targetline {}
} else {
- $ctext insert end "$line" $tags
- }
- if {!$dowords} {
- $ctext insert end "\n" $tags
+ incr diffline
}
}
- } elseif {$dowords && $prefix eq "~"} {
- $ctext insert end "\n" {}
- } else {
- # "\ No newline at end of file",
- # or something else we don't recognize
- $ctext insert end "$line\n" hunksep
+ if {$dowords && $worddiff eq [mc "Markup words"]} {
+ $ctext insert end "$words_pre_markup$line$words_post_markup" $tags
+ } else {
+ $ctext insert end "$line" $tags
+ }
+ if {!$dowords} {
+ $ctext insert end "\n" $tags
+ }
}
+ } elseif {$dowords && $prefix eq "~"} {
+ $ctext insert end "\n" {}
+ } else {
+ # "\ No newline at end of file",
+ # or something else we don't recognize
+ $ctext insert end "$line\n" hunksep
}
}
- if {[info exists seehere]} {
- mark_ctext_line [lindex [split $seehere .] 0]
- }
- maybe_scroll_ctext [eof $bdf]
- $ctext conf -state disabled
- if {[eof $bdf]} {
- catch {close $bdf}
- return 0
- }
- return [expr {$nr >= 1000? 2: 1}]
}
proc changediffdisp {} {
@@ -10878,6 +10993,23 @@ proc listrefs {id} {
return [list $x $y $z]
}
+proc add_tag_ctext {tag} {
+ global ctext cached_tagcontent tagids
+
+ if {![info exists cached_tagcontent($tag)]} {
+ catch {
+ set cached_tagcontent($tag) [exec git cat-file -p $tag]
+ }
+ }
+ $ctext insert end "[mc "Tag"]: $tag\n" bold
+ if {[info exists cached_tagcontent($tag)]} {
+ set text $cached_tagcontent($tag)
+ } else {
+ set text "[mc "Id"]: $tagids($tag)"
+ }
+ appendwithlinks $text {}
+}
+
proc showtag {tag isnew} {
global ctext cached_tagcontent tagids linknum tagobjid
@@ -10888,17 +11020,28 @@ proc showtag {tag isnew} {
clear_ctext
settabs 0
set linknum 0
- if {![info exists cached_tagcontent($tag)]} {
- catch {
- set cached_tagcontent($tag) [exec git cat-file -p $tag]
- }
+ add_tag_ctext $tag
+ maybe_scroll_ctext 1
+ $ctext conf -state disabled
+ init_flist {}
+}
+
+proc showtags {id isnew} {
+ global idtags ctext linknum
+
+ if {$isnew} {
+ addtohistory [list showtags $id 0] savectextpos
}
- if {[info exists cached_tagcontent($tag)]} {
- set text $cached_tagcontent($tag)
- } else {
- set text "[mc "Tag"]: $tag\n[mc "Id"]: $tagids($tag)"
+ $ctext conf -state normal
+ clear_ctext
+ settabs 0
+ set linknum 0
+ set sep {}
+ foreach tag $idtags($id) {
+ $ctext insert end $sep
+ add_tag_ctext $tag
+ set sep "\n\n"
}
- appendwithlinks $text {}
maybe_scroll_ctext 1
$ctext conf -state disabled
init_flist {}
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 68c77f6..3bc0f0b 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -548,6 +548,20 @@ our %feature = (
'sub' => sub { feature_bool('remote_heads', @_) },
'override' => 0,
'default' => [0]},
+
+ # Enable showing branches under other refs in addition to heads
+
+ # To set system wide extra branch refs have in $GITWEB_CONFIG
+ # $feature{'extra-branch-refs'}{'default'} = ['dirs', 'of', 'choice'];
+ # To have project specific config enable override in $GITWEB_CONFIG
+ # $feature{'extra-branch-refs'}{'override'} = 1;
+ # and in project config gitweb.extrabranchrefs = dirs of choice
+ # Every directory is separated with whitespace.
+
+ 'extra-branch-refs' => {
+ 'sub' => \&feature_extra_branch_refs,
+ 'override' => 0,
+ 'default' => []},
);
sub gitweb_get_feature {
@@ -626,6 +640,21 @@ sub feature_avatar {
return @val ? @val : @_;
}
+sub feature_extra_branch_refs {
+ my (@branch_refs) = @_;
+ my $values = git_get_project_config('extrabranchrefs');
+
+ if ($values) {
+ $values = config_to_multi ($values);
+ @branch_refs = ();
+ foreach my $value (@{$values}) {
+ push @branch_refs, split /\s+/, $value;
+ }
+ }
+
+ return @branch_refs;
+}
+
# checking HEAD file with -e is fragile if the repository was
# initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed
# and then pruned.
@@ -656,6 +685,18 @@ sub filter_snapshot_fmts {
!$known_snapshot_formats{$_}{'disabled'}} @fmts;
}
+sub filter_and_validate_refs {
+ my @refs = @_;
+ my %unique_refs = ();
+
+ foreach my $ref (@refs) {
+ die_error(500, "Invalid ref '$ref' in 'extra-branch-refs' feature") unless (is_valid_ref_format($ref));
+ # 'heads' are added implicitly in get_branch_refs().
+ $unique_refs{$ref} = 1 if ($ref ne 'heads');
+ }
+ return sort keys %unique_refs;
+}
+
# If it is set to code reference, it is code that it is to be run once per
# request, allowing updating configurations that change with each request,
# while running other code in config file only once.
@@ -994,7 +1035,7 @@ our ($action, $project, $file_name, $file_parent, $hash, $hash_parent, $hash_bas
sub evaluate_and_validate_params {
our $action = $input_params{'action'};
if (defined $action) {
- if (!validate_action($action)) {
+ if (!is_valid_action($action)) {
die_error(400, "Invalid action parameter");
}
}
@@ -1002,7 +1043,7 @@ sub evaluate_and_validate_params {
# parameters which are pathnames
our $project = $input_params{'project'};
if (defined $project) {
- if (!validate_project($project)) {
+ if (!is_valid_project($project)) {
undef $project;
die_error(404, "No such project");
}
@@ -1010,21 +1051,21 @@ sub evaluate_and_validate_params {
our $project_filter = $input_params{'project_filter'};
if (defined $project_filter) {
- if (!validate_pathname($project_filter)) {
+ if (!is_valid_pathname($project_filter)) {
die_error(404, "Invalid project_filter parameter");
}
}
our $file_name = $input_params{'file_name'};
if (defined $file_name) {
- if (!validate_pathname($file_name)) {
+ if (!is_valid_pathname($file_name)) {
die_error(400, "Invalid file parameter");
}
}
our $file_parent = $input_params{'file_parent'};
if (defined $file_parent) {
- if (!validate_pathname($file_parent)) {
+ if (!is_valid_pathname($file_parent)) {
die_error(400, "Invalid file parent parameter");
}
}
@@ -1032,21 +1073,21 @@ sub evaluate_and_validate_params {
# parameters which are refnames
our $hash = $input_params{'hash'};
if (defined $hash) {
- if (!validate_refname($hash)) {
+ if (!is_valid_refname($hash)) {
die_error(400, "Invalid hash parameter");
}
}
our $hash_parent = $input_params{'hash_parent'};
if (defined $hash_parent) {
- if (!validate_refname($hash_parent)) {
+ if (!is_valid_refname($hash_parent)) {
die_error(400, "Invalid hash parent parameter");
}
}
our $hash_base = $input_params{'hash_base'};
if (defined $hash_base) {
- if (!validate_refname($hash_base)) {
+ if (!is_valid_refname($hash_base)) {
die_error(400, "Invalid hash base parameter");
}
}
@@ -1066,7 +1107,7 @@ sub evaluate_and_validate_params {
our $hash_parent_base = $input_params{'hash_parent_base'};
if (defined $hash_parent_base) {
- if (!validate_refname($hash_parent_base)) {
+ if (!is_valid_refname($hash_parent_base)) {
die_error(400, "Invalid hash parent base parameter");
}
}
@@ -1113,7 +1154,7 @@ sub evaluate_git_dir {
our $git_dir = "$projectroot/$project" if $project;
}
-our (@snapshot_fmts, $git_avatar);
+our (@snapshot_fmts, $git_avatar, @extra_branch_refs);
sub configure_gitweb_features {
# list of supported snapshot formats
our @snapshot_fmts = gitweb_get_feature('snapshot');
@@ -1131,6 +1172,13 @@ sub configure_gitweb_features {
} else {
$git_avatar = '';
}
+
+ our @extra_branch_refs = gitweb_get_feature('extra-branch-refs');
+ @extra_branch_refs = filter_and_validate_refs (@extra_branch_refs);
+}
+
+sub get_branch_refs {
+ return ('heads', @extra_branch_refs);
}
# custom error handler: 'die <message>' is Internal Server Error
@@ -1418,27 +1466,30 @@ sub href {
## ======================================================================
## validation, quoting/unquoting and escaping
-sub validate_action {
- my $input = shift || return undef;
+sub is_valid_action {
+ my $input = shift;
return undef unless exists $actions{$input};
- return $input;
+ return 1;
}
-sub validate_project {
- my $input = shift || return undef;
- if (!validate_pathname($input) ||
+sub is_valid_project {
+ my $input = shift;
+
+ return unless defined $input;
+ if (!is_valid_pathname($input) ||
!(-d "$projectroot/$input") ||
!check_export_ok("$projectroot/$input") ||
($strict_export && !project_in_list($input))) {
return undef;
} else {
- return $input;
+ return 1;
}
}
-sub validate_pathname {
- my $input = shift || return undef;
+sub is_valid_pathname {
+ my $input = shift;
+ return undef unless defined $input;
# no '.' or '..' as elements of path, i.e. no '.' nor '..'
# at the beginning, at the end, and between slashes.
# also this catches doubled slashes
@@ -1449,24 +1500,33 @@ sub validate_pathname {
if ($input =~ m!\0!) {
return undef;
}
- return $input;
+ return 1;
}
-sub validate_refname {
- my $input = shift || return undef;
+sub is_valid_ref_format {
+ my $input = shift;
- # textual hashes are O.K.
- if ($input =~ m/^[0-9a-fA-F]{40}$/) {
- return $input;
- }
- # it must be correct pathname
- $input = validate_pathname($input)
- or return undef;
+ return undef unless defined $input;
# restrictions on ref name according to git-check-ref-format
if ($input =~ m!(/\.|\.\.|[\000-\040\177 ~^:?*\[]|/$)!) {
return undef;
}
- return $input;
+ return 1;
+}
+
+sub is_valid_refname {
+ my $input = shift;
+
+ return undef unless defined $input;
+ # textual hashes are O.K.
+ if ($input =~ m/^[0-9a-fA-F]{40}$/) {
+ return 1;
+ }
+ # it must be correct pathname
+ is_valid_pathname($input) or return undef;
+ # check git-check-ref-format restrictions
+ is_valid_ref_format($input) or return undef;
+ return 1;
}
# decode sequences of octets in utf8 into Perl's internal form,
@@ -2515,6 +2575,7 @@ sub format_snapshot_links {
sub get_feed_info {
my $format = shift || 'Atom';
my %res = (action => lc($format));
+ my $matched_ref = 0;
# feed links are possible only for project views
return unless (defined $project);
@@ -2522,12 +2583,17 @@ sub get_feed_info {
# or don't have specific feed yet (so they should use generic)
return if (!$action || $action =~ /^(?:tags|heads|forks|tag|search)$/x);
- my $branch;
- # branches refs uses 'refs/heads/' prefix (fullname) to differentiate
- # from tag links; this also makes possible to detect branch links
- if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||
- (defined $hash && $hash =~ m!^refs/heads/(.*)$!)) {
- $branch = $1;
+ my $branch = undef;
+ # branches refs uses 'refs/' + $get_branch_refs()[x] + '/' prefix
+ # (fullname) to differentiate from tag links; this also makes
+ # possible to detect branch links
+ for my $ref (get_branch_refs()) {
+ if ((defined $hash_base && $hash_base =~ m!^refs/\Q$ref\E/(.*)$!) ||
+ (defined $hash && $hash =~ m!^refs/\Q$ref\E/(.*)$!)) {
+ $branch = $1;
+ $matched_ref = $ref;
+ last;
+ }
}
# find log type for feed description (title)
my $type = 'log';
@@ -2540,7 +2606,7 @@ sub get_feed_info {
}
$res{-title} = $type;
- $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef);
+ $res{'hash'} = (defined $branch ? "refs/$matched_ref/$branch" : undef);
$res{'file_name'} = $file_name;
return %res;
@@ -3193,7 +3259,7 @@ sub git_get_last_activity {
'--format=%(committer)',
'--sort=-committerdate',
'--count=1',
- 'refs/heads') or return;
+ map { "refs/$_" } get_branch_refs ()) or return;
my $most_recent = <$fd>;
close $fd or return;
if (defined $most_recent &&
@@ -3644,7 +3710,7 @@ sub parse_from_to_diffinfo {
sub git_get_heads_list {
my ($limit, @classes) = @_;
- @classes = ('heads') unless @classes;
+ @classes = get_branch_refs() unless @classes;
my @patterns = map { "refs/$_" } @classes;
my @headslist;
@@ -3662,9 +3728,16 @@ sub git_get_heads_list {
my ($committer, $epoch, $tz) =
($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
$ref_item{'fullname'} = $name;
- $name =~ s!^refs/(?:head|remote)s/!!;
+ my $strip_refs = join '|', map { quotemeta } get_branch_refs();
+ $name =~ s!^refs/($strip_refs|remotes)/!!;
+ $ref_item{'name'} = $name;
+ # for refs neither in 'heads' nor 'remotes' we want to
+ # show their ref dir
+ my $ref_dir = (defined $1) ? $1 : '';
+ if ($ref_dir ne '' and $ref_dir ne 'heads' and $ref_dir ne 'remotes') {
+ $ref_item{'name'} .= ' (' . $ref_dir . ')';
+ }
- $ref_item{'name'} = $name;
$ref_item{'id'} = $hash;
$ref_item{'title'} = $title || '(no commit message)';
$ref_item{'epoch'} = $epoch;
@@ -7156,6 +7229,15 @@ sub git_tree {
git_footer_html();
}
+sub sanitize_for_filename {
+ my $name = shift;
+
+ $name =~ s!/!-!g;
+ $name =~ s/[^[:alnum:]_.-]//g;
+
+ return $name;
+}
+
sub snapshot_name {
my ($project, $hash) = @_;
@@ -7163,9 +7245,7 @@ sub snapshot_name {
# path/to/project/.git -> project
my $name = to_utf8($project);
$name =~ s,([^/])/*\.git$,$1,;
- $name = basename($name);
- # sanitize name
- $name =~ s/[[:cntrl:]]/?/g;
+ $name = sanitize_for_filename(basename($name));
my $ver = $hash;
if ($hash =~ /^[0-9a-fA-F]+$/) {
@@ -7179,13 +7259,25 @@ sub snapshot_name {
$ver = $1;
} else {
# branches and other need shortened SHA-1 hash
- if ($hash =~ m!^refs/(?:heads|remotes)/(.*)$!) {
- $ver = $1;
+ my $strip_refs = join '|', map { quotemeta } get_branch_refs();
+ if ($hash =~ m!^refs/($strip_refs|remotes)/(.*)$!) {
+ my $ref_dir = (defined $1) ? $1 : '';
+ $ver = $2;
+
+ $ref_dir = sanitize_for_filename($ref_dir);
+ # for refs neither in heads nor remotes we want to
+ # add a ref dir to archive name
+ if ($ref_dir ne '' and $ref_dir ne 'heads' and $ref_dir ne 'remotes') {
+ $ver = $ref_dir . '-' . $ver;
+ }
}
$ver .= '-' . git_get_short_hash($project, $hash);
}
+ # special case of sanitization for filename - we change
+ # slashes to dots instead of dashes
# in case of hierarchical branch names
$ver =~ s!/!.!g;
+ $ver =~ s/[^[:alnum:]_.-]//g;
# name = project-version_string
$name = "$name-$ver";
diff --git a/help.c b/help.c
index f068925..df7d16d 100644
--- a/help.c
+++ b/help.c
@@ -148,7 +148,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
while ((de = readdir(dir)) != NULL) {
int entlen;
- if (prefixcmp(de->d_name, prefix))
+ if (!starts_with(de->d_name, prefix))
continue;
strbuf_setlen(&buf, len);
@@ -255,7 +255,7 @@ static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "help.autocorrect"))
autocorrect = git_config_int(var,value);
/* Also use aliases for command lookup */
- if (!prefixcmp(var, "alias."))
+ if (starts_with(var, "alias."))
add_cmdname(&aliases, var + 6, strlen(var + 6));
return git_default_config(var, value, cb);
@@ -329,7 +329,7 @@ const char *help_unknown_cmd(const char *cmd)
if ((n < ARRAY_SIZE(common_cmds)) && !cmp) {
/* Yes, this is one of the common commands */
n++; /* use the entry from common_cmds[] */
- if (!prefixcmp(candidate, cmd)) {
+ if (starts_with(candidate, cmd)) {
/* Give prefix match a very good score */
main_cmds.names[i]->len = 0;
continue;
@@ -414,7 +414,7 @@ static int append_similar_ref(const char *refname, const unsigned char *sha1,
struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
char *branch = strrchr(refname, '/') + 1;
/* A remote branch of the same name is deemed similar */
- if (!prefixcmp(refname, "refs/remotes/") &&
+ if (starts_with(refname, "refs/remotes/") &&
!strcmp(branch, cb->base_ref))
string_list_append(cb->similar_refs,
refname + strlen("refs/remotes/"));
diff --git a/http-backend.c b/http-backend.c
index 8c464bd..d2c0a62 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -226,7 +226,7 @@ static int http_config(const char *var, const char *value, void *cb)
return 0;
}
- if (!prefixcmp(var, "http.")) {
+ if (starts_with(var, "http.")) {
int i;
for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
@@ -247,7 +247,7 @@ static struct rpc_service *select_service(const char *name)
struct rpc_service *svc = NULL;
int i;
- if (prefixcmp(name, "git-"))
+ if (!starts_with(name, "git-"))
forbidden("Unsupported service: '%s'", name);
for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
diff --git a/http-push.c b/http-push.c
index 34cb70f..d4b40c9 100644
--- a/http-push.c
+++ b/http-push.c
@@ -771,7 +771,7 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
lock->owner = xmalloc(strlen(ctx->cdata) + 1);
strcpy(lock->owner, ctx->cdata);
} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
- if (!prefixcmp(ctx->cdata, "Second-"))
+ if (starts_with(ctx->cdata, "Second-"))
lock->timeout =
strtol(ctx->cdata + 7, NULL, 10);
} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
@@ -1579,7 +1579,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
return;
/* If it's a symref, set the refname; otherwise try for a sha1 */
- if (!prefixcmp((char *)buffer.buf, "ref: ")) {
+ if (starts_with((char *)buffer.buf, "ref: ")) {
*symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
} else {
get_sha1_hex(buffer.buf, sha1);
diff --git a/http.c b/http.c
index bcf54aa..70eaa26 100644
--- a/http.c
+++ b/http.c
@@ -460,7 +460,7 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
credential_from_url(&http_auth, url);
if (!ssl_cert_password_required &&
getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") &&
- !prefixcmp(url, "https://"))
+ starts_with(url, "https://"))
ssl_cert_password_required = 1;
}
@@ -761,6 +761,12 @@ void finish_active_slot(struct active_request_slot *slot)
if (slot->results != NULL) {
slot->results->curl_result = slot->curl_result;
slot->results->http_code = slot->http_code;
+#if LIBCURL_VERSION_NUM >= 0x070a08
+ curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
+ &slot->results->auth_avail);
+#else
+ slot->results->auth_avail = 0;
+#endif
}
/* Run callback if appropriate */
@@ -994,7 +1000,7 @@ static int update_url_from_redirect(struct strbuf *base,
if (!strcmp(asked, got->buf))
return 0;
- if (prefixcmp(asked, base->buf))
+ if (!starts_with(asked, base->buf))
die("BUG: update_url_from_redirect: %s is not a superset of %s",
asked, base->buf);
@@ -1100,7 +1106,7 @@ int http_fetch_ref(const char *base, struct ref *ref)
strbuf_rtrim(&buffer);
if (buffer.len == 40)
ret = get_sha1_hex(buffer.buf, ref->old_sha1);
- else if (!prefixcmp(buffer.buf, "ref: ")) {
+ else if (starts_with(buffer.buf, "ref: ")) {
ref->symref = xstrdup(buffer.buf + 5);
ret = 0;
}
@@ -1201,8 +1207,8 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
case 'P':
i++;
if (i + 52 <= buf.len &&
- !prefixcmp(data + i, " pack-") &&
- !prefixcmp(data + i + 46, ".pack\n")) {
+ starts_with(data + i, " pack-") &&
+ starts_with(data + i + 46, ".pack\n")) {
get_sha1_hex(data + i + 6, sha1);
fetch_and_setup_pack_index(packs_head, sha1,
base_url);
diff --git a/http.h b/http.h
index 12ca5c8..cd37d58 100644
--- a/http.h
+++ b/http.h
@@ -54,6 +54,7 @@
struct slot_results {
CURLcode curl_result;
long http_code;
+ long auth_avail;
};
struct active_request_slot {
diff --git a/imap-send.c b/imap-send.c
index 6f5cc4f..0bc6f7f 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1263,7 +1263,7 @@ static int count_messages(struct strbuf *all_msgs)
char *p = all_msgs->buf;
while (1) {
- if (!prefixcmp(p, "From ")) {
+ if (starts_with(p, "From ")) {
p = strstr(p+5, "\nFrom: ");
if (!p) break;
p = strstr(p+7, "\nDate: ");
@@ -1297,7 +1297,7 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
data = &all_msgs->buf[*ofs];
len = all_msgs->len - *ofs;
- if (len < 5 || prefixcmp(data, "From "))
+ if (len < 5 || !starts_with(data, "From "))
return 0;
p = strchr(data, '\n');
@@ -1339,13 +1339,13 @@ static int git_imap_config(const char *key, const char *val, void *cb)
if (!strcmp("folder", key)) {
imap_folder = xstrdup(val);
} else if (!strcmp("host", key)) {
- if (!prefixcmp(val, "imap:"))
+ if (starts_with(val, "imap:"))
val += 5;
- else if (!prefixcmp(val, "imaps:")) {
+ else if (starts_with(val, "imaps:")) {
val += 6;
server.use_ssl = 1;
}
- if (!prefixcmp(val, "//"))
+ if (starts_with(val, "//"))
val += 2;
server.host = xstrdup(val);
} else if (!strcmp("user", key))
diff --git a/log-tree.c b/log-tree.c
index 8534d91..08970bf 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -98,7 +98,7 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
struct object *obj;
enum decoration_type type = DECORATION_NONE;
- if (!prefixcmp(refname, "refs/replace/")) {
+ if (starts_with(refname, "refs/replace/")) {
unsigned char original_sha1[20];
if (!read_replace_refs)
return 0;
@@ -116,11 +116,11 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
if (!obj)
return 0;
- if (!prefixcmp(refname, "refs/heads/"))
+ if (starts_with(refname, "refs/heads/"))
type = DECORATION_REF_LOCAL;
- else if (!prefixcmp(refname, "refs/remotes/"))
+ else if (starts_with(refname, "refs/remotes/"))
type = DECORATION_REF_REMOTE;
- else if (!prefixcmp(refname, "refs/tags/"))
+ else if (starts_with(refname, "refs/tags/"))
type = DECORATION_REF_TAG;
else if (!strcmp(refname, "refs/stash"))
type = DECORATION_REF_STASH;
@@ -134,6 +134,8 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
obj = ((struct tag *)obj)->tagged;
if (!obj)
break;
+ if (!obj->parsed)
+ parse_object(obj->sha1);
add_name_decoration(DECORATION_REF_TAG, refname, obj);
}
return 0;
@@ -734,7 +736,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS))
return 0;
- parse_commit(commit);
+ parse_commit_or_die(commit);
sha1 = commit->tree->object.sha1;
/* Root commit? */
@@ -759,7 +761,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
* parent, showing summary diff of the others
* we merged _in_.
*/
- parse_commit(parents->item);
+ parse_commit_or_die(parents->item);
diff_tree_sha1(parents->item->tree->object.sha1,
sha1, "", &opt->diffopt);
log_tree_diff_flush(opt);
@@ -774,7 +776,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
for (;;) {
struct commit *parent = parents->item;
- parse_commit(parent);
+ parse_commit_or_die(parent);
diff_tree_sha1(parent->tree->object.sha1,
sha1, "", &opt->diffopt);
log_tree_diff_flush(opt);
diff --git a/merge-recursive.c b/merge-recursive.c
index dbb7104..a18bd15 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -2063,13 +2063,13 @@ int parse_merge_opt(struct merge_options *o, const char *s)
o->recursive_variant = MERGE_RECURSIVE_THEIRS;
else if (!strcmp(s, "subtree"))
o->subtree_shift = "";
- else if (!prefixcmp(s, "subtree="))
+ else if (starts_with(s, "subtree="))
o->subtree_shift = s + strlen("subtree=");
else if (!strcmp(s, "patience"))
o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
else if (!strcmp(s, "histogram"))
o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
- else if (!prefixcmp(s, "diff-algorithm=")) {
+ else if (starts_with(s, "diff-algorithm=")) {
long value = parse_algorithm_value(s + strlen("diff-algorithm="));
if (value < 0)
return -1;
@@ -2088,7 +2088,7 @@ int parse_merge_opt(struct merge_options *o, const char *s)
o->renormalize = 1;
else if (!strcmp(s, "no-renormalize"))
o->renormalize = 0;
- else if (!prefixcmp(s, "rename-threshold=")) {
+ else if (starts_with(s, "rename-threshold=")) {
const char *score = s + strlen("rename-threshold=");
if ((o->rename_score = parse_rename_score(&score)) == -1 || *score != 0)
return -1;
diff --git a/notes-utils.c b/notes-utils.c
index 9107c37..2975dcd 100644
--- a/notes-utils.c
+++ b/notes-utils.c
@@ -18,7 +18,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
unsigned char parent_sha1[20];
if (!read_ref(t->ref, parent_sha1)) {
struct commit *parent = lookup_commit(parent_sha1);
- if (!parent || parse_commit(parent))
+ if (parse_commit(parent))
die("Failed to find/parse commit %s", t->ref);
commit_list_insert(parent, &parents);
}
@@ -70,7 +70,7 @@ static combine_notes_fn parse_combine_notes_fn(const char *v)
static int notes_rewrite_config(const char *k, const char *v, void *cb)
{
struct notes_rewrite_cfg *c = cb;
- if (!prefixcmp(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) {
+ if (starts_with(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) {
c->enabled = git_config_bool(k, v);
return 0;
} else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) {
@@ -85,7 +85,7 @@ static int notes_rewrite_config(const char *k, const char *v, void *cb)
} else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) {
/* note that a refs/ prefix is implied in the
* underlying for_each_glob_ref */
- if (!prefixcmp(v, "refs/notes/"))
+ if (starts_with(v, "refs/notes/"))
string_list_add_refs_by_glob(c->refs, v);
else
warning(_("Refusing to rewrite notes in %s"
diff --git a/notes.c b/notes.c
index b69c0b8..5f07c0b 100644
--- a/notes.c
+++ b/notes.c
@@ -1243,9 +1243,9 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) {
strbuf_addstr(sb, "\nNotes:\n");
} else {
- if (!prefixcmp(ref, "refs/"))
+ if (starts_with(ref, "refs/"))
ref += 5;
- if (!prefixcmp(ref, "notes/"))
+ if (starts_with(ref, "notes/"))
ref += 6;
strbuf_addf(sb, "\nNotes (%s):\n", ref);
}
@@ -1293,9 +1293,9 @@ int copy_note(struct notes_tree *t,
void expand_notes_ref(struct strbuf *sb)
{
- if (!prefixcmp(sb->buf, "refs/notes/"))
+ if (starts_with(sb->buf, "refs/notes/"))
return; /* we're happy */
- else if (!prefixcmp(sb->buf, "notes/"))
+ else if (starts_with(sb->buf, "notes/"))
strbuf_insert(sb, 0, "refs/", 5);
else
strbuf_insert(sb, 0, "refs/notes/", 11);
diff --git a/pack-write.c b/pack-write.c
index ca9e63b..605d01b 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -44,14 +44,13 @@ static int need_large_offset(off_t offset, const struct pack_idx_option *opts)
*/
const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects,
int nr_objects, const struct pack_idx_option *opts,
- unsigned char *sha1)
+ const unsigned char *sha1)
{
struct sha1file *f;
struct pack_idx_entry **sorted_by_sha, **list, **last;
off_t last_obj_offset = 0;
uint32_t array[256];
int i, fd;
- git_SHA_CTX ctx;
uint32_t index_version;
if (nr_objects) {
@@ -114,9 +113,6 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
}
sha1write(f, array, 256 * 4);
- /* compute the SHA1 hash of sorted object names. */
- git_SHA1_Init(&ctx);
-
/*
* Write the actual SHA1 entries..
*/
@@ -128,7 +124,6 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
sha1write(f, &offset, 4);
}
sha1write(f, obj->sha1, 20);
- git_SHA1_Update(&ctx, obj->sha1, 20);
if ((opts->flags & WRITE_IDX_STRICT) &&
(i && !hashcmp(list[-2]->sha1, obj->sha1)))
die("The same object %s appears twice in the pack",
@@ -178,7 +173,6 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
sha1write(f, sha1, 20);
sha1close(f, NULL, ((opts->flags & WRITE_IDX_VERIFY)
? CSUM_CLOSE : CSUM_FSYNC));
- git_SHA1_Final(sha1, &ctx);
return index_name;
}
@@ -189,8 +183,7 @@ off_t write_pack_header(struct sha1file *f, uint32_t nr_entries)
hdr.hdr_signature = htonl(PACK_SIGNATURE);
hdr.hdr_version = htonl(PACK_VERSION);
hdr.hdr_entries = htonl(nr_entries);
- if (sha1write(f, &hdr, sizeof(hdr)))
- return 0;
+ sha1write(f, &hdr, sizeof(hdr));
return sizeof(hdr);
}
diff --git a/pack.h b/pack.h
index aa6ee7d..12d9516 100644
--- a/pack.h
+++ b/pack.h
@@ -76,7 +76,7 @@ struct pack_idx_entry {
struct progress;
typedef int (*verify_fn)(const unsigned char*, enum object_type, unsigned long, void*, int*);
-extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, unsigned char *sha1);
+extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1);
extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
extern int verify_pack_index(struct packed_git *);
extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uint32_t);
diff --git a/pager.c b/pager.c
index fa19765..0cc75a8 100644
--- a/pager.c
+++ b/pager.c
@@ -80,8 +80,15 @@ void setup_pager(void)
pager_process.use_shell = 1;
pager_process.argv = pager_argv;
pager_process.in = -1;
- if (!getenv("LESS")) {
- static const char *env[] = { "LESS=FRSX", NULL };
+ if (!getenv("LESS") || !getenv("LV")) {
+ static const char *env[3];
+ int i = 0;
+
+ if (!getenv("LESS"))
+ env[i++] = "LESS=FRSX";
+ if (!getenv("LV"))
+ env[i++] = "LV=-c";
+ env[i] = NULL;
pager_process.env = env;
}
if (start_command(&pager_process))
@@ -151,7 +158,7 @@ int decimal_width(int number)
static int pager_command_config(const char *var, const char *value, void *data)
{
struct pager_config *c = data;
- if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) {
+ if (starts_with(var, "pager.") && !strcmp(var + 6, c->cmd)) {
int b = git_config_maybe_bool(var, value);
if (b >= 0)
c->want = b;
diff --git a/parse-options.c b/parse-options.c
index 62e9b1c..7b8d3fa 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -273,13 +273,13 @@ is_abbreviated:
if (options->flags & PARSE_OPT_NONEG)
continue;
/* negated and abbreviated very much? */
- if (!prefixcmp("no-", arg)) {
+ if (starts_with("no-", arg)) {
flags |= OPT_UNSET;
goto is_abbreviated;
}
/* negated? */
- if (prefixcmp(arg, "no-")) {
- if (!prefixcmp(long_name, "no-")) {
+ if (!starts_with(arg, "no-")) {
+ if (starts_with(long_name, "no-")) {
long_name += 3;
opt_flags |= OPT_UNSET;
goto again;
@@ -289,7 +289,7 @@ is_abbreviated:
flags |= OPT_UNSET;
rest = skip_prefix(arg + 3, long_name);
/* abbreviated and negated? */
- if (!rest && !prefixcmp(long_name, arg + 3))
+ if (!rest && starts_with(long_name, arg + 3))
goto is_abbreviated;
if (!rest)
continue;
@@ -334,7 +334,7 @@ static void check_typos(const char *arg, const struct option *options)
if (strlen(arg) < 3)
return;
- if (!prefixcmp(arg, "no-")) {
+ if (starts_with(arg, "no-")) {
error ("did you mean `--%s` (with two dashes ?)", arg);
exit(129);
}
@@ -342,7 +342,7 @@ static void check_typos(const char *arg, const struct option *options)
for (; options->type != OPTION_END; options++) {
if (!options->long_name)
continue;
- if (!prefixcmp(options->long_name, arg)) {
+ if (starts_with(options->long_name, arg)) {
error ("did you mean `--%s` (with two dashes ?)", arg);
exit(129);
}
diff --git a/parse-options.h b/parse-options.h
index 8736006..d670cb9 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -161,9 +161,6 @@ struct option {
N_("no-op (backward compatibility)"), \
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb }
-/* Deprecated synonym */
-#define OPT_BOOLEAN OPT_COUNTUP
-
/* parse_options() will filter out the processed options and leave the
* non-option arguments in argv[]. usagestr strings should be marked
* for translation with N_().
@@ -232,15 +229,15 @@ extern int parse_opt_tertiary(const struct option *, const char *, int);
extern int parse_opt_string_list(const struct option *, const char *, int);
extern int parse_opt_noop_cb(const struct option *, const char *, int);
-#define OPT__VERBOSE(var, h) OPT_BOOLEAN('v', "verbose", (var), (h))
-#define OPT__QUIET(var, h) OPT_BOOLEAN('q', "quiet", (var), (h))
+#define OPT__VERBOSE(var, h) OPT_COUNTUP('v', "verbose", (var), (h))
+#define OPT__QUIET(var, h) OPT_COUNTUP('q', "quiet", (var), (h))
#define OPT__VERBOSITY(var) \
{ OPTION_CALLBACK, 'v', "verbose", (var), NULL, N_("be more verbose"), \
PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
{ OPTION_CALLBACK, 'q', "quiet", (var), NULL, N_("be more quiet"), \
PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
-#define OPT__DRY_RUN(var, h) OPT_BOOLEAN('n', "dry-run", (var), (h))
-#define OPT__FORCE(var, h) OPT_BOOLEAN('f', "force", (var), (h))
+#define OPT__DRY_RUN(var, h) OPT_BOOL('n', "dry-run", (var), (h))
+#define OPT__FORCE(var, h) OPT_COUNTUP('f', "force", (var), (h))
#define OPT__ABBREV(var) \
{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \
N_("use <n> digits to display SHA-1s"), \
diff --git a/pathspec.c b/pathspec.c
index 4cf2bd3..6cb9fd3 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -71,8 +71,23 @@ static struct pathspec_magic {
{ PATHSPEC_LITERAL, 0, "literal" },
{ PATHSPEC_GLOB, '\0', "glob" },
{ PATHSPEC_ICASE, '\0', "icase" },
+ { PATHSPEC_EXCLUDE, '!', "exclude" },
};
+static void prefix_short_magic(struct strbuf *sb, int prefixlen,
+ unsigned short_magic)
+{
+ int i;
+ strbuf_addstr(sb, ":(");
+ for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
+ if (short_magic & pathspec_magic[i].bit) {
+ if (sb->buf[sb->len - 1] != '(')
+ strbuf_addch(sb, ',');
+ strbuf_addstr(sb, pathspec_magic[i].name);
+ }
+ strbuf_addf(sb, ",prefix:%d)", prefixlen);
+}
+
/*
* Take an element of a pathspec and check for magic signatures.
* Append the result to the prefix. Return the magic bitmap.
@@ -154,7 +169,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
magic |= pathspec_magic[i].bit;
break;
}
- if (!prefixcmp(copyfrom, "prefix:")) {
+ if (starts_with(copyfrom, "prefix:")) {
char *endptr;
pathspec_prefix = strtol(copyfrom + 7,
&endptr, 10);
@@ -197,11 +212,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
magic |= short_magic;
*p_short_magic = short_magic;
- /* --noglob-pathspec adds :(literal) _unless_ :(glob) is specifed */
+ /* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
if (noglob_global && !(magic & PATHSPEC_GLOB))
global_magic |= PATHSPEC_LITERAL;
- /* --glob-pathspec is overriden by :(literal) */
+ /* --glob-pathspec is overridden by :(literal) */
if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))
global_magic &= ~PATHSPEC_GLOB;
@@ -232,22 +247,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
*/
if (flags & PATHSPEC_PREFIX_ORIGIN) {
struct strbuf sb = STRBUF_INIT;
- const char *start = elt;
if (prefixlen && !literal_global) {
/* Preserve the actual prefix length of each pattern */
if (short_magic)
- die("BUG: prefixing on short magic is not supported");
+ prefix_short_magic(&sb, prefixlen, short_magic);
else if (long_magic_end) {
- strbuf_add(&sb, start, long_magic_end - start);
- strbuf_addf(&sb, ",prefix:%d", prefixlen);
- start = long_magic_end;
- } else {
- if (*start == ':')
- start++;
+ strbuf_add(&sb, elt, long_magic_end - elt);
+ strbuf_addf(&sb, ",prefix:%d)", prefixlen);
+ } else
strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
- }
}
- strbuf_add(&sb, start, copyfrom - start);
strbuf_addstr(&sb, match);
item->original = strbuf_detach(&sb, NULL);
} else
@@ -355,7 +364,7 @@ void parse_pathspec(struct pathspec *pathspec,
{
struct pathspec_item *item;
const char *entry = argv ? *argv : NULL;
- int i, n, prefixlen;
+ int i, n, prefixlen, nr_exclude = 0;
memset(pathspec, 0, sizeof(*pathspec));
@@ -412,6 +421,8 @@ void parse_pathspec(struct pathspec *pathspec,
if ((flags & PATHSPEC_LITERAL_PATH) &&
!(magic_mask & PATHSPEC_LITERAL))
item[i].magic |= PATHSPEC_LITERAL;
+ if (item[i].magic & PATHSPEC_EXCLUDE)
+ nr_exclude++;
if (item[i].magic & magic_mask)
unsupported_magic(entry,
item[i].magic & magic_mask,
@@ -427,6 +438,10 @@ void parse_pathspec(struct pathspec *pathspec,
pathspec->magic |= item[i].magic;
}
+ if (nr_exclude == n)
+ die(_("There is nothing to exclude from by :(exclude) patterns.\n"
+ "Perhaps you forgot to add either ':/' or '.' ?"));
+
if (pathspec->magic & PATHSPEC_MAXDEPTH) {
if (flags & PATHSPEC_KEEP_ORDER)
diff --git a/pathspec.h b/pathspec.h
index a75e924..0c11262 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -7,12 +7,14 @@
#define PATHSPEC_LITERAL (1<<2)
#define PATHSPEC_GLOB (1<<3)
#define PATHSPEC_ICASE (1<<4)
+#define PATHSPEC_EXCLUDE (1<<5)
#define PATHSPEC_ALL_MAGIC \
(PATHSPEC_FROMTOP | \
PATHSPEC_MAXDEPTH | \
PATHSPEC_LITERAL | \
PATHSPEC_GLOB | \
- PATHSPEC_ICASE)
+ PATHSPEC_ICASE | \
+ PATHSPEC_EXCLUDE)
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm
index b3bcd47..34e8af9 100644
--- a/perl/Git/SVN/Editor.pm
+++ b/perl/Git/SVN/Editor.pm
@@ -304,8 +304,12 @@ sub C {
my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
my $pbat = $self->ensure_path($dir, $deletions);
+ # workaround for a bug in svn serf backend (v1.8.5 and below):
+ # store third argument to ->add_file() in a local variable, to make it
+ # have the same lifetime as $fbat
+ my $upa = $self->url_path($m->{file_a});
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
- $self->url_path($m->{file_a}), $self->{r});
+ $upa, $self->{r});
print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
@@ -323,8 +327,10 @@ sub R {
my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
my $pbat = $self->ensure_path($dir, $deletions);
+ # workaround for a bug in svn serf backend, see comment in C() above
+ my $upa = $self->url_path($m->{file_a});
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
- $self->url_path($m->{file_a}), $self->{r});
+ $upa, $self->{r});
print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
$self->apply_autoprops($file, $fbat);
$self->chg_file($fbat, $m);
diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm
index 3f8350a..34f2869 100644
--- a/perl/Git/SVN/Log.pm
+++ b/perl/Git/SVN/Log.pm
@@ -117,6 +117,7 @@ sub run_pager {
}
open STDIN, '<&', $rfd or fatal "Can't redirect stdin: $!";
$ENV{LESS} ||= 'FRSX';
+ $ENV{LV} ||= '-c';
exec $pager or fatal "Can't run pager: $! ($pager)";
}
diff --git a/pkt-line.c b/pkt-line.c
index 70f1950..bc63b3b 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -24,8 +24,8 @@ static void packet_trace(const char *buf, unsigned int len, int write)
strbuf_addf(&out, "packet: %12s%c ",
packet_trace_prefix, write ? '>' : '<');
- if ((len >= 4 && !prefixcmp(buf, "PACK")) ||
- (len >= 5 && !prefixcmp(buf+1, "PACK"))) {
+ if ((len >= 4 && starts_with(buf, "PACK")) ||
+ (len >= 5 && starts_with(buf+1, "PACK"))) {
strbuf_addstr(&out, "PACK ...");
unsetenv(trace_key);
}
diff --git a/po/de.po b/po/de.po
index 5e2d709..c0bbb65 100644
--- a/po/de.po
+++ b/po/de.po
@@ -72,7 +72,7 @@ msgstr "Archivformat"
#: archive.c:328 builtin/log.c:1193
msgid "prefix"
-msgstr "Prefix"
+msgstr "Präfix"
#: archive.c:329
msgid "prepend prefix to each pathname in the archive"
@@ -3716,7 +3716,7 @@ msgid ""
msgstr ""
"Eingabehilfe:\n"
"1 - nummeriertes Element auswählen\n"
-"foo - Element anhand eines eindeutigen Prefix auswählen\n"
+"foo - Element anhand eines eindeutigen Präfix auswählen\n"
" - (leer) nichts auswählen"
#: builtin/clean.c:298
@@ -3734,7 +3734,7 @@ msgstr ""
"1 - einzelnes Element auswählen\n"
"3-5 - Bereich von Elementen auswählen\n"
"2-3,6-9 - mehrere Bereiche auswählen\n"
-"foo - Element anhand eines eindeutigen Prefix auswählen\n"
+"foo - Element anhand eines eindeutigen Präfix auswählen\n"
"-... - angegebenes Element abwählen\n"
"* - alle Elemente auswählen\n"
" - (leer) Auswahl beenden"
@@ -6452,7 +6452,7 @@ msgstr "kennzeichnet die Serie als n-te Fassung"
#: builtin/log.c:1194
msgid "Use [<prefix>] instead of [PATCH]"
-msgstr "verwendet [<Prefix>] anstatt [PATCH]"
+msgstr "verwendet [<Präfix>] anstatt [PATCH]"
#: builtin/log.c:1197
msgid "store resulting files in <dir>"
@@ -8182,7 +8182,7 @@ msgid ""
"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
msgstr ""
-"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<Prefix>] "
+"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<Präfix>] "
"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
"index-output=<Datei>] (--empty | <Commit-Referenz1> [<Commit-Referenz2> "
"[<Commit-Referenz3>]])"
@@ -9782,15 +9782,15 @@ msgstr "gibt Tag-Inhalte aus"
#: builtin/write-tree.c:13
msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
-msgstr "git write-tree [--missing-ok] [--prefix=<Prefix>/]"
+msgstr "git write-tree [--missing-ok] [--prefix=<Präfix>/]"
#: builtin/write-tree.c:26
msgid "<prefix>/"
-msgstr "<Prefix>/"
+msgstr "<Präfix>/"
#: builtin/write-tree.c:27
msgid "write tree object for a subdirectory <prefix>"
-msgstr "schreibt das \"Tree\"-Objekt für ein Unterverzeichnis <Prefix>"
+msgstr "schreibt das \"Tree\"-Objekt für ein Unterverzeichnis <Präfix>"
#: builtin/write-tree.c:30
msgid "only useful for debugging"
diff --git a/pretty.c b/pretty.c
index 962e82b..87db08b 100644
--- a/pretty.c
+++ b/pretty.c
@@ -40,7 +40,7 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c
const char *fmt;
int i;
- if (prefixcmp(var, "pretty."))
+ if (!starts_with(var, "pretty."))
return 0;
name = var + strlen("pretty.");
@@ -67,7 +67,7 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c
commit_format->name = xstrdup(name);
commit_format->format = CMIT_FMT_USERFORMAT;
git_config_string(&fmt, var, value);
- if (!prefixcmp(fmt, "format:") || !prefixcmp(fmt, "tformat:")) {
+ if (starts_with(fmt, "format:") || starts_with(fmt, "tformat:")) {
commit_format->is_tformat = fmt[0] == 't';
fmt = strchr(fmt, ':') + 1;
} else if (strchr(fmt, '%'))
@@ -115,7 +115,7 @@ static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
for (i = 0; i < commit_formats_len; i++) {
size_t match_len;
- if (prefixcmp(commit_formats[i].name, sought))
+ if (!starts_with(commit_formats[i].name, sought))
continue;
match_len = strlen(commit_formats[i].name);
@@ -151,7 +151,7 @@ void get_commit_format(const char *arg, struct rev_info *rev)
rev->commit_format = CMIT_FMT_DEFAULT;
return;
}
- if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
+ if (starts_with(arg, "format:") || starts_with(arg, "tformat:")) {
save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
return;
}
@@ -840,10 +840,10 @@ static void parse_commit_header(struct format_commit_context *context)
if (i == eol) {
break;
- } else if (!prefixcmp(msg + i, "author ")) {
+ } else if (starts_with(msg + i, "author ")) {
context->author.off = i + 7;
context->author.len = eol - i - 7;
- } else if (!prefixcmp(msg + i, "committer ")) {
+ } else if (starts_with(msg + i, "committer ")) {
context->committer.off = i + 10;
context->committer.len = eol - i - 10;
}
@@ -983,7 +983,7 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
if (!end)
return 0;
- if (!prefixcmp(begin, "auto,")) {
+ if (starts_with(begin, "auto,")) {
if (!want_color(c->pretty_ctx->color))
return end - placeholder + 1;
begin += 5;
@@ -994,16 +994,16 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
strbuf_addstr(sb, color);
return end - placeholder + 1;
}
- if (!prefixcmp(placeholder + 1, "red")) {
+ if (starts_with(placeholder + 1, "red")) {
strbuf_addstr(sb, GIT_COLOR_RED);
return 4;
- } else if (!prefixcmp(placeholder + 1, "green")) {
+ } else if (starts_with(placeholder + 1, "green")) {
strbuf_addstr(sb, GIT_COLOR_GREEN);
return 6;
- } else if (!prefixcmp(placeholder + 1, "blue")) {
+ } else if (starts_with(placeholder + 1, "blue")) {
strbuf_addstr(sb, GIT_COLOR_BLUE);
return 5;
- } else if (!prefixcmp(placeholder + 1, "reset")) {
+ } else if (starts_with(placeholder + 1, "reset")) {
strbuf_addstr(sb, GIT_COLOR_RESET);
return 6;
} else
@@ -1060,11 +1060,11 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
end = strchr(start, ')');
if (!end || end == start)
return 0;
- if (!prefixcmp(start, "trunc)"))
+ if (starts_with(start, "trunc)"))
c->truncate = trunc_right;
- else if (!prefixcmp(start, "ltrunc)"))
+ else if (starts_with(start, "ltrunc)"))
c->truncate = trunc_left;
- else if (!prefixcmp(start, "mtrunc)"))
+ else if (starts_with(start, "mtrunc)"))
c->truncate = trunc_middle;
else
return 0;
@@ -1089,7 +1089,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
/* these are independent of the commit */
switch (placeholder[0]) {
case 'C':
- if (!prefixcmp(placeholder + 1, "(auto)")) {
+ if (starts_with(placeholder + 1, "(auto)")) {
c->auto_color = 1;
return 7; /* consumed 7 bytes, "C(auto)" */
} else {
@@ -1556,7 +1556,7 @@ static void pp_header(struct pretty_print_context *pp,
continue;
}
- if (!prefixcmp(line, "parent ")) {
+ if (starts_with(line, "parent ")) {
if (linelen != 48)
die("bad parent line in commit");
continue;
@@ -1580,11 +1580,11 @@ static void pp_header(struct pretty_print_context *pp,
* FULL shows both authors but not dates.
* FULLER shows both authors and dates.
*/
- if (!prefixcmp(line, "author ")) {
+ if (starts_with(line, "author ")) {
strbuf_grow(sb, linelen + 80);
pp_user_info(pp, "Author", sb, line + 7, encoding);
}
- if (!prefixcmp(line, "committer ") &&
+ if (starts_with(line, "committer ") &&
(pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
strbuf_grow(sb, linelen + 80);
pp_user_info(pp, "Commit", sb, line + 10, encoding);
diff --git a/prompt.c b/prompt.c
index d851807..d7bb17c 100644
--- a/prompt.c
+++ b/prompt.c
@@ -22,6 +22,7 @@ static char *do_askpass(const char *cmd, const char *prompt)
if (start_command(&pass))
return NULL;
+ strbuf_reset(&buffer);
if (strbuf_read(&buffer, pass.out, 20) < 0)
err = 1;
@@ -38,7 +39,7 @@ static char *do_askpass(const char *cmd, const char *prompt)
strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n"));
- return strbuf_detach(&buffer, NULL);
+ return buffer.buf;
}
char *git_prompt(const char *prompt, int flags)
diff --git a/refs.c b/refs.c
index 5e5a382..490b57b 100644
--- a/refs.c
+++ b/refs.c
@@ -637,7 +637,7 @@ static int do_one_ref(struct ref_entry *entry, void *cb_data)
struct ref_entry *old_current_ref;
int retval;
- if (prefixcmp(entry->name, data->base))
+ if (!starts_with(entry->name, data->base))
return 0;
if (!(data->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
@@ -1042,7 +1042,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
if (refname) {
last = create_ref_entry(refname, sha1, REF_ISPACKED, 1);
if (peeled == PEELED_FULLY ||
- (peeled == PEELED_TAGS && !prefixcmp(refname, "refs/tags/")))
+ (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
last->flag |= REF_KNOWS_PEELED;
add_ref(dir, last);
continue;
@@ -1376,7 +1376,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
return NULL;
}
buffer[len] = 0;
- if (!prefixcmp(buffer, "refs/") &&
+ if (starts_with(buffer, "refs/") &&
!check_refname_format(buffer, 0)) {
strcpy(refname_buffer, buffer);
refname = refname_buffer;
@@ -1415,7 +1415,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
/*
* Is it a symbolic ref?
*/
- if (prefixcmp(buffer, "ref:")) {
+ if (!starts_with(buffer, "ref:")) {
/*
* Please note that FETCH_HEAD has a second
* line containing other data.
@@ -1837,7 +1837,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
struct ref_filter filter;
int ret;
- if (!prefix && prefixcmp(pattern, "refs/"))
+ if (!prefix && !starts_with(pattern, "refs/"))
strbuf_addstr(&real_pattern, "refs/");
else if (prefix)
strbuf_addstr(&real_pattern, prefix);
@@ -1874,9 +1874,9 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
const char *prettify_refname(const char *name)
{
return name + (
- !prefixcmp(name, "refs/heads/") ? 11 :
- !prefixcmp(name, "refs/tags/") ? 10 :
- !prefixcmp(name, "refs/remotes/") ? 13 :
+ starts_with(name, "refs/heads/") ? 11 :
+ starts_with(name, "refs/tags/") ? 10 :
+ starts_with(name, "refs/remotes/") ? 13 :
0);
}
@@ -2244,7 +2244,7 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)
struct pack_refs_cb_data *cb = cb_data;
enum peel_status peel_status;
struct ref_entry *packed_entry;
- int is_tag_ref = !prefixcmp(entry->name, "refs/tags/");
+ int is_tag_ref = starts_with(entry->name, "refs/tags/");
/* ALWAYS pack tags */
if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref)
@@ -2679,9 +2679,9 @@ int log_ref_setup(const char *refname, char *logfile, int bufsize)
git_snpath(logfile, bufsize, "logs/%s", refname);
if (log_all_ref_updates &&
- (!prefixcmp(refname, "refs/heads/") ||
- !prefixcmp(refname, "refs/remotes/") ||
- !prefixcmp(refname, "refs/notes/") ||
+ (starts_with(refname, "refs/heads/") ||
+ starts_with(refname, "refs/remotes/") ||
+ starts_with(refname, "refs/notes/") ||
!strcmp(refname, "HEAD"))) {
if (safe_create_leading_directories(logfile) < 0)
return error("unable to create directory for %s",
@@ -2751,7 +2751,7 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
static int is_branch(const char *refname)
{
- return !strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/");
+ return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
}
int write_ref_sha1(struct ref_lock *lock,
@@ -3334,29 +3334,6 @@ cleanup:
return ret;
}
-/*
- * generate a format suitable for scanf from a ref_rev_parse_rules
- * rule, that is replace the "%.*s" spec with a "%s" spec
- */
-static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
-{
- char *spec;
-
- spec = strstr(rule, "%.*s");
- if (!spec || strstr(spec + 4, "%.*s"))
- die("invalid rule in ref_rev_parse_rules: %s", rule);
-
- /* copy all until spec */
- strncpy(scanf_fmt, rule, spec - rule);
- scanf_fmt[spec - rule] = '\0';
- /* copy new spec */
- strcat(scanf_fmt, "%s");
- /* copy remaining rule */
- strcat(scanf_fmt, spec + 4);
-
- return;
-}
-
char *shorten_unambiguous_ref(const char *refname, int strict)
{
int i;
@@ -3364,23 +3341,29 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
static int nr_rules;
char *short_name;
- /* pre generate scanf formats from ref_rev_parse_rules[] */
if (!nr_rules) {
+ /*
+ * Pre-generate scanf formats from ref_rev_parse_rules[].
+ * Generate a format suitable for scanf from a
+ * ref_rev_parse_rules rule by interpolating "%s" at the
+ * location of the "%.*s".
+ */
size_t total_len = 0;
+ size_t offset = 0;
/* the rule list is NULL terminated, count them first */
for (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)
- /* no +1 because strlen("%s") < strlen("%.*s") */
- total_len += strlen(ref_rev_parse_rules[nr_rules]);
+ /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */
+ total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;
scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
- total_len = 0;
+ offset = 0;
for (i = 0; i < nr_rules; i++) {
- scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
- + total_len;
- gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
- total_len += strlen(ref_rev_parse_rules[i]);
+ assert(offset < total_len);
+ scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
+ offset += snprintf(scanf_fmts[i], total_len - offset,
+ ref_rev_parse_rules[i], 2, "%s") + 1;
}
}
@@ -3450,7 +3433,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
{
if (!strcmp("transfer.hiderefs", var) ||
/* NEEDSWORK: use parse_config_key() once both are merged */
- (!prefixcmp(var, section) && var[strlen(section)] == '.' &&
+ (starts_with(var, section) && var[strlen(section)] == '.' &&
!strcmp(var + strlen(section), ".hiderefs"))) {
char *ref;
int len;
@@ -3478,7 +3461,7 @@ int ref_is_hidden(const char *refname)
return 0;
for_each_string_list_item(item, hide_refs) {
int len;
- if (prefixcmp(refname, item->string))
+ if (!starts_with(refname, item->string))
continue;
len = strlen(item->string);
if (!refname[len] || refname[len] == '/')
diff --git a/remote-curl.c b/remote-curl.c
index d1fc163..10cb011 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -237,7 +237,7 @@ static struct discovery* discover_refs(const char *service, int for_push)
free_discovery(last);
strbuf_addf(&refs_url, "%sinfo/refs", url.buf);
- if ((!prefixcmp(url.buf, "http://") || !prefixcmp(url.buf, "https://")) &&
+ if ((starts_with(url.buf, "http://") || starts_with(url.buf, "https://")) &&
git_env_bool("GIT_SMART_HTTP", 1)) {
maybe_smart = 1;
if (!strchr(url.buf, '?'))
@@ -414,25 +414,29 @@ static size_t rpc_in(char *ptr, size_t eltsize,
return size;
}
-static int run_slot(struct active_request_slot *slot)
+static int run_slot(struct active_request_slot *slot,
+ struct slot_results *results)
{
int err;
- struct slot_results results;
+ struct slot_results results_buf;
- slot->results = &results;
+ if (!results)
+ results = &results_buf;
+
+ slot->results = results;
slot->curl_result = curl_easy_perform(slot->curl);
finish_active_slot(slot);
- err = handle_curl_result(&results);
+ err = handle_curl_result(results);
if (err != HTTP_OK && err != HTTP_REAUTH) {
error("RPC failed; result=%d, HTTP code = %ld",
- results.curl_result, results.http_code);
+ results->curl_result, results->http_code);
}
return err;
}
-static int probe_rpc(struct rpc_state *rpc)
+static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
{
struct active_request_slot *slot;
struct curl_slist *headers = NULL;
@@ -454,7 +458,7 @@ static int probe_rpc(struct rpc_state *rpc)
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buf);
- err = run_slot(slot);
+ err = run_slot(slot, results);
curl_slist_free_all(headers);
strbuf_release(&buf);
@@ -469,6 +473,7 @@ static int post_rpc(struct rpc_state *rpc)
char *gzip_body = NULL;
size_t gzip_size = 0;
int err, large_request = 0;
+ int needs_100_continue = 0;
/* Try to load the entire request, if we can fit it into the
* allocated buffer space we can use HTTP/1.0 and avoid the
@@ -492,18 +497,24 @@ static int post_rpc(struct rpc_state *rpc)
}
if (large_request) {
+ struct slot_results results;
+
do {
- err = probe_rpc(rpc);
+ err = probe_rpc(rpc, &results);
if (err == HTTP_REAUTH)
credential_fill(&http_auth);
} while (err == HTTP_REAUTH);
if (err != HTTP_OK)
return -1;
+
+ if (results.auth_avail & CURLAUTH_GSSNEGOTIATE)
+ needs_100_continue = 1;
}
headers = curl_slist_append(headers, rpc->hdr_content_type);
headers = curl_slist_append(headers, rpc->hdr_accept);
- headers = curl_slist_append(headers, "Expect:");
+ headers = curl_slist_append(headers, needs_100_continue ?
+ "Expect: 100-continue" : "Expect:");
retry:
slot = get_active_slot();
@@ -594,7 +605,7 @@ retry:
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
- err = run_slot(slot);
+ err = run_slot(slot, NULL);
if (err == HTTP_REAUTH && !large_request) {
credential_fill(&http_auth);
goto retry;
@@ -780,7 +791,7 @@ static void parse_fetch(struct strbuf *buf)
int alloc_heads = 0, nr_heads = 0;
do {
- if (!prefixcmp(buf->buf, "fetch ")) {
+ if (starts_with(buf->buf, "fetch ")) {
char *p = buf->buf + strlen("fetch ");
char *name;
struct ref *ref;
@@ -903,7 +914,7 @@ static void parse_push(struct strbuf *buf)
int alloc_spec = 0, nr_spec = 0, i, ret;
do {
- if (!prefixcmp(buf->buf, "push ")) {
+ if (starts_with(buf->buf, "push ")) {
ALLOC_GROW(specs, nr_spec + 1, alloc_spec);
specs[nr_spec++] = xstrdup(buf->buf + 5);
}
@@ -966,19 +977,19 @@ int main(int argc, const char **argv)
}
if (buf.len == 0)
break;
- if (!prefixcmp(buf.buf, "fetch ")) {
+ if (starts_with(buf.buf, "fetch ")) {
if (nongit)
die("Fetch attempted without a local repo");
parse_fetch(&buf);
- } else if (!strcmp(buf.buf, "list") || !prefixcmp(buf.buf, "list ")) {
+ } else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
int for_push = !!strstr(buf.buf + 4, "for-push");
output_refs(get_refs(for_push));
- } else if (!prefixcmp(buf.buf, "push ")) {
+ } else if (starts_with(buf.buf, "push ")) {
parse_push(&buf);
- } else if (!prefixcmp(buf.buf, "option ")) {
+ } else if (starts_with(buf.buf, "option ")) {
char *name = buf.buf + strlen("option ");
char *value = strchr(name, ' ');
int result;
diff --git a/remote-testsvn.c b/remote-testsvn.c
index d7cd5d2..078f1ff 100644
--- a/remote-testsvn.c
+++ b/remote-testsvn.c
@@ -82,7 +82,7 @@ static int parse_rev_note(const char *msg, struct rev_note *res)
len = end ? end - msg : strlen(msg);
key = "Revision-number: ";
- if (!prefixcmp(msg, key)) {
+ if (starts_with(msg, key)) {
long i;
char *end;
value = msg + strlen(key);
@@ -154,7 +154,7 @@ static void check_or_regenerate_marks(int latestrev)
} else {
strbuf_addf(&sb, ":%d ", latestrev);
while (strbuf_getline(&line, marksfile, '\n') != EOF) {
- if (!prefixcmp(line.buf, sb.buf)) {
+ if (starts_with(line.buf, sb.buf)) {
found++;
break;
}
@@ -264,7 +264,7 @@ static int do_command(struct strbuf *line)
return 1; /* end of command stream, quit */
}
if (batch_cmd) {
- if (prefixcmp(batch_cmd->name, line->buf))
+ if (!starts_with(batch_cmd->name, line->buf))
die("Active %s batch interrupted by %s", batch_cmd->name, line->buf);
/* buffer batch lines */
string_list_append(&batchlines, line->buf);
@@ -272,7 +272,7 @@ static int do_command(struct strbuf *line)
}
for (p = input_command_list; p->name; p++) {
- if (!prefixcmp(line->buf, p->name) && (strlen(p->name) == line->len ||
+ if (starts_with(line->buf, p->name) && (strlen(p->name) == line->len ||
line->buf[strlen(p->name)] == ' ')) {
if (p->batchable) {
batch_cmd = p;
@@ -304,7 +304,7 @@ int main(int argc, char **argv)
remote = remote_get(argv[1]);
url_in = (argc == 3) ? argv[2] : remote->url[0];
- if (!prefixcmp(url_in, "file://")) {
+ if (starts_with(url_in, "file://")) {
dump_from_file = 1;
url = url_decode(url_in + sizeof("file://")-1);
} else {
diff --git a/remote.c b/remote.c
index 9f1a8aa..a89efab 100644
--- a/remote.c
+++ b/remote.c
@@ -76,7 +76,7 @@ static const char *alias_url(const char *url, struct rewrites *r)
if (!r->rewrite[i])
continue;
for (j = 0; j < r->rewrite[i]->instead_of_nr; j++) {
- if (!prefixcmp(url, r->rewrite[i]->instead_of[j].s) &&
+ if (starts_with(url, r->rewrite[i]->instead_of[j].s) &&
(!longest ||
longest->len < r->rewrite[i]->instead_of[j].len)) {
longest = &(r->rewrite[i]->instead_of[j]);
@@ -239,13 +239,13 @@ static void read_remotes_file(struct remote *remote)
int value_list;
char *s, *p;
- if (!prefixcmp(buffer, "URL:")) {
+ if (starts_with(buffer, "URL:")) {
value_list = 0;
s = buffer + 4;
- } else if (!prefixcmp(buffer, "Push:")) {
+ } else if (starts_with(buffer, "Push:")) {
value_list = 1;
s = buffer + 5;
- } else if (!prefixcmp(buffer, "Pull:")) {
+ } else if (starts_with(buffer, "Pull:")) {
value_list = 2;
s = buffer + 5;
} else
@@ -337,7 +337,7 @@ static int handle_config(const char *key, const char *value, void *cb)
const char *subkey;
struct remote *remote;
struct branch *branch;
- if (!prefixcmp(key, "branch.")) {
+ if (starts_with(key, "branch.")) {
name = key + 7;
subkey = strrchr(name, '.');
if (!subkey)
@@ -361,7 +361,7 @@ static int handle_config(const char *key, const char *value, void *cb)
}
return 0;
}
- if (!prefixcmp(key, "url.")) {
+ if (starts_with(key, "url.")) {
struct rewrite *rewrite;
name = key + 4;
subkey = strrchr(name, '.');
@@ -380,7 +380,7 @@ static int handle_config(const char *key, const char *value, void *cb)
}
}
- if (prefixcmp(key, "remote."))
+ if (!starts_with(key, "remote."))
return 0;
name = key + 7;
@@ -487,7 +487,7 @@ static void read_config(void)
current_branch = NULL;
head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
if (head_ref && (flag & REF_ISSYMREF) &&
- !prefixcmp(head_ref, "refs/heads/")) {
+ starts_with(head_ref, "refs/heads/")) {
current_branch =
make_branch(head_ref + strlen("refs/heads/"), 0);
}
@@ -745,35 +745,66 @@ int for_each_remote(each_remote_fn fn, void *priv)
return result;
}
-void ref_remove_duplicates(struct ref *ref_map)
+static void handle_duplicate(struct ref *ref1, struct ref *ref2)
+{
+ if (strcmp(ref1->name, ref2->name)) {
+ if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+ ref2->fetch_head_status != FETCH_HEAD_IGNORE) {
+ die(_("Cannot fetch both %s and %s to %s"),
+ ref1->name, ref2->name, ref2->peer_ref->name);
+ } else if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+ ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+ warning(_("%s usually tracks %s, not %s"),
+ ref2->peer_ref->name, ref2->name, ref1->name);
+ } else if (ref1->fetch_head_status == FETCH_HEAD_IGNORE &&
+ ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+ die(_("%s tracks both %s and %s"),
+ ref2->peer_ref->name, ref1->name, ref2->name);
+ } else {
+ /*
+ * This last possibility doesn't occur because
+ * FETCH_HEAD_IGNORE entries always appear at
+ * the end of the list.
+ */
+ die(_("Internal error"));
+ }
+ }
+ free(ref2->peer_ref);
+ free(ref2);
+}
+
+struct ref *ref_remove_duplicates(struct ref *ref_map)
{
struct string_list refs = STRING_LIST_INIT_NODUP;
- struct string_list_item *item = NULL;
- struct ref *prev = NULL, *next = NULL;
- for (; ref_map; prev = ref_map, ref_map = next) {
- next = ref_map->next;
- if (!ref_map->peer_ref)
- continue;
+ struct ref *retval = NULL;
+ struct ref **p = &retval;
- item = string_list_lookup(&refs, ref_map->peer_ref->name);
- if (item) {
- if (strcmp(((struct ref *)item->util)->name,
- ref_map->name))
- die("%s tracks both %s and %s",
- ref_map->peer_ref->name,
- ((struct ref *)item->util)->name,
- ref_map->name);
- prev->next = ref_map->next;
- free(ref_map->peer_ref);
- free(ref_map);
- ref_map = prev; /* skip this; we freed it */
- continue;
- }
+ while (ref_map) {
+ struct ref *ref = ref_map;
+
+ ref_map = ref_map->next;
+ ref->next = NULL;
- item = string_list_insert(&refs, ref_map->peer_ref->name);
- item->util = ref_map;
+ if (!ref->peer_ref) {
+ *p = ref;
+ p = &ref->next;
+ } else {
+ struct string_list_item *item =
+ string_list_insert(&refs, ref->peer_ref->name);
+
+ if (item->util) {
+ /* Entry already existed */
+ handle_duplicate((struct ref *)item->util, ref);
+ } else {
+ *p = ref;
+ p = &ref->next;
+ item->util = ref;
+ }
+ }
}
+
string_list_clear(&refs, 0);
+ return retval;
}
int remote_has_url(struct remote *remote, const char *url)
@@ -821,10 +852,12 @@ static int match_name_with_pattern(const char *key, const char *name,
return ret;
}
-static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
+int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
{
int i;
int find_src = !query->src;
+ const char *needle = find_src ? query->dst : query->src;
+ char **result = find_src ? &query->src : &query->dst;
if (find_src && !query->dst)
return error("query_refspecs: need either src or dst");
@@ -833,8 +866,6 @@ static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *q
struct refspec *refspec = &refs[i];
const char *key = find_src ? refspec->dst : refspec->src;
const char *value = find_src ? refspec->src : refspec->dst;
- const char *needle = find_src ? query->dst : query->src;
- char **result = find_src ? &query->src : &query->dst;
if (!refspec->dst)
continue;
@@ -955,9 +986,9 @@ void sort_ref_list(struct ref **l, int (*cmp)(const void *, const void *))
*l = llist_mergesort(*l, ref_list_get_next, ref_list_set_next, cmp);
}
-static int count_refspec_match(const char *pattern,
- struct ref *refs,
- struct ref **matched_ref)
+int count_refspec_match(const char *pattern,
+ struct ref *refs,
+ struct ref **matched_ref)
{
int patlen = strlen(pattern);
struct ref *matched_weak = NULL;
@@ -982,8 +1013,8 @@ static int count_refspec_match(const char *pattern,
*/
if (namelen != patlen &&
patlen != namelen - 5 &&
- prefixcmp(name, "refs/heads/") &&
- prefixcmp(name, "refs/tags/")) {
+ !starts_with(name, "refs/heads/") &&
+ !starts_with(name, "refs/tags/")) {
/* We want to catch the case where only weak
* matches are found and there are multiple
* matches, and where more than one strong
@@ -1054,9 +1085,9 @@ static char *guess_ref(const char *name, struct ref *peer)
if (!r)
return NULL;
- if (!prefixcmp(r, "refs/heads/"))
+ if (starts_with(r, "refs/heads/"))
strbuf_addstr(&buf, "refs/heads/");
- else if (!prefixcmp(r, "refs/tags/"))
+ else if (starts_with(r, "refs/tags/"))
strbuf_addstr(&buf, "refs/tags/");
else
return NULL;
@@ -1104,7 +1135,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
dst_value = resolve_ref_unsafe(matched_src->name, sha1, 1, &flag);
if (!dst_value ||
((flag & REF_ISSYMREF) &&
- prefixcmp(dst_value, "refs/heads/")))
+ !starts_with(dst_value, "refs/heads/")))
die("%s cannot be resolved to branch.",
matched_src->name);
}
@@ -1193,7 +1224,7 @@ static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref
* including refs outside refs/heads/ hierarchy, but
* that does not make much sense these days.
*/
- if (!send_mirror && prefixcmp(ref->name, "refs/heads/"))
+ if (!send_mirror && !starts_with(ref->name, "refs/heads/"))
return NULL;
name = xstrdup(ref->name);
}
@@ -1248,7 +1279,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
add_to_tips(&sent_tips, ref->peer_ref->new_sha1);
else
add_to_tips(&sent_tips, ref->old_sha1);
- if (!prefixcmp(ref->name, "refs/tags/"))
+ if (starts_with(ref->name, "refs/tags/"))
string_list_append(&dst_tag, ref->name);
}
clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK);
@@ -1257,7 +1288,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
/* Collect tags they do not have. */
for (ref = src; ref; ref = ref->next) {
- if (prefixcmp(ref->name, "refs/tags/"))
+ if (!starts_with(ref->name, "refs/tags/"))
continue; /* not a tag */
if (string_list_has_string(&dst_tag, ref->name))
continue; /* they already have it */
@@ -1481,7 +1512,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
*/
else if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
- if (!prefixcmp(ref->name, "refs/tags/"))
+ if (starts_with(ref->name, "refs/tags/"))
reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
else if (!has_sha1_file(ref->old_sha1))
reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
@@ -1553,6 +1584,13 @@ static int ignore_symref_update(const char *refname)
return (flag & REF_ISSYMREF);
}
+/*
+ * Create and return a list of (struct ref) consisting of copies of
+ * each remote_ref that matches refspec. refspec must be a pattern.
+ * Fill in the copies' peer_ref to describe the local tracking refs to
+ * which they map. Omit any references that would map to an existing
+ * local symbolic ref.
+ */
static struct ref *get_expanded_map(const struct ref *remote_refs,
const struct refspec *refspec)
{
@@ -1560,9 +1598,9 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
struct ref *ret = NULL;
struct ref **tail = &ret;
- char *expn_name;
-
for (ref = remote_refs; ref; ref = ref->next) {
+ char *expn_name = NULL;
+
if (strchr(ref->name, '^'))
continue; /* a dereference item */
if (match_name_with_pattern(refspec->src, ref->name,
@@ -1571,12 +1609,12 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
struct ref *cpy = copy_ref(ref);
cpy->peer_ref = alloc_ref(expn_name);
- free(expn_name);
if (refspec->force)
cpy->peer_ref->force = 1;
*tail = cpy;
tail = &cpy->next;
}
+ free(expn_name);
}
return ret;
@@ -1607,12 +1645,12 @@ static struct ref *get_local_ref(const char *name)
if (!name || name[0] == '\0')
return NULL;
- if (!prefixcmp(name, "refs/"))
+ if (starts_with(name, "refs/"))
return alloc_ref(name);
- if (!prefixcmp(name, "heads/") ||
- !prefixcmp(name, "tags/") ||
- !prefixcmp(name, "remotes/"))
+ if (starts_with(name, "heads/") ||
+ starts_with(name, "tags/") ||
+ starts_with(name, "remotes/"))
return alloc_ref_with_prefix("refs/", 5, name);
return alloc_ref_with_prefix("refs/heads/", 11, name);
@@ -1647,7 +1685,7 @@ int get_fetch_map(const struct ref *remote_refs,
for (rmp = &ref_map; *rmp; ) {
if ((*rmp)->peer_ref) {
- if (prefixcmp((*rmp)->peer_ref->name, "refs/") ||
+ if (!starts_with((*rmp)->peer_ref->name, "refs/") ||
check_refname_format((*rmp)->peer_ref->name, 0)) {
struct ref *ignore = *rmp;
error("* Ignoring funny ref '%s' locally",
@@ -1931,7 +1969,7 @@ struct ref *guess_remote_head(const struct ref *head,
/* Look for another ref that points there */
for (r = refs; r; r = r->next) {
if (r != head &&
- !prefixcmp(r->name, "refs/heads/") &&
+ starts_with(r->name, "refs/heads/") &&
!hashcmp(r->old_sha1, head->old_sha1)) {
*tail = copy_ref(r);
tail = &((*tail)->next);
diff --git a/remote.h b/remote.h
index 3498091..fb7647f 100644
--- a/remote.h
+++ b/remote.h
@@ -129,6 +129,7 @@ struct ref *alloc_ref(const char *name);
struct ref *copy_ref(const struct ref *ref);
struct ref *copy_ref_list(const struct ref *ref);
void sort_ref_list(struct ref **, int (*cmp)(const void *, const void *));
+extern int count_refspec_match(const char *, struct ref *refs, struct ref **matched_ref);
int ref_compare_name(const void *, const void *);
int check_ref_type(const struct ref *ref, int flags);
@@ -148,15 +149,20 @@ int resolve_remote_symref(struct ref *ref, struct ref *list);
int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);
/*
- * Removes and frees any duplicate refs in the map.
+ * Remove and free all but the first of any entries in the input list
+ * that map the same remote reference to the same local reference. If
+ * there are two entries that map different remote references to the
+ * same local reference, emit an error message and die. Return a
+ * pointer to the head of the resulting list.
*/
-void ref_remove_duplicates(struct ref *ref_map);
+struct ref *ref_remove_duplicates(struct ref *ref_map);
int valid_fetch_refspec(const char *refspec);
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
void free_refspec(int nr_refspec, struct refspec *refspec);
+extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
const char *name);
diff --git a/replace_object.c b/replace_object.c
index d0b1548..cdcaf8c 100644
--- a/replace_object.c
+++ b/replace_object.c
@@ -97,9 +97,6 @@ const unsigned char *do_lookup_replace_object(const unsigned char *sha1)
int pos, depth = MAXREPLACEDEPTH;
const unsigned char *cur = sha1;
- if (!read_replace_refs)
- return sha1;
-
prepare_replace_object();
/* Try to recursively replace the object */
diff --git a/revision.c b/revision.c
index a8adb3f..a68fde6 100644
--- a/revision.c
+++ b/revision.c
@@ -1180,11 +1180,28 @@ struct all_refs_cb {
const char *name_for_errormsg;
};
+int ref_excluded(struct string_list *ref_excludes, const char *path)
+{
+ struct string_list_item *item;
+
+ if (!ref_excludes)
+ return 0;
+ for_each_string_list_item(item, ref_excludes) {
+ if (!fnmatch(item->string, path, 0))
+ return 1;
+ }
+ return 0;
+}
+
static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
struct all_refs_cb *cb = cb_data;
- struct object *object = get_reference(cb->all_revs, path, sha1,
- cb->all_flags);
+ struct object *object;
+
+ if (ref_excluded(cb->all_revs->ref_excludes, path))
+ return 0;
+
+ object = get_reference(cb->all_revs, path, sha1, cb->all_flags);
add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
add_pending_sha1(cb->all_revs, path, sha1, cb->all_flags);
return 0;
@@ -1197,6 +1214,24 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,
cb->all_flags = flags;
}
+void clear_ref_exclusion(struct string_list **ref_excludes_p)
+{
+ if (*ref_excludes_p) {
+ string_list_clear(*ref_excludes_p, 0);
+ free(*ref_excludes_p);
+ }
+ *ref_excludes_p = NULL;
+}
+
+void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude)
+{
+ if (!*ref_excludes_p) {
+ *ref_excludes_p = xcalloc(1, sizeof(**ref_excludes_p));
+ (*ref_excludes_p)->strdup_strings = 1;
+ }
+ string_list_append(*ref_excludes_p, exclude);
+}
+
static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,
int (*for_each)(const char *, each_ref_fn, void *))
{
@@ -1592,9 +1627,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
!strcmp(arg, "--tags") || !strcmp(arg, "--remotes") ||
!strcmp(arg, "--reflog") || !strcmp(arg, "--not") ||
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
- !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
- !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
- !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
+ !strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
+ starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
+ starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
{
unkv[(*unkc)++] = arg;
return 1;
@@ -1617,7 +1652,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->max_count = atoi(argv[1]);
revs->no_walk = 0;
return 2;
- } else if (!prefixcmp(arg, "-n")) {
+ } else if (starts_with(arg, "-n")) {
revs->max_count = atoi(arg + 2);
revs->no_walk = 0;
} else if ((argcount = parse_long_opt("max-age", argv, &optarg))) {
@@ -1677,7 +1712,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--author-date-order")) {
revs->sort_order = REV_SORT_BY_AUTHOR_DATE;
revs->topo_order = 1;
- } else if (!prefixcmp(arg, "--early-output")) {
+ } else if (starts_with(arg, "--early-output")) {
int count = 100;
switch (arg[14]) {
case '=':
@@ -1702,13 +1737,13 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->min_parents = 2;
} else if (!strcmp(arg, "--no-merges")) {
revs->max_parents = 1;
- } else if (!prefixcmp(arg, "--min-parents=")) {
+ } else if (starts_with(arg, "--min-parents=")) {
revs->min_parents = atoi(arg+14);
- } else if (!prefixcmp(arg, "--no-min-parents")) {
+ } else if (starts_with(arg, "--no-min-parents")) {
revs->min_parents = 0;
- } else if (!prefixcmp(arg, "--max-parents=")) {
+ } else if (starts_with(arg, "--max-parents=")) {
revs->max_parents = atoi(arg+14);
- } else if (!prefixcmp(arg, "--no-max-parents")) {
+ } else if (starts_with(arg, "--no-max-parents")) {
revs->max_parents = -1;
} else if (!strcmp(arg, "--boundary")) {
revs->boundary = 1;
@@ -1758,7 +1793,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->verify_objects = 1;
} else if (!strcmp(arg, "--unpacked")) {
revs->unpacked = 1;
- } else if (!prefixcmp(arg, "--unpacked=")) {
+ } else if (starts_with(arg, "--unpacked=")) {
die("--unpacked=<packfile> no longer supported.");
} else if (!strcmp(arg, "-r")) {
revs->diff = 1;
@@ -1783,7 +1818,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->verbose_header = 1;
revs->pretty_given = 1;
get_commit_format(arg+8, revs);
- } else if (!prefixcmp(arg, "--pretty=") || !prefixcmp(arg, "--format=")) {
+ } else if (starts_with(arg, "--pretty=") || starts_with(arg, "--format=")) {
/*
* Detached form ("--pretty X" as opposed to "--pretty=X")
* not allowed, since the argument is optional.
@@ -1797,12 +1832,12 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->notes_opt.use_default_notes = 1;
} else if (!strcmp(arg, "--show-signature")) {
revs->show_signature = 1;
- } else if (!prefixcmp(arg, "--show-notes=") ||
- !prefixcmp(arg, "--notes=")) {
+ } else if (starts_with(arg, "--show-notes=") ||
+ starts_with(arg, "--notes=")) {
struct strbuf buf = STRBUF_INIT;
revs->show_notes = 1;
revs->show_notes_given = 1;
- if (!prefixcmp(arg, "--show-notes")) {
+ if (starts_with(arg, "--show-notes")) {
if (revs->notes_opt.use_default_notes < 0)
revs->notes_opt.use_default_notes = 1;
strbuf_addstr(&buf, arg+13);
@@ -1845,7 +1880,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->abbrev = 0;
} else if (!strcmp(arg, "--abbrev")) {
revs->abbrev = DEFAULT_ABBREV;
- } else if (!prefixcmp(arg, "--abbrev=")) {
+ } else if (starts_with(arg, "--abbrev=")) {
revs->abbrev = strtoul(arg + 9, NULL, 10);
if (revs->abbrev < MINIMUM_ABBREV)
revs->abbrev = MINIMUM_ABBREV;
@@ -1969,40 +2004,51 @@ static int handle_revision_pseudo_opt(const char *submodule,
if (!strcmp(arg, "--all")) {
handle_refs(submodule, revs, *flags, for_each_ref_submodule);
handle_refs(submodule, revs, *flags, head_ref_submodule);
+ clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--branches")) {
handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
+ clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--bisect")) {
handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
revs->bisect = 1;
} else if (!strcmp(arg, "--tags")) {
handle_refs(submodule, revs, *flags, for_each_tag_ref_submodule);
+ clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--remotes")) {
handle_refs(submodule, revs, *flags, for_each_remote_ref_submodule);
+ clear_ref_exclusion(&revs->ref_excludes);
} else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, *flags);
for_each_glob_ref(handle_one_ref, optarg, &cb);
+ clear_ref_exclusion(&revs->ref_excludes);
+ return argcount;
+ } else if ((argcount = parse_long_opt("exclude", argv, &optarg))) {
+ add_ref_exclusion(&revs->ref_excludes, optarg);
return argcount;
- } else if (!prefixcmp(arg, "--branches=")) {
+ } else if (starts_with(arg, "--branches=")) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, *flags);
for_each_glob_ref_in(handle_one_ref, arg + 11, "refs/heads/", &cb);
- } else if (!prefixcmp(arg, "--tags=")) {
+ clear_ref_exclusion(&revs->ref_excludes);
+ } else if (starts_with(arg, "--tags=")) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, *flags);
for_each_glob_ref_in(handle_one_ref, arg + 7, "refs/tags/", &cb);
- } else if (!prefixcmp(arg, "--remotes=")) {
+ clear_ref_exclusion(&revs->ref_excludes);
+ } else if (starts_with(arg, "--remotes=")) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, *flags);
for_each_glob_ref_in(handle_one_ref, arg + 10, "refs/remotes/", &cb);
+ clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--reflog")) {
handle_reflog(revs, *flags);
} else if (!strcmp(arg, "--not")) {
*flags ^= UNINTERESTING | BOTTOM;
} else if (!strcmp(arg, "--no-walk")) {
revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
- } else if (!prefixcmp(arg, "--no-walk=")) {
+ } else if (starts_with(arg, "--no-walk=")) {
/*
* Detached form ("--no-walk X" as opposed to "--no-walk=X")
* not allowed, since the argument is optional.
diff --git a/revision.h b/revision.h
index 89132df..88967d6 100644
--- a/revision.h
+++ b/revision.h
@@ -61,6 +61,9 @@ struct rev_info {
/* The end-points specified by the end user */
struct rev_cmdline_info cmdline;
+ /* excluding from --branches, --refs, etc. expansion */
+ struct string_list *ref_excludes;
+
/* Basic information */
const char *prefix;
const char *def;
@@ -194,6 +197,11 @@ struct rev_info {
struct saved_parents *saved_parents_slab;
};
+extern int ref_excluded(struct string_list *, const char *path);
+void clear_ref_exclusion(struct string_list **);
+void add_ref_exclusion(struct string_list **, const char *exclude);
+
+
#define REV_TREE_SAME 0
#define REV_TREE_NEW 1 /* Only new files */
#define REV_TREE_OLD 2 /* Only files removed */
diff --git a/send-pack.c b/send-pack.c
index cdcdea7..6129b0f 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -110,7 +110,7 @@ static int receive_status(int in, struct ref *refs)
struct ref *hint;
int ret = 0;
char *line = packet_read_line(in, NULL);
- if (prefixcmp(line, "unpack "))
+ if (!starts_with(line, "unpack "))
return error("did not receive remote status");
if (strcmp(line, "unpack ok")) {
error("unpack failed: %s", line + 7);
@@ -123,7 +123,7 @@ static int receive_status(int in, struct ref *refs)
line = packet_read_line(in, NULL);
if (!line)
break;
- if (prefixcmp(line, "ok ") && prefixcmp(line, "ng ")) {
+ if (!starts_with(line, "ok ") && !starts_with(line, "ng ")) {
error("invalid ref status from remote: %s", line);
ret = -1;
break;
@@ -222,6 +222,8 @@ int send_pack(struct send_pack_args *args,
quiet_supported = 1;
if (server_supports("agent"))
agent_supported = 1;
+ if (server_supports("no-thin"))
+ args->use_thin_pack = 0;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
diff --git a/sequencer.c b/sequencer.c
index 06e52b4..90cac7b 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -41,7 +41,7 @@ static int is_cherry_picked_from_line(const char *buf, int len)
* We only care that it looks roughly like (cherry picked from ...)
*/
return len > strlen(cherry_picked_prefix) + 1 &&
- !prefixcmp(buf, cherry_picked_prefix) && buf[len - 1] == ')';
+ starts_with(buf, cherry_picked_prefix) && buf[len - 1] == ')';
}
/*
@@ -180,7 +180,7 @@ static char *get_encoding(const char *message)
while (*p && *p != '\n') {
for (eol = p + 1; *eol && *eol != '\n'; eol++)
; /* do nothing */
- if (!prefixcmp(p, "encoding ")) {
+ if (starts_with(p, "encoding ")) {
char *result = xmalloc(eol - 8 - p);
strlcpy(result, p + 9, eol - 8 - p);
return result;
@@ -705,10 +705,10 @@ static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *
char *end_of_object_name;
int saved, status, padding;
- if (!prefixcmp(bol, "pick")) {
+ if (starts_with(bol, "pick")) {
action = REPLAY_PICK;
bol += strlen("pick");
- } else if (!prefixcmp(bol, "revert")) {
+ } else if (starts_with(bol, "revert")) {
action = REPLAY_REVERT;
bol += strlen("revert");
} else
diff --git a/setup.c b/setup.c
index 5432a31..6c3f85f 100644
--- a/setup.c
+++ b/setup.c
@@ -82,7 +82,7 @@ int check_filename(const char *prefix, const char *arg)
const char *name;
struct stat st;
- if (!prefixcmp(arg, ":/")) {
+ if (starts_with(arg, ":/")) {
if (arg[2] == '\0') /* ":/" is root dir, always exists */
return 1;
name = arg + 2;
@@ -304,7 +304,7 @@ const char *read_gitfile(const char *path)
if (len != st.st_size)
die("Error reading %s", path);
buf[len] = '\0';
- if (prefixcmp(buf, "gitdir: "))
+ if (!starts_with(buf, "gitdir: "))
die("Invalid gitfile format: %s", path);
while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
len--;
diff --git a/sha1_file.c b/sha1_file.c
index 7dadd04..e13bd2c 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -807,15 +807,38 @@ void free_pack_by_name(const char *pack_name)
static unsigned int get_max_fd_limit(void)
{
#ifdef RLIMIT_NOFILE
- struct rlimit lim;
+ {
+ struct rlimit lim;
- if (getrlimit(RLIMIT_NOFILE, &lim))
- die_errno("cannot get RLIMIT_NOFILE");
+ if (!getrlimit(RLIMIT_NOFILE, &lim))
+ return lim.rlim_cur;
+ }
+#endif
+
+#ifdef _SC_OPEN_MAX
+ {
+ long open_max = sysconf(_SC_OPEN_MAX);
+ if (0 < open_max)
+ return open_max;
+ /*
+ * Otherwise, we got -1 for one of the two
+ * reasons:
+ *
+ * (1) sysconf() did not understand _SC_OPEN_MAX
+ * and signaled an error with -1; or
+ * (2) sysconf() said there is no limit.
+ *
+ * We _could_ clear errno before calling sysconf() to
+ * tell these two cases apart and return a huge number
+ * in the latter case to let the caller cap it to a
+ * value that is not so selfish, but letting the
+ * fallback OPEN_MAX codepath take care of these cases
+ * is a lot simpler.
+ */
+ }
+#endif
- return lim.rlim_cur;
-#elif defined(_SC_OPEN_MAX)
- return sysconf(_SC_OPEN_MAX);
-#elif defined(OPEN_MAX)
+#ifdef OPEN_MAX
return OPEN_MAX;
#else
return 1; /* see the caller ;-) */
@@ -1442,51 +1465,6 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
return map;
}
-/*
- * There used to be a second loose object header format which
- * was meant to mimic the in-pack format, allowing for direct
- * copy of the object data. This format turned up not to be
- * really worth it and we no longer write loose objects in that
- * format.
- */
-static int experimental_loose_object(unsigned char *map)
-{
- unsigned int word;
-
- /*
- * We must determine if the buffer contains the standard
- * zlib-deflated stream or the experimental format based
- * on the in-pack object format. Compare the header byte
- * for each format:
- *
- * RFC1950 zlib w/ deflate : 0www1000 : 0 <= www <= 7
- * Experimental pack-based : Stttssss : ttt = 1,2,3,4
- *
- * If bit 7 is clear and bits 0-3 equal 8, the buffer MUST be
- * in standard loose-object format, UNLESS it is a Git-pack
- * format object *exactly* 8 bytes in size when inflated.
- *
- * However, RFC1950 also specifies that the 1st 16-bit word
- * must be divisible by 31 - this checksum tells us our buffer
- * is in the standard format, giving a false positive only if
- * the 1st word of the Git-pack format object happens to be
- * divisible by 31, ie:
- * ((byte0 * 256) + byte1) % 31 = 0
- * => 0ttt10000www1000 % 31 = 0
- *
- * As it happens, this case can only arise for www=3 & ttt=1
- * - ie, a Commit object, which would have to be 8 bytes in
- * size. As no Commit can be that small, we find that the
- * combination of these two criteria (bitmask & checksum)
- * can always correctly determine the buffer format.
- */
- word = (map[0] << 8) + map[1];
- if ((map[0] & 0x8F) == 0x08 && !(word % 31))
- return 0;
- else
- return 1;
-}
-
unsigned long unpack_object_header_buffer(const unsigned char *buf,
unsigned long len, enum object_type *type, unsigned long *sizep)
{
@@ -1514,14 +1492,6 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
{
- unsigned long size, used;
- static const char valid_loose_object_type[8] = {
- 0, /* OBJ_EXT */
- 1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */
- 0, /* "delta" and others are invalid in a loose object */
- };
- enum object_type type;
-
/* Get the data stream */
memset(stream, 0, sizeof(*stream));
stream->next_in = map;
@@ -1529,27 +1499,6 @@ int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long ma
stream->next_out = buffer;
stream->avail_out = bufsiz;
- if (experimental_loose_object(map)) {
- /*
- * The old experimental format we no longer produce;
- * we can still read it.
- */
- used = unpack_object_header_buffer(map, mapsize, &type, &size);
- if (!used || !valid_loose_object_type[type])
- return -1;
- map += used;
- mapsize -= used;
-
- /* Set up the stream for the rest.. */
- stream->next_in = map;
- stream->avail_in = mapsize;
- git_inflate_init(stream);
-
- /* And generate the fake traditional header */
- stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
- typename(type), size);
- return 0;
- }
git_inflate_init(stream);
return git_inflate(stream, 0);
}
@@ -1741,6 +1690,38 @@ static off_t get_delta_base(struct packed_git *p,
return base_offset;
}
+/*
+ * Like get_delta_base above, but we return the sha1 instead of the pack
+ * offset. This means it is cheaper for REF deltas (we do not have to do
+ * the final object lookup), but more expensive for OFS deltas (we
+ * have to load the revidx to convert the offset back into a sha1).
+ */
+static const unsigned char *get_delta_base_sha1(struct packed_git *p,
+ struct pack_window **w_curs,
+ off_t curpos,
+ enum object_type type,
+ off_t delta_obj_offset)
+{
+ if (type == OBJ_REF_DELTA) {
+ unsigned char *base = use_pack(p, w_curs, curpos, NULL);
+ return base;
+ } else if (type == OBJ_OFS_DELTA) {
+ struct revindex_entry *revidx;
+ off_t base_offset = get_delta_base(p, w_curs, &curpos,
+ type, delta_obj_offset);
+
+ if (!base_offset)
+ return NULL;
+
+ revidx = find_pack_revindex(p, base_offset);
+ if (!revidx)
+ return NULL;
+
+ return nth_packed_object_sha1(p, revidx->nr);
+ } else
+ return NULL;
+}
+
int unpack_object_header(struct packed_git *p,
struct pack_window **w_curs,
off_t *curpos,
@@ -1898,6 +1879,22 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
}
}
+ if (oi->delta_base_sha1) {
+ if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+ const unsigned char *base;
+
+ base = get_delta_base_sha1(p, &w_curs, curpos,
+ type, obj_offset);
+ if (!base) {
+ type = OBJ_BAD;
+ goto out;
+ }
+
+ hashcpy(oi->delta_base_sha1, base);
+ } else
+ hashclr(oi->delta_base_sha1);
+ }
+
out:
unuse_pack(&w_curs);
return type;
@@ -2481,17 +2478,23 @@ static int sha1_loose_object_info(const unsigned char *sha1,
git_zstream stream;
char hdr[32];
+ if (oi->delta_base_sha1)
+ hashclr(oi->delta_base_sha1);
+
/*
* If we don't care about type or size, then we don't
- * need to look inside the object at all.
+ * need to look inside the object at all. Note that we
+ * do not optimize out the stat call, even if the
+ * caller doesn't care about the disk-size, since our
+ * return value implicitly indicates whether the
+ * object even exists.
*/
if (!oi->typep && !oi->sizep) {
- if (oi->disk_sizep) {
- struct stat st;
- if (stat_sha1_file(sha1, &st) < 0)
- return -1;
+ struct stat st;
+ if (stat_sha1_file(sha1, &st) < 0)
+ return -1;
+ if (oi->disk_sizep)
*oi->disk_sizep = st.st_size;
- }
return 0;
}
@@ -2514,13 +2517,14 @@ static int sha1_loose_object_info(const unsigned char *sha1,
return 0;
}
-int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
+int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
{
struct cached_object *co;
struct pack_entry e;
int rtype;
+ const unsigned char *real = lookup_replace_object_extended(sha1, flags);
- co = find_cached_object(sha1);
+ co = find_cached_object(real);
if (co) {
if (oi->typep)
*(oi->typep) = co->type;
@@ -2528,27 +2532,29 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
*(oi->sizep) = co->size;
if (oi->disk_sizep)
*(oi->disk_sizep) = 0;
+ if (oi->delta_base_sha1)
+ hashclr(oi->delta_base_sha1);
oi->whence = OI_CACHED;
return 0;
}
- if (!find_pack_entry(sha1, &e)) {
+ if (!find_pack_entry(real, &e)) {
/* Most likely it's a loose object. */
- if (!sha1_loose_object_info(sha1, oi)) {
+ if (!sha1_loose_object_info(real, oi)) {
oi->whence = OI_LOOSE;
return 0;
}
/* Not a loose object; someone else may have just packed it. */
reprepare_packed_git();
- if (!find_pack_entry(sha1, &e))
+ if (!find_pack_entry(real, &e))
return -1;
}
rtype = packed_object_info(e.p, e.offset, oi);
if (rtype < 0) {
- mark_bad_packed_object(e.p, sha1);
- return sha1_object_info_extended(sha1, oi);
+ mark_bad_packed_object(e.p, real);
+ return sha1_object_info_extended(real, oi, 0);
} else if (in_delta_base_cache(e.p, e.offset)) {
oi->whence = OI_DBCACHED;
} else {
@@ -2570,7 +2576,7 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
oi.typep = &type;
oi.sizep = sizep;
- if (sha1_object_info_extended(sha1, &oi) < 0)
+ if (sha1_object_info_extended(sha1, &oi, LOOKUP_REPLACE_OBJECT) < 0)
return -1;
return type;
}
@@ -2662,8 +2668,7 @@ void *read_sha1_file_extended(const unsigned char *sha1,
void *data;
char *path;
const struct packed_git *p;
- const unsigned char *repl = (flag & READ_SHA1_FILE_REPLACE)
- ? lookup_replace_object(sha1) : sha1;
+ const unsigned char *repl = lookup_replace_object_extended(sha1, flag);
errno = 0;
data = read_object(repl, type, size);
@@ -2857,7 +2862,9 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
/* Make sure the directory exists */
memcpy(buffer, filename, dirlen);
buffer[dirlen-1] = 0;
- if (mkdir(buffer, 0777) || adjust_shared_perm(buffer))
+ if (mkdir(buffer, 0777) && errno != EEXIST)
+ return -1;
+ if (adjust_shared_perm(buffer))
return -1;
/* Try again */
diff --git a/sha1_name.c b/sha1_name.c
index e9c2999..a5578f7 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -451,9 +451,9 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
int at, reflog_len, nth_prior = 0;
if (len == 40 && !get_sha1_hex(str, sha1)) {
- if (warn_on_object_refname_ambiguity) {
+ if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
- if (refs_found > 0 && warn_ambiguous_refs) {
+ if (refs_found > 0) {
warning(warn_msg, len, str);
if (advice_object_name_warning)
fprintf(stderr, "%s\n", _(object_name_msg));
@@ -546,7 +546,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
if (read_ref_at(real_ref, at_time, nth, sha1, NULL,
&co_time, &co_tz, &co_cnt)) {
if (!len) {
- if (!prefixcmp(real_ref, "refs/heads/")) {
+ if (starts_with(real_ref, "refs/heads/")) {
str = real_ref + 11;
len = strlen(real_ref + 11);
} else {
@@ -581,8 +581,6 @@ static int get_parent(const char *name, int len,
if (ret)
return ret;
commit = lookup_commit_reference(sha1);
- if (!commit)
- return -1;
if (parse_commit(commit))
return -1;
if (!idx) {
@@ -676,15 +674,15 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
return -1;
sp++; /* beginning of type name, or closing brace for empty */
- if (!prefixcmp(sp, "commit}"))
+ if (starts_with(sp, "commit}"))
expected_type = OBJ_COMMIT;
- else if (!prefixcmp(sp, "tag}"))
+ else if (starts_with(sp, "tag}"))
expected_type = OBJ_TAG;
- else if (!prefixcmp(sp, "tree}"))
+ else if (starts_with(sp, "tree}"))
expected_type = OBJ_TREE;
- else if (!prefixcmp(sp, "blob}"))
+ else if (starts_with(sp, "blob}"))
expected_type = OBJ_BLOB;
- else if (!prefixcmp(sp, "object}"))
+ else if (starts_with(sp, "object}"))
expected_type = OBJ_ANY;
else if (sp[0] == '}')
expected_type = OBJ_NONE;
@@ -911,7 +909,7 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
const char *match = NULL, *target = NULL;
size_t len;
- if (!prefixcmp(message, "checkout: moving from ")) {
+ if (starts_with(message, "checkout: moving from ")) {
match = message + strlen("checkout: moving from ");
target = strstr(match, " to ");
}
@@ -1304,7 +1302,7 @@ static void diagnose_invalid_index_path(int stage,
static char *resolve_relative_path(const char *rel)
{
- if (prefixcmp(rel, "./") && prefixcmp(rel, "../"))
+ if (!starts_with(rel, "./") && !starts_with(rel, "../"))
return NULL;
if (!startup_info)
diff --git a/shallow.c b/shallow.c
index e483780..bbc98b5 100644
--- a/shallow.c
+++ b/shallow.c
@@ -99,8 +99,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
cur_depth = *(int *)commit->util;
}
}
- if (parse_commit(commit))
- die("invalid commit");
+ parse_commit_or_die(commit);
cur_depth++;
if ((depth != INFINITE_DEPTH && cur_depth >= depth) ||
(is_repository_shallow() && !commit->parents &&
diff --git a/shell.c b/shell.c
index 66350b2..5c0d47a 100644
--- a/shell.c
+++ b/shell.c
@@ -15,7 +15,7 @@ static int do_generic_cmd(const char *me, char *arg)
setup_path();
if (!arg || !(arg = sq_dequote(arg)))
die("bad argument");
- if (prefixcmp(me, "git-"))
+ if (!starts_with(me, "git-"))
die("bad command");
my_argv[0] = me + 4;
diff --git a/strbuf.c b/strbuf.c
index 1170d01..83caf4a 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,6 +1,15 @@
#include "cache.h"
#include "refs.h"
+int starts_with(const char *str, const char *prefix)
+{
+ for (; ; str++, prefix++)
+ if (!*prefix)
+ return 1;
+ else if (*str != *prefix)
+ return 0;
+}
+