summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/Makefile23
-rw-r--r--Documentation/RelNotes/1.7.7.2.txt44
-rw-r--r--Documentation/RelNotes/1.7.7.3.txt19
-rw-r--r--Documentation/RelNotes/1.7.7.4.txt14
-rw-r--r--Documentation/RelNotes/1.7.8.txt86
-rw-r--r--Documentation/RelNotes/1.7.9.txt27
-rw-r--r--Documentation/diff-options.txt2
-rw-r--r--Documentation/git-cherry-pick.txt3
-rw-r--r--Documentation/git-difftool.txt2
-rw-r--r--Documentation/git-fsck.txt11
-rw-r--r--Documentation/git-reset.txt8
-rw-r--r--Documentation/git-revert.txt3
-rw-r--r--Documentation/git-symbolic-ref.txt9
-rw-r--r--Documentation/git.txt5
-rw-r--r--Documentation/gitattributes.txt2
-rw-r--r--Documentation/gitweb.conf.txt5
-rwxr-xr-xDocumentation/install-doc-quick.sh44
-rw-r--r--Documentation/merge-options.txt1
-rw-r--r--Documentation/sequencer.txt13
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL29
-rw-r--r--Makefile50
l---------RelNotes2
-rw-r--r--branch.c1
-rw-r--r--builtin/apply.c3
-rw-r--r--builtin/blame.c5
-rw-r--r--builtin/branch.c15
-rw-r--r--builtin/checkout.c2
-rw-r--r--builtin/clone.c4
-rw-r--r--builtin/commit.c1
-rw-r--r--builtin/diff.c2
-rw-r--r--builtin/fetch.c33
-rw-r--r--builtin/fsck.c78
-rw-r--r--builtin/gc.c4
-rw-r--r--builtin/grep.c48
-rw-r--r--builtin/index-pack.c4
-rw-r--r--builtin/merge.c60
-rw-r--r--builtin/mktree.c1
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/pack-objects.c131
-rw-r--r--builtin/prune.c13
-rw-r--r--builtin/receive-pack.c17
-rw-r--r--builtin/reflog.c2
-rw-r--r--builtin/remote.c7
-rw-r--r--builtin/revert.c180
-rw-r--r--builtin/stripspace.c2
-rw-r--r--compat/mingw.c2
-rw-r--r--compat/mingw.h2
-rw-r--r--compat/msvc.h1
-rw-r--r--compat/strtoimax.c10
-rw-r--r--compat/vcbuild/include/arpa/inet.h1
-rw-r--r--compat/vcbuild/include/grp.h1
-rw-r--r--compat/vcbuild/include/inttypes.h1
-rw-r--r--compat/vcbuild/include/netdb.h1
-rw-r--r--compat/vcbuild/include/netinet/in.h1
-rw-r--r--compat/vcbuild/include/netinet/tcp.h1
-rw-r--r--compat/vcbuild/include/pwd.h1
-rw-r--r--compat/vcbuild/include/sys/ioctl.h1
-rw-r--r--compat/vcbuild/include/sys/select.h1
-rw-r--r--compat/vcbuild/include/sys/socket.h1
-rw-r--r--compat/vcbuild/include/sys/wait.h1
-rw-r--r--compat/vcbuild/include/termios.h1
-rw-r--r--compat/win32/poll.c (renamed from compat/win32/sys/poll.c)19
-rw-r--r--compat/win32/poll.h (renamed from compat/win32/sys/poll.h)0
-rw-r--r--config.c45
-rwxr-xr-xcontrib/completion/git-completion.bash16
-rw-r--r--contrib/diff-highlight/README57
-rwxr-xr-xcontrib/diff-highlight/diff-highlight124
-rwxr-xr-xcontrib/fast-import/git-p472
-rw-r--r--contrib/fast-import/git-p4.txt19
-rw-r--r--contrib/git-jump/README92
-rwxr-xr-xcontrib/git-jump/git-jump69
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki4
-rw-r--r--convert.c6
-rw-r--r--dir.c50
-rwxr-xr-xgit-am.sh7
-rw-r--r--git-compat-util.h17
-rwxr-xr-xgit-submodule.sh8
-rwxr-xr-xgit-svn.perl6
-rw-r--r--gitweb/INSTALL2
-rw-r--r--gitweb/Makefile6
-rwxr-xr-xgitweb/gitweb.perl9
-rw-r--r--http.c61
-rw-r--r--http.h2
-rw-r--r--list-objects.c9
-rw-r--r--mailmap.c5
-rw-r--r--name-hash.c2
-rw-r--r--notes-merge.c104
-rw-r--r--object.c2
-rw-r--r--pack-check.c28
-rw-r--r--pack-write.c4
-rw-r--r--pack.h9
-rw-r--r--perl/.gitignore1
-rw-r--r--perl/Git.pm88
-rw-r--r--pretty.c10
-rw-r--r--reachable.c55
-rw-r--r--reachable.h3
-rw-r--r--read-cache.c42
-rw-r--r--refs.c20
-rw-r--r--remote.c104
-rw-r--r--remote.h2
-rw-r--r--sequencer.h2
-rw-r--r--sha1_file.c5
-rw-r--r--submodule.c2
-rw-r--r--t/gitweb-lib.sh1
-rwxr-xr-xt/t3200-branch.sh5
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh54
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh127
-rwxr-xr-xt/t4018-diff-funcname.sh2
-rwxr-xr-xt/t4034-diff-words.sh1
-rw-r--r--t/t4034/matlab/expect14
-rw-r--r--t/t4034/matlab/post9
-rw-r--r--t/t4034/matlab/pre9
-rwxr-xr-xt/t5501-fetch-push-alternates.sh2
-rwxr-xr-xt/t5510-fetch.sh50
-rwxr-xr-xt/t5700-clone-reference.sh7
-rwxr-xr-xt/t6030-bisect-porcelain.sh2
-rwxr-xr-xt/t7106-reset-sequence.sh10
-rwxr-xr-xt/t7508-status.sh4
-rwxr-xr-xt/t7511-status-index.sh50
-rwxr-xr-xt/t8006-blame-textconv.sh11
-rwxr-xr-xt/t9700-perl-git.sh6
-rwxr-xr-xt/t9700/test.pl4
-rwxr-xr-xt/t9802-git-p4-filetype.sh31
-rwxr-xr-xt/t9805-skip-submit-edit.sh82
-rwxr-xr-xtemplates/hooks--pre-commit.sample8
-rw-r--r--tree-diff.c22
-rw-r--r--tree-walk.c75
-rw-r--r--tree-walk.h18
-rw-r--r--tree.c11
-rw-r--r--unpack-trees.c6
-rw-r--r--userdiff.c3
-rw-r--r--wt-status.c2
133 files changed, 2096 insertions, 764 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 5513256..304b31e 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -46,8 +46,8 @@ MANPAGE_XSL = manpage-normal.xsl
XMLTO_EXTRA =
INSTALL?=install
RM ?= rm -f
-DOC_REF = origin/man
-HTML_REF = origin/html
+MAN_REPO = ../../git-manpages
+HTML_REPO = ../../git-htmldocs
infodir?=$(prefix)/share/info
MAKEINFO=makeinfo
@@ -327,12 +327,23 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
install-webdoc : html
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
+# You must have a clone of git-htmldocs and git-manpages repositories
+# next to the git repository itself for the following to work.
+
quick-install: quick-install-man
-quick-install-man:
- '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
+require-manrepo::
+ @if test ! -d $(MAN_REPO); \
+ then echo "git-manpages repository must exist at $(MAN_REPO)"; exit 1; fi
+
+quick-install-man: require-manrepo
+ '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(MAN_REPO) $(DESTDIR)$(mandir)
+
+require-htmlrepo::
+ @if test ! -d $(HTML_REPO); \
+ then echo "git-htmldocs repository must exist at $(HTML_REPO)"; exit 1; fi
-quick-install-html:
- '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
+quick-install-html: require-htmlrepo
+ '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir)
.PHONY: FORCE
diff --git a/Documentation/RelNotes/1.7.7.2.txt b/Documentation/RelNotes/1.7.7.2.txt
new file mode 100644
index 0000000..e6bbef2
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.2.txt
@@ -0,0 +1,44 @@
+Git v1.7.7.2 Release Notes
+==========================
+
+Fixes since v1.7.7.1
+--------------------
+
+ * We used to drop error messages from libcurl on certain kinds of
+ errors.
+
+ * Error report from smart HTTP transport, when the connection was
+ broken in the middle of a transfer, showed a useless message on
+ a corrupt packet.
+
+ * "git fetch --prune" was unsafe when used with refspecs from the
+ command line.
+
+ * The attribute mechanism did not use case insensitive match when
+ core.ignorecase was set.
+
+ * "git bisect" did not notice when it failed to update the working tree
+ to the next commit to be tested.
+
+ * "git config --bool --get-regexp" failed to separate the variable name
+ and its value "true" when the variable is defined without "= true".
+
+ * "git remote rename $a $b" were not careful to match the remote name
+ against $a (i.e. source side of the remote nickname).
+
+ * "git mergetool" did not use its arguments as pathspec, but as a path to
+ the file that may not even have any conflict.
+
+ * "git diff --[num]stat" used to use the number of lines of context
+ different from the default, potentially giving different results from
+ "git diff | diffstat" and confusing the users.
+
+ * "git pull" and "git rebase" did not work well even when GIT_WORK_TREE is
+ set correctly with GIT_DIR if the current directory is outside the working
+ tree.
+
+ * "git send-email" did not honor the configured hostname when restarting
+ the HELO/EHLO exchange after switching TLS on.
+
+ * "gitweb" used to produce a non-working link while showing the contents
+ of a blob, when JavaScript actions are enabled.
diff --git a/Documentation/RelNotes/1.7.7.3.txt b/Documentation/RelNotes/1.7.7.3.txt
new file mode 100644
index 0000000..09301f0
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.3.txt
@@ -0,0 +1,19 @@
+Git v1.7.7.3 Release Notes
+==========================
+
+Fixes since v1.7.7.2
+--------------------
+
+ * Adjust the "quick-install-doc" procedures as preformatted
+ html/manpage are no longer in the source repository.
+
+ * The logic to optimize the locality of the data in a pack introduced in
+ 1.7.7 was grossly inefficient.
+
+ * The logic to filter out forked projects in the project list in
+ "gitweb" was broken for some time.
+
+ * "git branch -m/-M" advertised to update RENAME_REF ref in the
+ commit log message that introduced the feature but not anywhere in
+ the documentation, and never did update such a ref anyway. This
+ undocumented misfeature that did not exist has been excised.
diff --git a/Documentation/RelNotes/1.7.7.4.txt b/Documentation/RelNotes/1.7.7.4.txt
new file mode 100644
index 0000000..e523448
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.4.txt
@@ -0,0 +1,14 @@
+Git v1.7.7.4 Release Notes
+==========================
+
+Fixes since v1.7.7.3
+--------------------
+
+ * A few header dependencies were missing from the Makefile.
+
+ * Some newer parts of the code used C99 __VA_ARGS__ while we still
+ try to cater to older compilers.
+
+ * "git name-rev --all" tried to name all _objects_, naturally failing to
+ describe many blobs and trees, instead of showing only commits as
+ advertised in its documentation.
diff --git a/Documentation/RelNotes/1.7.8.txt b/Documentation/RelNotes/1.7.8.txt
index d7b2c76..b4d90bb 100644
--- a/Documentation/RelNotes/1.7.8.txt
+++ b/Documentation/RelNotes/1.7.8.txt
@@ -1,5 +1,5 @@
-Git v1.7.8 Release Notes (draft)
-================================
+Git v1.7.8 Release Notes
+========================
Updates since v1.7.7
--------------------
@@ -29,7 +29,7 @@ Updates since v1.7.7
files from the index, not from the working tree.
* Variants of "git cherry-pick" and "git revert" that take multiple
- commits learned to "--continue".
+ commits learned to "--continue" and "--abort".
* "git daemon" gives more human readble error messages to clients
using ERR packets when appropriate.
@@ -79,6 +79,9 @@ Updates since v1.7.7
* "git ls-remote" learned to respond to "-h"(elp) requests.
+ * "mediawiki" remote helper can interact with (surprise!) MediaWiki
+ with "git fetch" & "git push".
+
* "git merge" learned the "--edit" option to allow users to edit the
merge commit log message.
@@ -96,6 +99,9 @@ Updates since v1.7.7
* "git stash" learned "--include-untracked" option to stash away
untracked/ignored cruft from the working tree.
+ * "git submodule clone" does not leak an error message to the UI
+ level unnecessarily anymore.
+
* "git submodule update" learned to honor "none" as the value for
submodule.<name>.update to specify that the named submodule should
not be checked out by default.
@@ -107,12 +113,12 @@ Updates since v1.7.7
between commits in the superproject that has and does not have the
submodule in the tree without re-cloning.
- * "mediawiki" remote helper can interact with (surprise!) MediaWiki
- with "git fetch" & "git push".
-
* "gitweb" leaked unescaped control characters from syntax hiliter
outputs.
+ * "gitweb" can be told to give custom string at the end of the HTML
+ HEAD element.
+
* "gitweb" now has its own manual pages.
@@ -125,25 +131,14 @@ Fixes since v1.7.7
Unless otherwise noted, all fixes in the 1.7.7.X maintenance track are
included in this release.
- * We used to drop error messages from libcurl on certain kinds of
- errors.
- (merge be22d92eac8 jn/maint-http-error-message later to maint).
-
- * Error report from smart HTTP transport, when the connection was
- broken in the middle of a transfer, showed a useless message on
- a corrupt packet.
- (merge 6cdf022 sp/smart-http-failure later to maint).
-
* HTTP transport did not use pushurl correctly, and also did not tell
what host it is trying to authenticate with when asking for
credentials.
(merge deba493 jk/http-auth later to maint).
- * "git branch -m/-M" advertised to update RENAME_REF ref in the
- commit log message that introduced the feature but not anywhere in
- the documentation, and never did update such a ref anyway. This
- undocumented misfeature that did not exist has been excised.
- (merge b0eab01 jc/maint-remove-renamed-ref later to maint).
+ * "git blame" was aborted if started from an uncommitted content and
+ the path had the textconv filter in effect.
+ (merge 8518088 ss/blame-textconv-fake-working-tree later to maint).
* Adding many refs to the local repository in one go (e.g. "git fetch"
that fetches many tags) and looking up a ref by name in a repository
@@ -152,56 +147,15 @@ included in this release.
* Report from "git commit" on untracked files was confused under
core.ignorecase option.
- (merge 2548183b jk/name-hash-dirent later to maint).
-
- * The attribute mechanism did not use case insensitive match when
- core.ignorecase was set.
- (merge 6eba621 bc/attr-ignore-case later to maint).
-
- * "git bisect" did not notice when it failed to update the working tree
- to the next commit to be tested.
- (merge 1acf11717 js/bisect-no-checkout later to maint).
-
- * "git config --bool --get-regexp" failed to separate the variable name
- and its value "true" when the variable is defined without "= true".
- (merge 880e3cc mm/maint-config-explicit-bool-display later to maint).
-
- * "git remote rename $a $b" were not careful to match the remote name
- against $a (i.e. source side of the remote nickname).
- (merge b52d00aed mz/remote-rename later to maint).
-
- * "git diff --[num]stat" used to use the number of lines of context
- different from the default, potentially giving different results from
- "git diff | diffstat" and confusing the users.
- (merge f01cae918 jc/maint-diffstat-numstat-context later to maint).
+ (merge 395c7356 jk/name-hash-dirent later to maint).
* "git merge" did not understand ":/<pattern>" as a way to name a commit.
- * "git mergetool" learned to use its arguments as pathspec, not a path to
- the file that may not even have any conflict.
- (merge 6d9990a jm/mergetool-pathspec later to maint).
-
- * "git pull" and "git rebase" did not work well even when GIT_WORK_TREE is
- set correctly with GIT_DIR if the current directory is outside the working
- tree.
- (merge 035b5bf jk/pull-rebase-with-work-tree later to maint).
-
" "git push" on the receiving end used to call post-receive and post-update
hooks for attempted removal of non-existing refs.
(merge 160b81ed ph/push-to-delete-nothing later to maint).
- * "git send-email" did not honor the configured hostname when restarting
- the HELO/EHLO exchange after switching TLS on.
- (merge 155b940 md/smtp-tls-hello-again later to maint).
-
- * "gitweb" used to produce a non-working link while showing the contents
- of a blob, when JavaScript actions are enabled.
- (merge 2b07ff3ff ps/gitweb-js-with-lineno later to maint).
-
----
-exec >/var/tmp/1
-O=v1.7.7-485-g9ee3d37
-echo O=$(git describe --always master)
-git log --first-parent --oneline --reverse ^$O master
-echo
-git shortlog --no-merges ^$O master
+ * Help text for "git remote set-url" and "git remote set-branches"
+ were misspelled.
+ (merge c49904e fc/remote-seturl-usage-fix later to maint).
+ (merge 656cdf0 jc/remote-setbranches-usage-fix later to maint).
diff --git a/Documentation/RelNotes/1.7.9.txt b/Documentation/RelNotes/1.7.9.txt
new file mode 100644
index 0000000..7f05936
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.txt
@@ -0,0 +1,27 @@
+Git v1.7.9 Release Notes (draft)
+========================
+
+Updates since v1.7.8
+--------------------
+
+ * Porcelain commands like "git reset" did not distinguish deletions
+ and type-changes from ordinary modification, and reported them with
+ the same 'M' moniker. They now use 'D' (for deletion) and 'T' (for
+ type-change) to match "git status -s" and "git diff --name-status".
+
+ * fsck and prune are relatively lengthy operations that still go
+ silent while making the end-user wait. They learned to give progress
+ output like other slow operations.
+
+ * The set of built-in function-header patterns for various languages
+ knows MATLAB.
+
+May also contain documentation updates and code clean-ups.
+
+
+Fixes since v1.7.8
+------------------
+
+ * In some codepaths (notably, checkout and merge), the ignore patterns
+ recorded in $GIT_DIR/info/exclude were not honored. They now are.
+ (merge fc001b5 nd/maint-ignore-exclude later to maint).
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 08b581f..9f7cba2 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -413,6 +413,7 @@ endif::git-format-patch[]
Show whole surrounding functions of changes.
ifndef::git-format-patch[]
+ifndef::git-log[]
--exit-code::
Make the program exit with codes similar to diff(1).
That is, it exits with 1 if there were differences and
@@ -420,6 +421,7 @@ ifndef::git-format-patch[]
--quiet::
Disable all output of the program. Implies `--exit-code`.
+endif::git-log[]
endif::git-format-patch[]
--ext-diff::
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 2660a84..fed5097 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -9,8 +9,9 @@ SYNOPSIS
--------
[verse]
'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...
-'git cherry-pick' --reset
'git cherry-pick' --continue
+'git cherry-pick' --quit
+'git cherry-pick' --abort
DESCRIPTION
-----------
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index a03515f..19d473c 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -31,7 +31,7 @@ OPTIONS
-t <tool>::
--tool=<tool>::
Use the diff tool specified by <tool>.
- Valid merge tools are:
+ Valid diff tools are:
araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3,
kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff.
+
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index a2a508d..0a17b42 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -10,7 +10,8 @@ SYNOPSIS
--------
[verse]
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
- [--[no-]full] [--strict] [--verbose] [--lost-found] [<object>*]
+ [--[no-]full] [--strict] [--verbose] [--lost-found]
+ [--[no-]progress] [<object>*]
DESCRIPTION
-----------
@@ -72,6 +73,14 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless
a blob, the contents are written into the file, rather than
its object name.
+--progress::
+--no-progress::
+ Progress status is reported on the standard error stream by
+ default when it is attached to a terminal, unless
+ --no-progress or --verbose is specified. --progress forces
+ progress status even if the standard error stream is not
+ directed to a terminal.
+
It tests SHA1 and general object sanity, and it does full tracking of
the resulting reachability and everything else. It prints out any
corruption it finds (missing or bad objects), and if you use the
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index b2832fc..b674866 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -9,8 +9,8 @@ SYNOPSIS
--------
[verse]
'git reset' [-q] [<commit>] [--] <paths>...
-'git reset' [--patch|-p] [<commit>] [--] [<paths>...]
-'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
+'git reset' (--patch | -p) [<commit>] [--] [<paths>...]
+'git reset' (--soft | --mixed | --hard | --merge | --keep) [-q] [<commit>]
DESCRIPTION
-----------
@@ -34,7 +34,7 @@ Alternatively, using linkgit:git-checkout[1] and specifying a commit, you
can copy the contents of a path out of a commit to the index and to the
working tree in one go.
-'git reset' --patch|-p [<commit>] [--] [<paths>...]::
+'git reset' (--patch | -p) [<commit>] [--] [<paths>...]::
Interactively select hunks in the difference between the index
and <commit> (defaults to HEAD). The chosen hunks are applied
in reverse to the index.
@@ -43,7 +43,7 @@ This means that `git reset -p` is the opposite of `git add -p`, i.e.
you can use it to selectively reset hunks. See the ``Interactive Mode''
section of linkgit:git-add[1] to learn how to operate the `\--patch` mode.
-'git reset' [--<mode>] [<commit>]::
+'git reset' --<mode> [<commit>]::
This form resets the current branch head to <commit> and
possibly updates the index (resetting it to the tree of <commit>) and
the working tree depending on <mode>, which
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index f351941..b699a34 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,8 +9,9 @@ SYNOPSIS
--------
[verse]
'git revert' [--edit | --no-edit] [-n] [-m parent-number] [-s] <commit>...
-'git revert' --reset
'git revert' --continue
+'git revert' --quit
+'git revert' --abort
DESCRIPTION
-----------
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index 75b1ae5..a45d4c4 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -43,12 +43,9 @@ In the past, `.git/HEAD` was a symbolic link pointing at
`refs/heads/master`. When we wanted to switch to another branch,
we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we wanted
to find out which branch we are on, we did `readlink .git/HEAD`.
-This was fine, and internally that is what still happens by
-default, but on platforms that do not have working symlinks,
-or that do not have the `readlink(1)` command, this was a bit
-cumbersome. On some platforms, `ln -sf` does not even work as
-advertised (horrors). Therefore symbolic links are now deprecated
-and symbolic refs are used by default.
+But symbolic links are not entirely portable, so they are now
+deprecated and symbolic refs (as described above) are used by
+default.
'git symbolic-ref' will exit with status 0 if the contents of the
symbolic ref were printed correctly, with status 1 if the requested
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 5e80cfd..e869032 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -44,6 +44,11 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
+* link:v1.7.8/git.html[documentation for release 1.7.8]
+
+* release notes for
+ link:RelNotes/1.7.8.txt[1.7.8].
+
* link:v1.7.7.1/git.html[documentation for release 1.7.7.1]
* release notes for
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 25e46ae..a85b187 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -500,6 +500,8 @@ patterns are available:
- `java` suitable for source code in the Java language.
+- `matlab` suitable for source code in the MATLAB language.
+
- `objc` suitable for source code in the Objective-C language.
- `pascal` suitable for source code in the Pascal/Delphi language.
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index 4ca3e27..7aba497 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -364,6 +364,11 @@ $site_name::
+
Can be set using the `GITWEB_SITENAME` at build time. Unset by default.
+$site_html_head_string::
+ HTML snippet to be included in the <head> section of each page.
+ Can be set using `GITWEB_SITE_HTML_HEAD_STRING` at build time.
+ No default value.
+
$site_header::
Name of a file with HTML to be included at the top of each page.
Relative to the directory containing the 'gitweb.cgi' script.
diff --git a/Documentation/install-doc-quick.sh b/Documentation/install-doc-quick.sh
index 35f4408..327f69b 100755
--- a/Documentation/install-doc-quick.sh
+++ b/Documentation/install-doc-quick.sh
@@ -1,31 +1,39 @@
#!/bin/sh
-# This requires a branch named in $head
-# (usually 'man' or 'html', provided by the git.git repository)
-set -e
-head="$1"
-mandir="$2"
-SUBDIRECTORY_OK=t
-USAGE='<refname> <target directory>'
-. "$(git --exec-path)"/git-sh-setup
-cd_to_toplevel
+# This requires git-manpages and/or git-htmldocs repositories
-test -z "$mandir" && usage
-if ! git rev-parse --verify "$head^0" >/dev/null; then
- echo >&2 "head: $head does not exist in the current repository"
- usage
+repository=${1?repository}
+destdir=${2?destination}
+
+head=master GIT_DIR=
+for d in "$repository/.git" "$repository"
+do
+ if GIT_DIR="$d" git rev-parse refs/heads/master >/dev/null 2>&1
+ then
+ GIT_DIR="$d"
+ export GIT_DIR
+ break
+ fi
+done
+
+if test -z "$GIT_DIR"
+then
+ echo >&2 "Neither $repository nor $repository/.git is a repository"
+ exit 1
fi
-GIT_INDEX_FILE=`pwd`/.quick-doc.index
-export GIT_INDEX_FILE
+GIT_WORK_TREE=$(pwd)
+GIT_INDEX_FILE=$(pwd)/.quick-doc.$$
+export GIT_INDEX_FILE GIT_WORK_TREE
rm -f "$GIT_INDEX_FILE"
trap 'rm -f "$GIT_INDEX_FILE"' 0
git read-tree $head
-git checkout-index -a -f --prefix="$mandir"/
+git checkout-index -a -f --prefix="$destdir"/
-if test -n "$GZ"; then
+if test -n "$GZ"
+then
git ls-tree -r --name-only $head |
- xargs printf "$mandir/%s\n" |
+ xargs printf "$destdir/%s\n" |
xargs gzip -f
fi
rm -f "$GIT_INDEX_FILE"
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 6bd0b04..1a5c12e 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -9,7 +9,6 @@ inspect and further tweak the merge result before committing.
--edit::
-e::
-+
Invoke editor before committing successful merge to further
edit the default merge message.
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 3e6df33..5747f44 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -1,9 +1,12 @@
---reset::
- Forget about the current operation in progress. Can be used
- to clear the sequencer state after a failed cherry-pick or
- revert.
-
--continue::
Continue the operation in progress using the information in
'.git/sequencer'. Can be used to continue after resolving
conflicts in a failed cherry-pick or revert.
+
+--quit::
+ Forget about the current operation in progress. Can be used
+ to clear the sequencer state after a failed cherry-pick or
+ revert.
+
+--abort::
+ Cancel the operation and return to the pre-sequence state.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 19a142a..e18a30a 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.7.GIT
+DEF_VER=v1.7.8.GIT
LF='
'
diff --git a/INSTALL b/INSTALL
index bbb9d4d..bf0d97e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -139,34 +139,11 @@ Issues of note:
uses some compatibility wrappers to work on AsciiDoc 8. If you have
AsciiDoc 7, try "make ASCIIDOC7=YesPlease".
- Alternatively, pre-formatted documentation is available in
- "html" and "man" branches of the git repository itself. For
- example, you could:
-
- $ mkdir manual && cd manual
- $ git init
- $ git fetch-pack git://git.kernel.org/pub/scm/git/git.git man html |
- while read a b
- do
- echo $a >.git/$b
- done
- $ cp .git/refs/heads/man .git/refs/heads/master
- $ git checkout
-
- to checkout the pre-built man pages. Also in this repository:
-
- $ git checkout html
-
- would instead give you a copy of what you see at:
-
- http://www.kernel.org/pub/software/scm/git/docs/
-
There are also "make quick-install-doc", "make quick-install-man"
and "make quick-install-html" which install preformatted man pages
- and html documentation.
- This does not require asciidoc/xmlto, but it only works from within
- a cloned checkout of git.git with these two extra branches, and will
- not work for the maintainer for obvious chicken-and-egg reasons.
+ and html documentation. To use these build targets, you need to
+ clone two separate git-htmldocs and git-manpages repositories next
+ to the clone of git itself.
It has been reported that docbook-xsl version 1.72 and 1.73 are
buggy; 1.72 misformats manual pages for callouts, and 1.73 needs
diff --git a/Makefile b/Makefile
index 3139c19..b21d2f1 100644
--- a/Makefile
+++ b/Makefile
@@ -57,8 +57,8 @@ all::
#
# Define NO_STRLCPY if you don't have strlcpy.
#
-# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
-# If your compiler also does not support long long or does not have
+# Define NO_STRTOUMAX if you don't have both strtoimax and strtoumax in the
+# C library. If your compiler also does not support long long or does not have
# strtoull, define NO_STRTOULL.
#
# Define NO_SETENV if you don't have setenv in the C library.
@@ -250,6 +250,12 @@ all::
# DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
# DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
#
+# Define COMPUTE_HEADER_DEPENDENCIES to "yes" if you want dependencies on
+# header files to be automatically computed, to avoid rebuilding objects when
+# an unrelated header file changes. Define it to "no" to use the hard-coded
+# dependency rules. The default is "auto", which means to use computed header
+# dependencies if your compiler is detected to support it.
+#
# Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
# dependency rules.
#
@@ -515,9 +521,10 @@ LIB_H += compat/mingw.h
LIB_H += compat/obstack.h
LIB_H += compat/win32/pthread.h
LIB_H += compat/win32/syslog.h
-LIB_H += compat/win32/sys/poll.h
+LIB_H += compat/win32/poll.h
LIB_H += compat/win32/dirent.h
LIB_H += connected.h
+LIB_H += convert.h
LIB_H += csum-file.h
LIB_H += decorate.h
LIB_H += delta.h
@@ -1088,6 +1095,7 @@ ifeq ($(uname_S),Windows)
NO_PREAD = YesPlease
NEEDS_CRYPTO_WITH_SSL = YesPlease
NO_LIBGEN_H = YesPlease
+ NO_SYS_POLL_H = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_IPV6 = YesPlease
NO_SETENV = YesPlease
@@ -1126,7 +1134,7 @@ ifeq ($(uname_S),Windows)
BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
COMPAT_OBJS = compat/msvc.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
- compat/win32/sys/poll.o compat/win32/dirent.o
+ compat/win32/poll.o compat/win32/dirent.o
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
@@ -1181,6 +1189,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_PREAD = YesPlease
NEEDS_CRYPTO_WITH_SSL = YesPlease
NO_LIBGEN_H = YesPlease
+ NO_SYS_POLL_H = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_SETENV = YesPlease
NO_UNSETENV = YesPlease
@@ -1214,7 +1223,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
- compat/win32/sys/poll.o compat/win32/dirent.o
+ compat/win32/poll.o compat/win32/dirent.o
EXTLIBS += -lws2_32
PTHREAD_LIBS =
X = .exe
@@ -1243,21 +1252,32 @@ endif
endif
ifdef CHECK_HEADER_DEPENDENCIES
-COMPUTE_HEADER_DEPENDENCIES =
+COMPUTE_HEADER_DEPENDENCIES = no
USE_COMPUTED_HEADER_DEPENDENCIES =
-else
+endif
+
ifndef COMPUTE_HEADER_DEPENDENCIES
+COMPUTE_HEADER_DEPENDENCIES = auto
+endif
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),auto)
dep_check = $(shell $(CC) $(ALL_CFLAGS) \
-c -MF /dev/null -MMD -MP -x c /dev/null -o /dev/null 2>&1; \
echo $$?)
ifeq ($(dep_check),0)
-COMPUTE_HEADER_DEPENDENCIES=YesPlease
-endif
+override COMPUTE_HEADER_DEPENDENCIES = yes
+else
+override COMPUTE_HEADER_DEPENDENCIES = no
endif
endif
-ifdef COMPUTE_HEADER_DEPENDENCIES
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
USE_COMPUTED_HEADER_DEPENDENCIES = YesPlease
+else
+ifneq ($(COMPUTE_HEADER_DEPENDENCIES),no)
+$(error please set COMPUTE_HEADER_DEPENDENCIES to yes, no, or auto \
+(not "$(COMPUTE_HEADER_DEPENDENCIES)"))
+endif
endif
ifdef SANE_TOOL_PATH
@@ -1458,7 +1478,7 @@ ifdef NO_STRLCPY
endif
ifdef NO_STRTOUMAX
COMPAT_CFLAGS += -DNO_STRTOUMAX
- COMPAT_OBJS += compat/strtoumax.o
+ COMPAT_OBJS += compat/strtoumax.o compat/strtoimax.o
endif
ifdef NO_STRTOULL
COMPAT_CFLAGS += -DNO_STRTOULL
@@ -1904,7 +1924,7 @@ OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
-ifdef COMPUTE_HEADER_DEPENDENCIES
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
$(dep_dirs):
@mkdir -p $@
@@ -1917,7 +1937,7 @@ Please unset CHECK_HEADER_DEPENDENCIES and try again)
endif
endif
-ifndef COMPUTE_HEADER_DEPENDENCIES
+ifneq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
ifndef CHECK_HEADER_DEPENDENCIES
dep_dirs =
missing_dep_dirs =
@@ -2007,13 +2027,13 @@ builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o tra
builtin/bundle.o bundle.o transport.o: bundle.h
builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h
builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h
-builtin/grep.o builtin/pack-objects.o transport-helper.o: thread-utils.h
+builtin/grep.o builtin/pack-objects.o transport-helper.o thread-utils.o: thread-utils.h
builtin/send-pack.o transport.o: send-pack.h
builtin/log.o builtin/shortlog.o: shortlog.h
builtin/prune.o builtin/reflog.o reachable.o: reachable.h
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
builtin/tar-tree.o archive-tar.o: tar.h
-connect.o transport.o http-backend.o: url.h
+connect.o transport.o url.o http-backend.o: url.h
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
diff --git a/RelNotes b/RelNotes
index 7d92769..766bbaf 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.8.txt \ No newline at end of file
+Documentation/RelNotes/1.7.9.txt \ No newline at end of file
diff --git a/branch.c b/branch.c
index d809876..025a97b 100644
--- a/branch.c
+++ b/branch.c
@@ -241,6 +241,7 @@ void create_branch(const char *head,
void remove_branch_state(void)
{
unlink(git_path("CHERRY_PICK_HEAD"));
+ unlink(git_path("REVERT_HEAD"));
unlink(git_path("MERGE_HEAD"));
unlink(git_path("MERGE_RR"));
unlink(git_path("MERGE_MSG"));
diff --git a/builtin/apply.c b/builtin/apply.c
index 84a8a0b..b3b59db 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -250,9 +250,6 @@ static int fuzzy_matchlines(const char *s1, size_t n1,
const char *last2 = s2 + n2 - 1;
int result = 0;
- if (n1 < 0 || n2 < 0)
- return 0;
-
/* ignore line endings */
while ((*last1 == '\r') || (*last1 == '\n'))
last1--;
diff --git a/builtin/blame.c b/builtin/blame.c
index 26a5d42..80febbe 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -2096,6 +2096,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
if (!contents_from || strcmp("-", contents_from)) {
struct stat st;
const char *read_from;
+ char *buf_ptr;
unsigned long buf_len;
if (contents_from) {
@@ -2113,8 +2114,8 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
switch (st.st_mode & S_IFMT) {
case S_IFREG:
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
- textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len))
- buf.len = buf_len;
+ textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len))
+ strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
die_errno("cannot open or read '%s'", read_from);
break;
diff --git a/builtin/branch.c b/builtin/branch.c
index 009b713..55cad76 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -705,7 +705,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
- if (!delete && !rename && !force_create && argc == 0)
+ if (!delete && !rename && argc == 0)
list = 1;
if (!!delete + !!rename + !!force_create + !!list > 1)
@@ -719,11 +719,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
else if (list)
return print_ref_list(kinds, detached, verbose, abbrev,
with_commit, argv);
- else if (rename && (argc == 1))
- rename_branch(head, argv[0], rename > 1);
- else if (rename && (argc == 2))
- rename_branch(argv[0], argv[1], rename > 1);
- else if (argc <= 2) {
+ else if (rename) {
+ if (argc == 1)
+ rename_branch(head, argv[0], rename > 1);
+ else if (argc == 2)
+ rename_branch(argv[0], argv[1], rename > 1);
+ else
+ usage_with_options(builtin_branch_usage, options);
+ } else if (argc > 0 && argc <= 2) {
if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2a80772..51840b9 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -411,7 +411,7 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.fn = twoway_merge;
topts.dir = xcalloc(1, sizeof(*topts.dir));
topts.dir->flags |= DIR_SHOW_IGNORED;
- topts.dir->exclude_per_dir = ".gitignore";
+ setup_standard_excludes(topts.dir);
tree = parse_tree_indirect(old->commit ?
old->commit->object.sha1 :
EMPTY_TREE_SHA1_BIN);
diff --git a/builtin/clone.c b/builtin/clone.c
index 488f48e..efe8b6c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -577,9 +577,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (0 <= option_verbosity) {
if (option_bare)
- printf(_("Cloning into bare repository %s...\n"), dir);
+ printf(_("Cloning into bare repository '%s'...\n"), dir);
else
- printf(_("Cloning into %s...\n"), dir);
+ printf(_("Cloning into '%s'...\n"), dir);
}
init_db(option_template, INIT_DB_QUIET);
write_config(&option_config);
diff --git a/builtin/commit.c b/builtin/commit.c
index c46f2d1..8f2bebe 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1514,6 +1514,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
unlink(git_path("CHERRY_PICK_HEAD"));
+ unlink(git_path("REVERT_HEAD"));
unlink(git_path("MERGE_HEAD"));
unlink(git_path("MERGE_MSG"));
unlink(git_path("MERGE_MODE"));
diff --git a/builtin/diff.c b/builtin/diff.c
index 1118689..0fe638f 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -182,7 +182,7 @@ static int builtin_diff_combined(struct rev_info *revs,
hashcpy((unsigned char *)(parent + i), ent[i].item->sha1);
diff_tree_combined(parent[0], parent + 1, ents - 1,
revs->dense_combined_merges, revs);
- free(parent);
+ free((void *)parent);
return 0;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 1adf6c1..91731b9 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -510,10 +510,10 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
return ret;
}
-static int prune_refs(struct transport *transport, struct ref *ref_map)
+static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
{
int result = 0;
- struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map);
+ struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
const char *dangling_msg = dry_run
? _(" (%s will become dangling)\n")
: _(" (%s has become dangling)\n");
@@ -704,8 +704,31 @@ static int do_fetch(struct transport *transport,
free_refs(ref_map);
return 1;
}
- if (prune)
- prune_refs(transport, ref_map);
+ if (prune) {
+ /* If --tags was specified, pretend the user gave us the canonical tags refspec */
+ 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);
+ } else {
+ prune_refs(transport->remote->fetch, transport->remote->fetch_refspec_nr, ref_map);
+ }
+ }
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
@@ -888,7 +911,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
atexit(unlock_pack);
refspec = parse_fetch_refspec(ref_nr, refs);
exit_code = do_fetch(transport, refspec, ref_nr);
- free(refspec);
+ free_refspec(ref_nr, refspec);
transport_disconnect(transport);
transport = NULL;
return exit_code;
diff --git a/builtin/fsck.c b/builtin/fsck.c
index df1a88b..30d0dc8 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -11,6 +11,7 @@
#include "fsck.h"
#include "parse-options.h"
#include "dir.h"
+#include "progress.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -27,8 +28,10 @@ static const char *head_points_at;
static int errors_found;
static int write_lost_and_found;
static int verbose;
+static int show_progress = -1;
#define ERROR_OBJECT 01
#define ERROR_REACHABLE 02
+#define ERROR_PACK 04
#ifdef NO_D_INO_IN_DIRENT
#define SORT_DIRENT 0
@@ -137,7 +140,11 @@ static int traverse_one_object(struct object *obj)
static int traverse_reachable(void)
{
+ struct progress *progress = NULL;
+ unsigned int nr = 0;
int result = 0;
+ if (show_progress)
+ progress = start_progress_delay("Checking connectivity", 0, 0, 2);
while (pending.nr) {
struct object_array_entry *entry;
struct object *obj;
@@ -145,7 +152,9 @@ static int traverse_reachable(void)
entry = pending.objects + --pending.nr;
obj = entry->item;
result |= traverse_one_object(obj);
+ display_progress(progress, ++nr);
}
+ stop_progress(&progress);
return !!result;
}
@@ -281,14 +290,8 @@ static void check_connectivity(void)
}
}
-static int fsck_sha1(const unsigned char *sha1)
+static int fsck_obj(struct object *obj)
{
- struct object *obj = parse_object(sha1);
- if (!obj) {
- errors_found |= ERROR_OBJECT;
- return error("%s: object corrupt or missing",
- sha1_to_hex(sha1));
- }
if (obj->flags & SEEN)
return 0;
obj->flags |= SEEN;
@@ -331,6 +334,29 @@ static int fsck_sha1(const unsigned char *sha1)
return 0;
}
+static int fsck_sha1(const unsigned char *sha1)
+{
+ struct object *obj = parse_object(sha1);
+ if (!obj) {
+ errors_found |= ERROR_OBJECT;
+ return error("%s: object corrupt or missing",
+ sha1_to_hex(sha1));
+ }
+ return fsck_obj(obj);
+}
+
+static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
+ unsigned long size, void *buffer, int *eaten)
+{
+ struct object *obj;
+ obj = parse_object_buffer(sha1, type, size, buffer, eaten);
+ if (!obj) {
+ errors_found |= ERROR_OBJECT;
+ return error("%s: object corrupt or missing", sha1_to_hex(sha1));
+ }
+ return fsck_obj(obj);
+}
+
/*
* This is the sorting chunk size: make it reasonably
* big so that we can sort well..
@@ -512,15 +538,20 @@ static void get_default_heads(void)
static void fsck_object_dir(const char *path)
{
int i;
+ struct progress *progress = NULL;
if (verbose)
fprintf(stderr, "Checking object directory\n");
+ if (show_progress)
+ progress = start_progress("Checking object directories", 256);
for (i = 0; i < 256; i++) {
static char dir[4096];
sprintf(dir, "%s/%02x", path, i);
fsck_dir(i, dir);
+ display_progress(progress, i+1);
}
+ stop_progress(&progress);
fsck_sha1_list();
}
@@ -591,6 +622,7 @@ static struct option fsck_opts[] = {
OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
"write dangling objects in .git/lost-found"),
+ OPT_BOOL(0, "progress", &show_progress, "show progress"),
OPT_END(),
};
@@ -603,6 +635,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
read_replace_refs = 0;
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
+
+ if (show_progress == -1)
+ show_progress = isatty(2);
+ if (verbose)
+ show_progress = 0;
+
if (write_lost_and_found) {
check_full = 1;
include_reflogs = 0;
@@ -622,20 +660,28 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
if (check_full) {
struct packed_git *p;
+ uint32_t total = 0, count = 0;
+ struct progress *progress = NULL;
prepare_packed_git();
- for (p = packed_git; p; p = p->next)
- /* verify gives error messages itself */
- verify_pack(p);
+ if (show_progress) {
+ for (p = packed_git; p; p = p->next) {
+ if (open_pack_index(p))
+ continue;
+ total += p->num_objects;
+ }
+
+ progress = start_progress("Checking objects", total);
+ }
for (p = packed_git; p; p = p->next) {
- uint32_t j, num;
- if (open_pack_index(p))
- continue;
- num = p->num_objects;
- for (j = 0; j < num; j++)
- fsck_sha1(nth_packed_object_sha1(p, j));
+ /* verify gives error messages itself */
+ if (verify_pack(p, fsck_obj_buffer,
+ progress, count))
+ errors_found |= ERROR_PACK;
+ count += p->num_objects;
}
+ stop_progress(&progress);
}
heads = 0;
diff --git a/builtin/gc.c b/builtin/gc.c
index 0498094..271376d 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -32,7 +32,7 @@ static const char *prune_expire = "2.weeks.ago";
static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
-static const char *argv_prune[] = {"prune", "--expire", NULL, NULL};
+static const char *argv_prune[] = {"prune", "--expire", NULL, NULL, NULL};
static const char *argv_rerere[] = {"rerere", "gc", NULL};
static int gc_config(const char *var, const char *value, void *cb)
@@ -243,6 +243,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (prune_expire) {
argv_prune[2] = prune_expire;
+ if (quiet)
+ argv_prune[3] = "--no-progress";
if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
return error(FAILED_RUN, argv_prune[0]);
}
diff --git a/builtin/grep.c b/builtin/grep.c
index 7d0779f..988ea1d 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -74,13 +74,32 @@ static int all_work_added;
/* This lock protects all the variables above. */
static pthread_mutex_t grep_mutex;
+static inline void grep_lock(void)
+{
+ if (use_threads)
+ pthread_mutex_lock(&grep_mutex);
+}
+
+static inline void grep_unlock(void)
+{
+ if (use_threads)
+ pthread_mutex_unlock(&grep_mutex);
+}
+
/* Used to serialize calls to read_sha1_file. */
static pthread_mutex_t read_sha1_mutex;
-#define grep_lock() pthread_mutex_lock(&grep_mutex)
-#define grep_unlock() pthread_mutex_unlock(&grep_mutex)
-#define read_sha1_lock() pthread_mutex_lock(&read_sha1_mutex)
-#define read_sha1_unlock() pthread_mutex_unlock(&read_sha1_mutex)
+static inline void read_sha1_lock(void)
+{
+ if (use_threads)
+ pthread_mutex_lock(&read_sha1_mutex);
+}
+
+static inline void read_sha1_unlock(void)
+{
+ if (use_threads)
+ pthread_mutex_unlock(&read_sha1_mutex);
+}
/* Signalled when a new work_item is added to todo. */
static pthread_cond_t cond_add;
@@ -354,13 +373,9 @@ static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type
{
void *data;
- if (use_threads) {
- read_sha1_lock();
- data = read_sha1_file(sha1, type, size);
- read_sha1_unlock();
- } else {
- data = read_sha1_file(sha1, type, size);
- }
+ read_sha1_lock();
+ data = read_sha1_file(sha1, type, size);
+ read_sha1_unlock();
return data;
}
@@ -542,18 +557,19 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
struct tree_desc *tree, struct strbuf *base, int tn_len)
{
- int hit = 0, match = 0;
+ int hit = 0;
+ enum interesting match = entry_not_interesting;
struct name_entry entry;
int old_baselen = base->len;
while (tree_entry(tree, &entry)) {
- int te_len = tree_entry_len(entry.path, entry.sha1);
+ int te_len = tree_entry_len(&entry);
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&entry, base, tn_len, pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 0945adb..98025da 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1122,8 +1122,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (!index_name)
die("--verify with no packfile name given");
read_idx_option(&opts, index_name);
- opts.flags |= WRITE_IDX_VERIFY;
+ opts.flags |= WRITE_IDX_VERIFY | WRITE_IDX_STRICT;
}
+ if (strict)
+ opts.flags |= WRITE_IDX_STRICT;
curr_pack = open_pack_file(pack_name);
parse_pack_header();
diff --git a/builtin/merge.c b/builtin/merge.c
index dffd5ec..8a7bebd 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -316,13 +316,15 @@ static void squash_message(struct commit *commit)
struct rev_info rev;
struct strbuf out = STRBUF_INIT;
struct commit_list *j;
+ const char *filename;
int fd;
struct pretty_print_context ctx = {0};
printf(_("Squash commit -- not updating HEAD\n"));
- fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
+ filename = git_path("SQUASH_MSG");
+ fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
- die_errno(_("Could not write to '%s'"), git_path("SQUASH_MSG"));
+ die_errno(_("Could not write to '%s'"), filename);
init_revisions(&rev, NULL);
rev.ignore_merges = 1;
@@ -492,14 +494,16 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!strcmp(remote, "FETCH_HEAD") &&
!access(git_path("FETCH_HEAD"), R_OK)) {
+ const char *filename;
FILE *fp;
struct strbuf line = STRBUF_INIT;
char *ptr;
- fp = fopen(git_path("FETCH_HEAD"), "r");
+ filename = git_path("FETCH_HEAD");
+ fp = fopen(filename, "r");
if (!fp)
die_errno(_("could not open '%s' for reading"),
- git_path("FETCH_HEAD"));
+ filename);
strbuf_getline(&line, fp, '\n');
fclose(fp);
ptr = strstr(line.buf, "\tnot-for-merge\t");
@@ -771,7 +775,7 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
memset(&t, 0, sizeof(t));
memset(&dir, 0, sizeof(dir));
dir.flags |= DIR_SHOW_IGNORED;
- dir.exclude_per_dir = ".gitignore";
+ setup_standard_excludes(&dir);
opts.dir = &dir;
opts.head_idx = 1;
@@ -847,20 +851,22 @@ static void add_strategies(const char *string, unsigned attr)
static void write_merge_msg(struct strbuf *msg)
{
- int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
+ const char *filename = git_path("MERGE_MSG");
+ int fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
die_errno(_("Could not open '%s' for writing"),
- git_path("MERGE_MSG"));
+ filename);
if (write_in_full(fd, msg->buf, msg->len) != msg->len)
- die_errno(_("Could not write to '%s'"), git_path("MERGE_MSG"));
+ die_errno(_("Could not write to '%s'"), filename);
close(fd);
}
static void read_merge_msg(struct strbuf *msg)
{
+ const char *filename = git_path("MERGE_MSG");
strbuf_reset(msg);
- if (strbuf_read_file(msg, git_path("MERGE_MSG"), 0) < 0)
- die_errno(_("Could not read from '%s'"), git_path("MERGE_MSG"));
+ if (strbuf_read_file(msg, filename, 0) < 0)
+ die_errno(_("Could not read from '%s'"), filename);
}
static void write_merge_state(void);
@@ -948,13 +954,14 @@ static int finish_automerge(struct commit *head,
static int suggest_conflicts(int renormalizing)
{
+ const char *filename;
FILE *fp;
int pos;
- fp = fopen(git_path("MERGE_MSG"), "a");
+ filename = git_path("MERGE_MSG");
+ fp = fopen(filename, "a");
if (!fp)
- die_errno(_("Could not open '%s' for writing"),
- git_path("MERGE_MSG"));
+ die_errno(_("Could not open '%s' for writing"), filename);
fprintf(fp, "\nConflicts:\n");
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
@@ -1046,6 +1053,7 @@ static int setup_with_upstream(const char ***argv)
static void write_merge_state(void)
{
+ const char *filename;
int fd;
struct commit_list *j;
struct strbuf buf = STRBUF_INIT;
@@ -1053,24 +1061,25 @@ static void write_merge_state(void)
for (j = remoteheads; j; j = j->next)
strbuf_addf(&buf, "%s\n",
sha1_to_hex(j->item->object.sha1));
- fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
+ filename = git_path("MERGE_HEAD");
+ fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
- die_errno(_("Could not open '%s' for writing"),
- git_path("MERGE_HEAD"));
+ die_errno(_("Could not open '%s' for writing"), filename);
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
- die_errno(_("Could not write to '%s'"), git_path("MERGE_HEAD"));
+ die_errno(_("Could not write to '%s'"), filename);
close(fd);
strbuf_addch(&merge_msg, '\n');
write_merge_msg(&merge_msg);
- fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+ filename = git_path("MERGE_MODE");
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
- die_errno(_("Could not open '%s' for writing"),
- git_path("MERGE_MODE"));
+ die_errno(_("Could not open '%s' for writing"), filename);
strbuf_reset(&buf);
if (!allow_fast_forward)
strbuf_addf(&buf, "no-ff");
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
- die_errno(_("Could not write to '%s'"), git_path("MERGE_MODE"));
+ die_errno(_("Could not write to '%s'"), filename);
close(fd);
}
@@ -1160,9 +1169,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die(_("You cannot combine --no-ff with --ff-only."));
if (!abort_current_merge) {
- if (!argc && default_to_upstream)
- argc = setup_with_upstream(&argv);
- else if (argc == 1 && !strcmp(argv[0], "-"))
+ if (!argc) {
+ if (default_to_upstream)
+ argc = setup_with_upstream(&argv);
+ else
+ die(_("No commit specified and merge.defaultToUpstream not set."));
+ } else if (argc == 1 && !strcmp(argv[0], "-"))
argv[0] = "@{-1}";
}
if (!argc)
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 098395f..4ae1c41 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -60,6 +60,7 @@ static void write_tree(unsigned char *sha1)
}
write_sha1_file(buf.buf, buf.len, tree_type, sha1);
+ strbuf_release(&buf);
}
static const char *mktree_usage[] = {
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 7864056..1b37458 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -291,7 +291,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
max = get_max_object_index();
for (i = 0; i < max; i++) {
struct object *obj = get_indexed_object(i);
- if (!obj)
+ if (!obj || obj->type != OBJ_COMMIT)
continue;
show_name(obj, NULL,
always, allow_undefined, data.name_only);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index ba3705d..b1895aa 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -409,25 +409,56 @@ static unsigned long write_object(struct sha1file *f,
return hdrlen + datalen;
}
-static int write_one(struct sha1file *f,
- struct object_entry *e,
- off_t *offset)
+enum write_one_status {
+ WRITE_ONE_SKIP = -1, /* already written */
+ WRITE_ONE_BREAK = 0, /* writing this will bust the limit; not written */
+ WRITE_ONE_WRITTEN = 1, /* normal */
+ WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
+};
+
+static enum write_one_status write_one(struct sha1file *f,
+ struct object_entry *e,
+ off_t *offset)
{
unsigned long size;
+ int recursing;
- /* offset is non zero if object is written already. */
- if (e->idx.offset || e->preferred_base)
- return -1;
+ /*
+ * we set offset to 1 (which is an impossible value) to mark
+ * the fact that this object is involved in "write its base
+ * first before writing a deltified object" recursion.
+ */
+ recursing = (e->idx.offset == 1);
+ if (recursing) {
+ warning("recursive delta detected for object %s",
+ sha1_to_hex(e->idx.sha1));
+ return WRITE_ONE_RECURSIVE;
+ } else if (e->idx.offset || e->preferred_base) {
+ /* offset is non zero if object is written already. */
+ return WRITE_ONE_SKIP;
+ }
/* if we are deltified, write out base object first. */
- if (e->delta && !write_one(f, e->delta, offset))
- return 0;
+ if (e->delta) {
+ e->idx.offset = 1; /* now recurse */
+ switch (write_one(f, e->delta, offset)) {
+ case WRITE_ONE_RECURSIVE:
+ /* we cannot depend on this one */
+ e->delta = NULL;
+ break;
+ default:
+ break;
+ case WRITE_ONE_BREAK:
+ e->idx.offset = recursing;
+ return WRITE_ONE_BREAK;
+ }
+ }
e->idx.offset = *offset;
size = write_object(f, e, *offset);
if (!size) {
- e->idx.offset = 0;
- return 0;
+ e->idx.offset = recursing;
+ return WRITE_ONE_BREAK;
}
written_list[nr_written++] = &e->idx;
@@ -435,7 +466,7 @@ static int write_one(struct sha1file *f,
if (signed_add_overflows(*offset, size))
die("pack too large for current definition of off_t");
*offset += size;
- return 1;
+ return WRITE_ONE_WRITTEN;
}
static int mark_tagged(const char *path, const unsigned char *sha1, int flag,
@@ -454,8 +485,8 @@ static int mark_tagged(const char *path, const unsigned char *sha1, int flag,
return 0;
}
-static void add_to_write_order(struct object_entry **wo,
- int *endp,
+static inline void add_to_write_order(struct object_entry **wo,
+ unsigned int *endp,
struct object_entry *e)
{
if (e->filled)
@@ -465,32 +496,62 @@ static void add_to_write_order(struct object_entry **wo,
}
static void add_descendants_to_write_order(struct object_entry **wo,
- int *endp,
+ unsigned int *endp,
struct object_entry *e)
{
- struct object_entry *child;
-
- for (child = e->delta_child; child; child = child->delta_sibling)
- add_to_write_order(wo, endp, child);
- for (child = e->delta_child; child; child = child->delta_sibling)
- add_descendants_to_write_order(wo, endp, child);
+ int add_to_order = 1;
+ while (e) {
+ if (add_to_order) {
+ struct object_entry *s;
+ /* add this node... */
+ add_to_write_order(wo, endp, e);
+ /* all its siblings... */
+ for (s = e->delta_sibling; s; s = s->delta_sibling) {
+ add_to_write_order(wo, endp, s);
+ }
+ }
+ /* drop down a level to add left subtree nodes if possible */
+ if (e->delta_child) {
+ add_to_order = 1;
+ e = e->delta_child;
+ } else {
+ add_to_order = 0;
+ /* our sibling might have some children, it is next */
+ if (e->delta_sibling) {
+ e = e->delta_sibling;
+ continue;
+ }
+ /* go back to our parent node */
+ e = e->delta;
+ while (e && !e->delta_sibling) {
+ /* we're on the right side of a subtree, keep
+ * going up until we can go right again */
+ e = e->delta;
+ }
+ if (!e) {
+ /* done- we hit our original root node */
+ return;
+ }
+ /* pass it off to sibling at this level */
+ e = e->delta_sibling;
+ }
+ };
}
static void add_family_to_write_order(struct object_entry **wo,
- int *endp,
+ unsigned int *endp,
struct object_entry *e)
{
struct object_entry *root;
for (root = e; root->delta; root = root->delta)
; /* nothing */
- add_to_write_order(wo, endp, root);
add_descendants_to_write_order(wo, endp, root);
}
static struct object_entry **compute_write_order(void)
{
- int i, wo_end;
+ unsigned int i, wo_end, last_untagged;
struct object_entry **wo = xmalloc(nr_objects * sizeof(*wo));
@@ -506,8 +567,8 @@ static struct object_entry **compute_write_order(void)
* Make sure delta_sibling is sorted in the original
* recency order.
*/
- for (i = nr_objects - 1; 0 <= i; i--) {
- struct object_entry *e = &objects[i];
+ for (i = nr_objects; i > 0;) {
+ struct object_entry *e = &objects[--i];
if (!e->delta)
continue;
/* Mark me as the first child */
@@ -521,7 +582,7 @@ static struct object_entry **compute_write_order(void)
for_each_tag_ref(mark_tagged, NULL);
/*
- * Give the commits in the original recency order until
+ * Give the objects in the original recency order until
* we see a tagged tip.
*/
for (i = wo_end = 0; i < nr_objects; i++) {
@@ -529,6 +590,7 @@ static struct object_entry **compute_write_order(void)
break;
add_to_write_order(wo, &wo_end, &objects[i]);
}
+ last_untagged = i;
/*
* Then fill all the tagged tips.
@@ -541,7 +603,7 @@ static struct object_entry **compute_write_order(void)
/*
* And then all remaining commits and tags.
*/
- for (i = 0; i < nr_objects; i++) {
+ for (i = last_untagged; i < nr_objects; i++) {
if (objects[i].type != OBJ_COMMIT &&
objects[i].type != OBJ_TAG)
continue;
@@ -551,7 +613,7 @@ static struct object_entry **compute_write_order(void)
/*
* And then all the trees.
*/
- for (i = 0; i < nr_objects; i++) {
+ for (i = last_untagged; i < nr_objects; i++) {
if (objects[i].type != OBJ_TREE)
continue;
add_to_write_order(wo, &wo_end, &objects[i]);
@@ -560,8 +622,13 @@ static struct object_entry **compute_write_order(void)
/*
* Finally all the rest in really tight order
*/
- for (i = 0; i < nr_objects; i++)
- add_family_to_write_order(wo, &wo_end, &objects[i]);
+ for (i = last_untagged; i < nr_objects; i++) {
+ if (!objects[i].filled)
+ add_family_to_write_order(wo, &wo_end, &objects[i]);
+ }
+
+ if (wo_end != nr_objects)
+ die("ordered %u objects, expected %"PRIu32, wo_end, nr_objects);
return wo;
}
@@ -604,7 +671,7 @@ static void write_pack_file(void)
nr_written = 0;
for (; i < nr_objects; i++) {
struct object_entry *e = write_order[i];
- if (!write_one(f, e, &offset))
+ if (write_one(f, e, &offset) == WRITE_ONE_BREAK)
break;
display_progress(progress_state, written);
}
@@ -979,7 +1046,7 @@ static void add_pbase_object(struct tree_desc *tree,
while (tree_entry(tree,&entry)) {
if (S_ISGITLINK(entry.mode))
continue;
- cmp = tree_entry_len(entry.path, entry.sha1) != cmplen ? 1 :
+ cmp = tree_entry_len(&entry) != cmplen ? 1 :
memcmp(name, entry.path, cmplen);
if (cmp > 0)
continue;
diff --git a/builtin/prune.c b/builtin/prune.c
index e65690b..58d7cb8 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -5,6 +5,7 @@
#include "builtin.h"
#include "reachable.h"
#include "parse-options.h"
+#include "progress.h"
#include "dir.h"
static const char * const prune_usage[] = {
@@ -14,6 +15,7 @@ static const char * const prune_usage[] = {
static int show_only;
static int verbose;
static unsigned long expire;
+static int show_progress = -1;
static int prune_tmp_object(const char *path, const char *filename)
{
@@ -124,9 +126,11 @@ static void remove_temporary_files(const char *path)
int cmd_prune(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
+ struct progress *progress = NULL;
const struct option options[] = {
OPT__DRY_RUN(&show_only, "do not remove, show only"),
OPT__VERBOSE(&verbose, "report pruned objects"),
+ OPT_BOOL(0, "progress", &show_progress, "show progress"),
OPT_DATE(0, "expire", &expire,
"expire objects older than <time>"),
OPT_END()
@@ -152,7 +156,14 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
else
die("unrecognized argument: %s", name);
}
- mark_reachable_objects(&revs, 1);
+
+ if (show_progress == -1)
+ show_progress = isatty(2);
+ if (show_progress)
+ progress = start_progress_delay("Checking connectivity", 0, 0, 2);
+
+ mark_reachable_objects(&revs, 1, progress);
+ stop_progress(&progress);
prune_object_dir(get_object_directory());
prune_packed_objects(show_only);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 261b610..7ec68a1 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -634,7 +634,7 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
struct command **cmd_list = cb_data;
struct command *cmd = *cmd_list;
- if (!cmd)
+ if (!cmd || is_null_sha1(cmd->new_sha1))
return -1; /* end of list */
*cmd_list = NULL; /* this returns only one */
hashcpy(sha1, cmd->new_sha1);
@@ -659,11 +659,16 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
struct command **cmd_list = cb_data;
struct command *cmd = *cmd_list;
- if (!cmd)
- return -1; /* end of list */
- *cmd_list = cmd->next;
- hashcpy(sha1, cmd->new_sha1);
- return 0;
+ while (cmd) {
+ if (!is_null_sha1(cmd->new_sha1)) {
+ hashcpy(sha1, cmd->new_sha1);
+ *cmd_list = cmd->next;
+ return 0;
+ }
+ cmd = cmd->next;
+ }
+ *cmd_list = NULL;
+ return -1; /* end of list */
}
static void execute_commands(struct command *commands, const char *unpacker_error)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 3a9c80f..062d7da 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -647,7 +647,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
init_revisions(&cb.revs, prefix);
if (cb.verbose)
printf("Marking reachable objects...");
- mark_reachable_objects(&cb.revs, 0);
+ mark_reachable_objects(&cb.revs, 0, NULL);
if (cb.verbose)
putchar('\n');
}
diff --git a/builtin/remote.c b/builtin/remote.c
index 44eb879..c810643 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -349,7 +349,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
else
string_list_append(&states->tracked, abbrev_branch(ref->name));
}
- stale_refs = get_stale_heads(states->remote, fetch_map);
+ stale_refs = get_stale_heads(states->remote->fetch,
+ states->remote->fetch_refspec_nr, fetch_map);
for (ref = stale_refs; ref; ref = ref->next) {
struct string_list_item *item =
string_list_append(&states->stale, abbrev_branch(ref->name));
@@ -1398,7 +1399,7 @@ static int set_branches(int argc, const char **argv)
builtin_remote_setbranches_usage, 0);
if (argc == 0) {
error("no remote specified");
- usage_with_options(builtin_remote_seturl_usage, options);
+ usage_with_options(builtin_remote_setbranches_usage, options);
}
argv[argc] = NULL;
@@ -1426,7 +1427,7 @@ static int set_url(int argc, const char **argv)
"delete URLs"),
OPT_END()
};
- argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
+ argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
PARSE_OPT_KEEP_ARGV0);
if (add_mode && delete_mode)
diff --git a/builtin/revert.c b/builtin/revert.c
index 87df70e..1ea525c 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -40,7 +40,12 @@ static const char * const cherry_pick_usage[] = {
};
enum replay_action { REVERT, CHERRY_PICK };
-enum replay_subcommand { REPLAY_NONE, REPLAY_RESET, REPLAY_CONTINUE };
+enum replay_subcommand {
+ REPLAY_NONE,
+ REPLAY_REMOVE_STATE,
+ REPLAY_CONTINUE,
+ REPLAY_ROLLBACK
+};
struct replay_opts {
enum replay_action action;
@@ -133,11 +138,13 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
{
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
- int reset = 0;
+ int remove_state = 0;
int contin = 0;
+ int rollback = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "reset", &reset, "forget the current operation"),
- OPT_BOOLEAN(0, "continue", &contin, "continue the current operation"),
+ OPT_BOOLEAN(0, "quit", &remove_state, "end revert or cherry-pick sequence"),
+ OPT_BOOLEAN(0, "continue", &contin, "resume revert or cherry-pick sequence"),
+ OPT_BOOLEAN(0, "abort", &rollback, "cancel revert or cherry-pick sequence"),
OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"),
OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"),
OPT_NOOP_NOARG('r', NULL),
@@ -168,25 +175,32 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
/* Check for incompatible subcommands */
verify_opt_mutually_compatible(me,
- "--reset", reset,
+ "--quit", remove_state,
"--continue", contin,
+ "--abort", rollback,
NULL);
/* Set the subcommand */
- if (reset)
- opts->subcommand = REPLAY_RESET;
+ if (remove_state)
+ opts->subcommand = REPLAY_REMOVE_STATE;
else if (contin)
opts->subcommand = REPLAY_CONTINUE;
+ else if (rollback)
+ opts->subcommand = REPLAY_ROLLBACK;
else
opts->subcommand = REPLAY_NONE;
/* Check for incompatible command line arguments */
if (opts->subcommand != REPLAY_NONE) {
char *this_operation;
- if (opts->subcommand == REPLAY_RESET)
- this_operation = "--reset";
- else
+ if (opts->subcommand == REPLAY_REMOVE_STATE)
+ this_operation = "--quit";
+ else if (opts->subcommand == REPLAY_CONTINUE)
this_operation = "--continue";
+ else {
+ assert(opts->subcommand == REPLAY_ROLLBACK);
+ this_operation = "--abort";
+ }
verify_opt_compatible(me, this_operation,
"--no-commit", opts->no_commit,
@@ -286,19 +300,20 @@ static char *get_encoding(const char *message)
return NULL;
}
-static void write_cherry_pick_head(struct commit *commit)
+static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
{
+ const char *filename;
int fd;
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
- fd = open(git_path("CHERRY_PICK_HEAD"), O_WRONLY | O_CREAT, 0666);
+ filename = git_path("%s", pseudoref);
+ fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
- die_errno(_("Could not open '%s' for writing"),
- git_path("CHERRY_PICK_HEAD"));
+ die_errno(_("Could not open '%s' for writing"), filename);
if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
- die_errno(_("Could not write to '%s'"), git_path("CHERRY_PICK_HEAD"));
+ die_errno(_("Could not write to '%s'"), filename);
strbuf_release(&buf);
}
@@ -331,7 +346,7 @@ static void write_message(struct strbuf *msgbuf, const char *filename)
int msg_fd = hold_lock_file_for_update(&msg_file, filename,
LOCK_DIE_ON_ERROR);
if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
- die_errno(_("Could not write to %s."), filename);
+ die_errno(_("Could not write to %s"), filename);
strbuf_release(msgbuf);
if (commit_lock_file(&msg_file) < 0)
die(_("Error wrapping up %s"), filename);
@@ -593,7 +608,9 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
* write it at all.
*/
if (opts->action == CHERRY_PICK && !opts->no_commit && (res == 0 || res == 1))
- write_cherry_pick_head(commit);
+ write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
+ if (opts->action == REVERT && ((opts->no_commit && res == 0) || res == 1))
+ write_cherry_pick_head(commit, "REVERT_HEAD");
if (res) {
error(opts->action == REVERT
@@ -767,7 +784,7 @@ static void read_populate_todo(struct commit_list **todo_list,
fd = open(todo_file, O_RDONLY);
if (fd < 0)
- die_errno(_("Could not open %s."), todo_file);
+ die_errno(_("Could not open %s"), todo_file);
if (strbuf_read(&buf, fd, 0) < 0) {
close(fd);
strbuf_release(&buf);
@@ -842,10 +859,13 @@ static int create_seq_dir(void)
{
const char *seq_dir = git_path(SEQ_DIR);
- if (file_exists(seq_dir))
- return error(_("%s already exists."), seq_dir);
+ if (file_exists(seq_dir)) {
+ error(_("a cherry-pick or revert is already in progress"));
+ advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+ return -1;
+ }
else if (mkdir(seq_dir, 0777) < 0)
- die_errno(_("Could not create sequencer directory '%s'."), seq_dir);
+ die_errno(_("Could not create sequencer directory %s"), seq_dir);
return 0;
}
@@ -859,11 +879,77 @@ static void save_head(const char *head)
fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
strbuf_addf(&buf, "%s\n", head);
if (write_in_full(fd, buf.buf, buf.len) < 0)
- die_errno(_("Could not write to %s."), head_file);
+ die_errno(_("Could not write to %s"), head_file);
if (commit_lock_file(&head_lock) < 0)
die(_("Error wrapping up %s."), head_file);
}
+static int reset_for_rollback(const unsigned char *sha1)
+{
+ const char *argv[4]; /* reset --merge <arg> + NULL */
+ argv[0] = "reset";
+ argv[1] = "--merge";
+ argv[2] = sha1_to_hex(sha1);
+ argv[3] = NULL;
+ return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
+static int rollback_single_pick(void)
+{
+ unsigned char head_sha1[20];
+
+ if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
+ !file_exists(git_path("REVERT_HEAD")))
+ return error(_("no cherry-pick or revert in progress"));
+ if (!resolve_ref("HEAD", head_sha1, 0, NULL))
+ return error(_("cannot resolve HEAD"));
+ if (is_null_sha1(head_sha1))
+ return error(_("cannot abort from a branch yet to be born"));
+ return reset_for_rollback(head_sha1);
+}
+
+static int sequencer_rollback(struct replay_opts *opts)
+{
+ const char *filename;
+ FILE *f;
+ unsigned char sha1[20];
+ struct strbuf buf = STRBUF_INIT;
+
+ filename = git_path(SEQ_HEAD_FILE);
+ f = fopen(filename, "r");
+ if (!f && errno == ENOENT) {
+ /*
+ * There is no multiple-cherry-pick in progress.
+ * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
+ * a single-cherry-pick in progress, abort that.
+ */
+ return rollback_single_pick();
+ }
+ if (!f)
+ return error(_("cannot open %s: %s"), filename,
+ strerror(errno));
+ if (strbuf_getline(&buf, f, '\n')) {
+ error(_("cannot read %s: %s"), filename, ferror(f) ?
+ strerror(errno) : _("unexpected end of file"));
+ fclose(f);
+ goto fail;
+ }
+ fclose(f);
+ if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
+ error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
+ filename);
+ goto fail;
+ }
+ if (reset_for_rollback(sha1))
+ goto fail;
+ remove_sequencer_state(1);
+ strbuf_release(&buf);
+ return 0;
+fail:
+ strbuf_release(&buf);
+ return -1;
+}
+
static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
{
const char *todo_file = git_path(SEQ_TODO_FILE);
@@ -876,7 +962,7 @@ static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
die(_("Could not format %s."), todo_file);
if (write_in_full(fd, buf.buf, buf.len) < 0) {
strbuf_release(&buf);
- die_errno(_("Could not write to %s."), todo_file);
+ die_errno(_("Could not write to %s"), todo_file);
}
if (commit_lock_file(&todo_lock) < 0) {
strbuf_release(&buf);
@@ -964,43 +1050,41 @@ static int pick_revisions(struct replay_opts *opts)
* cherry-pick should be handled differently from an existing
* one that is being continued
*/
- if (opts->subcommand == REPLAY_RESET) {
+ if (opts->subcommand == REPLAY_REMOVE_STATE) {
remove_sequencer_state(1);
return 0;
- } else if (opts->subcommand == REPLAY_CONTINUE) {
+ }
+ if (opts->subcommand == REPLAY_ROLLBACK)
+ return sequencer_rollback(opts);
+ if (opts->subcommand == REPLAY_CONTINUE) {
if (!file_exists(git_path(SEQ_TODO_FILE)))
- goto error;
+ return error(_("No %s in progress"), action_name(opts));
read_populate_opts(&opts);
read_populate_todo(&todo_list, opts);
/* Verify that the conflict has been resolved */
if (!index_differs_from("HEAD", 0))
todo_list = todo_list->next;
- } else {
- /*
- * Start a new cherry-pick/ revert sequence; but
- * first, make sure that an existing one isn't in
- * progress
- */
+ return pick_commits(todo_list, opts);
+ }
- walk_revs_populate_todo(&todo_list, opts);
- if (create_seq_dir() < 0) {
- error(_("A cherry-pick or revert is in progress."));
- advise(_("Use --continue to continue the operation"));
- advise(_("or --reset to forget about it"));
- return -1;
- }
- if (get_sha1("HEAD", sha1)) {
- if (opts->action == REVERT)
- return error(_("Can't revert as initial commit"));
- return error(_("Can't cherry-pick into empty head"));
- }
- save_head(sha1_to_hex(sha1));
- save_opts(opts);
+ /*
+ * Start a new cherry-pick/ revert sequence; but
+ * first, make sure that an existing one isn't in
+ * progress
+ */
+
+ walk_revs_populate_todo(&todo_list, opts);
+ if (create_seq_dir() < 0)
+ return -1;
+ if (get_sha1("HEAD", sha1)) {
+ if (opts->action == REVERT)
+ return error(_("Can't revert as initial commit"));
+ return error(_("Can't cherry-pick into empty head"));
}
+ save_head(sha1_to_hex(sha1));
+ save_opts(opts);
return pick_commits(todo_list, opts);
-error:
- return error(_("No %s in progress"), action_name(opts));
}
int cmd_revert(int argc, const char **argv, const char *prefix)
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index 4d3b93f..1288ffc 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -22,8 +22,6 @@ static size_t cleanup(char *line, size_t len)
* Remove empty lines from the beginning and end
* and also trailing spaces from every line.
*
- * Note that the buffer will not be NUL-terminated.
- *
* Turn multiple consecutive empty lines between paragraphs
* into just one empty line.
*
diff --git a/compat/mingw.c b/compat/mingw.c
index efdc703..a0ac487 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1712,7 +1712,7 @@ char *getpass(const char *prompt)
return strbuf_detach(&buf, NULL);
}
-pid_t waitpid(pid_t pid, int *status, unsigned options)
+pid_t waitpid(pid_t pid, int *status, int options)
{
HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
FALSE, pid);
diff --git a/compat/mingw.h b/compat/mingw.h
index fecf0d0..0ff1e04 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -120,7 +120,7 @@ static inline int mingw_mkdir(const char *path, int mode)
#define mkdir mingw_mkdir
#define WNOHANG 1
-pid_t waitpid(pid_t pid, int *status, unsigned options);
+pid_t waitpid(pid_t pid, int *status, int options);
#define kill mingw_kill
int mingw_kill(pid_t pid, int sig);
diff --git a/compat/msvc.h b/compat/msvc.h
index a33b01c..aa4b563 100644
--- a/compat/msvc.h
+++ b/compat/msvc.h
@@ -4,6 +4,7 @@
#include <direct.h>
#include <process.h>
#include <malloc.h>
+#include <io.h>
/* porting function */
#define inline __inline
diff --git a/compat/strtoimax.c b/compat/strtoimax.c
new file mode 100644
index 0000000..ac09ed8
--- /dev/null
+++ b/compat/strtoimax.c
@@ -0,0 +1,10 @@
+#include "../git-compat-util.h"
+
+intmax_t gitstrtoimax (const char *nptr, char **endptr, int base)
+{
+#if defined(NO_STRTOULL)
+ return strtol(nptr, endptr, base);
+#else
+ return strtoll(nptr, endptr, base);
+#endif
+}
diff --git a/compat/vcbuild/include/arpa/inet.h b/compat/vcbuild/include/arpa/inet.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/arpa/inet.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/grp.h b/compat/vcbuild/include/grp.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/grp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/inttypes.h b/compat/vcbuild/include/inttypes.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/inttypes.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netdb.h b/compat/vcbuild/include/netdb.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/netdb.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/in.h b/compat/vcbuild/include/netinet/in.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/netinet/in.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/tcp.h b/compat/vcbuild/include/netinet/tcp.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/netinet/tcp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/pwd.h b/compat/vcbuild/include/pwd.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/pwd.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/ioctl.h b/compat/vcbuild/include/sys/ioctl.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/sys/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/select.h b/compat/vcbuild/include/sys/select.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/sys/select.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/socket.h b/compat/vcbuild/include/sys/socket.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/sys/socket.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/wait.h b/compat/vcbuild/include/sys/wait.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/sys/wait.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/termios.h b/compat/vcbuild/include/termios.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/termios.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/win32/sys/poll.c b/compat/win32/poll.c
index 708a6c9..403eaa7 100644
--- a/compat/win32/sys/poll.c
+++ b/compat/win32/poll.c
@@ -1,7 +1,7 @@
/* Emulation for poll(2)
Contributed by Paolo Bonzini.
- Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.
+ Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.
This file is part of gnulib.
@@ -27,7 +27,10 @@
#include <malloc.h>
#include <sys/types.h>
-#include "poll.h"
+
+/* Specification. */
+#include <poll.h>
+
#include <errno.h>
#include <limits.h>
#include <assert.h>
@@ -314,10 +317,7 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
#endif /* !MinGW */
int
-poll (pfd, nfd, timeout)
- struct pollfd *pfd;
- nfds_t nfd;
- int timeout;
+poll (struct pollfd *pfd, nfds_t nfd, int timeout)
{
#ifndef WIN32_NATIVE
fd_set rfds, wfds, efds;
@@ -454,6 +454,7 @@ poll (pfd, nfd, timeout)
if (!hEvent)
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+restart:
handle_array[0] = hEvent;
nhandles = 1;
FD_ZERO (&rfds);
@@ -594,6 +595,12 @@ poll (pfd, nfd, timeout)
rc++;
}
+ if (!rc && timeout == INFTIM)
+ {
+ SwitchToThread();
+ goto restart;
+ }
+
return rc;
#endif
}
diff --git a/compat/win32/sys/poll.h b/compat/win32/poll.h
index b7aa59d..b7aa59d 100644
--- a/compat/win32/sys/poll.h
+++ b/compat/win32/poll.h
diff --git a/config.c b/config.c
index edf9914..5ea101f 100644
--- a/config.c
+++ b/config.c
@@ -333,7 +333,7 @@ static int git_parse_file(config_fn_t fn, void *data)
die("bad config file line %d in %s", cf->linenr, cf->name);
}
-static int parse_unit_factor(const char *end, unsigned long *val)
+static int parse_unit_factor(const char *end, uintmax_t *val)
{
if (!*end)
return 1;
@@ -356,11 +356,23 @@ static int git_parse_long(const char *value, long *ret)
{
if (value && *value) {
char *end;
- long val = strtol(value, &end, 0);
- unsigned long factor = 1;
+ intmax_t val;
+ uintmax_t uval;
+ uintmax_t factor = 1;
+
+ errno = 0;
+ val = strtoimax(value, &end, 0);
+ if (errno == ERANGE)
+ return 0;
if (!parse_unit_factor(end, &factor))
return 0;
- *ret = val * factor;
+ uval = abs(val);
+ uval *= factor;
+ if ((uval > maximum_signed_value_of_type(long)) ||
+ (abs(val) > uval))
+ return 0;
+ val *= factor;
+ *ret = val;
return 1;
}
return 0;
@@ -370,9 +382,19 @@ int git_parse_ulong(const char *value, unsigned long *ret)
{
if (value && *value) {
char *end;
- unsigned long val = strtoul(value, &end, 0);
+ uintmax_t val;
+ uintmax_t oldval;
+
+ errno = 0;
+ val = strtoumax(value, &end, 0);
+ if (errno == ERANGE)
+ return 0;
+ oldval = val;
if (!parse_unit_factor(end, &val))
return 0;
+ if ((val > maximum_unsigned_value_of_type(long)) ||
+ (oldval > val))
+ return 0;
*ret = val;
return 1;
}
@@ -553,7 +575,7 @@ static int git_default_core_config(const char *var, const char *value)
if (!strcmp(var, "core.packedgitwindowsize")) {
int pgsz_x2 = getpagesize() * 2;
- packed_git_window_size = git_config_int(var, value);
+ packed_git_window_size = git_config_ulong(var, value);
/* This value must be multiple of (pagesize * 2) */
packed_git_window_size /= pgsz_x2;
@@ -564,18 +586,17 @@ static int git_default_core_config(const char *var, const char *value)
}
if (!strcmp(var, "core.bigfilethreshold")) {
- long n = git_config_int(var, value);
- big_file_threshold = 0 < n ? n : 0;
+ big_file_threshold = git_config_ulong(var, value);
return 0;
}
if (!strcmp(var, "core.packedgitlimit")) {
- packed_git_limit = git_config_int(var, value);
+ packed_git_limit = git_config_ulong(var, value);
return 0;
}
if (!strcmp(var, "core.deltabasecachelimit")) {
- delta_base_cache_limit = git_config_int(var, value);
+ delta_base_cache_limit = git_config_ulong(var, value);
return 0;
}
@@ -865,12 +886,12 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
home = getenv("HOME");
if (home) {
- char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
+ char buf[PATH_MAX];
+ char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
if (!access(user_config, R_OK)) {
ret += git_config_from_file(fn, user_config, data);
found += 1;
}
- free(user_config);
}
if (repo_config && !access(repo_config, R_OK)) {
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 888e8e1..b7c1edf 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -110,6 +110,7 @@ __git_ps1_show_upstream ()
local upstream=git legacy="" verbose=""
# get some config options from git-config
+ local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
while read key value; do
case "$key" in
bash.showupstream)
@@ -125,7 +126,7 @@ __git_ps1_show_upstream ()
upstream=svn+git # default upstream is SVN if available, else git
;;
esac
- done < <(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')
+ done <<< "$output"
# parse configuration values
for option in ${GIT_PS1_SHOWUPSTREAM}; do
@@ -1429,6 +1430,10 @@ _git_gitk ()
_gitk
}
+__git_match_ctag() {
+ awk "/^${1////\\/}/ { print \$1 }" "$2"
+}
+
_git_grep ()
{
__git_has_doubledash && return
@@ -1451,6 +1456,15 @@ _git_grep ()
;;
esac
+ case "$cword,$prev" in
+ 2,*|*,-*)
+ if test -r tags; then
+ __gitcomp "$(__git_match_ctag "$cur" tags)"
+ return
+ fi
+ ;;
+ esac
+
__gitcomp "$(__git_refs)"
}
diff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README
new file mode 100644
index 0000000..1b7b6df
--- /dev/null
+++ b/contrib/diff-highlight/README
@@ -0,0 +1,57 @@
+diff-highlight
+==============
+
+Line oriented diffs are great for reviewing code, because for most
+hunks, you want to see the old and the new segments of code next to each
+other. Sometimes, though, when an old line and a new line are very
+similar, it's hard to immediately see the difference.
+
+You can use "--color-words" to highlight only the changed portions of
+lines. However, this can often be hard to read for code, as it loses
+the line structure, and you end up with oddly formatted bits.
+
+Instead, this script post-processes the line-oriented diff, finds pairs
+of lines, and highlights the differing segments. It's currently very
+simple and stupid about doing these tasks. In particular:
+
+ 1. It will only highlight a pair of lines if they are the only two
+ lines in a hunk. It could instead try to match up "before" and
+ "after" lines for a given hunk into pairs of similar lines.
+ However, this may end up visually distracting, as the paired
+ lines would have other highlighted lines in between them. And in
+ practice, the lines which most need attention called to their
+ small, hard-to-see changes are touching only a single line.
+
+ 2. It will find the common prefix and suffix of two lines, and
+ consider everything in the middle to be "different". It could
+ instead do a real diff of the characters between the two lines and
+ find common subsequences. However, the point of the highlight is to
+ call attention to a certain area. Even if some small subset of the
+ highlighted area actually didn't change, that's OK. In practice it
+ ends up being more readable to just have a single blob on the line
+ showing the interesting bit.
+
+The goal of the script is therefore not to be exact about highlighting
+changes, but to call attention to areas of interest without being
+visually distracting. Non-diff lines and existing diff coloration is
+preserved; the intent is that the output should look exactly the same as
+the input, except for the occasional highlight.
+
+Use
+---
+
+You can try out the diff-highlight program with:
+
+---------------------------------------------
+git log -p --color | /path/to/diff-highlight
+---------------------------------------------
+
+If you want to use it all the time, drop it in your $PATH and put the
+following in your git configuration:
+
+---------------------------------------------
+[pager]
+ log = diff-highlight | less
+ show = diff-highlight | less
+ diff = diff-highlight | less
+---------------------------------------------
diff --git a/contrib/diff-highlight/diff-highlight b/contrib/diff-highlight/diff-highlight
new file mode 100755
index 0000000..d893898
--- /dev/null
+++ b/contrib/diff-highlight/diff-highlight
@@ -0,0 +1,124 @@
+#!/usr/bin/perl
+
+# Highlight by reversing foreground and background. You could do
+# other things like bold or underline if you prefer.
+my $HIGHLIGHT = "\x1b[7m";
+my $UNHIGHLIGHT = "\x1b[27m";
+my $COLOR = qr/\x1b\[[0-9;]*m/;
+
+my @window;
+
+while (<>) {
+ # We highlight only single-line changes, so we need
+ # a 4-line window to make a decision on whether
+ # to highlight.
+ push @window, $_;
+ next if @window < 4;
+ if ($window[0] =~ /^$COLOR*(\@| )/ &&
+ $window[1] =~ /^$COLOR*-/ &&
+ $window[2] =~ /^$COLOR*\+/ &&
+ $window[3] !~ /^$COLOR*\+/) {
+ print shift @window;
+ show_pair(shift @window, shift @window);
+ }
+ else {
+ print shift @window;
+ }
+
+ # Most of the time there is enough output to keep things streaming,
+ # but for something like "git log -Sfoo", you can get one early
+ # commit and then many seconds of nothing. We want to show
+ # that one commit as soon as possible.
+ #
+ # Since we can receive arbitrary input, there's no optimal
+ # place to flush. Flushing on a blank line is a heuristic that
+ # happens to match git-log output.
+ if (!length) {
+ local $| = 1;
+ }
+}
+
+# Special case a single-line hunk at the end of file.
+if (@window == 3 &&
+ $window[0] =~ /^$COLOR*(\@| )/ &&
+ $window[1] =~ /^$COLOR*-/ &&
+ $window[2] =~ /^$COLOR*\+/) {
+ print shift @window;
+ show_pair(shift @window, shift @window);
+}
+
+# And then flush any remaining lines.
+while (@window) {
+ print shift @window;
+}
+
+exit 0;
+
+sub show_pair {
+ my @a = split_line(shift);
+ my @b = split_line(shift);
+
+ # Find common prefix, taking care to skip any ansi
+ # color codes.
+ my $seen_plusminus;
+ my ($pa, $pb) = (0, 0);
+ while ($pa < @a && $pb < @b) {
+ if ($a[$pa] =~ /$COLOR/) {
+ $pa++;
+ }
+ elsif ($b[$pb] =~ /$COLOR/) {
+ $pb++;
+ }
+ elsif ($a[$pa] eq $b[$pb]) {
+ $pa++;
+ $pb++;
+ }
+ elsif (!$seen_plusminus && $a[$pa] eq '-' && $b[$pb] eq '+') {
+ $seen_plusminus = 1;
+ $pa++;
+ $pb++;
+ }
+ else {
+ last;
+ }
+ }
+
+ # Find common suffix, ignoring colors.
+ my ($sa, $sb) = ($#a, $#b);
+ while ($sa >= $pa && $sb >= $pb) {
+ if ($a[$sa] =~ /$COLOR/) {
+ $sa--;
+ }
+ elsif ($b[$sb] =~ /$COLOR/) {
+ $sb--;
+ }
+ elsif ($a[$sa] eq $b[$sb]) {
+ $sa--;
+ $sb--;
+ }
+ else {
+ last;
+ }
+ }
+
+ print highlight(\@a, $pa, $sa);
+ print highlight(\@b, $pb, $sb);
+}
+
+sub split_line {
+ local $_ = shift;
+ return map { /$COLOR/ ? $_ : (split //) }
+ split /($COLOR*)/;
+}
+
+sub highlight {
+ my ($line, $prefix, $suffix) = @_;
+
+ return join('',
+ @{$line}[0..($prefix-1)],
+ $HIGHLIGHT,
+ @{$line}[$prefix..$suffix],
+ $UNHIGHLIGHT,
+ @{$line}[($suffix+1)..$#$line]
+ );
+}
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index f885d70..7fd8bf0 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -847,6 +847,38 @@ class P4Submit(Command, P4UserMap):
return template
+ def edit_template(self, template_file):
+ """Invoke the editor to let the user change the submission
+ message. Return true if okay to continue with the submit."""
+
+ # if configured to skip the editing part, just submit
+ if gitConfig("git-p4.skipSubmitEdit") == "true":
+ return True
+
+ # look at the modification time, to check later if the user saved
+ # the file
+ mtime = os.stat(template_file).st_mtime
+
+ # invoke the editor
+ if os.environ.has_key("P4EDITOR"):
+ editor = os.environ.get("P4EDITOR")
+ else:
+ editor = read_pipe("git var GIT_EDITOR").strip()
+ system(editor + " " + template_file)
+
+ # If the file was not saved, prompt to see if this patch should
+ # be skipped. But skip this verification step if configured so.
+ if gitConfig("git-p4.skipSubmitEditCheck") == "true":
+ return True
+
+ if os.stat(template_file).st_mtime <= mtime:
+ while True:
+ response = raw_input("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ")
+ if response == 'y':
+ return True
+ if response == 'n':
+ return False
+
def applyCommit(self, id):
print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
@@ -1001,7 +1033,7 @@ class P4Submit(Command, P4UserMap):
separatorLine = "######## everything below this line is just the diff #######\n"
- [handle, fileName] = tempfile.mkstemp()
+ (handle, fileName) = tempfile.mkstemp()
tmpFile = os.fdopen(handle, "w+")
if self.isWindows:
submitTemplate = submitTemplate.replace("\n", "\r\n")
@@ -1009,25 +1041,9 @@ class P4Submit(Command, P4UserMap):
newdiff = newdiff.replace("\n", "\r\n")
tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
tmpFile.close()
- mtime = os.stat(fileName).st_mtime
- if os.environ.has_key("P4EDITOR"):
- editor = os.environ.get("P4EDITOR")
- else:
- editor = read_pipe("git var GIT_EDITOR").strip()
- system(editor + " " + fileName)
-
- if gitConfig("git-p4.skipSubmitEditCheck") == "true":
- checkModTime = False
- else:
- checkModTime = True
- response = "y"
- if checkModTime and (os.stat(fileName).st_mtime <= mtime):
- response = "x"
- while response != "y" and response != "n":
- response = raw_input("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ")
-
- if response == "y":
+ if self.edit_template(fileName):
+ # read the edited message and submit
tmpFile = open(fileName, "rb")
message = tmpFile.read()
tmpFile.close()
@@ -1039,11 +1055,12 @@ class P4Submit(Command, P4UserMap):
if self.preserveUser:
if p4User:
# Get last changelist number. Cannot easily get it from
- # the submit command output as the output is unmarshalled.
+ # the submit command output as the output is
+ # unmarshalled.
changelist = self.lastP4Changelist()
self.modifyChangelistUser(changelist, p4User)
-
else:
+ # skip this patch
for f in editedFiles:
p4_revert(f)
for f in filesToAdd:
@@ -1318,6 +1335,19 @@ class P4Sync(Command, P4UserMap):
text = p4_read_pipe(['print', '-q', '-o', '-', file['depotFile']])
contents = [ text ]
+ if type_base == "apple":
+ # Apple filetype files will be streamed as a concatenation of
+ # its appledouble header and the contents. This is useless
+ # on both macs and non-macs. If using "print -q -o xx", it
+ # will create "xx" with the data, and "%xx" with the header.
+ # This is also not very useful.
+ #
+ # Ideally, someday, this script can learn how to generate
+ # appledouble files directly and import those to git, but
+ # non-mac machines can never find a use for apple filetype.
+ print "\nIgnoring apple filetype file %s" % file['depotFile']
+ return
+
# Perhaps windows wants unicode, utf16 newlines translated too;
# but this is not doing it.
if self.isWindows and type_base == "text":
diff --git a/contrib/fast-import/git-p4.txt b/contrib/fast-import/git-p4.txt
index 52003ae..5044a12 100644
--- a/contrib/fast-import/git-p4.txt
+++ b/contrib/fast-import/git-p4.txt
@@ -202,11 +202,24 @@ able to find the relevant client. This client spec will be used to
both filter the files cloned by git and set the directory layout as
specified in the client (this implies --keep-path style semantics).
-git-p4.skipSubmitModTimeCheck
+git-p4.skipSubmitEdit
- git config [--global] git-p4.skipSubmitModTimeCheck false
+ git config [--global] git-p4.skipSubmitEdit false
-If true, submit will not check if the p4 change template has been modified.
+Normally, git-p4 invokes an editor after each commit is applied so
+that you can make changes to the submit message. Setting this
+variable to true will skip the editing step, submitting the change as is.
+
+git-p4.skipSubmitEditCheck
+
+ git config [--global] git-p4.skipSubmitEditCheck false
+
+After the editor is invoked, git-p4 normally makes sure you saved the
+change description, as an indication that you did indeed read it over
+and edit it. You can quit without saving to abort the submit (or skip
+this change and continue). Setting this variable to true will cause
+git-p4 not to check if you saved the change description. This variable
+only matters if git-p4.skipSubmitEdit has not been set to true.
git-p4.preserveUser
diff --git a/contrib/git-jump/README b/contrib/git-jump/README
new file mode 100644
index 0000000..1cebc32
--- /dev/null
+++ b/contrib/git-jump/README
@@ -0,0 +1,92 @@
+git-jump
+========
+
+Git-jump is a script for helping you jump to "interesting" parts of your
+project in your editor. It works by outputting a set of interesting
+spots in the "quickfix" format, which editors like vim can use as a
+queue of places to visit (this feature is usually used to jump to errors
+produced by a compiler). For example, given a diff like this:
+
+------------------------------------
+diff --git a/foo.c b/foo.c
+index a655540..5a59044 100644
+--- a/foo.c
++++ b/foo.c
+@@ -1,3 +1,3 @@
+ int main(void) {
+- printf("hello word!\n");
++ printf("hello world!\n");
+ }
+-----------------------------------
+
+git-jump will feed this to the editor:
+
+-----------------------------------
+foo.c:2: printf("hello word!\n");
+-----------------------------------
+
+Obviously this trivial case isn't that interesting; you could just open
+`foo.c` yourself. But when you have many changes scattered across a
+project, you can use the editor's support to "jump" from point to point.
+
+Git-jump can generate three types of interesting lists:
+
+ 1. The beginning of any diff hunks.
+
+ 2. The beginning of any merge conflict markers.
+
+ 3. Any grep matches.
+
+
+Using git-jump
+--------------
+
+To use it, just drop git-jump in your PATH, and then invoke it like
+this:
+
+--------------------------------------------------
+# jump to changes not yet staged for commit
+git jump diff
+
+# jump to changes that are staged for commit; you can give
+# arbitrary diff options
+git jump diff --cached
+
+# jump to merge conflicts
+git jump merge
+
+# jump to all instances of foo_bar
+git jump grep foo_bar
+
+# same as above, but case-insensitive; you can give
+# arbitrary grep options
+git jump grep -i foo_bar
+--------------------------------------------------
+
+
+Related Programs
+----------------
+
+You can accomplish some of the same things with individual tools. For
+example, you can use `git mergetool` to start vimdiff on each unmerged
+file. `git jump merge` is for the vim-wielding luddite who just wants to
+jump straight to the conflict text with no fanfare.
+
+As of git v1.7.2, `git grep` knows the `--open-files-in-pager` option,
+which does something similar to `git jump grep`. However, it is limited
+to positioning the cursor to the correct line in only the first file,
+leaving you to locate subsequent hits in that file or other files using
+the editor or pager. By contrast, git-jump provides the editor with a
+complete list of files and line numbers for each match.
+
+
+Limitations
+-----------
+
+This scripts was written and tested with vim. Given that the quickfix
+format is the same as what gcc produces, I expect emacs users have a
+similar feature for iterating through the list, but I know nothing about
+how to activate it.
+
+The shell snippets to generate the quickfix lines will almost certainly
+choke on filenames with exotic characters (like newlines).
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
new file mode 100755
index 0000000..a33674e
--- /dev/null
+++ b/contrib/git-jump/git-jump
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+usage() {
+ cat <<\EOF
+usage: git jump <mode> [<args>]
+
+Jump to interesting elements in an editor.
+The <mode> parameter is one of:
+
+diff: elements are diff hunks. Arguments are given to diff.
+
+merge: elements are merge conflicts. Arguments are ignored.
+
+grep: elements are grep hits. Arguments are given to grep.
+EOF
+}
+
+open_editor() {
+ editor=`git var GIT_EDITOR`
+ eval "$editor -q \$1"
+}
+
+mode_diff() {
+ git diff --relative "$@" |
+ perl -ne '
+ if (m{^\+\+\+ b/(.*)}) { $file = $1; next }
+ defined($file) or next;
+ if (m/^@@ .*\+(\d+)/) { $line = $1; next }
+ defined($line) or next;
+ if (/^ /) { $line++; next }
+ if (/^[-+]\s*(.*)/) {
+ print "$file:$line: $1\n";
+ $line = undef;
+ }
+ '
+}
+
+mode_merge() {
+ git ls-files -u |
+ perl -pe 's/^.*?\t//' |
+ sort -u |
+ while IFS= read fn; do
+ grep -Hn '^<<<<<<<' "$fn"
+ done
+}
+
+# Grep -n generates nice quickfix-looking lines by itself,
+# but let's clean up extra whitespace, so they look better if the
+# editor shows them to us in the status bar.
+mode_grep() {
+ git grep -n "$@" |
+ perl -pe '
+ s/[ \t]+/ /g;
+ s/^ *//;
+ '
+}
+
+if test $# -lt 1; then
+ usage >&2
+ exit 1
+fi
+mode=$1; shift
+
+trap 'rm -f "$tmp"' 0 1 2 3 15
+tmp=`mktemp -t git-jump.XXXXXX` || exit 1
+type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
+"mode_$mode" "$@" >"$tmp"
+test -s "$tmp" || exit 0
+open_editor "$tmp"
diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki
index 0b32d18..c18bfa1 100755
--- a/contrib/mw-to-git/git-remote-mediawiki
+++ b/contrib/mw-to-git/git-remote-mediawiki
@@ -109,6 +109,10 @@ $dumb_push = ($dumb_push eq "true");
my $wiki_name = $url;
$wiki_name =~ s/[^\/]*:\/\///;
+# If URL is like http://user:password@example.com/, we clearly don't
+# want the password in $wiki_name. While we're there, also remove user
+# and '@' sign, to avoid author like MWUser@HTTPUser@host.com
+$wiki_name =~ s/^.*@//;
# Commands parser
my $entry;
diff --git a/convert.c b/convert.c
index 3bb5a4d..86e9c29 100644
--- a/convert.c
+++ b/convert.c
@@ -641,7 +641,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
return 1;
}
-static int git_path_check_crlf(const char *path, struct git_attr_check *check)
+static enum crlf_action git_path_check_crlf(const char *path, struct git_attr_check *check)
{
const char *value = check->value;
@@ -658,7 +658,7 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check)
return CRLF_GUESS;
}
-static int git_path_check_eol(const char *path, struct git_attr_check *check)
+static enum eol git_path_check_eol(const char *path, struct git_attr_check *check)
{
const char *value = check->value;
@@ -811,7 +811,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str
src = dst->buf;
len = dst->len;
}
- return ret | convert_to_git(path, src, len, dst, 0);
+ return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);
}
/*****************************************************************
diff --git a/dir.c b/dir.c
index 6c0d782..0a78d00 100644
--- a/dir.c
+++ b/dir.c
@@ -968,34 +968,34 @@ static int read_directory_recursive(struct dir_struct *dir,
{
DIR *fdir = opendir(*base ? base : ".");
int contents = 0;
+ struct dirent *de;
+ char path[PATH_MAX + 1];
- if (fdir) {
- struct dirent *de;
- char path[PATH_MAX + 1];
- memcpy(path, base, baselen);
-
- while ((de = readdir(fdir)) != NULL) {
- int len;
- switch (treat_path(dir, de, path, sizeof(path),
- baselen, simplify, &len)) {
- case path_recurse:
- contents += read_directory_recursive
- (dir, path, len, 0, simplify);
- continue;
- case path_ignored:
- continue;
- case path_handled:
- break;
- }
- contents++;
- if (check_only)
- goto exit_early;
- else
- dir_add_name(dir, path, len);
+ if (!fdir)
+ return 0;
+
+ memcpy(path, base, baselen);
+
+ while ((de = readdir(fdir)) != NULL) {
+ int len;
+ switch (treat_path(dir, de, path, sizeof(path),
+ baselen, simplify, &len)) {
+ case path_recurse:
+ contents += read_directory_recursive(dir, path, len, 0, simplify);
+ continue;
+ case path_ignored:
+ continue;
+ case path_handled:
+ break;
}
-exit_early:
- closedir(fdir);
+ contents++;
+ if (check_only)
+ goto exit_early;
+ else
+ dir_add_name(dir, path, len);
}
+exit_early:
+ closedir(fdir);
return contents;
}
diff --git a/git-am.sh b/git-am.sh
index 9042432..1c13b13 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -530,7 +530,6 @@ else
echo "$sign" >"$dotest/sign"
echo "$utf8" >"$dotest/utf8"
echo "$keep" >"$dotest/keep"
- echo "$keepcr" >"$dotest/keepcr"
echo "$scissors" >"$dotest/scissors"
echo "$no_inbody_headers" >"$dotest/no_inbody_headers"
echo "$GIT_QUIET" >"$dotest/quiet"
@@ -576,12 +575,6 @@ if test "$(cat "$dotest/keep")" = t
then
keep=-k
fi
-case "$(cat "$dotest/keepcr")" in
-t)
- keepcr=--keep-cr ;;
-f)
- keepcr=--no-keep-cr ;;
-esac
case "$(cat "$dotest/scissors")" in
t)
scissors=--scissors ;;
diff --git a/git-compat-util.h b/git-compat-util.h
index 5ef8ff7..77062ed 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -116,7 +116,12 @@
#else
#include <poll.h>
#endif
-#ifndef __MINGW32__
+#if defined(__MINGW32__)
+/* pull in Windows compatibility stuff */
+#include "compat/mingw.h"
+#elif defined(_MSC_VER)
+#include "compat/msvc.h"
+#else
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/socket.h>
@@ -145,12 +150,6 @@
#include <grp.h>
#define _ALL_SOURCE 1
#endif
-#else /* __MINGW32__ */
-/* pull in Windows compatibility stuff */
-#include "compat/mingw.h"
-#endif /* __MINGW32__ */
-#ifdef _MSC_VER
-#include "compat/msvc.h"
#endif
#ifndef NO_LIBGEN_H
@@ -219,7 +218,7 @@ extern char *gitbasename(char *);
#define find_last_dir_sep(path) strrchr(path, '/')
#endif
-#if __HP_cc >= 61000
+#if defined(__HP_cc) && (__HP_cc >= 61000)
#define NORETURN __attribute__((noreturn))
#define NORETURN_PTR
#elif defined(__GNUC__) && !defined(NO_NORETURN)
@@ -351,6 +350,8 @@ extern size_t gitstrlcpy(char *, const char *, size_t);
#ifdef NO_STRTOUMAX
#define strtoumax gitstrtoumax
extern uintmax_t gitstrtoumax(const char *, char **, int);
+#define strtoimax gitstrtoimax
+extern intmax_t gitstrtoimax(const char *, char **, int);
#endif
#ifdef NO_STRTOK_R
diff --git a/git-submodule.sh b/git-submodule.sh
index 928a62f..3adab93 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -104,9 +104,9 @@ module_name()
re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
- test -z "$name" &&
- die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
- echo "$name"
+ test -z "$name" &&
+ die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+ echo "$name"
}
#
@@ -130,7 +130,7 @@ module_clone()
gitdir=
gitdir_base=
- name=$(module_name "$path")
+ name=$(module_name "$path" 2>/dev/null)
base_path=$(dirname "$path")
gitdir=$(git rev-parse --git-dir)
diff --git a/git-svn.perl b/git-svn.perl
index b67fef0..eeb83d3 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -684,7 +684,7 @@ sub populate_merge_info {
fatal "merge commit $d has ancestor $parent, but that change "
."does not have git-svn metadata!";
}
- unless ($branchurl =~ /^$rooturl(.*)/) {
+ unless ($branchurl =~ /^\Q$rooturl\E(.*)/) {
fatal "commit $parent git-svn metadata changed mid-run!";
}
my $branchpath = $1;
@@ -867,7 +867,7 @@ sub cmd_dcommit {
."has uuid $uuid!";
}
- unless ($branchurl =~ /^$rooturl(.*)/) {
+ unless ($branchurl =~ /^\Q$rooturl\E(.*)/) {
# This branch is very strange indeed.
fatal "merge parent $parent for $d is on branch "
."$branchurl, which is not under the "
@@ -5389,7 +5389,7 @@ sub apply_diff {
$self->{mergeinfo});
}
$self->rmdirs if $_rmdir;
- if (@$mods == 0) {
+ if (@$mods == 0 && !defined($self->{mergeinfo})) {
$self->abort_edit;
} else {
$self->close_edit;
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index d134ffe..6d45406 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -130,6 +130,8 @@ You can specify the following configuration variables when building GIT:
Points to an .html file which is included on the gitweb project
overview page ('projects_list' view), if it exists. Relative to
gitweb.cgi script. [Default: indextext.html]
+ * GITWEB_SITE_HTML_HEAD_STRING
+ html snippet to include in the <head> section of each page. [No default]
* GITWEB_SITE_HEADER
Filename of html text to include at top of each page. Relative to
gitweb.cgi script. [No default]
diff --git a/gitweb/Makefile b/gitweb/Makefile
index 1c85b5f..cd194d0 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -34,6 +34,7 @@ GITWEB_CSS = static/gitweb.css
GITWEB_LOGO = static/git-logo.png
GITWEB_FAVICON = static/git-favicon.png
GITWEB_JS = static/gitweb.js
+GITWEB_SITE_HTML_HEAD_STRING =
GITWEB_SITE_HEADER =
GITWEB_SITE_FOOTER =
HIGHLIGHT_BIN = highlight
@@ -144,6 +145,7 @@ GITWEB_REPLACE = \
-e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
-e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
-e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
+ -e 's|++GITWEB_SITE_HTML_HEAD_STRING++|$(GITWEB_SITE_HTML_HEAD_STRING)|g' \
-e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
-e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
-e 's|++HIGHLIGHT_BIN++|$(HIGHLIGHT_BIN)|g'
@@ -185,7 +187,9 @@ install: all
### Cleaning rules
clean:
- $(RM) gitweb.cgi static/gitweb.min.js static/gitweb.min.css GITWEB-BUILD-OPTIONS
+ $(RM) gitweb.cgi static/gitweb.js \
+ static/gitweb.min.js static/gitweb.min.css \
+ GITWEB-BUILD-OPTIONS
.PHONY: all clean install test test-installed .FORCE-GIT-VERSION-FILE FORCE
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 85d64b2..4f0c3bd 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -85,6 +85,8 @@ our $home_link_str = "++GITWEB_HOME_LINK_STR++";
our $site_name = "++GITWEB_SITENAME++"
|| ($ENV{'SERVER_NAME'} || "Untitled") . " Git";
+# html snippet to include in the <head> section of each page
+our $site_html_head_string = "++GITWEB_SITE_HTML_HEAD_STRING++";
# filename of html text to include at top of each page
our $site_header = "++GITWEB_SITE_HEADER++";
# html text to include at home page
@@ -2886,7 +2888,7 @@ sub filter_forks_from_projects_list {
$path =~ s/\.git$//; # forks of 'repo.git' are in 'repo/' directory
next if ($path =~ m!/$!); # skip non-bare repositories, e.g. 'repo/.git'
next unless ($path); # skip '.git' repository: tests, git-instaweb
- next unless (-d $path); # containing directory exists
+ next unless (-d "$projectroot/$path"); # containing directory exists
$pr->{'forks'} = []; # there can be 0 or more forks of project
# add to trie
@@ -3879,6 +3881,11 @@ EOF
print "<base href=\"".esc_url($base_url)."\" />\n";
}
print_header_links($status);
+
+ if (defined $site_html_head_string) {
+ print to_utf8($site_html_head_string);
+ }
+
print "</head>\n" .
"<body>\n";
diff --git a/http.c b/http.c
index a4bc770..44fcc4d 100644
--- a/http.c
+++ b/http.c
@@ -4,7 +4,6 @@
#include "run-command.h"
#include "url.h"
-int data_received;
int active_requests;
int http_is_verbose;
size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
@@ -99,13 +98,11 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
struct strbuf *buffer = buffer_;
strbuf_add(buffer, ptr, size);
- data_received++;
return size;
}
size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
{
- data_received++;
return eltsize * nmemb;
}
@@ -279,8 +276,6 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
#endif
- init_curl_http_auth(result);
-
if (ssl_cert != NULL)
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
if (has_cert_password())
@@ -538,7 +533,6 @@ struct active_request_slot *get_active_slot(void)
active_requests++;
slot->in_use = 1;
- slot->local = NULL;
slot->results = NULL;
slot->finished = NULL;
slot->callback_data = NULL;
@@ -642,8 +636,6 @@ void step_active_slots(void)
void run_active_slot(struct active_request_slot *slot)
{
#ifdef USE_CURL_MULTI
- long last_pos = 0;
- long current_pos;
fd_set readfds;
fd_set writefds;
fd_set excfds;
@@ -653,25 +645,33 @@ void run_active_slot(struct active_request_slot *slot)
slot->finished = &finished;
while (!finished) {
- data_received = 0;
step_active_slots();
- if (!data_received && slot->local != NULL) {
- current_pos = ftell(slot->local);
- if (current_pos > last_pos)
- data_received++;
- last_pos = current_pos;
- }
+ if (slot->in_use) {
+#if LIBCURL_VERSION_NUM >= 0x070f04
+ long curl_timeout;
+ curl_multi_timeout(curlm, &curl_timeout);
+ if (curl_timeout == 0) {
+ continue;
+ } else if (curl_timeout == -1) {
+ select_timeout.tv_sec = 0;
+ select_timeout.tv_usec = 50000;
+ } else {
+ select_timeout.tv_sec = curl_timeout / 1000;
+ select_timeout.tv_usec = (curl_timeout % 1000) * 1000;
+ }
+#else
+ select_timeout.tv_sec = 0;
+ select_timeout.tv_usec = 50000;
+#endif
- if (slot->in_use && !data_received) {
- max_fd = 0;
+ max_fd = -1;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&excfds);
- select_timeout.tv_sec = 0;
- select_timeout.tv_usec = 50000;
- select(max_fd, &readfds, &writefds,
- &excfds, &select_timeout);
+ curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd);
+
+ select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
}
}
#else
@@ -749,14 +749,6 @@ static inline int needs_quote(int ch)
return 1;
}
-static inline int hex(int v)
-{
- if (v < 10)
- return '0' + v;
- else
- return 'A' + v - 10;
-}
-
static char *quote_ref_url(const char *base, const char *ref)
{
struct strbuf buf = STRBUF_INIT;
@@ -824,7 +816,6 @@ static int http_request(const char *url, void *result, int target, int options)
headers = curl_slist_append(headers, buf.buf);
strbuf_reset(&buf);
}
- slot->local = result;
} else
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer);
@@ -846,7 +837,7 @@ static int http_request(const char *url, void *result, int target, int options)
else if (missing_target(&results))
ret = HTTP_MISSING_TARGET;
else if (results.http_code == 401) {
- if (user_name) {
+ if (user_name && user_pass) {
ret = HTTP_NOAUTH;
} else {
/*
@@ -855,7 +846,8 @@ static int http_request(const char *url, void *result, int target, int options)
* but that is non-portable. Using git_getpass() can at least be stubbed
* on other platforms with a different implementation if/when necessary.
*/
- user_name = xstrdup(git_getpass_with_description("Username", description));
+ if (!user_name)
+ user_name = xstrdup(git_getpass_with_description("Username", description));
init_curl_http_auth(slot->curl);
ret = HTTP_REAUTH;
}
@@ -871,7 +863,6 @@ static int http_request(const char *url, void *result, int target, int options)
ret = HTTP_START_FAILED;
}
- slot->local = NULL;
curl_slist_free_all(headers);
strbuf_release(&buf);
@@ -1066,7 +1057,6 @@ void release_http_pack_request(struct http_pack_request *preq)
if (preq->packfile != NULL) {
fclose(preq->packfile);
preq->packfile = NULL;
- preq->slot->local = NULL;
}
if (preq->range_header != NULL) {
curl_slist_free_all(preq->range_header);
@@ -1088,7 +1078,6 @@ int finish_http_pack_request(struct http_pack_request *preq)
fclose(preq->packfile);
preq->packfile = NULL;
- preq->slot->local = NULL;
lst = preq->lst;
while (*lst != p)
@@ -1157,7 +1146,6 @@ struct http_pack_request *new_http_pack_request(
}
preq->slot = get_active_slot();
- preq->slot->local = preq->packfile;
curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
@@ -1214,7 +1202,6 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
git_SHA1_Update(&freq->c, expn,
sizeof(expn) - freq->stream.avail_out);
} while (freq->stream.avail_in && freq->zret == Z_OK);
- data_received++;
return size;
}
diff --git a/http.h b/http.h
index 3c332a9..ee16069 100644
--- a/http.h
+++ b/http.h
@@ -49,7 +49,6 @@ struct slot_results {
struct active_request_slot {
CURL *curl;
- FILE *local;
int in_use;
CURLcode curl_result;
long http_code;
@@ -89,7 +88,6 @@ extern void step_active_slots(void);
extern void http_init(struct remote *remote, const char *url);
extern void http_cleanup(void);
-extern int data_received;
extern int active_requests;
extern int http_is_verbose;
extern size_t http_post_buffer;
diff --git a/list-objects.c b/list-objects.c
index 39d80c0..3dd4a96 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -71,7 +71,8 @@ static void process_tree(struct rev_info *revs,
struct tree_desc desc;
struct name_entry entry;
struct name_path me;
- int match = revs->diffopt.pathspec.nr == 0 ? 2 : 0;
+ enum interesting match = revs->diffopt.pathspec.nr == 0 ?
+ all_entries_interesting: entry_not_interesting;
int baselen = base->len;
if (!revs->tree_objects)
@@ -97,12 +98,12 @@ static void process_tree(struct rev_info *revs,
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&entry, base, 0,
&revs->diffopt.pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
diff --git a/mailmap.c b/mailmap.c
index 02fcfde..8c3196c 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -70,8 +70,7 @@ static void add_mapping(struct string_list *map,
} else {
/* create mailmap entry */
struct string_list_item *item = string_list_insert_at_index(map, index, old_email);
- item->util = xmalloc(sizeof(struct mailmap_entry));
- memset(item->util, 0, sizeof(struct mailmap_entry));
+ item->util = xcalloc(1, sizeof(struct mailmap_entry));
((struct mailmap_entry *)item->util)->namemap.strdup_strings = 1;
}
me = (struct mailmap_entry *)map->items[index].util;
@@ -88,7 +87,7 @@ static void add_mapping(struct string_list *map,
me->email = xstrdup(new_email);
}
} else {
- struct mailmap_info *mi = xmalloc(sizeof(struct mailmap_info));
+ struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
debug_mm("mailmap: adding (complex) entry for %s at index %d\n", old_email, index);
if (new_name)
mi->name = xstrdup(new_name);
diff --git a/name-hash.c b/name-hash.c
index 225dd76..d8d25c2 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -74,7 +74,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
if (ce->ce_flags & CE_HASHED)
return;
ce->ce_flags |= CE_HASHED;
- ce->next = NULL;
+ ce->next = ce->dir_next = NULL;
hash = hash_name(ce->name, ce_namelen(ce));
pos = insert_hash(hash, ce, &istate->name_hash);
if (pos) {
diff --git a/notes-merge.c b/notes-merge.c
index e9e4199..ce10aac 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -21,14 +21,6 @@ void init_notes_merge_options(struct notes_merge_options *o)
o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
}
-#define OUTPUT(o, v, ...) \
- do { \
- if ((o)->verbosity >= (v)) { \
- printf(__VA_ARGS__); \
- puts(""); \
- } \
- } while (0)
-
static int path_to_sha1(const char *path, unsigned char *sha1)
{
char hex_sha1[40];
@@ -392,21 +384,26 @@ static int merge_one_change_manual(struct notes_merge_options *o,
strbuf_addf(&(o->commit_msg), "\t%s\n", sha1_to_hex(p->obj));
- OUTPUT(o, 2, "Auto-merging notes for %s", sha1_to_hex(p->obj));
+ if (o->verbosity >= 2)
+ printf("Auto-merging notes for %s\n", sha1_to_hex(p->obj));
check_notes_merge_worktree(o);
if (is_null_sha1(p->local)) {
/* D/F conflict, checkout p->remote */
assert(!is_null_sha1(p->remote));
- OUTPUT(o, 1, "CONFLICT (delete/modify): Notes for object %s "
- "deleted in %s and modified in %s. Version from %s "
- "left in tree.", sha1_to_hex(p->obj), lref, rref, rref);
+ if (o->verbosity >= 1)
+ printf("CONFLICT (delete/modify): Notes for object %s "
+ "deleted in %s and modified in %s. Version from %s "
+ "left in tree.\n",
+ sha1_to_hex(p->obj), lref, rref, rref);
write_note_to_worktree(p->obj, p->remote);
} else if (is_null_sha1(p->remote)) {
/* D/F conflict, checkout p->local */
assert(!is_null_sha1(p->local));
- OUTPUT(o, 1, "CONFLICT (delete/modify): Notes for object %s "
- "deleted in %s and modified in %s. Version from %s "
- "left in tree.", sha1_to_hex(p->obj), rref, lref, lref);
+ if (o->verbosity >= 1)
+ printf("CONFLICT (delete/modify): Notes for object %s "
+ "deleted in %s and modified in %s. Version from %s "
+ "left in tree.\n",
+ sha1_to_hex(p->obj), rref, lref, lref);
write_note_to_worktree(p->obj, p->local);
} else {
/* "regular" conflict, checkout result of ll_merge() */
@@ -415,8 +412,9 @@ static int merge_one_change_manual(struct notes_merge_options *o,
reason = "add/add";
assert(!is_null_sha1(p->local));
assert(!is_null_sha1(p->remote));
- OUTPUT(o, 1, "CONFLICT (%s): Merge conflict in notes for "
- "object %s", reason, sha1_to_hex(p->obj));
+ if (o->verbosity >= 1)
+ printf("CONFLICT (%s): Merge conflict in notes for "
+ "object %s\n", reason, sha1_to_hex(p->obj));
ll_merge_in_worktree(o, p);
}
@@ -438,24 +436,30 @@ static int merge_one_change(struct notes_merge_options *o,
case NOTES_MERGE_RESOLVE_MANUAL:
return merge_one_change_manual(o, p, t);
case NOTES_MERGE_RESOLVE_OURS:
- OUTPUT(o, 2, "Using local notes for %s", sha1_to_hex(p->obj));
+ if (o->verbosity >= 2)
+ printf("Using local notes for %s\n",
+ sha1_to_hex(p->obj));
/* nothing to do */
return 0;
case NOTES_MERGE_RESOLVE_THEIRS:
- OUTPUT(o, 2, "Using remote notes for %s", sha1_to_hex(p->obj));
+ if (o->verbosity >= 2)
+ printf("Using remote notes for %s\n",
+ sha1_to_hex(p->obj));
if (add_note(t, p->obj, p->remote, combine_notes_overwrite))
die("BUG: combine_notes_overwrite failed");
return 0;
case NOTES_MERGE_RESOLVE_UNION:
- OUTPUT(o, 2, "Concatenating local and remote notes for %s",
- sha1_to_hex(p->obj));
+ if (o->verbosity >= 2)
+ printf("Concatenating local and remote notes for %s\n",
+ sha1_to_hex(p->obj));
if (add_note(t, p->obj, p->remote, combine_notes_concatenate))
die("failed to concatenate notes "
"(combine_notes_concatenate)");
return 0;
case NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ:
- OUTPUT(o, 2, "Concatenating unique lines in local and remote "
- "notes for %s", sha1_to_hex(p->obj));
+ if (o->verbosity >= 2)
+ printf("Concatenating unique lines in local and remote "
+ "notes for %s\n", sha1_to_hex(p->obj));
if (add_note(t, p->obj, p->remote, combine_notes_cat_sort_uniq))
die("failed to concatenate notes "
"(combine_notes_cat_sort_uniq)");
@@ -518,8 +522,9 @@ static int merge_from_diffs(struct notes_merge_options *o,
conflicts = merge_changes(o, changes, &num_changes, t);
free(changes);
- OUTPUT(o, 4, "Merge result: %i unmerged notes and a %s notes tree",
- conflicts, t->dirty ? "dirty" : "clean");
+ if (o->verbosity >= 4)
+ printf("Merge result: %i unmerged notes and a %s notes tree\n",
+ conflicts, t->dirty ? "dirty" : "clean");
return conflicts ? -1 : 1;
}
@@ -617,33 +622,40 @@ int notes_merge(struct notes_merge_options *o,
if (!bases) {
base_sha1 = null_sha1;
base_tree_sha1 = EMPTY_TREE_SHA1_BIN;
- OUTPUT(o, 4, "No merge base found; doing history-less merge");
+ if (o->verbosity >= 4)
+ printf("No merge base found; doing history-less merge\n");
} else if (!bases->next) {
base_sha1 = bases->item->object.sha1;
base_tree_sha1 = bases->item->tree->object.sha1;
- OUTPUT(o, 4, "One merge base found (%.7s)",
- sha1_to_hex(base_sha1));
+ if (o->verbosity >= 4)
+ printf("One merge base found (%.7s)\n",
+ sha1_to_hex(base_sha1));
} else {
/* TODO: How to handle multiple merge-bases? */
base_sha1 = bases->item->object.sha1;
base_tree_sha1 = bases->item->tree->object.sha1;
- OUTPUT(o, 3, "Multiple merge bases found. Using the first "
- "(%.7s)", sha1_to_hex(base_sha1));
+ if (o->verbosity >= 3)
+ printf("Multiple merge bases found. Using the first "
+ "(%.7s)\n", sha1_to_hex(base_sha1));
}
- OUTPUT(o, 4, "Merging remote commit %.7s into local commit %.7s with "
- "merge-base %.7s", sha1_to_hex(remote->object.sha1),
- sha1_to_hex(local->object.sha1), sha1_to_hex(base_sha1));
+ if (o->verbosity >= 4)
+ printf("Merging remote commit %.7s into local commit %.7s with "
+ "merge-base %.7s\n", sha1_to_hex(remote->object.sha1),
+ sha1_to_hex(local->object.sha1),
+ sha1_to_hex(base_sha1));
if (!hashcmp(remote->object.sha1, base_sha1)) {
/* Already merged; result == local commit */
- OUTPUT(o, 2, "Already up-to-date!");
+ if (o->verbosity >= 2)
+ printf("Already up-to-date!\n");
hashcpy(result_sha1, local->object.sha1);
goto found_result;
}
if (!hashcmp(local->object.sha1, base_sha1)) {
/* Fast-forward; result == remote commit */
- OUTPUT(o, 2, "Fast-forward");
+ if (o->verbosity >= 2)
+ printf("Fast-forward\n");
hashcpy(result_sha1, remote->object.sha1);
goto found_result;
}
@@ -685,8 +697,9 @@ int notes_merge_commit(struct notes_merge_options *o,
int path_len = strlen(path), i;
const char *msg = strstr(partial_commit->buffer, "\n\n");
- OUTPUT(o, 3, "Committing notes in notes merge worktree at %.*s",
- path_len - 1, path);
+ if (o->verbosity >= 3)
+ printf("Committing notes in notes merge worktree at %.*s\n",
+ path_len - 1, path);
if (!msg || msg[2] == '\0')
die("partial notes commit has empty message");
@@ -701,7 +714,9 @@ int notes_merge_commit(struct notes_merge_options *o,
unsigned char obj_sha1[20], blob_sha1[20];
if (ent->len - path_len != 40 || get_sha1_hex(relpath, obj_sha1)) {
- OUTPUT(o, 3, "Skipping non-SHA1 entry '%s'", ent->name);
+ if (o->verbosity >= 3)
+ printf("Skipping non-SHA1 entry '%s'\n",
+ ent->name);
continue;
}
@@ -713,14 +728,16 @@ int notes_merge_commit(struct notes_merge_options *o,
if (add_note(partial_tree, obj_sha1, blob_sha1, NULL))
die("Failed to add resolved note '%s' to notes tree",
ent->name);
- OUTPUT(o, 4, "Added resolved note for object %s: %s",
- sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
+ if (o->verbosity >= 4)
+ printf("Added resolved note for object %s: %s\n",
+ sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
}
create_notes_commit(partial_tree, partial_commit->parents, msg,
result_sha1);
- OUTPUT(o, 4, "Finalized notes merge commit: %s",
- sha1_to_hex(result_sha1));
+ if (o->verbosity >= 4)
+ printf("Finalized notes merge commit: %s\n",
+ sha1_to_hex(result_sha1));
free(path);
return 0;
}
@@ -732,7 +749,8 @@ int notes_merge_abort(struct notes_merge_options *o)
int ret;
strbuf_addstr(&buf, git_path(NOTES_MERGE_WORKTREE));
- OUTPUT(o, 3, "Removing notes merge worktree at %s", buf.buf);
+ if (o->verbosity >= 3)
+ printf("Removing notes merge worktree at %s\n", buf.buf);
ret = remove_dir_recursively(&buf, 0);
strbuf_release(&buf);
return ret;
diff --git a/object.c b/object.c
index 31976b5..d8d09f9 100644
--- a/object.c
+++ b/object.c
@@ -149,6 +149,8 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
struct tree *tree = lookup_tree(sha1);
if (tree) {
obj = &tree->object;
+ if (!tree->buffer)
+ tree->object.parsed = 0;
if (!tree->object.parsed) {
if (parse_tree_buffer(tree, buffer, size))
return NULL;
diff --git a/pack-check.c b/pack-check.c
index 0c19b6e..63a595c 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "pack.h"
#include "pack-revindex.h"
+#include "progress.h"
struct idx_entry {
off_t offset;
@@ -42,7 +43,10 @@ int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,
}
static int verify_packfile(struct packed_git *p,
- struct pack_window **w_curs)
+ struct pack_window **w_curs,
+ verify_fn fn,
+ struct progress *progress, uint32_t base_count)
+
{
off_t index_size = p->index_size;
const unsigned char *index_base = p->index_data;
@@ -113,20 +117,25 @@ static int verify_packfile(struct packed_git *p,
p->pack_name, (uintmax_t)offset);
}
data = unpack_entry(p, entries[i].offset, &type, &size);
- if (!data) {
+ if (!data)
err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
sha1_to_hex(entries[i].sha1), p->pack_name,
(uintmax_t)entries[i].offset);
- break;
- }
- if (check_sha1_signature(entries[i].sha1, data, size, typename(type))) {
+ else if (check_sha1_signature(entries[i].sha1, data, size, typename(type)))
err = error("packed %s from %s is corrupt",
sha1_to_hex(entries[i].sha1), p->pack_name);
- free(data);
- break;
+ else if (fn) {
+ int eaten = 0;
+ fn(entries[i].sha1, type, size, data, &eaten);
+ if (eaten)
+ data = NULL;
}
+ if (((base_count + i) & 1023) == 0)
+ display_progress(progress, base_count + i);
free(data);
+
}
+ display_progress(progress, base_count + i);
free(entries);
return err;
@@ -155,7 +164,8 @@ int verify_pack_index(struct packed_git *p)
return err;
}
-int verify_pack(struct packed_git *p)
+int verify_pack(struct packed_git *p, verify_fn fn,
+ struct progress *progress, uint32_t base_count)
{
int err = 0;
struct pack_window *w_curs = NULL;
@@ -164,7 +174,7 @@ int verify_pack(struct packed_git *p)
if (!p->index_data)
return -1;
- err |= verify_packfile(p, &w_curs);
+ err |= verify_packfile(p, &w_curs, fn, progress, base_count);
unuse_pack(&w_curs);
return err;
diff --git a/pack-write.c b/pack-write.c
index 9cd3bfb..f84adde 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -129,6 +129,10 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
}
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",
+ sha1_to_hex(obj->sha1));
}
if (index_version >= 2) {
diff --git a/pack.h b/pack.h
index 722a54e..a8d9b9f 100644
--- a/pack.h
+++ b/pack.h
@@ -37,7 +37,8 @@ struct pack_header {
struct pack_idx_option {
unsigned flags;
/* flag bits */
-#define WRITE_IDX_VERIFY 01
+#define WRITE_IDX_VERIFY 01 /* verify only, do not write the idx file */
+#define WRITE_IDX_STRICT 02
uint32_t version;
uint32_t off32_limit;
@@ -70,10 +71,14 @@ struct pack_idx_entry {
off_t offset;
};
+
+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 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 *);
+extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uint32_t);
extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
extern char *index_pack_lockfile(int fd);
extern int encode_in_pack_object_header(enum object_type, uintmax_t, unsigned char *);
diff --git a/perl/.gitignore b/perl/.gitignore
index 98b2477..9235e73 100644
--- a/perl/.gitignore
+++ b/perl/.gitignore
@@ -1,5 +1,6 @@
perl.mak
perl.mak.old
+MYMETA.yml
blib
blibdirs
pm_to_blib
diff --git a/perl/Git.pm b/perl/Git.pm
index c279bfb..f7ce511 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -570,30 +570,10 @@ does. In scalar context requires the variable to be set only one time
(exception is thrown otherwise), in array context returns allows the
variable to be set multiple times and returns all the values.
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config {
- my ($self, $var) = _maybe_self(@_);
-
- try {
- my @cmd = ('config');
- unshift @cmd, $self if $self;
- if (wantarray) {
- return command(@cmd, '--get-all', $var);
- } else {
- return command_oneline(@cmd, '--get', $var);
- }
- } catch Git::Error::Command with {
- my $E = shift;
- if ($E->value() == 1) {
- # Key not found.
- return;
- } else {
- throw $E;
- }
- };
+ return _config_common({}, @_);
}
@@ -603,28 +583,18 @@ Retrieve the bool configuration C<VARIABLE>. The return value
is usable as a boolean in perl (and C<undef> if it's not defined,
of course).
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config_bool {
- my ($self, $var) = _maybe_self(@_);
+ my $val = scalar _config_common({'kind' => '--bool'}, @_);
- try {
- my @cmd = ('config', '--bool', '--get', $var);
- unshift @cmd, $self if $self;
- my $val = command_oneline(@cmd);
- return undef unless defined $val;
+ # Do not rewrite this as return (defined $val && $val eq 'true')
+ # as some callers do care what kind of falsehood they receive.
+ if (!defined $val) {
+ return undef;
+ } else {
return $val eq 'true';
- } catch Git::Error::Command with {
- my $E = shift;
- if ($E->value() == 1) {
- # Key not found.
- return undef;
- } else {
- throw $E;
- }
- };
+ }
}
@@ -633,32 +603,13 @@ sub config_bool {
Retrieve the path configuration C<VARIABLE>. The return value
is an expanded path or C<undef> if it's not defined.
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config_path {
- my ($self, $var) = _maybe_self(@_);
-
- try {
- my @cmd = ('config', '--path');
- unshift @cmd, $self if $self;
- if (wantarray) {
- return command(@cmd, '--get-all', $var);
- } else {
- return command_oneline(@cmd, '--get', $var);
- }
- } catch Git::Error::Command with {
- my $E = shift;
- if ($E->value() == 1) {
- # Key not found.
- return undef;
- } else {
- throw $E;
- }
- };
+ return _config_common({'kind' => '--path'}, @_);
}
+
=item config_int ( VARIABLE )
Retrieve the integer configuration C<VARIABLE>. The return value
@@ -667,22 +618,31 @@ or 'g' in the config file will cause the value to be multiplied
by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
It would return C<undef> if configuration variable is not defined,
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config_int {
+ return scalar _config_common({'kind' => '--int'}, @_);
+}
+
+# Common subroutine to implement bulk of what the config* family of methods
+# do. This curently wraps command('config') so it is not so fast.
+sub _config_common {
+ my ($opts) = shift @_;
my ($self, $var) = _maybe_self(@_);
try {
- my @cmd = ('config', '--int', '--get', $var);
+ my @cmd = ('config', $opts->{'kind'} ? $opts->{'kind'} : ());
unshift @cmd, $self if $self;
- return command_oneline(@cmd);
+ if (wantarray) {
+ return command(@cmd, '--get-all', $var);
+ } else {
+ return command_oneline(@cmd, '--get', $var);
+ }
} catch Git::Error::Command with {
my $E = shift;
if ($E->value() == 1) {
# Key not found.
- return undef;
+ return;
} else {
throw $E;
}
diff --git a/pretty.c b/pretty.c
index f45eb54..230fe1c 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1094,7 +1094,6 @@ void format_commit_message(const struct commit *commit,
{
struct format_commit_context context;
static const char utf8[] = "UTF-8";
- const char *enc;
const char *output_enc = pretty_ctx->output_encoding;
memset(&context, 0, sizeof(context));
@@ -1103,10 +1102,13 @@ void format_commit_message(const struct commit *commit,
context.wrap_start = sb->len;
context.message = commit->buffer;
if (output_enc) {
- enc = get_header(commit, "encoding");
- enc = enc ? enc : utf8;
- if (strcmp(enc, output_enc))
+ char *enc = get_header(commit, "encoding");
+ if (strcmp(enc ? enc : utf8, output_enc)) {
context.message = logmsg_reencode(commit, output_enc);
+ if (!context.message)
+ context.message = commit->buffer;
+ }
+ free(enc);
}
strbuf_expand(sb, format, format_commit_item, &context);
diff --git a/reachable.c b/reachable.c
index 3fc6b1d..bf79706 100644
--- a/reachable.c
+++ b/reachable.c
@@ -7,11 +7,25 @@
#include "revision.h"
#include "reachable.h"
#include "cache-tree.h"
+#include "progress.h"
+
+struct connectivity_progress {
+ struct progress *progress;
+ unsigned long count;
+};
+
+static void update_progress(struct connectivity_progress *cp)
+{
+ cp->count++;
+ if ((cp->count & 1023) == 0)
+ display_progress(cp->progress, cp->count);
+}
static void process_blob(struct blob *blob,
struct object_array *p,
struct name_path *path,
- const char *name)
+ const char *name,
+ struct connectivity_progress *cp)
{
struct object *obj = &blob->object;
@@ -20,6 +34,7 @@ static void process_blob(struct blob *blob,
if (obj->flags & SEEN)
return;
obj->flags |= SEEN;
+ update_progress(cp);
/* Nothing to do, really .. The blob lookup was the important part */
}
@@ -34,7 +49,8 @@ static void process_gitlink(const unsigned char *sha1,
static void process_tree(struct tree *tree,
struct object_array *p,
struct name_path *path,
- const char *name)
+ const char *name,
+ struct connectivity_progress *cp)
{
struct object *obj = &tree->object;
struct tree_desc desc;
@@ -46,6 +62,7 @@ static void process_tree(struct tree *tree,
if (obj->flags & SEEN)
return;
obj->flags |= SEEN;
+ update_progress(cp);
if (parse_tree(tree) < 0)
die("bad tree object %s", sha1_to_hex(obj->sha1));
add_object(obj, p, path, name);
@@ -57,23 +74,25 @@ static void process_tree(struct tree *tree,
while (tree_entry(&desc, &entry)) {
if (S_ISDIR(entry.mode))
- process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
+ process_tree(lookup_tree(entry.sha1), p, &me, entry.path, cp);
else if (S_ISGITLINK(entry.mode))
process_gitlink(entry.sha1, p, &me, entry.path);
else
- process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
+ process_blob(lookup_blob(entry.sha1), p, &me, entry.path, cp);
}
free(tree->buffer);
tree->buffer = NULL;
}
-static void process_tag(struct tag *tag, struct object_array *p, const char *name)
+static void process_tag(struct tag *tag, struct object_array *p,
+ const char *name, struct connectivity_progress *cp)
{
struct object *obj = &tag->object;
if (obj->flags & SEEN)
return;
obj->flags |= SEEN;
+ update_progress(cp);
if (parse_tag(tag) < 0)
die("bad tag object %s", sha1_to_hex(obj->sha1));
@@ -81,15 +100,18 @@ static void process_tag(struct tag *tag, struct object_array *p, const char *nam
add_object(tag->tagged, p, NULL, name);
}
-static void walk_commit_list(struct rev_info *revs)
+static void walk_commit_list(struct rev_info *revs,
+ struct connectivity_progress *cp)
{
int i;
struct commit *commit;
struct object_array objects = OBJECT_ARRAY_INIT;
/* Walk all commits, process their trees */
- while ((commit = get_revision(revs)) != NULL)
- process_tree(commit->tree, &objects, NULL, "");
+ while ((commit = get_revision(revs)) != NULL) {
+ process_tree(commit->tree, &objects, NULL, "", cp);
+ update_progress(cp);
+ }
/* Then walk all the pending objects, recursively processing them too */
for (i = 0; i < revs->pending.nr; i++) {
@@ -97,15 +119,15 @@ static void walk_commit_list(struct rev_info *revs)
struct object *obj = pending->item;
const char *name = pending->name;
if (obj->type == OBJ_TAG) {
- process_tag((struct tag *) obj, &objects, name);
+ process_tag((struct tag *) obj, &objects, name, cp);
continue;
}
if (obj->type == OBJ_TREE) {
- process_tree((struct tree *)obj, &objects, NULL, name);
+ process_tree((struct tree *)obj, &objects, NULL, name, cp);
continue;
}
if (obj->type == OBJ_BLOB) {
- process_blob((struct blob *)obj, &objects, NULL, name);
+ process_blob((struct blob *)obj, &objects, NULL, name, cp);
continue;
}
die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
@@ -191,8 +213,11 @@ static void add_cache_refs(struct rev_info *revs)
add_cache_tree(active_cache_tree, revs);
}
-void mark_reachable_objects(struct rev_info *revs, int mark_reflog)
+void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
+ struct progress *progress)
{
+ struct connectivity_progress cp;
+
/*
* Set up revision parsing, and mark us as being interested
* in all object types, not just commits.
@@ -211,11 +236,15 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog)
if (mark_reflog)
for_each_reflog(add_one_reflog, revs);
+ cp.progress = progress;
+ cp.count = 0;
+
/*
* Set up the revision walk - this will move all commits
* from the pending list to the commit walking list.
*/
if (prepare_revision_walk(revs))
die("revision walk setup failed");
- walk_commit_list(revs);
+ walk_commit_list(revs, &cp);
+ display_progress(cp.progress, cp.count);
}
diff --git a/reachable.h b/reachable.h
index 4075181..5d082ad 100644
--- a/reachable.h
+++ b/reachable.h
@@ -1,6 +1,7 @@
#ifndef REACHEABLE_H
#define REACHEABLE_H
-extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog);
+struct progress;
+extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog, struct progress *);
#endif
diff --git a/read-cache.c b/read-cache.c
index dea7cd8..a51bba1 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1001,7 +1001,8 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
*/
static struct cache_entry *refresh_cache_ent(struct index_state *istate,
struct cache_entry *ce,
- unsigned int options, int *err)
+ unsigned int options, int *err,
+ int *changed_ret)
{
struct stat st;
struct cache_entry *updated;
@@ -1033,6 +1034,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
}
changed = ie_match_stat(istate, ce, &st, options);
+ if (changed_ret)
+ *changed_ret = changed;
if (!changed) {
/*
* The path is unchanged. If we were told to ignore
@@ -1102,14 +1105,21 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
int first = 1;
int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
- const char *needs_update_fmt;
- const char *needs_merge_fmt;
-
- needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
- needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
+ const char *modified_fmt;
+ const char *deleted_fmt;
+ const char *typechange_fmt;
+ const char *added_fmt;
+ const char *unmerged_fmt;
+
+ modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
+ deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n");
+ typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n");
+ added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n");
+ unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new;
int cache_errno = 0;
+ int changed = 0;
ce = istate->cache[i];
if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
@@ -1122,7 +1132,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
i--;
if (allow_unmerged)
continue;
- show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg);
+ show_file(unmerged_fmt, ce->name, in_porcelain, &first, header_msg);
has_errors = 1;
continue;
}
@@ -1130,10 +1140,12 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
continue;
- new = refresh_cache_ent(istate, ce, options, &cache_errno);
+ new = refresh_cache_ent(istate, ce, options, &cache_errno, &changed);
if (new == ce)
continue;
if (!new) {
+ const char *fmt;
+
if (not_new && cache_errno == ENOENT)
continue;
if (really && cache_errno == EINVAL) {
@@ -1145,7 +1157,17 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
}
if (quiet)
continue;
- show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg);
+
+ if (cache_errno == ENOENT)
+ fmt = deleted_fmt;
+ else if (ce->ce_flags & CE_INTENT_TO_ADD)
+ fmt = added_fmt; /* must be before other checks */
+ else if (changed & TYPE_CHANGED)
+ fmt = typechange_fmt;
+ else
+ fmt = modified_fmt;
+ show_file(fmt,
+ ce->name, in_porcelain, &first, header_msg);
has_errors = 1;
continue;
}
@@ -1157,7 +1179,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
{
- return refresh_cache_ent(&the_index, ce, really, NULL);
+ return refresh_cache_ent(&the_index, ce, really, NULL, NULL);
}
static int verify_hdr(struct cache_header *hdr, unsigned long size)
diff --git a/refs.c b/refs.c
index e69ba26..e7843eb 100644
--- a/refs.c
+++ b/refs.c
@@ -48,7 +48,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
}
static void add_ref(const char *name, const unsigned char *sha1,
- int flag, struct ref_array *refs,
+ int flag, int check_name, struct ref_array *refs,
struct ref_entry **new_entry)
{
int len;
@@ -59,7 +59,8 @@ static void add_ref(const char *name, const unsigned char *sha1,
entry = xmalloc(sizeof(struct ref_entry) + len);
hashcpy(entry->sha1, sha1);
hashclr(entry->peeled);
- if (check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
+ if (check_name &&
+ check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
die("Reference has invalid format: '%s'", name);
memcpy(entry->name, name, len);
entry->flag = flag;
@@ -234,7 +235,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
name = parse_ref_line(refline, sha1);
if (name) {
- add_ref(name, sha1, flag, array, &last);
+ add_ref(name, sha1, flag, 1, array, &last);
continue;
}
if (last &&
@@ -249,7 +250,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
void add_extra_ref(const char *name, const unsigned char *sha1, int flag)
{
- add_ref(name, sha1, flag, &extra_refs, NULL);
+ add_ref(name, sha1, flag, 0, &extra_refs, NULL);
}
void clear_extra_refs(void)
@@ -333,12 +334,11 @@ static void get_ref_dir(const char *submodule, const char *base,
hashclr(sha1);
flag |= REF_ISBROKEN;
}
- } else
- if (!resolve_ref(ref, sha1, 1, &flag)) {
- hashclr(sha1);
- flag |= REF_ISBROKEN;
- }
- add_ref(ref, sha1, flag, array, NULL);
+ } else if (!resolve_ref(ref, sha1, 1, &flag)) {
+ hashclr(sha1);
+ flag |= REF_ISBROKEN;
+ }
+ add_ref(ref, sha1, flag, 1, array, NULL);
}
free(ref);
closedir(dir);
diff --git a/remote.c b/remote.c
index 2f62c9a..e2ef991 100644
--- a/remote.c
+++ b/remote.c
@@ -803,59 +803,56 @@ static int match_name_with_pattern(const char *key, const char *name,
return ret;
}
-char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
- const char *name)
+static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
{
int i;
- char *ret = NULL;
- for (i = 0; i < nr_refspec; i++) {
- struct refspec *refspec = refspecs + i;
- if (refspec->pattern) {
- if (match_name_with_pattern(refspec->src, name,
- refspec->dst, &ret))
- return ret;
- } else if (!strcmp(refspec->src, name))
- return xstrdup(refspec->dst);
- }
- return NULL;
-}
+ int find_src = !query->src;
-int remote_find_tracking(struct remote *remote, struct refspec *refspec)
-{
- int find_src = refspec->src == NULL;
- char *needle, **result;
- int i;
+ if (find_src && !query->dst)
+ return error("query_refspecs: need either src or dst");
- if (find_src) {
- if (!refspec->dst)
- return error("find_tracking: need either src or dst");
- needle = refspec->dst;
- result = &refspec->src;
- } else {
- needle = refspec->src;
- result = &refspec->dst;
- }
+ for (i = 0; i < ref_count; i++) {
+ 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;
- for (i = 0; i < remote->fetch_refspec_nr; i++) {
- struct refspec *fetch = &remote->fetch[i];
- const char *key = find_src ? fetch->dst : fetch->src;
- const char *value = find_src ? fetch->src : fetch->dst;
- if (!fetch->dst)
+ if (!refspec->dst)
continue;
- if (fetch->pattern) {
+ if (refspec->pattern) {
if (match_name_with_pattern(key, needle, value, result)) {
- refspec->force = fetch->force;
+ query->force = refspec->force;
return 0;
}
} else if (!strcmp(needle, key)) {
*result = xstrdup(value);
- refspec->force = fetch->force;
+ query->force = refspec->force;
return 0;
}
}
return -1;
}
+char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
+ const char *name)
+{
+ struct refspec query;
+
+ memset(&query, 0, sizeof(struct refspec));
+ query.src = (char *)name;
+
+ if (query_refspecs(refspecs, nr_refspec, &query))
+ return NULL;
+
+ return query.dst;
+}
+
+int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+{
+ return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec);
+}
+
static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
const char *name)
{
@@ -1659,36 +1656,47 @@ struct ref *guess_remote_head(const struct ref *head,
}
struct stale_heads_info {
- struct remote *remote;
struct string_list *ref_names;
struct ref **stale_refs_tail;
+ struct refspec *refs;
+ int ref_count;
};
static int get_stale_heads_cb(const char *refname,
const unsigned char *sha1, int flags, void *cb_data)
{
struct stale_heads_info *info = cb_data;
- struct refspec refspec;
- memset(&refspec, 0, sizeof(refspec));
- refspec.dst = (char *)refname;
- if (!remote_find_tracking(info->remote, &refspec)) {
- if (!((flags & REF_ISSYMREF) ||
- string_list_has_string(info->ref_names, refspec.src))) {
- struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
- hashcpy(ref->new_sha1, sha1);
- }
+ struct refspec query;
+ memset(&query, 0, sizeof(struct refspec));
+ query.dst = (char *)refname;
+
+ if (query_refspecs(info->refs, info->ref_count, &query))
+ return 0; /* No matches */
+
+ /*
+ * If we did find a suitable refspec and it's not a symref and
+ * it's not in the list of refs that currently exist in that
+ * remote we consider it to be stale.
+ */
+ if (!((flags & REF_ISSYMREF) ||
+ string_list_has_string(info->ref_names, query.src))) {
+ struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
+ hashcpy(ref->new_sha1, sha1);
}
+
+ free(query.src);
return 0;
}
-struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map)
+struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map)
{
struct ref *ref, *stale_refs = NULL;
struct string_list ref_names = STRING_LIST_INIT_NODUP;
struct stale_heads_info info;
- info.remote = remote;
info.ref_names = &ref_names;
info.stale_refs_tail = &stale_refs;
+ info.refs = refs;
+ info.ref_count = ref_count;
for (ref = fetch_map; ref; ref = ref->next)
string_list_append(&ref_names, ref->name);
sort_string_list(&ref_names);
diff --git a/remote.h b/remote.h
index 6729477..b395598 100644
--- a/remote.h
+++ b/remote.h
@@ -164,6 +164,6 @@ struct ref *guess_remote_head(const struct ref *head,
int all);
/* Return refs which no longer exist on remote */
-struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map);
+struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map);
#endif
diff --git a/sequencer.h b/sequencer.h
index 905d295..f435fdb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -13,7 +13,7 @@
*
* With the aggressive flag, it additionally removes SEQ_OLD_DIR,
* ignoring any errors. Inteded to be used by the sequencer's
- * '--reset' subcommand.
+ * '--quit' subcommand.
*/
void remove_sequencer_state(int aggressive);
diff --git a/sha1_file.c b/sha1_file.c
index 27f3b9b..956422b 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1267,7 +1267,8 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
while (c & 0x80) {
if (len <= used || bitsizeof(long) <= shift) {
error("bad object header");
- return 0;
+ size = used = 0;
+ break;
}
c = buf[used++];
size += (c & 0x7f) << shift;
@@ -2616,7 +2617,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
if ((type == OBJ_BLOB) && path) {
struct strbuf nbuf = STRBUF_INIT;
if (convert_to_git(path, buf, size, &nbuf,
- write_object ? safe_crlf : 0)) {
+ write_object ? safe_crlf : SAFE_CRLF_FALSE)) {
buf = strbuf_detach(&nbuf, &size);
re_allocated = 1;
}
diff --git a/submodule.c b/submodule.c
index 0fd10a0..52cdcc6 100644
--- a/submodule.c
+++ b/submodule.c
@@ -391,7 +391,7 @@ static void commit_need_pushing(struct commit *commit, struct commit_list *paren
rev.diffopt.format_callback_data = needs_pushing;
diff_tree_combined(commit->object.sha1, parents, n, 1, &rev);
- free(parents);
+ free((void *)parents);
}
int check_submodule_needs_pushing(unsigned char new_sha1[20], const char *remotes_name)
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
index 292753f..21d11d6 100644
--- a/t/gitweb-lib.sh
+++ b/t/gitweb-lib.sh
@@ -16,6 +16,7 @@ our \$projectroot = "$safe_pwd";
our \$project_maxdepth = 8;
our \$home_link_str = 'projects';
our \$site_name = '[localhost]';
+our \$site_html_head_string = '';
our \$site_header = '';
our \$site_footer = '';
our \$home_text = 'indextext.html';
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 2f5eada..bc73c20 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -75,6 +75,11 @@ test_expect_success \
git branch l'
test_expect_success \
+ 'git branch -m dumps usage' \
+ 'test_expect_code 129 git branch -m 2>err &&
+ grep "[Uu]sage: git branch" err'
+
+test_expect_success \
'git branch -m m m/m should work' \
'git branch -l m &&
git branch -m m m/m &&
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index cb45574..ee1659c 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -253,6 +253,60 @@ test_expect_success 'revert also handles conflicts sanely' '
test_cmp expected actual
'
+test_expect_success 'failed revert sets REVERT_HEAD' '
+ pristine_detach initial &&
+ test_must_fail git revert picked &&
+ test_cmp_rev picked REVERT_HEAD
+'
+
+test_expect_success 'successful revert does not set REVERT_HEAD' '
+ pristine_detach base &&
+ git revert base &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+ test_must_fail git rev-parse --verify REVERT_HEAD
+'
+
+test_expect_success 'revert --no-commit sets REVERT_HEAD' '
+ pristine_detach base &&
+ git revert --no-commit base &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+ test_cmp_rev base REVERT_HEAD
+'
+
+test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
+ pristine_detach base &&
+ echo foo > foo &&
+ test_must_fail git revert base &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+ test_must_fail git rev-parse --verify REVERT_HEAD
+'
+
+test_expect_success 'GIT_CHERRY_PICK_HELP does not suppress REVERT_HEAD' '
+ pristine_detach initial &&
+ (
+ GIT_CHERRY_PICK_HELP="and then do something else" &&
+ GIT_REVERT_HELP="and then do something else, again" &&
+ export GIT_CHERRY_PICK_HELP GIT_REVERT_HELP &&
+ test_must_fail git revert picked
+ ) &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+ test_cmp_rev picked REVERT_HEAD
+'
+
+test_expect_success 'git reset clears REVERT_HEAD' '
+ pristine_detach initial &&
+ test_must_fail git revert picked &&
+ git reset &&
+ test_must_fail git rev-parse --verify REVERT_HEAD
+'
+
+test_expect_success 'failed commit does not clear REVERT_HEAD' '
+ pristine_detach initial &&
+ test_must_fail git revert picked &&
+ test_must_fail git commit &&
+ test_cmp_rev picked REVERT_HEAD
+'
+
test_expect_success 'revert conflict, diff3 -m style' '
pristine_detach initial &&
git config merge.conflictstyle diff3 &&
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 3bca2b3..2c4c1c8 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -2,6 +2,7 @@
test_description='Test cherry-pick continuation features
+ + yetanotherpick: rewrites foo to e
+ anotherpick: rewrites foo to d
+ picked: rewrites foo to c
+ unrelatedpick: rewrites unrelated to reallyunrelated
@@ -13,12 +14,18 @@ test_description='Test cherry-pick continuation features
. ./test-lib.sh
pristine_detach () {
- git cherry-pick --reset &&
+ git cherry-pick --quit &&
git checkout -f "$1^0" &&
git read-tree -u --reset HEAD &&
git clean -d -f -f -q -x
}
+test_cmp_rev () {
+ git rev-parse --verify "$1" >expect.rev &&
+ git rev-parse --verify "$2" >actual.rev &&
+ test_cmp expect.rev actual.rev
+}
+
test_expect_success setup '
echo unrelated >unrelated &&
git add unrelated &&
@@ -27,6 +34,7 @@ test_expect_success setup '
test_commit unrelatedpick unrelated reallyunrelated &&
test_commit picked foo c &&
test_commit anotherpick foo d &&
+ test_commit yetanotherpick foo e &&
git config advice.detachedhead false
'
@@ -70,18 +78,117 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
test_path_is_missing .git/sequencer
'
-test_expect_success '--reset does not complain when no cherry-pick is in progress' '
+test_expect_success '--quit does not complain when no cherry-pick is in progress' '
pristine_detach initial &&
- git cherry-pick --reset
+ git cherry-pick --quit
'
-test_expect_success '--reset cleans up sequencer state' '
+test_expect_success '--abort requires cherry-pick in progress' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick --abort
+'
+
+test_expect_success '--quit cleans up sequencer state' '
pristine_detach initial &&
test_must_fail git cherry-pick base..picked &&
- git cherry-pick --reset &&
+ git cherry-pick --quit &&
test_path_is_missing .git/sequencer
'
+test_expect_success '--quit keeps HEAD and conflicted index intact' '
+ pristine_detach initial &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :100644 100644 OBJID OBJID M unrelated
+ OBJID
+ :000000 100644 OBJID OBJID A foo
+ :000000 100644 OBJID OBJID A unrelated
+ EOF
+ test_must_fail git cherry-pick base..picked &&
+ git cherry-pick --quit &&
+ test_path_is_missing .git/sequencer &&
+ test_must_fail git update-index --refresh &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--abort to cancel multiple cherry-pick' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ git cherry-pick --abort &&
+ test_path_is_missing .git/sequencer &&
+ test_cmp_rev initial HEAD &&
+ git update-index --refresh &&
+ git diff-index --exit-code HEAD
+'
+
+test_expect_success '--abort to cancel single cherry-pick' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick picked &&
+ git cherry-pick --abort &&
+ test_path_is_missing .git/sequencer &&
+ test_cmp_rev initial HEAD &&
+ git update-index --refresh &&
+ git diff-index --exit-code HEAD
+'
+
+test_expect_success 'cherry-pick --abort to cancel multiple revert' '
+ pristine_detach anotherpick &&
+ test_must_fail git revert base..picked &&
+ git cherry-pick --abort &&
+ test_path_is_missing .git/sequencer &&
+ test_cmp_rev anotherpick HEAD &&
+ git update-index --refresh &&
+ git diff-index --exit-code HEAD
+'
+
+test_expect_success 'revert --abort works, too' '
+ pristine_detach anotherpick &&
+ test_must_fail git revert base..picked &&
+ git revert --abort &&
+ test_path_is_missing .git/sequencer &&
+ test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success '--abort to cancel single revert' '
+ pristine_detach anotherpick &&
+ test_must_fail git revert picked &&
+ git revert --abort &&
+ test_path_is_missing .git/sequencer &&
+ test_cmp_rev anotherpick HEAD &&
+ git update-index --refresh &&
+ git diff-index --exit-code HEAD
+'
+
+test_expect_success '--abort keeps unrelated change, easy case' '
+ pristine_detach unrelatedpick &&
+ echo changed >expect &&
+ test_must_fail git cherry-pick picked..yetanotherpick &&
+ echo changed >unrelated &&
+ git cherry-pick --abort &&
+ test_cmp expect unrelated
+'
+
+test_expect_success '--abort refuses to clobber unrelated change, harder case' '
+ pristine_detach initial &&
+ echo changed >expect &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ echo changed >unrelated &&
+ test_must_fail git cherry-pick --abort &&
+ test_cmp expect unrelated &&
+ git rev-list HEAD >log &&
+ test_line_count = 2 log &&
+ test_must_fail git update-index --refresh &&
+
+ git checkout unrelated &&
+ git cherry-pick --abort &&
+ test_cmp_rev initial HEAD
+'
+
test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '
pristine_detach initial &&
test_must_fail git cherry-pick base..picked &&
@@ -106,6 +213,16 @@ test_expect_success 'cherry-pick cleans up sequencer state when one commit is le
test_cmp expect actual
'
+test_expect_failure '--abort after last commit in sequence' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..picked &&
+ git cherry-pick --abort &&
+ test_path_is_missing .git/sequencer &&
+ test_cmp_rev initial HEAD &&
+ git update-index --refresh &&
+ git diff-index --exit-code HEAD
+'
+
test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
pristine_detach initial &&
test_must_fail git cherry-pick base..anotherpick &&
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index b68c56b..4bd2a1c 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -105,7 +105,7 @@ test_expect_funcname () {
grep "^@@.*@@ $1" diff
}
-for p in bibtex cpp csharp fortran html java objc pascal perl php python ruby tex
+for p in bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex
do
test_expect_success "builtin $p pattern compiles" '
echo "*.java diff=$p" >.gitattributes &&
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index c374aa4..6f1e5a2 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -299,6 +299,7 @@ test_language_driver csharp
test_language_driver fortran
test_language_driver html
test_language_driver java
+test_language_driver matlab
test_language_driver objc
test_language_driver pascal
test_language_driver perl
diff --git a/t/t4034/matlab/expect b/t/t4034/matlab/expect
new file mode 100644
index 0000000..72cf3e9
--- /dev/null
+++ b/t/t4034/matlab/expect
@@ -0,0 +1,14 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index dc204db..70e05f0 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,9 +1,9 @@<RESET>
+(<RED>1<RESET><GREEN>0<RESET>) (<RED>-1e10<RESET><GREEN>-0e10<RESET>) '<RED>b<RESET><GREEN>y<RESET>';
+[<RED>a<RESET><GREEN>x<RESET>] {<RED>a<RESET><GREEN>x<RESET>} <RED>a<RESET><GREEN>x<RESET>.<RED>b<RESET><GREEN>y<RESET>;
+~<RED>a<RESET><GREEN>x<RESET>;
+<RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>.*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>./<RED>b a<RESET><GREEN>y x<RESET>^<RED>b a<RESET><GREEN>y x<RESET>.^<RED>b a<RESET><GREEN>y x<RESET>.\<RED>b a<RESET><GREEN>y x<RESET>.';
+<RED>a<RESET><GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>;
+<RED>a<RESET><GREEN>x<RESET>&<RED>b a<RESET><GREEN>y x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>|<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET><GREEN>y<RESET>;
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET><GREEN>y<RESET>;
+<RED>a<RESET><GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>~=<RED>b<RESET><GREEN>y<RESET>;
+<RED>a<RESET><GREEN>x<RESET>,<RED>b<RESET><GREEN>y<RESET>;
diff --git a/t/t4034/matlab/post b/t/t4034/matlab/post
new file mode 100644
index 0000000..70e05f0
--- /dev/null
+++ b/t/t4034/matlab/post
@@ -0,0 +1,9 @@
+(0) (-0e10) 'y';
+[x] {x} x.y;
+~x;
+x*y x.*y x/y x./y x^y x.^y x.\y x.';
+x+y x-y;
+x&y x&&y x|y x||y;
+x<y x<=y x>y x>=y;
+x==y x~=y;
+x,y;
diff --git a/t/t4034/matlab/pre b/t/t4034/matlab/pre
new file mode 100644
index 0000000..dc204db
--- /dev/null
+++ b/t/t4034/matlab/pre
@@ -0,0 +1,9 @@
+(1) (-1e10) 'b';
+[a] {a} a.b;
+~a;
+a*b a.*b a/b a./b a^b a.^b a.\b a.';
+a+b a-b;
+a&b a&&b a|b a||b;
+a<b a<=b a>b a>=b;
+a==b a~=b;
+a,b;
diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh
index b5ced84..1bc57ac 100755
--- a/t/t5501-fetch-push-alternates.sh
+++ b/t/t5501-fetch-push-alternates.sh
@@ -28,7 +28,7 @@ test_expect_success setup '
done
) &&
(
- git clone --reference=original "file:///$(pwd)/original" one &&
+ git clone --reference=original "file://$(pwd)/original" one &&
cd one &&
echo Z >count &&
git add count &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 7e433b1..e0af4c4 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -76,6 +76,56 @@ test_expect_success "fetch test for-merge" '
cut -f -2 .git/FETCH_HEAD >actual &&
test_cmp expected actual'
+test_expect_success 'fetch --prune on its own works as expected' '
+ cd "$D" &&
+ git clone . prune &&
+ cd prune &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune origin &&
+ test_must_fail git rev-parse origin/extrabranch
+'
+
+test_expect_success 'fetch --prune with a branch name keeps branches' '
+ cd "$D" &&
+ git clone . prune-branch &&
+ cd prune-branch &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune origin master &&
+ git rev-parse origin/extrabranch
+'
+
+test_expect_success 'fetch --prune with a namespace keeps other namespaces' '
+ cd "$D" &&
+ git clone . prune-namespace &&
+ cd prune-namespace &&
+
+ git fetch --prune origin refs/heads/a/*:refs/remotes/origin/a/* &&
+ git rev-parse origin/master
+'
+
+test_expect_success 'fetch --prune --tags does not delete the remote-tracking branches' '
+ cd "$D" &&
+ git clone . prune-tags &&
+ cd prune-tags &&
+ git fetch origin refs/heads/master:refs/tags/sometag &&
+
+ git fetch --prune --tags origin &&
+ git rev-parse origin/master &&
+ test_must_fail git rev-parse somebranch
+'
+
+test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' '
+ cd "$D" &&
+ git clone . prune-tags-branch &&
+ cd prune-tags-branch &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune --tags origin master &&
+ git rev-parse origin/extrabranch
+'
+
test_expect_success 'fetch tags when there is no tags' '
cd "$D" &&
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 895f559..c4c375a 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -146,4 +146,11 @@ test_expect_success 'cloning with reference being subset of source (-l -s)' \
cd "$base_dir"
+test_expect_success 'clone with reference from a tagged repository' '
+ (
+ cd A && git tag -a -m 'tagged' HEAD
+ ) &&
+ git clone --reference=A A I
+'
+
test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index c6f1f9f..691e4a4 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -164,7 +164,7 @@ test_expect_success 'bisect start: existing ".git/BISECT_START" not modified if
cp .git/BISECT_START saved &&
test_must_fail git bisect start $HASH4 foo -- &&
git branch > branch.output &&
- grep "* (no branch)" branch.output > /dev/null &&
+ test_i18ngrep "* (no branch)" branch.output > /dev/null &&
test_cmp saved .git/BISECT_START
'
test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
diff --git a/t/t7106-reset-sequence.sh b/t/t7106-reset-sequence.sh
index 4956caa..83f7ea5 100755
--- a/t/t7106-reset-sequence.sh
+++ b/t/t7106-reset-sequence.sh
@@ -12,7 +12,7 @@ test_description='Test interaction of reset --hard with sequencer
. ./test-lib.sh
pristine_detach () {
- git cherry-pick --reset &&
+ git cherry-pick --quit &&
git checkout -f "$1^0" &&
git read-tree -u --reset HEAD &&
git clean -d -f -f -q -x
@@ -41,4 +41,12 @@ test_expect_success 'reset --hard cleans up sequencer state, providing one-level
test_path_is_missing .git/sequencer-old
'
+test_expect_success 'cherry-pick --abort does not leave sequencer-old dir' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ git cherry-pick --abort &&
+ test_path_is_missing .git/sequencer &&
+ test_path_is_missing .git/sequencer-old
+'
+
test_done
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 905255a..fc57b13 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -189,7 +189,7 @@ test_expect_success 'status with gitignore' '
# untracked
EOF
git status --ignored >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success 'status with gitignore (nothing untracked)' '
@@ -247,7 +247,7 @@ test_expect_success 'status with gitignore (nothing untracked)' '
# untracked
EOF
git status --ignored >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
rm -f .gitignore
diff --git a/t/t7511-status-index.sh b/t/t7511-status-index.sh
new file mode 100755
index 0000000..b5fdc04
--- /dev/null
+++ b/t/t7511-status-index.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='git status with certain file name lengths'
+
+. ./test-lib.sh
+
+files="0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z"
+
+check() {
+ len=$1
+ prefix=$2
+
+ for i in $files
+ do
+ : >$prefix$i
+ done
+
+ test_expect_success "status, filename length $len" "
+ git add $prefix* &&
+ git status
+ "
+ rm $prefix* .git/index
+}
+
+check 1
+check 2 p
+check 3 px
+check 4 pre
+check 5 pref
+check 6 prefi
+check 7 prefix
+check 8 prefix-
+check 9 prefix-p
+check 10 prefix-pr
+check 11 prefix-pre
+check 12 prefix-pref
+check 13 prefix-prefi
+check 14 prefix-prefix
+check 15 prefix-prefix-
+check 16 prefix-prefix-p
+check 17 prefix-prefix-pr
+check 18 prefix-prefix-pre
+check 19 prefix-prefix-pref
+check 20 prefix-prefix-prefi
+check 21 prefix-prefix-prefix
+check 22 prefix-prefix-prefix-
+check 23 prefix-prefix-prefix-p
+check 24 prefix-prefix-prefix-pr
+
+test_done
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 32ec82a..4ee42f1 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -15,6 +15,7 @@ EOF
chmod +x helper
test_expect_success 'setup ' '
+ echo "bin: test number 0" >zero.bin &&
echo "bin: test 1" >one.bin &&
echo "bin: test number 2" >two.bin &&
if test_have_prereq SYMLINKS; then
@@ -43,6 +44,7 @@ test_expect_success 'no filter specified' '
test_expect_success 'setup textconv filters' '
echo "*.bin diff=test" >.gitattributes &&
+ echo "zero.bin eol=crlf" >>.gitattributes &&
git config diff.test.textconv ./helper &&
git config diff.test.cachetextconv false
'
@@ -74,6 +76,15 @@ test_expect_success 'blame --textconv going through revisions' '
test_cmp expected result
'
+test_expect_success 'blame --textconv with local changes' '
+ test_when_finished "git checkout zero.bin" &&
+ printf "bin: updated number 0\015" >zero.bin &&
+ git blame --textconv zero.bin >blame &&
+ expect="(Not Committed Yet ....-..-.. ..:..:.. +0000 1)" &&
+ expect="$expect converted: updated number 0" &&
+ expr "$(find_blame <blame)" : "^$expect"
+'
+
test_expect_success 'setup +cachetextconv' '
git config diff.test.cachetextconv true
'
diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh
index 3787186..435d896 100755
--- a/t/t9700-perl-git.sh
+++ b/t/t9700-perl-git.sh
@@ -43,7 +43,11 @@ test_expect_success \
git config --add test.booltrue true &&
git config --add test.boolfalse no &&
git config --add test.boolother other &&
- git config --add test.int 2k
+ git config --add test.int 2k &&
+ git config --add test.path "~/foo" &&
+ git config --add test.pathexpanded "$HOME/foo" &&
+ git config --add test.pathmulti foo &&
+ git config --add test.pathmulti bar
'
# The external test will outputs its own plan
diff --git a/t/t9700/test.pl b/t/t9700/test.pl
index 13ba96e..3b9b484 100755
--- a/t/t9700/test.pl
+++ b/t/t9700/test.pl
@@ -33,6 +33,10 @@ is($r->config_int("test.int"), 2048, "config_int: integer");
is($r->config_int("test.nonexistent"), undef, "config_int: nonexistent");
ok($r->config_bool("test.booltrue"), "config_bool: true");
ok(!$r->config_bool("test.boolfalse"), "config_bool: false");
+is($r->config_path("test.path"), $r->config("test.pathexpanded"),
+ "config_path: ~/foo expansion");
+is_deeply([$r->config_path("test.pathmulti")], ["foo", "bar"],
+ "config_path: multiple values");
our $ansi_green = "\x1b[32m";
is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color");
# Cannot test $r->get_colorbool("color.foo")) because we do not
diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh
index 3b358ef..992bb8c 100755
--- a/t/t9802-git-p4-filetype.sh
+++ b/t/t9802-git-p4-filetype.sh
@@ -101,6 +101,37 @@ test_expect_success 'keyword file test' '
)
'
+build_gendouble() {
+ cat >gendouble.py <<-\EOF
+ import sys
+ import struct
+ import array
+
+ s = array.array("c", '\0' * 26)
+ struct.pack_into(">L", s, 0, 0x00051607) # AppleDouble
+ struct.pack_into(">L", s, 4, 0x00020000) # version 2
+ s.tofile(sys.stdout)
+ EOF
+}
+
+test_expect_success 'ignore apple' '
+ test_when_finished rm -f gendouble.py &&
+ build_gendouble &&
+ (
+ cd "$cli" &&
+ test-genrandom apple 1024 >double.png &&
+ "$PYTHON_PATH" "$TRASH_DIRECTORY/gendouble.py" >%double.png &&
+ p4 add -t apple double.png &&
+ p4 submit -d appledouble
+ ) &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot@all &&
+ (
+ cd "$git" &&
+ test ! -f double.png
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9805-skip-submit-edit.sh b/t/t9805-skip-submit-edit.sh
new file mode 100755
index 0000000..734ccf2
--- /dev/null
+++ b/t/t9805-skip-submit-edit.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+test_description='git-p4 skipSubmitEdit config variables'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+test_expect_success 'init depot' '
+ (
+ cd "$cli" &&
+ echo file1 >file1 &&
+ p4 add file1 &&
+ p4 submit -d "change 1"
+ )
+'
+
+# this works because EDITOR is set to :
+test_expect_success 'no config, unedited, say yes' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ echo line >>file1 &&
+ git commit -a -m "change 2" &&
+ echo y | "$GITP4" submit &&
+ p4 changes //depot/... >wc &&
+ test_line_count = 2 wc
+ )
+'
+
+test_expect_success 'no config, unedited, say no' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ echo line >>file1 &&
+ git commit -a -m "change 3 (not really)" &&
+ printf "bad response\nn\n" | "$GITP4" submit
+ p4 changes //depot/... >wc &&
+ test_line_count = 2 wc
+ )
+'
+
+test_expect_success 'skipSubmitEdit' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ # will fail if editor is even invoked
+ git config core.editor /bin/false &&
+ echo line >>file1 &&
+ git commit -a -m "change 3" &&
+ "$GITP4" submit &&
+ p4 changes //depot/... >wc &&
+ test_line_count = 3 wc
+ )
+'
+
+test_expect_success 'skipSubmitEditCheck' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ echo line >>file1 &&
+ git commit -a -m "change 4" &&
+ "$GITP4" submit &&
+ p4 changes //depot/... >wc &&
+ test_line_count = 4 wc
+ )
+'
+
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample
index b187c4b..18c4829 100755
--- a/templates/hooks--pre-commit.sample
+++ b/templates/hooks--pre-commit.sample
@@ -18,6 +18,9 @@ fi
# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)
+# Redirect output to stderr.
+exec 1>&2
+
# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
@@ -25,8 +28,8 @@ if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
- test "$(git diff --cached --name-only --diff-filter=A -z $against |
- LC_ALL=C tr -d '[ -~]\0')"
+ test $(git diff --cached --name-only --diff-filter=A -z $against |
+ LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
echo "Error: Attempt to add a non-ascii file name."
echo
@@ -43,4 +46,5 @@ then
exit 1
fi
+# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --
diff --git a/tree-diff.c b/tree-diff.c
index b3cc2e4..7a51d09 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -21,8 +21,8 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
sha1 = tree_entry_extract(t1, &path1, &mode1);
sha2 = tree_entry_extract(t2, &path2, &mode2);
- pathlen1 = tree_entry_len(path1, sha1);
- pathlen2 = tree_entry_len(path2, sha2);
+ pathlen1 = tree_entry_len(&t1->entry);
+ pathlen2 = tree_entry_len(&t2->entry);
cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
if (cmp < 0) {
show_entry(opt, "-", t1, base);
@@ -64,14 +64,14 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
static void show_tree(struct diff_options *opt, const char *prefix,
struct tree_desc *desc, struct strbuf *base)
{
- int match = 0;
+ enum interesting match = entry_not_interesting;
for (; desc->size; update_tree_entry(desc)) {
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&desc->entry, base, 0,
&opt->pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
show_entry(opt, prefix, desc, base);
@@ -85,7 +85,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
unsigned mode;
const char *path;
const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
- int pathlen = tree_entry_len(path, sha1);
+ int pathlen = tree_entry_len(&desc->entry);
int old_baselen = base->len;
strbuf_add(base, path, pathlen);
@@ -114,12 +114,13 @@ static void show_entry(struct diff_options *opt, const char *prefix,
}
static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
- struct diff_options *opt, int *match)
+ struct diff_options *opt,
+ enum interesting *match)
{
while (t->size) {
*match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
if (*match) {
- if (*match < 0)
+ if (*match == all_entries_not_interesting)
t->size = 0;
break;
}
@@ -132,7 +133,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
{
struct strbuf base;
int baselen = strlen(base_str);
- int t1_match = 0, t2_match = 0;
+ enum interesting t1_match = entry_not_interesting;
+ enum interesting t2_match = entry_not_interesting;
/* Enable recursion indefinitely */
opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
diff --git a/tree-walk.c b/tree-walk.c
index 418107e..f82dba6 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -116,7 +116,7 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
{
- int len = tree_entry_len(n->path, n->sha1);
+ int len = tree_entry_len(n);
int pathlen = info->pathlen;
path[pathlen + len] = 0;
@@ -126,7 +126,7 @@ char *make_traverse_path(char *path, const struct traverse_info *info, const str
break;
path[--pathlen] = '/';
n = &info->name;
- len = tree_entry_len(n->path, n->sha1);
+ len = tree_entry_len(n);
info = info->prev;
pathlen -= len;
}
@@ -253,7 +253,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
* The caller wants "first" from this tree, or nothing.
*/
path = a->path;
- len = tree_entry_len(a->path, a->sha1);
+ len = tree_entry_len(a);
switch (check_entry_match(first, first_len, path, len)) {
case -1:
entry_clear(a);
@@ -271,7 +271,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
while (probe.size) {
entry_extract(&probe, a);
path = a->path;
- len = tree_entry_len(a->path, a->sha1);
+ len = tree_entry_len(a);
switch (check_entry_match(first, first_len, path, len)) {
case -1:
entry_clear(a);
@@ -362,7 +362,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
e = entry + i;
if (!e->path)
continue;
- len = tree_entry_len(e->path, e->sha1);
+ len = tree_entry_len(e);
if (!first) {
first = e->path;
first_len = len;
@@ -381,7 +381,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
/* Cull the ones that are not the earliest */
if (!e->path)
continue;
- len = tree_entry_len(e->path, e->sha1);
+ len = tree_entry_len(e);
if (name_compare(e->path, len, first, first_len))
entry_clear(e);
}
@@ -434,8 +434,8 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
int entrylen, cmp;
sha1 = tree_entry_extract(t, &entry, mode);
+ entrylen = tree_entry_len(&t->entry);
update_tree_entry(t);
- entrylen = tree_entry_len(entry, sha1);
if (entrylen > namelen)
continue;
cmp = memcmp(name, entry, entrylen);
@@ -465,7 +465,6 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
int retval;
void *tree;
unsigned long size;
- struct tree_desc t;
unsigned char root[20];
tree = read_object_with_reference(tree_sha1, tree_type, &size, root);
@@ -478,8 +477,13 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
return 0;
}
- init_tree_desc(&t, tree, size);
- retval = find_tree_entry(&t, name, sha1, mode);
+ if (!size) {
+ retval = -1;
+ } else {
+ struct tree_desc t;
+ init_tree_desc(&t, tree, size);
+ retval = find_tree_entry(&t, name, sha1, mode);
+ }
free(tree);
return retval;
}
@@ -573,30 +577,26 @@ static int match_dir_prefix(const char *base,
*
* Pre-condition: either baselen == base_offset (i.e. empty path)
* or base[baselen-1] == '/' (i.e. with trailing slash).
- *
- * Return:
- * - 2 for "yes, and all subsequent entries will be"
- * - 1 for yes
- * - zero for no
- * - negative for "no, and no subsequent entries will be either"
*/
-int tree_entry_interesting(const struct name_entry *entry,
- struct strbuf *base, int base_offset,
- const struct pathspec *ps)
+enum interesting tree_entry_interesting(const struct name_entry *entry,
+ struct strbuf *base, int base_offset,
+ const struct pathspec *ps)
{
int i;
int pathlen, baselen = base->len - base_offset;
- int never_interesting = ps->has_wildcard ? 0 : -1;
+ int never_interesting = ps->has_wildcard ?
+ entry_not_interesting : all_entries_not_interesting;
if (!ps->nr) {
if (!ps->recursive || ps->max_depth == -1)
- return 2;
- return !!within_depth(base->buf + base_offset, baselen,
- !!S_ISDIR(entry->mode),
- ps->max_depth);
+ return all_entries_interesting;
+ return within_depth(base->buf + base_offset, baselen,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth) ?
+ entry_interesting : entry_not_interesting;
}
- pathlen = tree_entry_len(entry->path, entry->sha1);
+ pathlen = tree_entry_len(entry);
for (i = ps->nr - 1; i >= 0; i--) {
const struct pathspec_item *item = ps->items+i;
@@ -610,12 +610,13 @@ int tree_entry_interesting(const struct name_entry *entry,
goto match_wildcards;
if (!ps->recursive || ps->max_depth == -1)
- return 2;
+ return all_entries_interesting;
- return !!within_depth(base_str + matchlen + 1,
- baselen - matchlen - 1,
- !!S_ISDIR(entry->mode),
- ps->max_depth);
+ return within_depth(base_str + matchlen + 1,
+ baselen - matchlen - 1,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth) ?
+ entry_interesting : entry_not_interesting;
}
/* Either there must be no base, or the base must match. */
@@ -623,25 +624,25 @@ int tree_entry_interesting(const struct name_entry *entry,
if (match_entry(entry, pathlen,
match + baselen, matchlen - baselen,
&never_interesting))
- return 1;
+ return entry_interesting;
- if (ps->items[i].use_wildcard) {
+ if (item->use_wildcard) {
if (!fnmatch(match + baselen, entry->path, 0))
- return 1;
+ return entry_interesting;
/*
* Match all directories. We'll try to
* match files later on.
*/
if (ps->recursive && S_ISDIR(entry->mode))
- return 1;
+ return entry_interesting;
}
continue;
}
match_wildcards:
- if (!ps->items[i].use_wildcard)
+ if (!item->use_wildcard)
continue;
/*
@@ -653,7 +654,7 @@ match_wildcards:
if (!fnmatch(match, base->buf + base_offset, 0)) {
strbuf_setlen(base, base_offset + baselen);
- return 1;
+ return entry_interesting;
}
strbuf_setlen(base, base_offset + baselen);
@@ -662,7 +663,7 @@ match_wildcards:
* later on.
*/
if (ps->recursive && S_ISDIR(entry->mode))
- return 1;
+ return entry_interesting;
}
return never_interesting; /* No matches */
}
diff --git a/tree-walk.h b/tree-walk.h
index 0089581..2bf0db9 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -20,9 +20,9 @@ static inline const unsigned char *tree_entry_extract(struct tree_desc *desc, co
return desc->entry.sha1;
}
-static inline int tree_entry_len(const char *name, const unsigned char *sha1)
+static inline int tree_entry_len(const struct name_entry *ne)
{
- return (const char *)sha1 - name - 1;
+ return (const char *)ne->sha1 - ne->path - 1;
}
void update_tree_entry(struct tree_desc *);
@@ -58,9 +58,19 @@ extern void setup_traverse_info(struct traverse_info *info, const char *base);
static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
{
- return info->pathlen + tree_entry_len(n->path, n->sha1);
+ return info->pathlen + tree_entry_len(n);
}
-extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);
+/* in general, positive means "kind of interesting" */
+enum interesting {
+ all_entries_not_interesting = -1, /* no, and no subsequent entries will be either */
+ entry_not_interesting = 0,
+ entry_interesting = 1,
+ all_entries_interesting = 2 /* yes, and all subsequent entries will be */
+};
+
+extern enum interesting tree_entry_interesting(const struct name_entry *,
+ struct strbuf *, int,
+ const struct pathspec *ps);
#endif
diff --git a/tree.c b/tree.c
index 698ecf7..676e9f7 100644
--- a/tree.c
+++ b/tree.c
@@ -52,7 +52,8 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
struct tree_desc desc;
struct name_entry entry;
unsigned char sha1[20];
- int len, retval = 0, oldlen = base->len;
+ int len, oldlen = base->len;
+ enum interesting retval = entry_not_interesting;
if (parse_tree(tree))
return -1;
@@ -60,11 +61,11 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
- if (retval != 2) {
+ if (retval != all_entries_interesting) {
retval = tree_entry_interesting(&entry, base, 0, pathspec);
- if (retval < 0)
+ if (retval == all_entries_not_interesting)
break;
- if (retval == 0)
+ if (retval == entry_not_interesting)
continue;
}
@@ -99,7 +100,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
else
continue;
- len = tree_entry_len(entry.path, entry.sha1);
+ len = tree_entry_len(&entry);
strbuf_add(base, entry.path, len);
strbuf_addch(base, '/');
retval = read_tree_1(lookup_tree(sha1),
diff --git a/unpack-trees.c b/unpack-trees.c
index 8282f5e..7c9ecf6 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -446,7 +446,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
newinfo.prev = info;
newinfo.pathspec = info->pathspec;
newinfo.name = *p;
- newinfo.pathlen += tree_entry_len(p->path, p->sha1) + 1;
+ newinfo.pathlen += tree_entry_len(p) + 1;
newinfo.conflicts |= df_conflicts;
for (i = 0; i < n; i++, dirmask >>= 1) {
@@ -495,7 +495,7 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_
ce_len -= pathlen;
ce_name = ce->name + pathlen;
- len = tree_entry_len(n->path, n->sha1);
+ len = tree_entry_len(n);
return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
}
@@ -626,7 +626,7 @@ static int find_cache_pos(struct traverse_info *info,
struct unpack_trees_options *o = info->data;
struct index_state *index = o->src_index;
int pfxlen = info->pathlen;
- int p_len = tree_entry_len(p->path, p->sha1);
+ int p_len = tree_entry_len(p);
for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
struct cache_entry *ce = index->cache[pos];
diff --git a/userdiff.c b/userdiff.c
index bf553ad..7c983c1 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -37,6 +37,9 @@ PATTERNS("java",
"|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
"|[-+*/<>%&^|=!]="
"|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("matlab",
+ "^[[:space:]]*((classdef|function)[[:space:]].*)$|^%%[[:space:]].*$",
+ "[a-zA-Z_][a-zA-Z0-9_]*|[-+0-9.e]+|[=~<>]=|\\.[*/\\^']|\\|\\||&&"),
PATTERNS("objc",
/* Negate C statements that can look like functions */
"!^[ \t]*(do|for|if|else|return|switch|while)\n"
diff --git a/wt-status.c b/wt-status.c
index 8836a52..70fdb76 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -396,7 +396,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
if (s->ignore_submodule_arg) {
DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
- }
+ }
rev.diffopt.format_callback = wt_status_collect_changed_cb;
rev.diffopt.format_callback_data = s;
init_pathspec(&rev.prune_data, s->pathspec);