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.8.txt75
-rw-r--r--Documentation/diff-options.txt2
-rw-r--r--Documentation/gitweb.conf.txt5
-rwxr-xr-xDocumentation/install-doc-quick.sh44
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL29
-rw-r--r--Makefile8
-rw-r--r--builtin/archive.c6
-rw-r--r--builtin/blame.c5
-rw-r--r--builtin/branch.c13
-rw-r--r--builtin/clone.c4
-rw-r--r--builtin/fetch.c33
-rw-r--r--builtin/grep.c37
-rw-r--r--builtin/pack-objects.c74
-rw-r--r--builtin/receive-pack.c17
-rw-r--r--builtin/remote.c7
-rw-r--r--builtin/upload-archive.c68
-rw-r--r--compat/mingw.h2
-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
-rwxr-xr-xcontrib/completion/git-completion.bash13
-rw-r--r--contrib/diff-highlight/README57
-rwxr-xr-xcontrib/diff-highlight/diff-highlight124
-rwxr-xr-xcontrib/fast-import/git-p413
-rw-r--r--contrib/git-jump/README92
-rwxr-xr-xcontrib/git-jump/git-jump69
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki4
-rwxr-xr-xgit-submodule.sh8
-rwxr-xr-xgit-svn.perl4
-rw-r--r--gitweb/INSTALL2
-rw-r--r--gitweb/Makefile6
-rwxr-xr-xgitweb/gitweb.perl9
-rw-r--r--http.c7
-rw-r--r--name-hash.c2
-rw-r--r--perl/Git.pm88
-rw-r--r--pretty.c10
-rw-r--r--read-cache.c6
-rw-r--r--remote.c104
-rw-r--r--remote.h2
-rw-r--r--t/gitweb-lib.sh1
-rwxr-xr-xt/t3200-branch.sh5
-rwxr-xr-xt/t5000-tar-tree.sh10
-rwxr-xr-xt/t5510-fetch.sh50
-rwxr-xr-xt/t6030-bisect-porcelain.sh2
-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-xtemplates/hooks--pre-commit.sample8
54 files changed, 976 insertions, 362 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.8.txt b/Documentation/RelNotes/1.7.8.txt
index d7b2c76..7626fee 100644
--- a/Documentation/RelNotes/1.7.8.txt
+++ b/Documentation/RelNotes/1.7.8.txt
@@ -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,15 @@ 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".
+ * "git upload-archive" (hence "git archive --remote") can be built
+ and used on mingw port of Git.
* "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 +134,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,55 +150,22 @@ 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).
+ * 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).
---
exec >/var/tmp/1
-O=v1.7.7-485-g9ee3d37
+O=v1.7.8-rc1-11-gd7a0129
echo O=$(git describe --always master)
git log --first-parent --oneline --reverse ^$O master
echo
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/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/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 19a142a..cc8a3d2 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-rc1
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..ee34eab 100644
--- a/Makefile
+++ b/Makefile
@@ -515,7 +515,7 @@ 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 += csum-file.h
@@ -1088,6 +1088,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 +1127,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 +1182,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 +1216,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
diff --git a/builtin/archive.c b/builtin/archive.c
index 931956d..e405566 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -87,6 +87,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
const char *exec = "git-upload-archive";
const char *output = NULL;
const char *remote = NULL;
+ int is_remote = 0;
struct option local_opts[] = {
OPT_STRING('o', "output", &output, "file",
"write the archive to this file"),
@@ -94,6 +95,9 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
"retrieve the archive from remote repository <repo>"),
OPT_STRING(0, "exec", &exec, "cmd",
"path to the remote git-upload-archive command"),
+ { OPTION_BOOLEAN, 0, "remote-request", &is_remote, NULL,
+ "indicate we are serving a remote request",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_END()
};
@@ -108,5 +112,5 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- return write_archive(argc, argv, prefix, 1, output, 0);
+ return write_archive(argc, argv, prefix, 1, output, is_remote);
}
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..51ca6a0 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -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 <= 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/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/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/grep.c b/builtin/grep.c
index 7d0779f..3d7329d 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;
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index ba3705d..824ecee 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -454,8 +454,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 +465,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 +536,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 +551,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 +559,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 +572,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 +582,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 +591,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;
}
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/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/upload-archive.c b/builtin/upload-archive.c
index 2d0b383..c57e8bd 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -6,6 +6,7 @@
#include "archive.h"
#include "pkt-line.h"
#include "sideband.h"
+#include "run-command.h"
static const char upload_archive_usage[] =
"git upload-archive <repo>";
@@ -18,28 +19,17 @@ static const char lostchild[] =
#define MAX_ARGS (64)
-static int run_upload_archive(int argc, const char **argv, const char *prefix)
+static void prepare_argv(const char **sent_argv, const char **argv)
{
- const char *sent_argv[MAX_ARGS];
const char *arg_cmd = "argument ";
char *p, buf[4096];
int sent_argc;
int len;
- if (argc != 2)
- usage(upload_archive_usage);
-
- if (strlen(argv[1]) + 1 > sizeof(buf))
- die("insanely long repository name");
-
- strcpy(buf, argv[1]); /* enter-repo smudges its argument */
-
- if (!enter_repo(buf, 0))
- die("'%s' does not appear to be a git repository", buf);
-
/* put received options in sent_argv[] */
- sent_argc = 1;
- sent_argv[0] = "git-upload-archive";
+ sent_argc = 2;
+ sent_argv[0] = "archive";
+ sent_argv[1] = "--remote-request";
for (p = buf;;) {
/* This will die if not enough free space in buf */
len = packet_read_line(0, p, (buf + sizeof buf) - p);
@@ -62,9 +52,6 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix)
*p++ = 0;
}
sent_argv[sent_argc] = NULL;
-
- /* parse all options sent by the client */
- return write_archive(sent_argc, sent_argv, prefix, 0, NULL, 1);
}
__attribute__((format (printf, 1, 2)))
@@ -96,38 +83,25 @@ static ssize_t process_input(int child_fd, int band)
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
{
- pid_t writer;
- int fd1[2], fd2[2];
- /*
- * Set up sideband subprocess.
- *
- * We (parent) monitor and read from child, sending its fd#1 and fd#2
- * multiplexed out to our fd#1. If the child dies, we tell the other
- * end over channel #3.
- */
- if (pipe(fd1) < 0 || pipe(fd2) < 0) {
- int err = errno;
- packet_write(1, "NACK pipe failed on the remote side\n");
- die("upload-archive: %s", strerror(err));
- }
- writer = fork();
- if (writer < 0) {
+ const char *sent_argv[MAX_ARGS];
+ struct child_process cld = { sent_argv };
+ cld.out = cld.err = -1;
+ cld.git_cmd = 1;
+
+ if (argc != 2)
+ usage(upload_archive_usage);
+
+ if (!enter_repo(argv[1], 0))
+ die("'%s' does not appear to be a git repository", argv[1]);
+
+ prepare_argv(sent_argv, argv);
+ if (start_command(&cld)) {
int err = errno;
packet_write(1, "NACK fork failed on the remote side\n");
die("upload-archive: %s", strerror(err));
}
- if (!writer) {
- /* child - connect fd#1 and fd#2 to the pipe */
- dup2(fd1[1], 1);
- dup2(fd2[1], 2);
- close(fd1[1]); close(fd2[1]);
- close(fd1[0]); close(fd2[0]); /* we do not read from pipe */
-
- exit(run_upload_archive(argc, argv, prefix));
- }
/* parent - read from child, multiplex and send out to fd#1 */
- close(fd1[1]); close(fd2[1]); /* we do not write to pipe */
packet_write(1, "ACK\n");
packet_flush(1);
@@ -135,9 +109,9 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
struct pollfd pfd[2];
int status;
- pfd[0].fd = fd1[0];
+ pfd[0].fd = cld.out;
pfd[0].events = POLLIN;
- pfd[1].fd = fd2[0];
+ pfd[1].fd = cld.err;
pfd[1].events = POLLIN;
if (poll(pfd, 2, -1) < 0) {
if (errno != EINTR) {
@@ -156,7 +130,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
if (process_input(pfd[0].fd, 1))
continue;
- if (waitpid(writer, &status, 0) < 0)
+ if (waitpid(cld.pid, &status, 0) < 0)
error_clnt("%s", lostchild);
else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
error_clnt("%s", deadchild);
diff --git a/compat/mingw.h b/compat/mingw.h
index fecf0d0..dfb0e87 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -85,8 +85,6 @@ static inline int symlink(const char *oldpath, const char *newpath)
{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
-static inline pid_t fork(void)
-{ errno = ENOSYS; return -1; }
static inline unsigned int alarm(unsigned int seconds)
{ return 0; }
static inline int fsync(int fd)
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/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 32df141..b7c1edf 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1430,6 +1430,10 @@ _git_gitk ()
_gitk
}
+__git_match_ctag() {
+ awk "/^${1////\\/}/ { print \$1 }" "$2"
+}
+
_git_grep ()
{
__git_has_doubledash && return
@@ -1452,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..b975d67 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -1318,6 +1318,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/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/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..e30df22 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 "
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..008ad72 100644
--- a/http.c
+++ b/http.c
@@ -279,8 +279,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())
@@ -846,7 +844,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 +853,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;
}
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/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/read-cache.c b/read-cache.c
index 01a0e25..5790a91 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1249,9 +1249,9 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
{
- long per_entry;
-
- per_entry = sizeof(struct cache_entry) - sizeof(struct ondisk_cache_entry);
+ size_t fix_size_mem = offsetof(struct cache_entry, name);
+ size_t fix_size_dsk = offsetof(struct ondisk_cache_entry, name);
+ long per_entry = (fix_size_mem - fix_size_dsk + 7) & ~7;
/*
* Alignment can cause differences. This should be "alignof", but
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/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/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index d906898..889842e 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -96,7 +96,7 @@ test_expect_success 'git archive with --output' \
'git archive --output=b4.tar HEAD &&
test_cmp b.tar b4.tar'
-test_expect_success NOT_MINGW 'git archive --remote' \
+test_expect_success 'git archive --remote' \
'git archive --remote=. HEAD >b5.tar &&
test_cmp b.tar b5.tar'
@@ -266,7 +266,7 @@ test_expect_success 'archive --list mentions user filter' '
grep "^bar\$" output
'
-test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' '
+test_expect_success 'archive --list shows only enabled remote filters' '
git archive --list --remote=. >output &&
! grep "^tar\.foo\$" output &&
grep "^bar\$" output
@@ -298,7 +298,7 @@ test_expect_success 'extension matching requires dot' '
test_cmp b.tar config-implicittar.foo
'
-test_expect_success NOT_MINGW 'only enabled filters are available remotely' '
+test_expect_success 'only enabled filters are available remotely' '
test_must_fail git archive --remote=. --format=tar.foo HEAD \
>remote.tar.foo &&
git archive --remote=. --format=bar >remote.bar HEAD &&
@@ -341,12 +341,12 @@ test_expect_success GZIP,GUNZIP 'extract tgz file' '
test_cmp b.tar j.tar
'
-test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' '
+test_expect_success GZIP 'remote tar.gz is allowed by default' '
git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
test_cmp j.tgz remote.tar.gz
'
-test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' '
+test_expect_success GZIP 'remote tar.gz can be disabled' '
git config tar.tar.gz.remote false &&
test_must_fail git archive --remote=. --format=tar.gz HEAD \
>remote.tar.gz
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/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/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/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 --