summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/RelNotes-1.7.1.txt20
-rw-r--r--Documentation/diff-options.txt4
-rw-r--r--Documentation/git-branch.txt6
-rw-r--r--Documentation/git-cvsimport.txt18
-rw-r--r--Documentation/git-grep.txt6
-rw-r--r--Documentation/git-hash-object.txt2
-rw-r--r--Documentation/git-imap-send.txt4
-rw-r--r--Documentation/git-show-branch.txt6
-rw-r--r--Documentation/technical/api-parse-options.txt12
-rw-r--r--Makefile273
l---------RelNotes2
-rw-r--r--abspath.c5
-rw-r--r--builtin-branch.c2
-rw-r--r--builtin-checkout.c24
-rw-r--r--builtin-fetch.c20
-rw-r--r--builtin-for-each-ref.c77
-rw-r--r--builtin-grep.c42
-rw-r--r--builtin-hash-object.c8
-rw-r--r--builtin-init-db.c9
-rw-r--r--builtin-pack-objects.c31
-rw-r--r--builtin-rev-parse.c4
-rw-r--r--builtin-send-pack.c191
-rw-r--r--builtin-shortlog.c2
-rw-r--r--builtin-show-branch.c4
-rw-r--r--cache.h1
-rw-r--r--color.c3
-rw-r--r--compat/mingw.c16
-rw-r--r--compat/mingw.h6
-rw-r--r--connect.c83
-rw-r--r--diff.c9
-rw-r--r--exec_cmd.c2
-rw-r--r--fast-import.c29
-rwxr-xr-xgit-cvsimport.perl21
-rw-r--r--[-rwxr-xr-x]git-parse-remote.sh0
-rwxr-xr-xgit-request-pull.sh8
-rw-r--r--[-rwxr-xr-x]git-sh-setup.sh0
-rwxr-xr-xgit-submodule.sh9
-rwxr-xr-xgit-svn.perl21
-rw-r--r--git.c5
-rwxr-xr-xgitweb/gitweb.perl11
-rw-r--r--imap-send.c146
-rw-r--r--merge-recursive.c23
-rw-r--r--pack-write.c27
-rw-r--r--pack.h1
-rw-r--r--parse-options.c16
-rw-r--r--parse-options.h7
-rw-r--r--path.c9
-rw-r--r--perl/Git.pm2
-rw-r--r--setup.c17
-rw-r--r--sha1_file.c7
-rwxr-xr-xt/t1007-hash-object.sh18
-rwxr-xr-xt/t1509-root-worktree.sh249
-rw-r--r--t/t1509/excludes14
-rwxr-xr-xt/t1509/prepare-chroot.sh38
-rwxr-xr-xt/t5510-fetch.sh7
-rwxr-xr-xt/t6023-merge-file.sh4
-rwxr-xr-xt/t7002-grep.sh52
-rwxr-xr-xt/t7401-submodule-summary.sh7
-rwxr-xr-xt/t9119-git-svn-info.sh3
-rwxr-xr-xt/t9151-svn-mergeinfo.sh15
-rw-r--r--t/t9151/make-svnmerge-dump89
-rw-r--r--t/t9151/svn-mergeinfo.dump578
-rwxr-xr-xt/t9600-cvsimport.sh36
-rw-r--r--transport.c41
-rw-r--r--transport.h11
-rw-r--r--xdiff-interface.c17
-rw-r--r--xdiff-interface.h1
68 files changed, 1847 insertions, 585 deletions
diff --git a/.gitignore b/.gitignore
index 8df8f88bea..7b3acb7664 100644
--- a/.gitignore
+++ b/.gitignore
@@ -177,6 +177,7 @@
*.exe
*.[aos]
*.py[co]
+*.o.d
*+
/config.mak
/autom4te.cache
diff --git a/Documentation/RelNotes-1.7.1.txt b/Documentation/RelNotes-1.7.1.txt
new file mode 100644
index 0000000000..8c18ca5d22
--- /dev/null
+++ b/Documentation/RelNotes-1.7.1.txt
@@ -0,0 +1,20 @@
+Git v1.7.1 Release Notes
+========================
+
+Updates since v1.7.0
+--------------------
+
+ * "git grep" learned "--no-index" option, to search inside contents that
+ are not managed by git.
+
+Fixes since v1.7.0
+------------------
+
+All of the fixes in v1.7.0.X maintenance series are included in this
+release, unless otherwise noted.
+
+---
+exec >/var/tmp/1
+echo O=$(git describe)
+O=v1.7.0-36-gfaa3b47
+git shortlog --no-merges ^maint $O..
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 8707d0e740..60e922e6ef 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -117,12 +117,14 @@ any of those replacements occurred.
option and lists the commits in that commit range like the 'summary'
option of linkgit:git-submodule[1] does.
---color::
+--color[=<when>]::
Show colored diff.
+ The value must be always (the default), never, or auto.
--no-color::
Turn off colored diff, even when the configuration file
gives the default to color output.
+ Same as `--color=never`.
--color-words[=<regex>]::
Show colored word diff, i.e., color words which have changed.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 6b6c3da2d9..903a690f10 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -8,7 +8,7 @@ git-branch - List, create, or delete branches
SYNOPSIS
--------
[verse]
-'git branch' [--color | --no-color] [-r | -a]
+'git branch' [--color[=<when>] | --no-color] [-r | -a]
[-v [--abbrev=<length> | --no-abbrev]]
[(--merged | --no-merged | --contains) [<commit>]]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
@@ -84,12 +84,14 @@ OPTIONS
-M::
Move/rename a branch even if the new branch name already exists.
---color::
+--color[=<when>]::
Color branches to highlight current, local, and remote branches.
+ The value must be always (the default), never, or auto.
--no-color::
Turn off branch colors, even when the configuration file gives the
default to color output.
+ Same as `--color=never`.
-r::
List or delete (if used with -d) the remote-tracking branches.
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index ddfcb3d143..8bcd875a67 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[-A <author-conv-file>] [-p <options-for-cvsps>] [-P <file>]
[-C <git_repository>] [-z <fuzz>] [-i] [-k] [-u] [-s <subst>]
[-a] [-m] [-M <regex>] [-S <regex>] [-L <commitlimit>]
- [-r <remote>] [<CVS_module>]
+ [-r <remote>] [-R] [<CVS_module>]
DESCRIPTION
@@ -157,6 +157,22 @@ It is not recommended to use this feature if you intend to
export changes back to CVS again later with
'git cvsexportcommit'.
+-R::
+ Generate a `$GIT_DIR/cvs-revisions` file containing a mapping from CVS
+ revision numbers to newly-created Git commit IDs. The generated file
+ will contain one line for each (filename, revision) pair imported;
+ each line will look like
++
+---------
+src/widget.c 1.1 1d862f173cdc7325b6fa6d2ae1cfd61fd1b512b7
+---------
++
+The revision data is appended to the file if it already exists, for use when
+doing incremental imports.
++
+This option may be useful if you have CVS revision numbers stored in commit
+messages, bug-tracking systems, email archives, and the like.
+
-h::
Print a short usage message and exit.
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index ee506e67f0..4b32322a67 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -17,7 +17,7 @@ SYNOPSIS
[-z | --null]
[-c | --count] [--all-match] [-q | --quiet]
[--max-depth <depth>]
- [--color | --no-color]
+ [--color[=<when>] | --no-color]
[-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e] <pattern>
[--and|--or|--not|(|)|-e <pattern>...]
@@ -114,12 +114,14 @@ OPTIONS
Instead of showing every matched line, show the number of
lines that match.
---color::
+--color[=<when>]::
Show colored matches.
+ The value must be always (the default), never, or auto.
--no-color::
Turn off match highlighting, even when the configuration file
gives the default to color output.
+ Same as `--color=never`.
-[ABC] <context>::
Show `context` trailing (`A` -- after), or leading (`B`
diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt
index 479fce4693..6904739a48 100644
--- a/Documentation/git-hash-object.txt
+++ b/Documentation/git-hash-object.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...
-'git hash-object' [-t <type>] [-w] --stdin-paths < <list-of-paths>
+'git hash-object' [-t <type>] [-w] --stdin-paths [--no-filters] < <list-of-paths>
DESCRIPTION
-----------
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 57db955bd4..6cafbe2ec1 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -71,6 +71,10 @@ imap.preformattedHTML::
option causes Thunderbird to send the patch as a plain/text,
format=fixed email. Default is `false`.
+imap.authMethod::
+ Specify authenticate method for authentication with IMAP server.
+ Current supported method is 'CRAM-MD5' only.
+
Examples
~~~~~~~~
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index b9c4154e73..f1499bba88 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git show-branch' [-a|--all] [-r|--remotes] [--topo-order | --date-order]
- [--current] [--color | --no-color] [--sparse]
+ [--current] [--color[=<when>] | --no-color] [--sparse]
[--more=<n> | --list | --independent | --merge-base]
[--no-name | --sha1-name] [--topics]
[<rev> | <glob>]...
@@ -117,13 +117,15 @@ OPTIONS
When no explicit <ref> parameter is given, it defaults to the
current branch (or `HEAD` if it is detached).
---color::
+--color[=<when>]::
Color the status sign (one of these: `*` `!` `+` `-`) of each commit
corresponding to the branch it's in.
+ The value must be always (the default), never, or auto.
--no-color::
Turn off colored output, even when the configuration file gives the
default to color output.
+ Same as `--color=never`.
Note that --more, --list, --independent and --merge-base options
are mutually exclusive.
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 50f9e9ac17..312e3b2e2b 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -115,6 +115,9 @@ There are some macros to easily define options:
`OPT__ABBREV(&int_var)`::
Add `\--abbrev[=<n>]`.
+`OPT__COLOR(&int_var, description)`::
+ Add `\--color[=<when>]` and `--no-color`.
+
`OPT__DRY_RUN(&int_var)`::
Add `-n, \--dry-run`.
@@ -183,6 +186,15 @@ There are some macros to easily define options:
arguments. Short options that happen to be digits take
precedence over it.
+`OPT_COLOR_FLAG(short, long, &int_var, description)`::
+ Introduce an option that takes an optional argument that can
+ have one of three values: "always", "never", or "auto". If the
+ argument is not given, it defaults to "always". The `--no-` form
+ works like `--long=never`; it cannot take an argument. If
+ "always", set `int_var` to 1; if "never", set `int_var` to 0; if
+ "auto", set `int_var` to 1 if stdout is a tty or a pager,
+ 0 otherwise.
+
The last element of the array must be `OPT_END()`.
diff --git a/Makefile b/Makefile
index 4387d4207f..f64610a57b 100644
--- a/Makefile
+++ b/Makefile
@@ -214,6 +214,13 @@ all::
# DEFAULT_EDITOR='~/bin/vi',
# DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
# DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
+#
+# Define COMPUTE_HEADER_DEPENDENCIES if your compiler supports the -MMD option
+# and you want to avoid rebuilding objects when an unrelated header file
+# changes.
+#
+# Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
+# dependency rules.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -311,11 +318,13 @@ COMPAT_CFLAGS =
COMPAT_OBJS =
LIB_H =
LIB_OBJS =
+PROGRAM_OBJS =
PROGRAMS =
SCRIPT_PERL =
SCRIPT_PYTHON =
SCRIPT_SH =
-TEST_PROGRAMS =
+SCRIPT_LIB =
+TEST_PROGRAMS_NEED_X =
SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
@@ -326,20 +335,21 @@ SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
-SCRIPT_SH += git-mergetool--lib.sh
SCRIPT_SH += git-notes.sh
-SCRIPT_SH += git-parse-remote.sh
SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
SCRIPT_SH += git-rebase--interactive.sh
SCRIPT_SH += git-rebase.sh
SCRIPT_SH += git-repack.sh
SCRIPT_SH += git-request-pull.sh
-SCRIPT_SH += git-sh-setup.sh
SCRIPT_SH += git-stash.sh
SCRIPT_SH += git-submodule.sh
SCRIPT_SH += git-web--browse.sh
+SCRIPT_LIB += git-mergetool--lib
+SCRIPT_LIB += git-parse-remote
+SCRIPT_LIB += git-sh-setup
+
SCRIPT_PERL += git-add--interactive.perl
SCRIPT_PERL += git-difftool.perl
SCRIPT_PERL += git-archimport.perl
@@ -360,12 +370,31 @@ EXTRA_PROGRAMS =
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS += $(EXTRA_PROGRAMS)
-PROGRAMS += git-fast-import$X
-PROGRAMS += git-imap-send$X
-PROGRAMS += git-shell$X
-PROGRAMS += git-show-index$X
-PROGRAMS += git-upload-pack$X
-PROGRAMS += git-http-backend$X
+
+PROGRAM_OBJS += fast-import.o
+PROGRAM_OBJS += imap-send.o
+PROGRAM_OBJS += shell.o
+PROGRAM_OBJS += show-index.o
+PROGRAM_OBJS += upload-pack.o
+PROGRAM_OBJS += http-backend.o
+
+PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
+
+TEST_PROGRAMS_NEED_X += test-chmtime
+TEST_PROGRAMS_NEED_X += test-ctype
+TEST_PROGRAMS_NEED_X += test-date
+TEST_PROGRAMS_NEED_X += test-delta
+TEST_PROGRAMS_NEED_X += test-dump-cache-tree
+TEST_PROGRAMS_NEED_X += test-genrandom
+TEST_PROGRAMS_NEED_X += test-match-trees
+TEST_PROGRAMS_NEED_X += test-parse-options
+TEST_PROGRAMS_NEED_X += test-path-utils
+TEST_PROGRAMS_NEED_X += test-run-command
+TEST_PROGRAMS_NEED_X += test-sha1
+TEST_PROGRAMS_NEED_X += test-sigchain
+TEST_PROGRAMS_NEED_X += test-index-version
+
+TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
# List built-in command $C whose implementation cmd_$C() is not in
# builtin-$C.o but is linked in as part of some other command.
@@ -425,6 +454,7 @@ LIB_H += blob.h
LIB_H += builtin.h
LIB_H += cache.h
LIB_H += cache-tree.h
+LIB_H += color.h
LIB_H += commit.h
LIB_H += compat/bswap.h
LIB_H += compat/cygwin.h
@@ -436,6 +466,7 @@ LIB_H += delta.h
LIB_H += diffcore.h
LIB_H += diff.h
LIB_H += dir.h
+LIB_H += exec_cmd.h
LIB_H += fsck.h
LIB_H += git-compat-util.h
LIB_H += graph.h
@@ -478,7 +509,8 @@ LIB_H += tree-walk.h
LIB_H += unpack-trees.h
LIB_H += userdiff.h
LIB_H += utf8.h
-LIB_H += wt-status.h
+LIB_H += xdiff-interface.h
+LIB_H += xdiff/xdiff.h
LIB_OBJS += abspath.o
LIB_OBJS += advice.o
@@ -1020,6 +1052,14 @@ endif
-include config.mak.autogen
-include config.mak
+ifdef CHECK_HEADER_DEPENDENCIES
+USE_COMPUTED_HEADER_DEPENDENCIES =
+endif
+
+ifdef COMPUTE_HEADER_DEPENDENCIES
+USE_COMPUTED_HEADER_DEPENDENCIES = YesPlease
+endif
+
ifdef SANE_TOOL_PATH
SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix $(SANE_TOOL_PATH_SQ)|'
@@ -1075,11 +1115,12 @@ else
REMOTE_CURL_PRIMARY = git-remote-http$X
REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X
REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
- PROGRAMS += $(REMOTE_CURL_NAMES) git-http-fetch$X
+ PROGRAM_OBJS += http-fetch.o
+ PROGRAMS += $(REMOTE_CURL_NAMES)
curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
ifeq "$(curl_check)" "070908"
ifndef NO_EXPAT
- PROGRAMS += git-http-push$X
+ PROGRAM_OBJS += http-push.o
endif
endif
ifndef NO_EXPAT
@@ -1099,7 +1140,7 @@ endif
EXTLIBS += -lz
ifndef NO_POSIX_ONLY_PROGRAMS
- PROGRAMS += git-daemon$X
+ PROGRAM_OBJS += daemon.o
endif
ifndef NO_OPENSSL
OPENSSL_LIBSSL = -lssl
@@ -1265,10 +1306,12 @@ endif
ifdef BLK_SHA1
SHA1_HEADER = "block-sha1/sha1.h"
LIB_OBJS += block-sha1/sha1.o
+ LIB_H += block-sha1/sha1.h
else
ifdef PPC_SHA1
SHA1_HEADER = "ppc/sha1.h"
LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
+ LIB_H += ppc/sha1.h
else
SHA1_HEADER = <openssl/sha.h>
EXTLIBS += $(LIB_4_CRYPTO)
@@ -1410,7 +1453,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
SHELL = $(SHELL_PATH)
-all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
+all:: shell_compatibility_test $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
ifneq (,$X)
$(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
endif
@@ -1461,17 +1504,25 @@ common-cmds.h: ./generate-cmdlist.sh command-list.txt
common-cmds.h: $(wildcard Documentation/git-*.txt)
$(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
+define cmd_munge_script
+$(RM) $@ $@+ && \
+sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
+ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
+ -e $(BROKEN_PATH_FIX) \
+ $@.sh >$@+
+endef
+
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
- $(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
- -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
- -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
- -e $(BROKEN_PATH_FIX) \
- $@.sh >$@+ && \
+ $(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
+$(SCRIPT_LIB) : % : %.sh
+ $(QUIET_GEN)$(cmd_munge_script) && \
+ mv $@+ $@
+
ifndef NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
@@ -1581,12 +1632,133 @@ git.o git.spec \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
: GIT-VERSION-FILE
-%.o: %.c GIT-CFLAGS
- $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
+ git.o http.o http-walker.o remote-curl.o
+XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
+ xdiff/xmerge.o xdiff/xpatience.o
+OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS)
+
+dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
+dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
+
+ifdef COMPUTE_HEADER_DEPENDENCIES
+$(dep_dirs):
+ mkdir -p $@
+
+missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
+dep_file = $(dir $@).depend/$(notdir $@).d
+dep_args = -MF $(dep_file) -MMD -MP
+ifdef CHECK_HEADER_DEPENDENCIES
+$(error cannot compute header dependencies outside a normal build. \
+Please unset CHECK_HEADER_DEPENDENCIES and try again)
+endif
+endif
+
+ifndef COMPUTE_HEADER_DEPENDENCIES
+ifndef CHECK_HEADER_DEPENDENCIES
+dep_dirs =
+missing_dep_dirs =
+dep_args =
+endif
+endif
+
+ifdef CHECK_HEADER_DEPENDENCIES
+ifndef PRINT_HEADER_DEPENDENCIES
+missing_deps = $(filter-out $(notdir $^), \
+ $(notdir $(shell $(MAKE) -s $@ \
+ CHECK_HEADER_DEPENDENCIES=YesPlease \
+ USE_COMPUTED_HEADER_DEPENDENCIES=YesPlease \
+ PRINT_HEADER_DEPENDENCIES=YesPlease)))
+endif
+endif
+
+ASM_SRC := $(wildcard $(OBJECTS:o=S))
+ASM_OBJ := $(ASM_SRC:S=o)
+C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+
+.SUFFIXES:
+
+ifdef PRINT_HEADER_DEPENDENCIES
+$(C_OBJ): %.o: %.c FORCE
+ echo $^
+$(ASM_OBJ): %.o: %.S FORCE
+ echo $^
+
+ifndef CHECK_HEADER_DEPENDENCIES
+$(error cannot print header dependencies during a normal build. \
+Please set CHECK_HEADER_DEPENDENCIES and try again)
+endif
+endif
+
+ifndef PRINT_HEADER_DEPENDENCIES
+ifdef CHECK_HEADER_DEPENDENCIES
+$(C_OBJ): %.o: %.c $(dep_files) FORCE
+ @set -e; echo CHECK $@; \
+ missing_deps="$(missing_deps)"; \
+ if test "$$missing_deps"; \
+ then \
+ echo missing dependencies: $$missing_deps; \
+ false; \
+ fi
+$(ASM_OBJ): %.o: %.S $(dep_files) FORCE
+ @set -e; echo CHECK $@; \
+ missing_deps="$(missing_deps)"; \
+ if test "$$missing_deps"; \
+ then \
+ echo missing dependencies: $$missing_deps; \
+ false; \
+ fi
+endif
+endif
+
+ifndef CHECK_HEADER_DEPENDENCIES
+$(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+ $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $<
+$(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
+ $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $<
+endif
+
%.s: %.c GIT-CFLAGS FORCE
$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
-%.o: %.S GIT-CFLAGS
- $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+
+ifdef USE_COMPUTED_HEADER_DEPENDENCIES
+# Take advantage of gcc's on-the-fly dependency generation
+# See <http://gcc.gnu.org/gcc-3.0/features.html>.
+dep_files_present := $(wildcard $(dep_files))
+ifneq ($(dep_files_present),)
+include $(dep_files_present)
+endif
+else
+# Dependencies on header files, for platforms that do not support
+# the gcc -MMD option.
+#
+# Dependencies on automatically generated headers such as common-cmds.h
+# should _not_ be included here, since they are necessary even when
+# building an object for the first time.
+#
+# XXX. Please check occasionally that these include all dependencies
+# gcc detects!
+
+$(GIT_OBJS): $(LIB_H)
+builtin-branch.o builtin-checkout.o builtin-clone.o builtin-reset.o branch.o transport.o: branch.h
+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: 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
+builtin-pack-objects.o: thread-utils.h
+http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
+http.o http-walker.o http-push.o remote-curl.o: http.h
+
+xdiff-interface.o $(XDIFF_OBJS): \
+ xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
+ xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+endif
exec_cmd.s exec_cmd.o: ALL_CFLAGS += \
'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
@@ -1601,7 +1773,6 @@ config.s config.o: ALL_CFLAGS += -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
http.s http.o: ALL_CFLAGS += -DGIT_USER_AGENT='"git/$(GIT_VERSION)"'
ifdef NO_EXPAT
-http-walker.o: http.h
http-walker.s http-walker.o: ALL_CFLAGS += -DNO_EXPAT
endif
@@ -1612,10 +1783,6 @@ git-imap-send$X: imap-send.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
-http.o http-walker.o http-push.o: http.h
-
-http.o http-walker.o: $(LIB_H)
-
git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL)
@@ -1633,18 +1800,9 @@ $(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
-$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
-$(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h)
-builtin-revert.o wt-status.o: wt-status.h
-
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
-XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
- xdiff/xmerge.o xdiff/xpatience.o
-$(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
- xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
-
$(XDIFF_LIB): $(XDIFF_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(XDIFF_OBJS)
@@ -1710,24 +1868,6 @@ GIT-GUI-VARS: FORCE
fi
endif
-### Testing rules
-
-TEST_PROGRAMS_NEED_X += test-chmtime
-TEST_PROGRAMS_NEED_X += test-ctype
-TEST_PROGRAMS_NEED_X += test-date
-TEST_PROGRAMS_NEED_X += test-delta
-TEST_PROGRAMS_NEED_X += test-dump-cache-tree
-TEST_PROGRAMS_NEED_X += test-genrandom
-TEST_PROGRAMS_NEED_X += test-match-trees
-TEST_PROGRAMS_NEED_X += test-parse-options
-TEST_PROGRAMS_NEED_X += test-path-utils
-TEST_PROGRAMS_NEED_X += test-run-command
-TEST_PROGRAMS_NEED_X += test-sha1
-TEST_PROGRAMS_NEED_X += test-sigchain
-TEST_PROGRAMS_NEED_X += test-index-version
-
-TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
-
test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
all:: $(TEST_PROGRAMS) $(test_bindir_programs)
@@ -1745,6 +1885,8 @@ bin-wrappers/%: wrap-for-bin.sh
export NO_SVN_TESTS
+### Testing rules
+
test: all
$(MAKE) -C t/ all
@@ -1756,9 +1898,7 @@ test-delta$X: diff-delta.o patch-delta.o
test-parse-options$X: parse-options.o
-test-parse-options.o: parse-options.h
-
-.PRECIOUS: $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+.PRECIOUS: $(TEST_OBJS)
test-%$X: test-%.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
@@ -1804,6 +1944,7 @@ install: all
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+ $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
ifndef NO_PERL
@@ -1923,9 +2064,10 @@ distclean: clean
clean:
$(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
$(LIB_FILE) $(XDIFF_LIB)
- $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
+ $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
$(RM) $(TEST_PROGRAMS)
$(RM) -r bin-wrappers
+ $(RM) -r $(dep_dirs)
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
$(RM) -r autom4te.cache
$(RM) config.log config.mak.autogen config.mak.append config.status config.cache
@@ -1955,7 +2097,7 @@ endif
### Check documentation
#
check-docs::
- @(for v in $(ALL_PROGRAMS) $(BUILT_INS) git gitk; \
+ @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \
do \
case "$$v" in \
git-merge-octopus | git-merge-ours | git-merge-recursive | \
@@ -1998,9 +2140,12 @@ check-docs::
documented,gitrepository-layout | \
documented,gittutorial | \
documented,gittutorial-2 | \
+ documented,git-bisect-lk2009 | \
+ documented.git-remote-helpers | \
+ documented,gitworkflows | \
sentinel,not,matching,is,ok ) continue ;; \
esac; \
- case " $(ALL_PROGRAMS) $(BUILT_INS) git gitk " in \
+ case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \
*" $$cmd "*) ;; \
*) echo "removed but $$how: $$cmd" ;; \
esac; \
diff --git a/RelNotes b/RelNotes
index 02e74966cd..00e77229dd 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.7.0.3.txt \ No newline at end of file
+Documentation/RelNotes-1.7.1.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index b88122cbe7..c91a29cb29 100644
--- a/abspath.c
+++ b/abspath.c
@@ -54,8 +54,9 @@ const char *make_absolute_path(const char *path)
if (len + strlen(last_elem) + 2 > PATH_MAX)
die ("Too long path name: '%s/%s'",
buf, last_elem);
- buf[len] = '/';
- strcpy(buf + len + 1, last_elem);
+ if (len && buf[len-1] != '/')
+ buf[len++] = '/';
+ strcpy(buf + len, last_elem);
free(last_elem);
last_elem = NULL;
}
diff --git a/builtin-branch.c b/builtin-branch.c
index a28a13986d..6cf7e721e6 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -610,7 +610,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
BRANCH_TRACK_EXPLICIT),
OPT_SET_INT( 0, "set-upstream", &track, "change upstream info",
BRANCH_TRACK_OVERRIDE),
- OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
+ OPT__COLOR(&branch_use_color, "use colored output"),
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
REF_REMOTE_BRANCH),
{
diff --git a/builtin-checkout.c b/builtin-checkout.c
index c5ab7835e1..acefaaf41a 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -128,24 +128,6 @@ static int checkout_stage(int stage, struct cache_entry *ce, int pos,
(stage == 2) ? "our" : "their");
}
-/* NEEDSWORK: share with merge-recursive */
-static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
-{
- unsigned long size;
- enum object_type type;
-
- if (!hashcmp(sha1, null_sha1)) {
- mm->ptr = xstrdup("");
- mm->size = 0;
- return;
- }
-
- mm->ptr = read_sha1_file(sha1, &type, &size);
- if (!mm->ptr || type != OBJ_BLOB)
- die("unable to read blob object %s", sha1_to_hex(sha1));
- mm->size = size;
-}
-
static int checkout_merged(int pos, struct checkout *state)
{
struct cache_entry *ce = active_cache[pos];
@@ -163,9 +145,9 @@ static int checkout_merged(int pos, struct checkout *state)
ce_stage(active_cache[pos+2]) != 3)
return error("path '%s' does not have all 3 versions", path);
- fill_mm(active_cache[pos]->sha1, &ancestor);
- fill_mm(active_cache[pos+1]->sha1, &ours);
- fill_mm(active_cache[pos+2]->sha1, &theirs);
+ read_mmblob(&ancestor, active_cache[pos]->sha1);
+ read_mmblob(&ours, active_cache[pos+1]->sha1);
+ read_mmblob(&theirs, active_cache[pos+2]->sha1);
status = ll_merge(&result_buf, path, &ancestor,
&ours, "ours", &theirs, "theirs", 0);
diff --git a/builtin-fetch.c b/builtin-fetch.c
index b059d652c6..b6c5b344be 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -11,6 +11,7 @@
#include "run-command.h"
#include "parse-options.h"
#include "sigchain.h"
+#include "transport.h"
static const char * const builtin_fetch_usage[] = {
"git fetch [options] [<repository> <refspec>...]",
@@ -205,7 +206,6 @@ static int s_update_ref(const char *action,
return 0;
}
-#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
#define REFCOL_WIDTH 10
static int update_local_ref(struct ref *ref,
@@ -224,7 +224,7 @@ static int update_local_ref(struct ref *ref,
if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
if (verbosity > 0)
- sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH,
+ sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH,
"[up to date]", REFCOL_WIDTH, remote,
pretty_ref);
return 0;
@@ -239,7 +239,7 @@ static int update_local_ref(struct ref *ref,
* the head, and the old value of the head isn't empty...
*/
sprintf(display, "! %-*s %-*s -> %s (can't fetch in current branch)",
- SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
+ TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
pretty_ref);
return 1;
}
@@ -249,7 +249,7 @@ static int update_local_ref(struct ref *ref,
int r;
r = s_update_ref("updating tag", ref, 0);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-',
- SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote,
+ TRANSPORT_SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote,
pretty_ref, r ? " (unable to update local ref)" : "");
return r;
}
@@ -271,7 +271,7 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref(msg, ref, 0);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
- SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
+ TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
r ? " (unable to update local ref)" : "");
return r;
}
@@ -284,7 +284,7 @@ static int update_local_ref(struct ref *ref,
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
r = s_update_ref("fast-forward", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
- SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
+ TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
pretty_ref, r ? " (unable to update local ref)" : "");
return r;
} else if (force || ref->force) {
@@ -295,13 +295,13 @@ static int update_local_ref(struct ref *ref,
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
r = s_update_ref("forced-update", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+',
- SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
+ TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
pretty_ref,
r ? "unable to update local ref" : "forced update");
return r;
} else {
sprintf(display, "! %-*s %-*s -> %s (non-fast-forward)",
- SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
+ TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
pretty_ref);
return 1;
}
@@ -393,7 +393,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
rc |= update_local_ref(ref, what, note);
else
sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
- SUMMARY_WIDTH, *kind ? kind : "branch",
+ TRANSPORT_SUMMARY_WIDTH, *kind ? kind : "branch",
REFCOL_WIDTH, *what ? what : "HEAD");
if (*note) {
if (verbosity >= 0 && !shown_url) {
@@ -514,7 +514,7 @@ static int prune_refs(struct transport *transport, struct ref *ref_map)
result |= delete_ref(ref->name, NULL, 0);
if (verbosity >= 0) {
fprintf(stderr, " x %-*s %-*s -> %s\n",
- SUMMARY_WIDTH, "[deleted]",
+ TRANSPORT_SUMMARY_WIDTH, "[deleted]",
REFCOL_WIDTH, "(none)", prettify_refname(ref->name));
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index a5a83f1469..62be1bbfd6 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -33,6 +33,8 @@ struct ref_sort {
struct refinfo {
char *refname;
unsigned char objectname[20];
+ int flag;
+ const char *symref;
struct atom_value *value;
};
@@ -68,6 +70,8 @@ static struct {
{ "body" },
{ "contents" },
{ "upstream" },
+ { "symref" },
+ { "flag" },
};
/*
@@ -82,7 +86,7 @@ static struct {
*/
static const char **used_atom;
static cmp_type *used_atom_type;
-static int used_atom_cnt, sort_atom_limit, need_tagged;
+static int used_atom_cnt, sort_atom_limit, need_tagged, need_symref;
/*
* Used to parse format string and sort specifiers
@@ -133,6 +137,10 @@ static int parse_atom(const char *atom, const char *ep)
(sizeof(*used_atom_type) * used_atom_cnt));
used_atom[at] = xmemdupz(atom, ep - atom);
used_atom_type[at] = valid_atom[i].cmp_type;
+ if (*atom == '*')
+ need_tagged = 1;
+ if (!strcmp(used_atom[at], "symref"))
+ need_symref = 1;
return at;
}
@@ -143,7 +151,8 @@ static const char *find_next(const char *cp)
{
while (*cp) {
if (*cp == '%') {
- /* %( is the start of an atom;
+ /*
+ * %( is the start of an atom;
* %% is a quoted per-cent.
*/
if (cp[1] == '(')
@@ -420,7 +429,8 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
grab_date(wholine, v, name);
}
- /* For a tag or a commit object, if "creator" or "creatordate" is
+ /*
+ * For a tag or a commit object, if "creator" or "creatordate" is
* requested, do something special.
*/
if (strcmp(who, "tagger") && strcmp(who, "committer"))
@@ -502,7 +512,8 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
}
}
-/* We want to have empty print-string for field requests
+/*
+ * We want to have empty print-string for field requests
* that do not apply (e.g. "authordate" for a tag object)
*/
static void fill_missing_values(struct atom_value *val)
@@ -548,6 +559,13 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
}
}
+static inline char *copy_advance(char *dst, const char *src)
+{
+ while (*src)
+ *dst++ = *src++;
+ return dst;
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
@@ -561,6 +579,16 @@ static void populate_value(struct refinfo *ref)
ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt);
+ if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
+ unsigned char unused1[20];
+ const char *symref;
+ symref = resolve_ref(ref->refname, unused1, 1, NULL);
+ if (symref)
+ ref->symref = xstrdup(symref);
+ else
+ ref->symref = "";
+ }
+
/* Fill in specials first */
for (i = 0; i < used_atom_cnt; i++) {
const char *name = used_atom[i];
@@ -576,6 +604,8 @@ static void populate_value(struct refinfo *ref)
if (!prefixcmp(name, "refname"))
refname = ref->refname;
+ else if (!prefixcmp(name, "symref"))
+ refname = ref->symref ? ref->symref : "";
else if (!prefixcmp(name, "upstream")) {
struct branch *branch;
/* only local branches may have an upstream */
@@ -588,6 +618,20 @@ static void populate_value(struct refinfo *ref)
continue;
refname = branch->merge[0]->dst;
}
+ else if (!strcmp(name, "flag")) {
+ char buf[256], *cp = buf;
+ if (ref->flag & REF_ISSYMREF)
+ cp = copy_advance(cp, ",symref");
+ if (ref->flag & REF_ISPACKED)
+ cp = copy_advance(cp, ",packed");
+ if (cp == buf)
+ v->s = "";
+ else {
+ *cp = '\0';
+ v->s = xstrdup(buf + 1);
+ }
+ continue;
+ }
else
continue;
@@ -633,18 +677,21 @@ static void populate_value(struct refinfo *ref)
if (!eaten)
free(buf);
- /* If there is no atom that wants to know about tagged
+ /*
+ * If there is no atom that wants to know about tagged
* object, we are done.
*/
if (!need_tagged || (obj->type != OBJ_TAG))
return;
- /* If it is a tag object, see if we use a value that derefs
+ /*
+ * If it is a tag object, see if we use a value that derefs
* the object, and if we do grab the object it refers to.
*/
tagged = ((struct tag *)obj)->tagged->sha1;
- /* NEEDSWORK: This derefs tag only once, which
+ /*
+ * NEEDSWORK: This derefs tag only once, which
* is good to deal with chains of trust, but
* is not consistent with what deref_tag() does
* which peels the onion to the core.
@@ -681,9 +728,8 @@ struct grab_ref_cbdata {
};
/*
- * A call-back given to for_each_ref(). It is unfortunate that we
- * need to use global variables to pass extra information to this
- * function.
+ * A call-back given to for_each_ref(). Filter refs and keep them for
+ * later object processing.
*/
static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
@@ -711,13 +757,15 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
return 0;
}
- /* We do not open the object yet; sort may only need refname
+ /*
+ * We do not open the object yet; sort may only need refname
* to do its job and the resulting list may yet to be pruned
* by maxcount logic.
*/
ref = xcalloc(1, sizeof(*ref));
ref->refname = xstrdup(refname);
hashcpy(ref->objectname, sha1);
+ ref->flag = flag;
cnt = cb->grab_cnt;
cb->grab_array = xrealloc(cb->grab_array,
@@ -938,13 +986,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
refs = cbdata.grab_array;
num_refs = cbdata.grab_cnt;
- for (i = 0; i < used_atom_cnt; i++) {
- if (used_atom[i][0] == '*') {
- need_tagged = 1;
- break;
- }
- }
-
sort_refs(sort, refs, num_refs);
if (!maxcount || num_refs < maxcount)
diff --git a/builtin-grep.c b/builtin-grep.c
index 371db0aa9e..40b9a93127 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -14,6 +14,7 @@
#include "userdiff.h"
#include "grep.h"
#include "quote.h"
+#include "dir.h"
#ifndef NO_PTHREADS
#include "thread-utils.h"
@@ -652,6 +653,24 @@ static int grep_object(struct grep_opt *opt, const char **paths,
die("unable to grep from object of type %s", typename(obj->type));
}
+static int grep_directory(struct grep_opt *opt, const char **paths)
+{
+ struct dir_struct dir;
+ int i, hit = 0;
+
+ memset(&dir, 0, sizeof(dir));
+ setup_standard_excludes(&dir);
+
+ fill_directory(&dir, paths);
+ for (i = 0; i < dir.nr; i++) {
+ hit |= grep_file(opt, dir.entries[i]->name);
+ if (hit && opt->status_only)
+ break;
+ }
+ free_grep_patterns(opt);
+ return hit;
+}
+
static int context_callback(const struct option *opt, const char *arg,
int unset)
{
@@ -746,9 +765,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
const char **paths = NULL;
int i;
int dummy;
+ int nongit = 0, use_index = 1;
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
"search in index instead of in the work tree"),
+ OPT_BOOLEAN(0, "index", &use_index,
+ "--no-index finds in contents not managed by git"),
OPT_GROUP(""),
OPT_BOOLEAN('v', "invert-match", &opt.invert,
"show non-matching lines"),
@@ -789,7 +811,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
"print NUL after filenames"),
OPT_BOOLEAN('c', "count", &opt.count,
"show the number of matches instead of matching lines"),
- OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1),
+ OPT__COLOR(&opt.color, "highlight matches"),
OPT_GROUP(""),
OPT_CALLBACK('C', NULL, &opt, "n",
"show <n> context lines before and after matches",
@@ -831,6 +853,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_END()
};
+ prefix = setup_git_directory_gently(&nongit);
+
/*
* 'git grep -h', unlike 'git grep -h <pattern>', is a request
* to show usage information and exit.
@@ -869,6 +893,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
+ if (use_index && nongit)
+ /* die the same way as if we did it at the beginning */
+ setup_git_directory();
+
/*
* skip a -- separator; we know it cannot be
* separating revisions from pathnames if
@@ -940,6 +968,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
paths[1] = NULL;
}
+ if (!use_index) {
+ int hit;
+ if (cached)
+ die("--cached cannot be used with --no-index.");
+ if (list.nr)
+ die("--no-index cannot be used with revs.");
+ hit = grep_directory(&opt, paths);
+ if (use_threads)
+ hit |= wait_all();
+ return !hit;
+ }
+
if (!list.nr) {
int hit;
if (!cached)
diff --git a/builtin-hash-object.c b/builtin-hash-object.c
index 6a5f5b5f0e..080af1a01b 100644
--- a/builtin-hash-object.c
+++ b/builtin-hash-object.c
@@ -33,6 +33,8 @@ static void hash_object(const char *path, const char *type, int write_object,
hash_fd(fd, type, write_object, vpath);
}
+static int no_filters;
+
static void hash_stdin_paths(const char *type, int write_objects)
{
struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
@@ -44,7 +46,8 @@ static void hash_stdin_paths(const char *type, int write_objects)
die("line is badly quoted");
strbuf_swap(&buf, &nbuf);
}
- hash_object(buf.buf, type, write_objects, buf.buf);
+ hash_object(buf.buf, type, write_objects,
+ no_filters ? NULL : buf.buf);
}
strbuf_release(&buf);
strbuf_release(&nbuf);
@@ -60,7 +63,6 @@ static const char *type;
static int write_object;
static int hashstdin;
static int stdin_paths;
-static int no_filters;
static const char *vpath;
static const struct option hash_object_options[] = {
@@ -100,8 +102,6 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
errstr = "Can't specify files with --stdin-paths";
else if (vpath)
errstr = "Can't use --stdin-paths with --path";
- else if (no_filters)
- errstr = "Can't use --stdin-paths with --no-filters";
}
else {
if (hashstdin > 1)
diff --git a/builtin-init-db.c b/builtin-init-db.c
index dd84caecbc..aae7a4d7ee 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -331,11 +331,14 @@ int init_db(const char *template_dir, unsigned int flags)
git_config_set("receive.denyNonFastforwards", "true");
}
- if (!(flags & INIT_DB_QUIET))
- printf("%s%s Git repository in %s/\n",
+ if (!(flags & INIT_DB_QUIET)) {
+ const char *git_dir = get_git_dir();
+ int len = strlen(git_dir);
+ printf("%s%s Git repository in %s%s\n",
reinit ? "Reinitialized existing" : "Initialized empty",
shared_repository ? " shared" : "",
- get_git_dir());
+ git_dir, len && git_dir[len-1] != '/' ? "/" : "");
+ }
return 0;
}
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 539e75d56f..97802585ea 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -155,33 +155,6 @@ static unsigned long do_compress(void **pptr, unsigned long size)
}
/*
- * The per-object header is a pretty dense thing, which is
- * - first byte: low four bits are "size", then three bits of "type",
- * and the high bit is "size continues".
- * - each byte afterwards: low seven bits are size continuation,
- * with the high bit being "size continues"
- */
-static int encode_header(enum object_type type, unsigned long size, unsigned char *hdr)
-{
- int n = 1;
- unsigned char c;
-
- if (type < OBJ_COMMIT || type > OBJ_REF_DELTA)
- die("bad type %d", type);
-
- c = (type << 4) | (size & 15);
- size >>= 4;
- while (size) {
- *hdr++ = c | 0x80;
- c = size & 0x7f;
- size >>= 7;
- n++;
- }
- *hdr = c;
- return n;
-}
-
-/*
* we are going to reuse the existing object data as is. make
* sure it is not corrupt.
*/
@@ -321,7 +294,7 @@ static unsigned long write_object(struct sha1file *f,
* The object header is a byte of 'type' followed by zero or
* more bytes of length.
*/
- hdrlen = encode_header(type, size, header);
+ hdrlen = encode_in_pack_object_header(type, size, header);
if (type == OBJ_OFS_DELTA) {
/*
@@ -372,7 +345,7 @@ static unsigned long write_object(struct sha1file *f,
if (entry->delta)
type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
- hdrlen = encode_header(type, entry->size, header);
+ hdrlen = encode_in_pack_object_header(type, entry->size, header);
offset = entry->in_pack_offset;
revidx = find_pack_revindex(p, offset);
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index b76f205e62..8fbf9d0db6 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -644,6 +644,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--git-dir")) {
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
static char cwd[PATH_MAX];
+ int len;
if (gitdir) {
puts(gitdir);
continue;
@@ -654,7 +655,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!getcwd(cwd, PATH_MAX))
die_errno("unable to get current working directory");
- printf("%s/.git\n", cwd);
+ len = strlen(cwd);
+ printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
continue;
}
if (!strcmp(arg, "--is-inside-git-dir")) {
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 2183a47052..6019eac918 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -7,6 +7,7 @@
#include "remote.h"
#include "send-pack.h"
#include "quote.h"
+#include "transport.h"
static const char send_pack_usage[] =
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -169,156 +170,6 @@ static int receive_status(int in, struct ref *refs)
return ret;
}
-static void update_tracking_ref(struct remote *remote, struct ref *ref)
-{
- struct refspec rs;
-
- if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
- return;
-
- rs.src = ref->name;
- rs.dst = NULL;
-
- if (!remote_find_tracking(remote, &rs)) {
- if (args.verbose)
- fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
- if (ref->deletion) {
- delete_ref(rs.dst, NULL, 0);
- } else
- update_ref("update by push", rs.dst,
- ref->new_sha1, NULL, 0, 0);
- free(rs.dst);
- }
-}
-
-#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
-
-static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
-{
- fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
- if (from)
- fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
- else
- fputs(prettify_refname(to->name), stderr);
- if (msg) {
- fputs(" (", stderr);
- fputs(msg, stderr);
- fputc(')', stderr);
- }
- fputc('\n', stderr);
-}
-
-static const char *status_abbrev(unsigned char sha1[20])
-{
- return find_unique_abbrev(sha1, DEFAULT_ABBREV);
-}
-
-static void print_ok_ref_status(struct ref *ref)
-{
- if (ref->deletion)
- print_ref_status('-', "[deleted]", ref, NULL, NULL);
- else if (is_null_sha1(ref->old_sha1))
- print_ref_status('*',
- (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
- "[new branch]"),
- ref, ref->peer_ref, NULL);
- else {
- char quickref[84];
- char type;
- const char *msg;
-
- strcpy(quickref, status_abbrev(ref->old_sha1));
- if (ref->nonfastforward) {
- strcat(quickref, "...");
- type = '+';
- msg = "forced update";
- } else {
- strcat(quickref, "..");
- type = ' ';
- msg = NULL;
- }
- strcat(quickref, status_abbrev(ref->new_sha1));
-
- print_ref_status(type, quickref, ref, ref->peer_ref, msg);
- }
-}
-
-static int print_one_push_status(struct ref *ref, const char *dest, int count)
-{
- if (!count)
- fprintf(stderr, "To %s\n", dest);
-
- switch(ref->status) {
- case REF_STATUS_NONE:
- print_ref_status('X', "[no match]", ref, NULL, NULL);
- break;
- case REF_STATUS_REJECT_NODELETE:
- print_ref_status('!', "[rejected]", ref, NULL,
- "remote does not support deleting refs");
- break;
- case REF_STATUS_UPTODATE:
- print_ref_status('=', "[up to date]", ref,
- ref->peer_ref, NULL);
- break;
- case REF_STATUS_REJECT_NONFASTFORWARD:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "non-fast-forward");
- break;
- case REF_STATUS_REMOTE_REJECT:
- print_ref_status('!', "[remote rejected]", ref,
- ref->deletion ? NULL : ref->peer_ref,
- ref->remote_status);
- break;
- case REF_STATUS_EXPECTING_REPORT:
- print_ref_status('!', "[remote failure]", ref,
- ref->deletion ? NULL : ref->peer_ref,
- "remote failed to report status");
- break;
- case REF_STATUS_OK:
- print_ok_ref_status(ref);
- break;
- }
-
- return 1;
-}
-
-static void print_push_status(const char *dest, struct ref *refs)
-{
- struct ref *ref;
- int n = 0;
-
- if (args.verbose) {
- for (ref = refs; ref; ref = ref->next)
- if (ref->status == REF_STATUS_UPTODATE)
- n += print_one_push_status(ref, dest, n);
- }
-
- for (ref = refs; ref; ref = ref->next)
- if (ref->status == REF_STATUS_OK)
- n += print_one_push_status(ref, dest, n);
-
- for (ref = refs; ref; ref = ref->next) {
- if (ref->status != REF_STATUS_NONE &&
- ref->status != REF_STATUS_UPTODATE &&
- ref->status != REF_STATUS_OK)
- n += print_one_push_status(ref, dest, n);
- }
-}
-
-static int refs_pushed(struct ref *ref)
-{
- for (; ref; ref = ref->next) {
- switch(ref->status) {
- case REF_STATUS_NONE:
- case REF_STATUS_UPTODATE:
- break;
- default:
- return 1;
- }
- }
- return 0;
-}
-
static void print_helper_status(struct ref *ref)
{
struct strbuf buf = STRBUF_INIT;
@@ -523,37 +374,6 @@ int send_pack(struct send_pack_args *args,
return 0;
}
-static void verify_remote_names(int nr_heads, const char **heads)
-{
- int i;
-
- for (i = 0; i < nr_heads; i++) {
- const char *local = heads[i];
- const char *remote = strrchr(heads[i], ':');
-
- if (*local == '+')
- local++;
-
- /* A matching refspec is okay. */
- if (remote == local && remote[1] == '\0')
- continue;
-
- remote = remote ? (remote + 1) : local;
- switch (check_ref_format(remote)) {
- case 0: /* ok */
- case CHECK_REF_FORMAT_ONELEVEL:
- /* ok but a single level -- that is fine for
- * a match pattern.
- */
- case CHECK_REF_FORMAT_WILDCARD:
- /* ok but ends with a pattern-match character */
- continue;
- }
- die("remote part of refspec is not a valid name in %s",
- heads[i]);
- }
-}
-
int cmd_send_pack(int argc, const char **argv, const char *prefix)
{
int i, nr_refspecs = 0;
@@ -570,6 +390,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
int send_all = 0;
const char *receivepack = "git-receive-pack";
int flags;
+ int nonfastforward = 0;
argv++;
for (i = 1; i < argc; i++, argv++) {
@@ -662,7 +483,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
&extra_have);
- verify_remote_names(nr_refspecs, refspecs);
+ transport_verify_remote_names(nr_refspecs, refspecs);
local_refs = get_local_heads();
@@ -691,15 +512,15 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
ret |= finish_connect(conn);
if (!helper_status)
- print_push_status(dest, remote_refs);
+ transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward);
if (!args.dry_run && remote) {
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next)
- update_tracking_ref(remote, ref);
+ transport_update_tracking_ref(remote, ref, args.verbose);
}
- if (!ret && !refs_pushed(remote_refs))
+ if (!ret && !transport_refs_pushed(remote_refs))
fprintf(stderr, "Everything up-to-date\n");
return ret;
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index ecd2d45a00..06320f5285 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -295,6 +295,8 @@ parse_done:
if (!nongit && !rev.pending.nr && isatty(0))
add_head_to_pending(&rev);
if (rev.pending.nr == 0) {
+ if (isatty(0))
+ fprintf(stderr, "(reading log message from standard input)\n");
read_from_stdin(&log);
}
else
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index 35a709e630..e20fcf3e93 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -6,7 +6,7 @@
#include "parse-options.h"
static const char* show_branch_usage[] = {
- "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...",
+ "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...",
"git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]",
NULL
};
@@ -661,7 +661,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
"show remote-tracking and local branches"),
OPT_BOOLEAN('r', "remotes", &all_remotes,
"show remote-tracking branches"),
- OPT_BOOLEAN(0, "color", &showbranch_use_color,
+ OPT__COLOR(&showbranch_use_color,
"color '*!+-' corresponding to the branch"),
{ OPTION_INTEGER, 0, "more", &extra, "n",
"show <n> more commits after the common ancestor",
diff --git a/cache.h b/cache.h
index 6e54993256..89f6a40d1a 100644
--- a/cache.h
+++ b/cache.h
@@ -688,6 +688,7 @@ int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, const char *prefix_list);
char *strip_path_suffix(const char *path, const char *suffix);
int daemon_avoid_alias(const char *path);
+int offset_1st_component(const char *path);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *);
diff --git a/color.c b/color.c
index 62977f4808..8f07fc9547 100644
--- a/color.c
+++ b/color.c
@@ -138,6 +138,9 @@ int git_config_colorbool(const char *var, const char *value, int stdout_is_tty)
goto auto_color;
}
+ if (!var)
+ return -1;
+
/* Missing or explicit false to turn off colorization */
if (!git_config_bool(var, value))
return 0;
diff --git a/compat/mingw.c b/compat/mingw.c
index ab65f77ab9..c5bfb39b39 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -140,6 +140,22 @@ int mingw_open (const char *filename, int oflags, ...)
return fd;
}
+#undef fopen
+FILE *mingw_fopen (const char *filename, const char *otype)
+{
+ if (!strcmp(filename, "/dev/null"))
+ filename = "nul";
+ return fopen(filename, otype);
+}
+
+#undef freopen
+FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
+{
+ if (filename && !strcmp(filename, "/dev/null"))
+ filename = "nul";
+ return freopen(filename, otype, stream);
+}
+
/*
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
diff --git a/compat/mingw.h b/compat/mingw.h
index e254fb4e06..e81e752ed2 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -170,6 +170,12 @@ int link(const char *oldpath, const char *newpath);
int mingw_open (const char *filename, int oflags, ...);
#define open mingw_open
+FILE *mingw_fopen (const char *filename, const char *otype);
+#define fopen mingw_fopen
+
+FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
+#define freopen mingw_freopen
+
char *mingw_getcwd(char *pointer, int len);
#define getcwd mingw_getcwd
diff --git a/connect.c b/connect.c
index beaff987c7..323a771b69 100644
--- a/connect.c
+++ b/connect.c
@@ -152,6 +152,28 @@ static enum protocol get_protocol(const char *name)
#define STR_(s) # s
#define STR(s) STR_(s)
+static void get_host_and_port(char **host, const char **port)
+{
+ char *colon, *end;
+
+ if (*host[0] == '[') {
+ end = strchr(*host + 1, ']');
+ if (end) {
+ *end = 0;
+ end++;
+ (*host)++;
+ } else
+ end = *host;
+ } else
+ end = *host;
+ colon = strchr(end, ':');
+
+ if (colon) {
+ *colon = 0;
+ *port = colon + 1;
+ }
+}
+
#ifndef NO_IPV6
static const char *ai_name(const struct addrinfo *ai)
@@ -170,30 +192,14 @@ static const char *ai_name(const struct addrinfo *ai)
static int git_tcp_connect_sock(char *host, int flags)
{
int sockfd = -1, saved_errno = 0;
- char *colon, *end;
const char *port = STR(DEFAULT_GIT_PORT);
struct addrinfo hints, *ai0, *ai;
int gai;
int cnt = 0;
- if (host[0] == '[') {
- end = strchr(host + 1, ']');
- if (end) {
- *end = 0;
- end++;
- host++;
- } else
- end = host;
- } else
- end = host;
- colon = strchr(end, ':');
-
- if (colon) {
- *colon = 0;
- port = colon + 1;
- if (!*port)
- port = "<none>";
- }
+ get_host_and_port(&host, &port);
+ if (!*port)
+ port = "<none>";
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
@@ -251,30 +257,15 @@ static int git_tcp_connect_sock(char *host, int flags)
static int git_tcp_connect_sock(char *host, int flags)
{
int sockfd = -1, saved_errno = 0;
- char *colon, *end;
- char *port = STR(DEFAULT_GIT_PORT), *ep;
+ const char *port = STR(DEFAULT_GIT_PORT);
+ char *ep;
struct hostent *he;
struct sockaddr_in sa;
char **ap;
unsigned int nport;
int cnt;
- if (host[0] == '[') {
- end = strchr(host + 1, ']');
- if (end) {
- *end = 0;
- end++;
- host++;
- } else
- end = host;
- } else
- end = host;
- colon = strchr(end, ':');
-
- if (colon) {
- *colon = 0;
- port = colon + 1;
- }
+ get_host_and_port(&host, &port);
if (flags & CONNECT_VERBOSE)
fprintf(stderr, "Looking up %s ... ", host);
@@ -406,26 +397,10 @@ static int git_use_proxy(const char *host)
static void git_proxy_connect(int fd[2], char *host)
{
const char *port = STR(DEFAULT_GIT_PORT);
- char *colon, *end;
const char *argv[4];
struct child_process proxy;
- if (host[0] == '[') {
- end = strchr(host + 1, ']');
- if (end) {
- *end = 0;
- end++;
- host++;
- } else
- end = host;
- } else
- end = host;
- colon = strchr(end, ':');
-
- if (colon) {
- *colon = 0;
- port = colon + 1;
- }
+ get_host_and_port(&host, &port);
argv[0] = git_proxy_command;
argv[1] = host;
diff --git a/diff.c b/diff.c
index 0d465faa1e..dfdfa1a813 100644
--- a/diff.c
+++ b/diff.c
@@ -2826,6 +2826,15 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_OPT_SET(options, FOLLOW_RENAMES);
else if (!strcmp(arg, "--color"))
DIFF_OPT_SET(options, COLOR_DIFF);
+ else if (!prefixcmp(arg, "--color=")) {
+ int value = git_config_colorbool(NULL, arg+8, -1);
+ if (value == 0)
+ DIFF_OPT_CLR(options, COLOR_DIFF);
+ else if (value > 0)
+ DIFF_OPT_SET(options, COLOR_DIFF);
+ else
+ return error("option `color' expects \"always\", \"auto\", or \"never\"");
+ }
else if (!strcmp(arg, "--no-color"))
DIFF_OPT_CLR(options, COLOR_DIFF);
else if (!strcmp(arg, "--color-words")) {
diff --git a/exec_cmd.c b/exec_cmd.c
index 408e4e55e1..b2c07c70ce 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -28,7 +28,7 @@ const char *system_path(const char *path)
!(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
!(prefix = strip_path_suffix(argv0_path, "git"))) {
prefix = PREFIX;
- fprintf(stderr, "RUNTIME_PREFIX requested, "
+ trace_printf("RUNTIME_PREFIX requested, "
"but prefix computation failed. "
"Using static fallback '%s'.\n", prefix);
}
diff --git a/fast-import.c b/fast-import.c
index 74f08bd554..309f2c58a2 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -980,29 +980,6 @@ static void cycle_packfile(void)
start_packfile();
}
-static size_t encode_header(
- enum object_type type,
- uintmax_t size,
- unsigned char *hdr)
-{
- int n = 1;
- unsigned char c;
-
- if (type < OBJ_COMMIT || type > OBJ_REF_DELTA)
- die("bad type %d", type);
-
- c = (type << 4) | (size & 15);
- size >>= 4;
- while (size) {
- *hdr++ = c | 0x80;
- c = size & 0x7f;
- size >>= 7;
- n++;
- }
- *hdr = c;
- return n;
-}
-
static int store_object(
enum object_type type,
struct strbuf *dat,
@@ -1103,7 +1080,7 @@ static int store_object(
delta_count_by_type[type]++;
e->depth = last->depth + 1;
- hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
+ hdrlen = encode_in_pack_object_header(OBJ_OFS_DELTA, deltalen, hdr);
sha1write(pack_file, hdr, hdrlen);
pack_size += hdrlen;
@@ -1114,7 +1091,7 @@ static int store_object(
pack_size += sizeof(hdr) - pos;
} else {
e->depth = 0;
- hdrlen = encode_header(type, dat->len, hdr);
+ hdrlen = encode_in_pack_object_header(type, dat->len, hdr);
sha1write(pack_file, hdr, hdrlen);
pack_size += hdrlen;
}
@@ -1188,7 +1165,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
memset(&s, 0, sizeof(s));
deflateInit(&s, pack_compression_level);
- hdrlen = encode_header(OBJ_BLOB, len, out_buf);
+ hdrlen = encode_in_pack_object_header(OBJ_BLOB, len, out_buf);
if (out_sz <= hdrlen)
die("impossibly large object header");
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 4853bf7a0d..9e03eee458 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -29,7 +29,7 @@ use IPC::Open2;
$SIG{'PIPE'}="IGNORE";
$ENV{'TZ'}="UTC";
-our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r);
+our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R);
my (%conv_author_name, %conv_author_email);
sub usage(;$) {
@@ -40,7 +40,7 @@ Usage: git cvsimport # fetch/update GIT from CVS
[-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
[-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
[-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
- [-r remote] [CVS_module]
+ [-r remote] [-R] [CVS_module]
END
exit(1);
}
@@ -110,7 +110,7 @@ sub read_repo_config {
}
}
-my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:";
+my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:R";
read_repo_config($opts);
Getopt::Long::Configure( 'no_ignore_case', 'bundling' );
@@ -659,6 +659,11 @@ if ($opt_A) {
write_author_info("$git_dir/cvs-authors");
}
+# open .git/cvs-revisions, if requested
+open my $revision_map, '>>', "$git_dir/cvs-revisions"
+ or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
+ if defined $opt_R;
+
#
# run cvsps into a file unless we are getting
@@ -742,7 +747,7 @@ sub write_tree () {
}
my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
-my (@old,@new,@skipped,%ignorebranch);
+my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
# commits that cvsps cannot place anywhere...
$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
@@ -825,6 +830,11 @@ sub commit {
system('git' , 'update-ref', "$remote/$branch", $cid) == 0
or die "Cannot write branch $branch for update: $!\n";
+ if ($revision_map) {
+ print $revision_map "@$_ $cid\n" for @commit_revisions;
+ }
+ @commit_revisions = ();
+
if ($tag) {
my ($xtag) = $tag;
$xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
@@ -959,6 +969,7 @@ while (<CVS>) {
push(@skipped, $fn);
next;
}
+ push @commit_revisions, [$fn, $rev];
print "Fetching $fn v $rev\n" if $opt_v;
my ($tmpname, $size) = $cvs->file($fn,$rev);
if ($size == -1) {
@@ -981,7 +992,9 @@ while (<CVS>) {
unlink($tmpname);
} elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
my $fn = $1;
+ my $rev = $2;
$fn =~ s#^/+##;
+ push @commit_revisions, [$fn, $rev];
push(@old,$fn);
print "Delete $fn\n" if $opt_v;
} elsif ($state == 9 and /^\s*$/) {
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 5f47b18141..5f47b18141 100755..100644
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
diff --git a/git-request-pull.sh b/git-request-pull.sh
index 630ceddf03..8fd15f6df4 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -65,11 +65,11 @@ if [ -z "$branch" ]; then
status=1
fi
-echo "The following changes since commit $baserev:"
-git shortlog --max-count=1 $baserev | sed -e 's/^\(.\)/ \1/'
+git show -s --format='The following changes since commit %H:
-echo "are available in the git repository at:"
-echo
+ %s (%ci)
+
+are available in the git repository at:' $baserev
echo " $url $branch"
echo
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 6131670860..6131670860 100755..100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
diff --git a/git-submodule.sh b/git-submodule.sh
index e2082fd149..f21d0bfce7 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -553,12 +553,15 @@ cmd_summary() {
test $summary_limit = 0 && return
- if rev=$(git rev-parse -q --verify "$1^0")
+ if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
then
head=$rev
- shift
+ test $# = 0 || shift
+ elif test -z "$1" -o "$1" = "HEAD"
+ then
+ return
else
- head=HEAD
+ head="HEAD"
fi
if [ -n "$files" ]
diff --git a/git-svn.perl b/git-svn.perl
index 473a0b9d55..1a26843f44 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -36,11 +36,13 @@ $ENV{TZ} = 'UTC';
$| = 1; # unbuffer STDOUT
sub fatal (@) { print STDERR "@_\n"; exit 1 }
-require SVN::Core; # use()-ing this causes segfaults for me... *shrug*
-require SVN::Ra;
-require SVN::Delta;
-if ($SVN::Core::VERSION lt '1.1.0') {
- fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";
+sub _req_svn {
+ require SVN::Core; # use()-ing this causes segfaults for me... *shrug*
+ require SVN::Ra;
+ require SVN::Delta;
+ if ($SVN::Core::VERSION lt '1.1.0') {
+ fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";
+ }
}
my $can_compress = eval { require Compress::Zlib; 1};
push @Git::SVN::Ra::ISA, 'SVN::Ra';
@@ -349,6 +351,7 @@ information.
}
sub version {
+ ::_req_svn();
print "git-svn version $VERSION (svn $SVN::Core::VERSION)\n";
exit 0;
}
@@ -367,7 +370,6 @@ sub do_git_init_db {
command_noisy(@init_db);
$_repository = Git->repository(Repository => ".git");
}
- command_noisy('config', 'core.autocrlf', 'false');
my $set;
my $pfx = "svn-remote.$Git::SVN::default_repo_id";
foreach my $i (keys %icv) {
@@ -730,6 +732,8 @@ sub cmd_branch {
$src=~s/^http:/https:/;
}
+ ::_req_svn();
+
my $ctx = SVN::Client->new(
auth => Git::SVN::Ra::_auth_providers(),
log_msg => sub {
@@ -1098,6 +1102,7 @@ sub cmd_info {
if ($@) {
$result .= "Repository Root: (offline)\n";
}
+ ::_req_svn();
$result .= "Repository UUID: $uuid\n" unless $diff_status eq "A" &&
($SVN::Core::VERSION le '1.5.4' || $file_type ne "dir");
$result .= "Revision: " . ($diff_status eq "A" ? 0 : $rev) . "\n";
@@ -3273,7 +3278,7 @@ sub find_extra_svn_parents {
"$new_parents[$i]..$new_parents[$j]",
);
if ( !$revs ) {
- undef($new_parents[$i]);
+ undef($new_parents[$j]);
}
}
}
@@ -4859,6 +4864,8 @@ sub new {
$url =~ s!/+$!!;
return $RA if ($RA && $RA->{url} eq $url);
+ ::_req_svn();
+
SVN::_Core::svn_config_ensure($config_dir, undef);
my ($baton, $callbacks) = SVN::Core::auth_open_helper(_auth_providers);
my $config = SVN::Core::config_get_config($config_dir);
diff --git a/git.c b/git.c
index c445d7bcc2..f09948eed9 100644
--- a/git.c
+++ b/git.c
@@ -54,6 +54,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
{
int handled = 0;
+ if (!getenv("GIT_ASKPASS") && getenv("SSH_ASKPASS"))
+ setenv("GIT_ASKPASS", getenv("SSH_ASKPASS"), 1);
+
while (*argc > 0) {
const char *cmd = (*argv)[0];
if (cmd[0] != '-')
@@ -317,7 +320,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "fsck-objects", cmd_fsck, RUN_SETUP },
{ "gc", cmd_gc, RUN_SETUP },
{ "get-tar-commit-id", cmd_get_tar_commit_id },
- { "grep", cmd_grep, RUN_SETUP | USE_PAGER },
+ { "grep", cmd_grep, USE_PAGER },
{ "hash-object", cmd_hash_object },
{ "help", cmd_help },
{ "index-pack", cmd_index_pack },
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3d80deba01..a2d2283ec9 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1150,6 +1150,7 @@ sub validate_refname {
# in utf-8 thanks to "binmode STDOUT, ':utf8'" at beginning
sub to_utf8 {
my $str = shift;
+ return undef unless defined $str;
if (utf8::valid($str)) {
utf8::decode($str);
return $str;
@@ -1162,6 +1163,7 @@ sub to_utf8 {
# correct, but quoted slashes look too horrible in bookmarks
sub esc_param {
my $str = shift;
+ return undef unless defined $str;
$str =~ s/([^A-Za-z0-9\-_.~()\/:@ ]+)/CGI::escape($1)/eg;
$str =~ s/ /\+/g;
return $str;
@@ -1170,6 +1172,7 @@ sub esc_param {
# quote unsafe chars in whole URL, so some charactrs cannot be quoted
sub esc_url {
my $str = shift;
+ return undef unless defined $str;
$str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg;
$str =~ s/\+/%2B/g;
$str =~ s/ /\+/g;
@@ -1181,6 +1184,8 @@ sub esc_html {
my $str = shift;
my %opts = @_;
+ return undef unless defined $str;
+
$str = to_utf8($str);
$str = $cgi->escapeHTML($str);
if ($opts{'-nbsp'}) {
@@ -1195,6 +1200,8 @@ sub esc_path {
my $str = shift;
my %opts = @_;
+ return undef unless defined $str;
+
$str = to_utf8($str);
$str = $cgi->escapeHTML($str);
if ($opts{'-nbsp'}) {
@@ -3382,7 +3389,7 @@ sub git_footer_html {
"</html>";
}
-# die_error(<http_status_code>, <error_message>)
+# die_error(<http_status_code>, <error_message>[, <detailed_html_description>])
# Example: die_error(404, 'Hash not found')
# By convention, use the following status codes (as defined in RFC 2616):
# 400: Invalid or missing CGI parameters, or
@@ -3397,7 +3404,7 @@ sub git_footer_html {
# or down for maintenance). Generally, this is a temporary state.
sub die_error {
my $status = shift || 500;
- my $error = shift || "Internal server error";
+ my $error = esc_html(shift) || "Internal Server Error";
my $extra = shift;
my %http_responses = (
diff --git a/imap-send.c b/imap-send.c
index 5631930bc3..fa703838cf 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -27,6 +27,9 @@
#include "run-command.h"
#ifdef NO_OPENSSL
typedef void *SSL;
+#else
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
#endif
struct store_conf {
@@ -139,6 +142,20 @@ struct imap_server_conf {
int use_ssl;
int ssl_verify;
int use_html;
+ char *auth_method;
+};
+
+static struct imap_server_conf server = {
+ NULL, /* name */
+ NULL, /* tunnel */
+ NULL, /* host */
+ 0, /* port */
+ NULL, /* user */
+ NULL, /* pass */
+ 0, /* use_ssl */
+ 1, /* ssl_verify */
+ 0, /* use_html */
+ NULL, /* auth_method */
};
struct imap_store_conf {
@@ -213,6 +230,7 @@ enum CAPABILITY {
LITERALPLUS,
NAMESPACE,
STARTTLS,
+ AUTH_CRAM_MD5,
};
static const char *cap_list[] = {
@@ -221,6 +239,7 @@ static const char *cap_list[] = {
"LITERAL+",
"NAMESPACE",
"STARTTLS",
+ "AUTH=CRAM-MD5",
};
#define RESP_OK 0
@@ -948,6 +967,87 @@ static void imap_close_store(struct store *ctx)
free(ctx);
}
+#ifndef NO_OPENSSL
+
+/*
+ * hexchar() and cram() functions are based on the code from the isync
+ * project (http://isync.sf.net/).
+ */
+static char hexchar(unsigned int b)
+{
+ return b < 10 ? '0' + b : 'a' + (b - 10);
+}
+
+#define ENCODED_SIZE(n) (4*((n+2)/3))
+static char *cram(const char *challenge_64, const char *user, const char *pass)
+{
+ int i, resp_len, encoded_len, decoded_len;
+ HMAC_CTX hmac;
+ unsigned char hash[16];
+ char hex[33];
+ char *response, *response_64, *challenge;
+
+ /*
+ * length of challenge_64 (i.e. base-64 encoded string) is a good
+ * enough upper bound for challenge (decoded result).
+ */
+ encoded_len = strlen(challenge_64);
+ challenge = xmalloc(encoded_len);
+ decoded_len = EVP_DecodeBlock((unsigned char *)challenge,
+ (unsigned char *)challenge_64, encoded_len);
+ if (decoded_len < 0)
+ die("invalid challenge %s", challenge_64);
+ HMAC_Init(&hmac, (unsigned char *)pass, strlen(pass), EVP_md5());
+ HMAC_Update(&hmac, (unsigned char *)challenge, decoded_len);
+ HMAC_Final(&hmac, hash, NULL);
+ HMAC_CTX_cleanup(&hmac);
+
+ hex[32] = 0;
+ for (i = 0; i < 16; i++) {
+ hex[2 * i] = hexchar((hash[i] >> 4) & 0xf);
+ hex[2 * i + 1] = hexchar(hash[i] & 0xf);
+ }
+
+ /* response: "<user> <digest in hex>" */
+ resp_len = strlen(user) + 1 + strlen(hex) + 1;
+ response = xmalloc(resp_len);
+ sprintf(response, "%s %s", user, hex);
+
+ response_64 = xmalloc(ENCODED_SIZE(resp_len) + 1);
+ encoded_len = EVP_EncodeBlock((unsigned char *)response_64,
+ (unsigned char *)response, resp_len);
+ if (encoded_len < 0)
+ die("EVP_EncodeBlock error");
+ response_64[encoded_len] = '\0';
+ return (char *)response_64;
+}
+
+#else
+
+static char *cram(const char *challenge_64, const char *user, const char *pass)
+{
+ die("If you want to use CRAM-MD5 authenticate method, "
+ "you have to build git-imap-send with OpenSSL library.");
+}
+
+#endif
+
+static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const char *prompt)
+{
+ int ret;
+ char *response;
+
+ response = cram(prompt, server.user, server.pass);
+
+ ret = socket_write(&ctx->imap->buf.sock, response, strlen(response));
+ if (ret != strlen(response))
+ return error("IMAP error: sending response failed\n");
+
+ free(response);
+
+ return 0;
+}
+
static struct store *imap_open_store(struct imap_server_conf *srvc)
{
struct imap_store *ctx;
@@ -1129,9 +1229,34 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
if (!imap->buf.sock.ssl)
imap_warn("*** IMAP Warning *** Password is being "
"sent in the clear\n");
- if (imap_exec(ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass) != RESP_OK) {
- fprintf(stderr, "IMAP error: LOGIN failed\n");
- goto bail;
+
+ if (srvc->auth_method) {
+ struct imap_cmd_cb cb;
+
+ if (!strcmp(srvc->auth_method, "CRAM-MD5")) {
+ if (!CAP(AUTH_CRAM_MD5)) {
+ fprintf(stderr, "You specified"
+ "CRAM-MD5 as authentication method, "
+ "but %s doesn't support it.\n", srvc->host);
+ goto bail;
+ }
+ /* CRAM-MD5 */
+
+ memset(&cb, 0, sizeof(cb));
+ cb.cont = auth_cram_md5;
+ if (imap_exec(ctx, &cb, "AUTHENTICATE CRAM-MD5") != RESP_OK) {
+ fprintf(stderr, "IMAP error: AUTHENTICATE CRAM-MD5 failed\n");
+ goto bail;
+ }
+ } else {
+ fprintf(stderr, "Unknown authentication method:%s\n", srvc->host);
+ goto bail;
+ }
+ } else {
+ if (imap_exec(ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass) != RESP_OK) {
+ fprintf(stderr, "IMAP error: LOGIN failed\n");
+ goto bail;
+ }
}
} /* !preauth */
@@ -1348,18 +1473,6 @@ static int split_msg(struct msg_data *all_msgs, struct msg_data *msg, int *ofs)
return 1;
}
-static struct imap_server_conf server = {
- NULL, /* name */
- NULL, /* tunnel */
- NULL, /* host */
- 0, /* port */
- NULL, /* user */
- NULL, /* pass */
- 0, /* use_ssl */
- 1, /* ssl_verify */
- 0, /* use_html */
-};
-
static char *imap_folder;
static int git_imap_config(const char *key, const char *val, void *cb)
@@ -1399,6 +1512,9 @@ static int git_imap_config(const char *key, const char *val, void *cb)
server.port = git_config_int(key, val);
else if (!strcmp("tunnel", key))
server.tunnel = xstrdup(val);
+ else if (!strcmp("authmethod", key))
+ server.auth_method = xstrdup(val);
+
return 0;
}
diff --git a/merge-recursive.c b/merge-recursive.c
index cb53b01c19..195ebf9744 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -599,23 +599,6 @@ struct merge_file_info
merge:1;
};
-static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
-{
- unsigned long size;
- enum object_type type;
-
- if (!hashcmp(sha1, null_sha1)) {
- mm->ptr = xstrdup("");
- mm->size = 0;
- return;
- }
-
- mm->ptr = read_sha1_file(sha1, &type, &size);
- if (!mm->ptr || type != OBJ_BLOB)
- die("unable to read blob object %s", sha1_to_hex(sha1));
- mm->size = size;
-}
-
static int merge_3way(struct merge_options *o,
mmbuffer_t *result_buf,
struct diff_filespec *one,
@@ -653,9 +636,9 @@ static int merge_3way(struct merge_options *o,
name2 = xstrdup(mkpath("%s", branch2));
}
- fill_mm(one->sha1, &orig);
- fill_mm(a->sha1, &src1);
- fill_mm(b->sha1, &src2);
+ read_mmblob(&orig, one->sha1);
+ read_mmblob(&src1, a->sha1);
+ read_mmblob(&src2, b->sha1);
merge_status = ll_merge(result_buf, a->path, &orig,
&src1, name1, &src2, name2,
diff --git a/pack-write.c b/pack-write.c
index 9f47cf9961..a905ca4486 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -253,3 +253,30 @@ char *index_pack_lockfile(int ip_out)
}
return NULL;
}
+
+/*
+ * The per-object header is a pretty dense thing, which is
+ * - first byte: low four bits are "size", then three bits of "type",
+ * and the high bit is "size continues".
+ * - each byte afterwards: low seven bits are size continuation,
+ * with the high bit being "size continues"
+ */
+int encode_in_pack_object_header(enum object_type type, uintmax_t size, unsigned char *hdr)
+{
+ int n = 1;
+ unsigned char c;
+
+ if (type < OBJ_COMMIT || type > OBJ_REF_DELTA)
+ die("bad type %d", type);
+
+ c = (type << 4) | (size & 15);
+ size >>= 4;
+ while (size) {
+ *hdr++ = c | 0x80;
+ c = size & 0x7f;
+ size >>= 7;
+ n++;
+ }
+ *hdr = c;
+ return n;
+}
diff --git a/pack.h b/pack.h
index b759a23d4d..d268c014c9 100644
--- a/pack.h
+++ b/pack.h
@@ -60,6 +60,7 @@ extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off
extern int verify_pack(struct packed_git *);
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 *);
#define PH_ERROR_EOF (-1)
#define PH_ERROR_PACK_SIGNATURE (-2)
diff --git a/parse-options.c b/parse-options.c
index d218122af5..c83035d013 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -2,6 +2,7 @@
#include "parse-options.h"
#include "cache.h"
#include "commit.h"
+#include "color.h"
static int parse_options_usage(const char * const *usagestr,
const struct option *opts);
@@ -599,6 +600,21 @@ int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
return 0;
}
+int parse_opt_color_flag_cb(const struct option *opt, const char *arg,
+ int unset)
+{
+ int value;
+
+ if (!arg)
+ arg = unset ? "never" : (const char *)opt->defval;
+ value = git_config_colorbool(NULL, arg, -1);
+ if (value < 0)
+ return opterror(opt,
+ "expects \"always\", \"auto\", or \"never\"", 0);
+ *(int *)opt->value = value;
+ return 0;
+}
+
int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
int unset)
{
diff --git a/parse-options.h b/parse-options.h
index 0c996916b6..9429f7e361 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -135,6 +135,10 @@ struct option {
PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
#define OPT_FILENAME(s, l, v, h) { OPTION_FILENAME, (s), (l), (v), \
"FILE", (h) }
+#define OPT_COLOR_FLAG(s, l, v, h) \
+ { OPTION_CALLBACK, (s), (l), (v), "when", (h), PARSE_OPT_OPTARG, \
+ parse_opt_color_flag_cb, (intptr_t)"always" }
+
/* parse_options() will filter out the processed options and leave the
* non-option arguments in argv[].
@@ -187,6 +191,7 @@ extern int parse_options_end(struct parse_opt_ctx_t *ctx);
/*----- some often used options -----*/
extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
+extern int parse_opt_color_flag_cb(const struct option *, const char *, int);
extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
extern int parse_opt_with_commit(const struct option *, const char *, int);
extern int parse_opt_tertiary(const struct option *, const char *, int);
@@ -203,5 +208,7 @@ extern int parse_opt_tertiary(const struct option *, const char *, int);
{ OPTION_CALLBACK, 0, "abbrev", (var), "n", \
"use <n> digits to display SHA-1s", \
PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__COLOR(var, h) \
+ OPT_COLOR_FLAG(0, "color", (var), (h))
#endif
diff --git a/path.c b/path.c
index aaa9345ebc..b4c8d91722 100644
--- a/path.c
+++ b/path.c
@@ -415,7 +415,7 @@ char *enter_repo(char *path, int strict)
if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
validate_headref("HEAD") == 0) {
- setenv(GIT_DIR_ENVIRONMENT, ".", 1);
+ set_git_dir(".");
check_repository_format();
return path;
}
@@ -728,3 +728,10 @@ int daemon_avoid_alias(const char *p)
}
}
}
+
+int offset_1st_component(const char *path)
+{
+ if (has_dos_drive_prefix(path))
+ return 2 + is_dir_sep(path[2]);
+ return is_dir_sep(path[0]);
+}
diff --git a/perl/Git.pm b/perl/Git.pm
index 970fe434ed..1926dc9a4b 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -842,7 +842,7 @@ sub _open_hash_and_insert_object_if_needed {
($self->{hash_object_pid}, $self->{hash_object_in},
$self->{hash_object_out}, $self->{hash_object_ctx}) =
- command_bidi_pipe(qw(hash-object -w --stdin-paths));
+ command_bidi_pipe(qw(hash-object -w --stdin-paths --no-filters));
}
sub _close_hash_and_insert_object {
diff --git a/setup.c b/setup.c
index fac34f77a7..5716d90b57 100644
--- a/setup.c
+++ b/setup.c
@@ -18,14 +18,15 @@ const char *prefix_path(const char *prefix, int len, const char *path)
if (normalize_path_copy(sanitized, sanitized))
goto error_out;
if (is_absolute_path(orig)) {
- size_t len, total;
+ size_t root_len, len, total;
const char *work_tree = get_git_work_tree();
if (!work_tree)
goto error_out;
len = strlen(work_tree);
+ root_len = offset_1st_component(work_tree);
total = strlen(sanitized) + 1;
if (strncmp(sanitized, work_tree, len) ||
- (sanitized[len] != '\0' && sanitized[len] != '/')) {
+ (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
error_out:
die("'%s' is outside repository", orig);
}
@@ -321,7 +322,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
static char cwd[PATH_MAX+1];
const char *gitdirenv;
const char *gitfile_dir;
- int len, offset, ceil_offset;
+ int len, offset, ceil_offset, root_len;
/*
* Let's assume that we are in a git repository.
@@ -403,10 +404,11 @@ const char *setup_git_directory_gently(int *nongit_ok)
if (!work_tree_env)
inside_work_tree = 0;
if (offset != len) {
- cwd[offset] = '\0';
- setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+ root_len = offset_1st_component(cwd);
+ cwd[offset > root_len ? offset : root_len] = '\0';
+ set_git_dir(cwd);
} else
- setenv(GIT_DIR_ENVIRONMENT, ".", 1);
+ set_git_dir(".");
check_repository_format_gently(nongit_ok);
return NULL;
}
@@ -427,7 +429,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
inside_git_dir = 0;
if (!work_tree_env)
inside_work_tree = 1;
- git_work_tree_cfg = xstrndup(cwd, offset);
+ root_len = offset_1st_component(cwd);
+ git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len);
if (check_repository_format_gently(nongit_ok))
return NULL;
if (offset == len)
diff --git a/sha1_file.c b/sha1_file.c
index c23cc5e6e1..a08a9d0880 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -35,13 +35,6 @@ static size_t sz_fmt(size_t s) { return s; }
const unsigned char null_sha1[20];
-static inline int offset_1st_component(const char *path)
-{
- if (has_dos_drive_prefix(path))
- return 2 + (path[2] == '/');
- return *path == '/';
-}
-
int safe_create_leading_directories(char *path)
{
char *pos = path + offset_1st_component(path);
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index fd98e445bf..dd32432d62 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -65,10 +65,6 @@ test_expect_success "Can't use --path with --stdin-paths" '
echo example | test_must_fail git hash-object --stdin-paths --path=foo
'
-test_expect_success "Can't use --stdin-paths with --no-filters" '
- echo example | test_must_fail git hash-object --stdin-paths --no-filters
-'
-
test_expect_success "Can't use --path with --no-filters" '
test_must_fail git hash-object --no-filters --path=foo
'
@@ -141,6 +137,20 @@ test_expect_success 'check that --no-filters option works' '
git config --unset core.autocrlf
'
+test_expect_success 'check that --no-filters option works with --stdin-paths' '
+ echo fooQ | tr Q "\\015" >file0 &&
+ cp file0 file1 &&
+ echo "file0 -crlf" >.gitattributes &&
+ echo "file1 crlf" >>.gitattributes &&
+ git config core.autocrlf true &&
+ file0_sha=$(git hash-object file0) &&
+ file1_sha=$(git hash-object file1) &&
+ test "$file0_sha" != "$file1_sha" &&
+ nofilters_file1=$(echo "file1" | git hash-object --stdin-paths --no-filters) &&
+ test "$file0_sha" = "$nofilters_file1" &&
+ git config --unset core.autocrlf
+'
+
pop_repo
for args in "-w --stdin" "--stdin -w"; do
diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
new file mode 100755
index 0000000000..5322a3bf97
--- /dev/null
+++ b/t/t1509-root-worktree.sh
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+test_description='Test Git when git repository is located at root
+
+This test requires write access in root. Do not bother if you do not
+have a throwaway chroot or VM.
+
+Script t1509/prepare-chroot.sh may help you setup chroot, then you
+can chroot in and execute this test from there.
+'
+
+. ./test-lib.sh
+
+test_cmp_val() {
+ echo "$1" > expected
+ echo "$2" > result
+ test_cmp expected result
+}
+
+test_vars() {
+ test_expect_success "$1: gitdir" '
+ test_cmp_val "'"$2"'" "$(git rev-parse --git-dir)"
+ '
+
+ test_expect_success "$1: worktree" '
+ test_cmp_val "'"$3"'" "$(git rev-parse --show-toplevel)"
+ '
+
+ test_expect_success "$1: prefix" '
+ test_cmp_val "'"$4"'" "$(git rev-parse --show-prefix)"
+ '
+}
+
+test_foobar_root() {
+ test_expect_success 'add relative' '
+ test -z "$(cd / && git ls-files)" &&
+ git add foo/foome &&
+ git add foo/bar/barme &&
+ git add me &&
+ ( cd / && git ls-files --stage ) > result &&
+ test_cmp /ls.expected result &&
+ rm "$(git rev-parse --git-dir)/index"
+ '
+
+ test_expect_success 'add absolute' '
+ test -z "$(cd / && git ls-files)" &&
+ git add /foo/foome &&
+ git add /foo/bar/barme &&
+ git add /me &&
+ ( cd / && git ls-files --stage ) > result &&
+ test_cmp /ls.expected result &&
+ rm "$(git rev-parse --git-dir)/index"
+ '
+
+}
+
+test_foobar_foo() {
+ test_expect_success 'add relative' '
+ test -z "$(cd / && git ls-files)" &&
+ git add foome &&
+ git add bar/barme &&
+ git add ../me &&
+ ( cd / && git ls-files --stage ) > result &&
+ test_cmp /ls.expected result &&
+ rm "$(git rev-parse --git-dir)/index"
+ '
+
+ test_expect_success 'add absolute' '
+ test -z "$(cd / && git ls-files)" &&
+ git add /foo/foome &&
+ git add /foo/bar/barme &&
+ git add /me &&
+ ( cd / && git ls-files --stage ) > result &&
+ test_cmp /ls.expected result &&
+ rm "$(git rev-parse --git-dir)/index"
+ '
+}
+
+test_foobar_foobar() {
+ test_expect_success 'add relative' '
+ test -z "$(cd / && git ls-files)" &&
+ git add ../foome &&
+ git add barme &&
+ git add ../../me &&
+ ( cd / && git ls-files --stage ) > result &&
+ test_cmp /ls.expected result &&
+ rm "$(git rev-parse --git-dir)/index"
+ '
+
+ test_expect_success 'add absolute' '
+ test -z "$(cd / && git ls-files)" &&
+ git add /foo/foome &&
+ git add /foo/bar/barme &&
+ git add /me &&
+ ( cd / && git ls-files --stage ) > result &&
+ test_cmp /ls.expected result &&
+ rm "$(git rev-parse --git-dir)/index"
+ '
+}
+
+if ! test_have_prereq POSIXPERM || ! [ -w / ]; then
+ say "Dangerous test skipped. Read this test if you want to execute it"
+ test_done
+fi
+
+if [ "$IKNOWWHATIAMDOING" != "YES" ]; then
+ say "You must set env var IKNOWWHATIAMDOING=YES in order to run this test"
+ test_done
+fi
+
+if [ "$UID" = 0 ]; then
+ say "No you can't run this with root"
+ test_done
+fi
+
+ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
+
+test_expect_success 'setup' '
+ rm -rf /foo
+ mkdir /foo &&
+ mkdir /foo/bar &&
+ echo 1 > /foo/foome &&
+ echo 1 > /foo/bar/barme &&
+ echo 1 > /me
+'
+
+say "GIT_DIR absolute, GIT_WORK_TREE set"
+
+test_expect_success 'go to /' 'cd /'
+
+cat >ls.expected <<EOF
+100644 $ONE_SHA1 0 foo/bar/barme
+100644 $ONE_SHA1 0 foo/foome
+100644 $ONE_SHA1 0 me
+EOF
+
+export GIT_DIR="$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'abs gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+test_vars 'abs gitdir, foo' "$GIT_DIR" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+test_vars 'abs gitdir, foo/bar' "$GIT_DIR" "/" "foo/bar/"
+test_foobar_foobar
+
+say "GIT_DIR relative, GIT_WORK_TREE set"
+
+test_expect_success 'go to /' 'cd /'
+
+export GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+export GIT_DIR="../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+export GIT_DIR="../../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+say "GIT_DIR relative, GIT_WORK_TREE relative"
+
+test_expect_success 'go to /' 'cd /'
+
+export GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git"
+export GIT_WORK_TREE=.
+
+test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /' 'cd /foo'
+
+export GIT_DIR="../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=..
+
+test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+export GIT_DIR="../../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=../..
+
+test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+say ".git at root"
+
+unset GIT_DIR
+unset GIT_WORK_TREE
+
+test_expect_success 'go to /' 'cd /'
+test_expect_success 'setup' '
+ rm -rf /.git
+ echo "Initialized empty Git repository in /.git/" > expected &&
+ git init > result &&
+ test_cmp expected result
+'
+
+test_vars 'auto gitdir, root' ".git" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+test_vars 'auto gitdir, foo' "/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+test_vars 'auto gitdir, foo/bar' "/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+test_expect_success 'cleanup' 'rm -rf /.git'
+
+say "auto bare gitdir"
+
+# DESTROYYYYY!!!!!
+test_expect_success 'setup' '
+ rm -rf /refs /objects /info /hooks
+ rm /*
+ cd / &&
+ echo "Initialized empty Git repository in /" > expected &&
+ git init --bare > result &&
+ test_cmp expected result
+'
+
+test_vars 'auto gitdir, root' "." "" ""
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+test_vars 'auto gitdir, root' "/" "" ""
+
+test_done
diff --git a/t/t1509/excludes b/t/t1509/excludes
new file mode 100644
index 0000000000..d4d21d31a9
--- /dev/null
+++ b/t/t1509/excludes
@@ -0,0 +1,14 @@
+*.o
+*~
+*.bak
+*.c
+*.h
+.git
+contrib
+Documentation
+git-gui
+gitk-git
+gitweb
+t/t4013
+t/t5100
+t/t5515
diff --git a/t/t1509/prepare-chroot.sh b/t/t1509/prepare-chroot.sh
new file mode 100755
index 0000000000..c5334a8fa4
--- /dev/null
+++ b/t/t1509/prepare-chroot.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+die() {
+ echo >&2 "$@"
+ exit 1
+}
+
+xmkdir() {
+ while [ -n "$1" ]; do
+ [ -d "$1" ] || mkdir "$1" || die "Unable to mkdir $1"
+ shift
+ done
+}
+
+R="$1"
+
+[ -n "$R" ] || die "Usage: prepare-chroot.sh <root>"
+[ -x git ] || die "This script needs to be executed at git source code's top directory"
+[ -x /bin/busybox ] || die "You need busybox"
+
+xmkdir "$R" "$R/bin" "$R/etc" "$R/lib" "$R/dev"
+[ -c "$R/dev/null" ] || die "/dev/null is missing. Do mknod $R/dev/null c 1 3 && chmod 666 $R/dev/null"
+echo "root:x:0:0:root:/:/bin/sh" > "$R/etc/passwd"
+echo "$(id -nu):x:$(id -u):$(id -g)::$(pwd)/t:/bin/sh" >> "$R/etc/passwd"
+echo "root::0:root" > "$R/etc/group"
+echo "$(id -ng)::$(id -g):$(id -nu)" >> "$R/etc/group"
+
+[ -x "$R/bin/busybox" ] || cp /bin/busybox "$R/bin/busybox"
+[ -x "$R/bin/sh" ] || ln -s /bin/busybox "$R/bin/sh"
+[ -x "$R/bin/su" ] || ln -s /bin/busybox "$R/bin/su"
+
+mkdir -p "$R$(pwd)"
+rsync --exclude-from t/t1509/excludes -Ha . "$R$(pwd)"
+ldd git | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do
+ mkdir -p "$R$(dirname $i)"
+ cp "$i" "$R/$i"
+done
+echo "Execute this in root: 'chroot $R /bin/su - $(id -nu)'"
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 169af1edde..721821ec92 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -341,6 +341,13 @@ test_expect_success 'fetch into the current branch with --update-head-ok' '
'
+test_expect_success 'fetch --dry-run' '
+
+ rm -f .git/FETCH_HEAD &&
+ git fetch --dry-run . &&
+ ! test -f .git/FETCH_HEAD
+'
+
test_expect_success "should be able to fetch with duplicate refspecs" '
mkdir dups &&
cd dups &&
diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh
index 6291307cd0..d605024cf8 100755
--- a/t/t6023-merge-file.sh
+++ b/t/t6023-merge-file.sh
@@ -64,6 +64,10 @@ cp new1.txt test.txt
test_expect_success "merge without conflict" \
"git merge-file test.txt orig.txt new2.txt"
+cp new1.txt test.txt
+test_expect_success "merge without conflict (--quiet)" \
+ "git merge-file --quiet test.txt orig.txt new2.txt"
+
cp new1.txt test2.txt
test_expect_success "merge without conflict (missing LF at EOF)" \
"git merge-file test2.txt orig.txt new2.txt"
diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh
index af63d6ec6d..e249c3ed41 100755
--- a/t/t7002-grep.sh
+++ b/t/t7002-grep.sh
@@ -442,6 +442,58 @@ test_expect_success 'grep -Fi' '
test_cmp expected actual
'
+test_expect_success 'outside of git repository' '
+ rm -fr non &&
+ mkdir -p non/git/sub &&
+ echo hello >non/git/file1 &&
+ echo world >non/git/sub/file2 &&
+ echo ".*o*" >non/git/.gitignore &&
+ {
+ echo file1:hello &&
+ echo sub/file2:world
+ } >non/expect.full &&
+ echo file2:world >non/expect.sub
+ (
+ GIT_CEILING_DIRECTORIES="$(pwd)/non/git" &&
+ export GIT_CEILING_DIRECTORIES &&
+ cd non/git &&
+ test_must_fail git grep o &&
+ git grep --no-index o >../actual.full &&
+ test_cmp ../expect.full ../actual.full
+ cd sub &&
+ test_must_fail git grep o &&
+ git grep --no-index o >../../actual.sub &&
+ test_cmp ../../expect.sub ../../actual.sub
+ )
+'
+
+test_expect_success 'inside git repository but with --no-index' '
+ rm -fr is &&
+ mkdir -p is/git/sub &&
+ echo hello >is/git/file1 &&
+ echo world >is/git/sub/file2 &&
+ echo ".*o*" >is/git/.gitignore &&
+ {
+ echo file1:hello &&
+ echo sub/file2:world
+ } >is/expect.full &&
+ : >is/expect.empty &&
+ echo file2:world >is/expect.sub
+ (
+ cd is/git &&
+ git init &&
+ test_must_fail git grep o >../actual.full &&
+ test_cmp ../expect.empty ../actual.full &&
+ git grep --no-index o >../actual.full &&
+ test_cmp ../expect.full ../actual.full &&
+ cd sub &&
+ test_must_fail git grep o >../../actual.sub &&
+ test_cmp ../../expect.empty ../../actual.sub &&
+ git grep --no-index o >../../actual.sub &&
+ test_cmp ../../expect.sub ../../actual.sub
+ )
+'
+
test_expect_success 'setup double-dash tests' '
cat >double-dash <<EOF &&
--
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index d3c039f724..cee319da0a 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -227,4 +227,11 @@ test_expect_success 'fail when using --files together with --cached' "
test_must_fail git submodule summary --files --cached
"
+test_expect_success 'should not fail in an empty repo' "
+ git init xyzzy &&
+ cd xyzzy &&
+ git submodule summary >output 2>&1 &&
+ test_cmp output /dev/null
+"
+
test_done
diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh
index 95741cbbac..a9a558d292 100755
--- a/t/t9119-git-svn-info.sh
+++ b/t/t9119-git-svn-info.sh
@@ -7,9 +7,10 @@ test_description='git svn info'
. ./lib-git-svn.sh
# Tested with: svn, version 1.4.4 (r25188)
+# Tested with: svn, version 1.6.[12345689]
v=`svn_cmd --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'`
case $v in
-1.[45].*)
+1.[456].*)
;;
*)
say "skipping svn-info test (SVN version: $v not supported)"
diff --git a/t/t9151-svn-mergeinfo.sh b/t/t9151-svn-mergeinfo.sh
index 3569c62096..16408244d2 100755
--- a/t/t9151-svn-mergeinfo.sh
+++ b/t/t9151-svn-mergeinfo.sh
@@ -33,6 +33,21 @@ test_expect_success 'svn non-merge merge commits did not become git merge commit
[ -z "$bad_non_merges" ]
'
+test_expect_success 'commit made to merged branch is reachable from the merge' '
+ before_commit=$(git rev-list --all --grep="trunk commit before merging trunk to b2")
+ merge_commit=$(git rev-list --all --grep="Merge trunk to b2")
+ not_reachable=$(git rev-list -1 $before_commit --not $merge_commit)
+ [ -z "$not_reachable" ]
+ '
+
+test_expect_success 'merging two branches in one commit is detected correctly' '
+ f1_commit=$(git rev-list --all --grep="make f1 branch from trunk")
+ f2_commit=$(git rev-list --all --grep="make f2 branch from trunk")
+ merge_commit=$(git rev-list --all --grep="Merge f1 and f2 to trunk")
+ not_reachable=$(git rev-list -1 $f1_commit $f2_commit --not $merge_commit)
+ [ -z "$not_reachable" ]
+ '
+
test_expect_failure 'everything got merged in the end' '
unmerged=$(git rev-list --all --not master)
[ -z "$unmerged" ]
diff --git a/t/t9151/make-svnmerge-dump b/t/t9151/make-svnmerge-dump
index 3d73f140f8..e1e138cb1a 100644
--- a/t/t9151/make-svnmerge-dump
+++ b/t/t9151/make-svnmerge-dump
@@ -156,6 +156,89 @@ svn merge ../branches/right --accept postpone
i=$(commit $i "non-merge right to trunk 2")
cd ..
+say "Branching b1 from trunk"
+svn update
+svn cp trunk branches/b1
+i=$(commit $i "make b1 branch from trunk")
+
+say "Branching b2 from trunk"
+svn update
+svn cp trunk branches/b2
+i=$(commit $i "make b2 branch from trunk")
+
+say "Make a commit to b2"
+svn update
+cd branches/b2
+echo "b2" > b2file
+svn add b2file
+i=$(commit $i "b2 update 1")
+cd ../..
+
+say "Make a commit to b1"
+svn update
+cd branches/b1
+echo "b1" > b1file
+svn add b1file
+i=$(commit $i "b1 update 1")
+cd ../..
+
+say "Merge b1 to trunk"
+svn update
+cd trunk
+svn merge ../branches/b1/ --accept postpone
+i=$(commit $i "Merge b1 to trunk")
+cd ..
+
+say "Make a commit to trunk before merging trunk to b2"
+svn update
+cd trunk
+echo "trunk" > trunkfile
+svn add trunkfile
+i=$(commit $i "trunk commit before merging trunk to b2")
+cd ..
+
+say "Merge trunk to b2"
+svn update
+cd branches/b2
+svn merge ../../trunk/ --accept postpone
+i=$(commit $i "Merge trunk to b2")
+cd ../..
+
+say "Merge b2 to trunk"
+svn update
+cd trunk
+svn merge ../branches/b2/ --accept postpone
+svn resolved b1file
+svn resolved trunkfile
+i=$(commit $i "Merge b2 to trunk")
+cd ..
+
+say "Creating f1 from trunk with a new file"
+svn update
+svn cp trunk branches/f1
+cd branches/f1
+echo "f1" > f1file
+svn add f1file
+cd ../..
+i=$(commit $i "make f1 branch from trunk with a new file")
+
+say "Creating f2 from trunk with a new file"
+svn update
+svn cp trunk branches/f2
+cd branches/f2
+echo "f2" > f2file
+svn add f2file
+cd ../..
+i=$(commit $i "make f2 branch from trunk with a new file")
+
+say "Merge f1 and f2 to trunk in one go"
+svn update
+cd trunk
+svn merge ../branches/f1/ --accept postpone
+svn merge ../branches/f2/ --accept postpone
+i=$(commit $i "Merge f1 and f2 to trunk")
+cd ..
+
say "Adding subdirectory to LEFT"
svn update
cd branches/left
@@ -174,8 +257,8 @@ cd ..
say "Make PARTIAL branch"
svn update
-i=$(commit $i "make partial branch")
svn cp trunk/subdir branches/partial
+i=$(commit $i "make partial branch")
say "Make a commit to PARTIAL"
svn update
@@ -194,13 +277,13 @@ cd ../../
say "Tagging trunk"
svn update
-i=$(commit $i "tagging v1.0")
svn cp trunk tags/v1.0
+i=$(commit $i "tagging v1.0")
say "Branching BUGFIX from v1.0"
svn update
-i=$(commit $i "make bugfix branch from tag")
svn cp tags/v1.0 branches/bugfix
+i=$(commit $i "make bugfix branch from tag")
say "Make a commit to BUGFIX"
svn update
diff --git a/t/t9151/svn-mergeinfo.dump b/t/t9151/svn-mergeinfo.dump
index ebf386ebd5..47cafcf528 100644
--- a/t/t9151/svn-mergeinfo.dump
+++ b/t/t9151/svn-mergeinfo.dump
@@ -1633,13 +1633,427 @@ PROPS-END
Revision-number: 25
+Prop-content-length: 129
+Content-length: 129
+
+K 7
+svn:log
+V 31
+(r25) make b1 branch from trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:18:56.084589Z
+PROPS-END
+
+Node-path: branches/b1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 24
+Node-copyfrom-path: trunk
+
+
+Revision-number: 26
+Prop-content-length: 129
+Content-length: 129
+
+K 7
+svn:log
+V 31
+(r26) make b2 branch from trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:18:59.076940Z
+PROPS-END
+
+Node-path: branches/b2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 25
+Node-copyfrom-path: trunk
+
+
+Revision-number: 27
+Prop-content-length: 115
+Content-length: 115
+
+K 7
+svn:log
+V 17
+(r27) b2 update 1
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:01.095762Z
+PROPS-END
+
+Node-path: branches/b2/b2file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 5edbdd57cba621eb3c6e601bf563b4dc
+Text-content-sha1: 9d4b38049776bd0a2074d67cad23f8eaed35a3b3
+Content-length: 13
+
+PROPS-END
+b2
+
+
+Revision-number: 28
+Prop-content-length: 115
+Content-length: 115
+
+K 7
+svn:log
+V 17
+(r28) b1 update 1
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:03.097465Z
+PROPS-END
+
+Node-path: branches/b1/b1file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 08778dfd9ac4f603231896aba7aad523
+Text-content-sha1: b551771aa4ad5b14123fc3bd98d89db2bc0edd4f
+Content-length: 13
+
+PROPS-END
+b1
+
+
+Revision-number: 29
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 23
+(r29) Merge b1 to trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:06.073175Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 118
+Content-length: 118
+
+K 13
+svn:mergeinfo
+V 83
+/branches/b1:25-28
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+PROPS-END
+
+
+Node-path: trunk/b1file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 28
+Node-copyfrom-path: branches/b1/b1file
+Text-copy-source-md5: 08778dfd9ac4f603231896aba7aad523
+Text-copy-source-sha1: b551771aa4ad5b14123fc3bd98d89db2bc0edd4f
+
+
+Revision-number: 30
+Prop-content-length: 143
+Content-length: 143
+
+K 7
+svn:log
+V 45
+(r30) trunk commit before merging trunk to b2
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:08.096353Z
+PROPS-END
+
+Node-path: trunk/trunkfile
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 6
+Text-content-md5: edf45fe5c98c5367733b39bbb2bb20d9
+Text-content-sha1: 7361d1685e5c86dfc523620cfaf598f196f86239
+Content-length: 16
+
+PROPS-END
+trunk
+
+
+Revision-number: 31
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 23
+(r31) Merge trunk to b2
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:11.081541Z
+PROPS-END
+
+Node-path: branches/b2
+Node-kind: dir
+Node-action: change
+Prop-content-length: 131
+Content-length: 131
+
+K 13
+svn:mergeinfo
+V 96
+/branches/b1:25-28
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+/trunk:26-30
+PROPS-END
+
+
+Node-path: branches/b2/b1file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 30
+Node-copyfrom-path: trunk/b1file
+Text-copy-source-md5: 08778dfd9ac4f603231896aba7aad523
+Text-copy-source-sha1: b551771aa4ad5b14123fc3bd98d89db2bc0edd4f
+
+
+Node-path: branches/b2/trunkfile
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 30
+Node-copyfrom-path: trunk/trunkfile
+Text-copy-source-md5: edf45fe5c98c5367733b39bbb2bb20d9
+Text-copy-source-sha1: 7361d1685e5c86dfc523620cfaf598f196f86239
+
+
+Revision-number: 32
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 23
+(r32) Merge b2 to trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:14.117939Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 138
+Content-length: 138
+
+K 13
+svn:mergeinfo
+V 102
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+PROPS-END
+
+
+Node-path: trunk/b2file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 31
+Node-copyfrom-path: branches/b2/b2file
+Text-copy-source-md5: 5edbdd57cba621eb3c6e601bf563b4dc
+Text-copy-source-sha1: 9d4b38049776bd0a2074d67cad23f8eaed35a3b3
+
+
+Revision-number: 33
+Prop-content-length: 145
+Content-length: 145
+
+K 7
+svn:log
+V 47
+(r33) make f1 branch from trunk with a new file
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:17.105832Z
+PROPS-END
+
+Node-path: branches/f1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 32
+Node-copyfrom-path: trunk
+
+
+Node-path: branches/f1/f1file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 2b1abc6b6c5c0018851f9f8e6475563b
+Text-content-sha1: aece6dfba588900e00d95601d22b4408d49580af
+Content-length: 13
+
+PROPS-END
+f1
+
+
+Revision-number: 34
+Prop-content-length: 145
+Content-length: 145
+
+K 7
+svn:log
+V 47
+(r34) make f2 branch from trunk with a new file
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:20.110057Z
+PROPS-END
+
+Node-path: branches/f2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 33
+Node-copyfrom-path: trunk
+
+
+Node-path: branches/f2/f2file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 575c5638d60271457e54ab7d07309502
+Text-content-sha1: 1c49a440c352f3473efa9512255033b94dc7def0
+Content-length: 13
+
+PROPS-END
+f2
+
+
+Revision-number: 35
+Prop-content-length: 128
+Content-length: 128
+
+K 7
+svn:log
+V 30
+(r35) Merge f1 and f2 to trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:24.081490Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 173
+Content-length: 173
+
+K 13
+svn:mergeinfo
+V 137
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/f1:33-34
+/branches/f2:34
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+PROPS-END
+
+
+Node-path: trunk/f1file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 34
+Node-copyfrom-path: branches/f1/f1file
+Text-copy-source-md5: 2b1abc6b6c5c0018851f9f8e6475563b
+Text-copy-source-sha1: aece6dfba588900e00d95601d22b4408d49580af
+
+
+Node-path: trunk/f2file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 34
+Node-copyfrom-path: branches/f2/f2file
+Text-copy-source-md5: 575c5638d60271457e54ab7d07309502
+Text-copy-source-sha1: 1c49a440c352f3473efa9512255033b94dc7def0
+
+
+Revision-number: 36
Prop-content-length: 135
Content-length: 135
K 7
svn:log
V 37
-(r25) add subdirectory to left branch
+(r36) add subdirectory to left branch
K 10
svn:author
V 3
@@ -1647,7 +2061,7 @@ adm
K 8
svn:date
V 27
-2010-01-19T04:14:46.052649Z
+2010-02-22T06:19:26.113516Z
PROPS-END
Node-path: branches/left/subdir
@@ -1672,14 +2086,14 @@ PROPS-END
Yeehaw
-Revision-number: 26
+Revision-number: 37
Prop-content-length: 123
Content-length: 123
K 7
svn:log
V 25
-(r26) merge left to trunk
+(r37) merge left to trunk
K 10
svn:author
V 3
@@ -1687,19 +2101,23 @@ adm
K 8
svn:date
V 27
-2010-01-19T04:14:49.040783Z
+2010-02-22T06:19:29.073699Z
PROPS-END
Node-path: trunk
Node-kind: dir
Node-action: change
-Prop-content-length: 99
-Content-length: 99
+Prop-content-length: 173
+Content-length: 173
K 13
svn:mergeinfo
-V 64
-/branches/left:2-25
+V 137
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/f1:33-34
+/branches/f2:34
+/branches/left:2-36
/branches/left-sub:4-19
/branches/right:2-22
PROPS-END
@@ -1708,18 +2126,18 @@ PROPS-END
Node-path: trunk/subdir
Node-kind: dir
Node-action: add
-Node-copyfrom-rev: 25
+Node-copyfrom-rev: 36
Node-copyfrom-path: branches/left/subdir
-Revision-number: 27
-Prop-content-length: 118
-Content-length: 118
+Revision-number: 38
+Prop-content-length: 123
+Content-length: 123
K 7
svn:log
-V 20
-(r28) partial update
+V 25
+(r38) make partial branch
K 10
svn:author
V 3
@@ -1727,16 +2145,34 @@ adm
K 8
svn:date
V 27
-2010-01-19T04:14:53.049037Z
+2010-02-22T06:19:32.072243Z
PROPS-END
Node-path: branches/partial
Node-kind: dir
Node-action: add
-Node-copyfrom-rev: 26
+Node-copyfrom-rev: 37
Node-copyfrom-path: trunk/subdir
+Revision-number: 39
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 20
+(r39) partial update
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:34.097961Z
+PROPS-END
+
Node-path: branches/partial/palindromes
Node-kind: file
Node-action: add
@@ -1750,14 +2186,14 @@ PROPS-END
racecar
-Revision-number: 28
+Revision-number: 40
Prop-content-length: 126
Content-length: 126
K 7
svn:log
V 28
-(r29) merge partial to trunk
+(r40) merge partial to trunk
K 10
svn:author
V 3
@@ -1765,21 +2201,25 @@ adm
K 8
svn:date
V 27
-2010-01-19T04:14:56.041526Z
+2010-02-22T06:19:37.080211Z
PROPS-END
Node-path: trunk/subdir
Node-kind: dir
Node-action: change
-Prop-content-length: 142
-Content-length: 142
+Prop-content-length: 246
+Content-length: 246
K 13
svn:mergeinfo
-V 106
-/branches/left/subdir:2-25
+V 210
+/branches/b1/subdir:25-28
+/branches/b2/subdir:26-31
+/branches/f1/subdir:33-34
+/branches/f2/subdir:34
+/branches/left/subdir:2-36
/branches/left-sub/subdir:4-19
-/branches/partial:27
+/branches/partial:38-39
/branches/right/subdir:2-22
PROPS-END
@@ -1787,20 +2227,20 @@ PROPS-END
Node-path: trunk/subdir/palindromes
Node-kind: file
Node-action: add
-Node-copyfrom-rev: 27
+Node-copyfrom-rev: 39
Node-copyfrom-path: branches/partial/palindromes
Text-copy-source-md5: 5d1c2024fb5efc4eef812856df1b080c
Text-copy-source-sha1: 5f8509ddd14c91a52864dd1447344e706f9bbc69
-Revision-number: 29
-Prop-content-length: 131
-Content-length: 131
+Revision-number: 41
+Prop-content-length: 116
+Content-length: 116
K 7
svn:log
-V 33
-(r31) make bugfix branch from tag
+V 18
+(r41) tagging v1.0
K 10
svn:author
V 3
@@ -1808,24 +2248,24 @@ adm
K 8
svn:date
V 27
-2010-01-19T04:15:00.039761Z
+2010-02-22T06:19:40.083460Z
PROPS-END
Node-path: tags/v1.0
Node-kind: dir
Node-action: add
-Node-copyfrom-rev: 28
+Node-copyfrom-rev: 40
Node-copyfrom-path: trunk
-Revision-number: 30
-Prop-content-length: 120
-Content-length: 120
+Revision-number: 42
+Prop-content-length: 131
+Content-length: 131
K 7
svn:log
-V 22
-(r32) commit to bugfix
+V 33
+(r42) make bugfix branch from tag
K 10
svn:author
V 3
@@ -1833,16 +2273,34 @@ adm
K 8
svn:date
V 27
-2010-01-19T04:15:03.043218Z
+2010-02-22T06:19:43.118075Z
PROPS-END
Node-path: branches/bugfix
Node-kind: dir
Node-action: add
-Node-copyfrom-rev: 29
+Node-copyfrom-rev: 41
Node-copyfrom-path: tags/v1.0
+Revision-number: 43
+Prop-content-length: 120
+Content-length: 120
+
+K 7
+svn:log
+V 22
+(r43) commit to bugfix
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:45.079536Z
+PROPS-END
+
Node-path: branches/bugfix/subdir/palindromes
Node-kind: file
Node-action: change
@@ -1855,14 +2313,14 @@ racecar
kayak
-Revision-number: 31
+Revision-number: 44
Prop-content-length: 125
Content-length: 125
K 7
svn:log
V 27
-(r33) Merge BUGFIX to TRUNK
+(r44) Merge BUGFIX to TRUNK
K 10
svn:author
V 3
@@ -1870,41 +2328,49 @@ adm
K 8
svn:date
V 27
-2010-01-19T04:15:06.043723Z
+2010-02-22T06:19:48.078914Z
PROPS-END
Node-path: trunk
Node-kind: dir
Node-action: change
-Prop-content-length: 133
-Content-length: 133
+Prop-content-length: 210
+Content-length: 210
K 13
svn:mergeinfo
-V 98
-/branches/bugfix:30
-/branches/left:2-25
+V 174
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/bugfix:42-43
+/branches/f1:33-34
+/branches/f2:34
+/branches/left:2-36
/branches/left-sub:4-19
/branches/right:2-22
-/tags/v1.0:29
+/tags/v1.0:41
PROPS-END
Node-path: trunk/subdir
Node-kind: dir
Node-action: change
-Prop-content-length: 190
-Content-length: 190
+Prop-content-length: 297
+Content-length: 297
K 13
svn:mergeinfo
-V 154
-/branches/bugfix/subdir:30
-/branches/left/subdir:2-25
+V 261
+/branches/b1/subdir:25-28
+/branches/b2/subdir:26-31
+/branches/bugfix/subdir:42-43
+/branches/f1/subdir:33-34
+/branches/f2/subdir:34
+/branches/left/subdir:2-36
/branches/left-sub/subdir:4-19
-/branches/partial:27
+/branches/partial:38-39
/branches/right/subdir:2-22
-/tags/v1.0/subdir:29
+/tags/v1.0/subdir:41
PROPS-END
diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh
index 363345faef..b572ce3ab7 100755
--- a/t/t9600-cvsimport.sh
+++ b/t/t9600-cvsimport.sh
@@ -47,13 +47,20 @@ EOF
test_expect_success 'import a trivial module' '
- git cvsimport -a -z 0 -C module-git module &&
+ git cvsimport -a -R -z 0 -C module-git module &&
test_cmp module-cvs/o_fortuna module-git/o_fortuna
'
test_expect_success 'pack refs' 'cd module-git && git gc && cd ..'
+test_expect_success 'initial import has correct .git/cvs-revisions' '
+
+ (cd module-git &&
+ git log --format="o_fortuna 1.1 %H" -1) > expected &&
+ test_cmp expected module-git/.git/cvs-revisions
+'
+
test_expect_success 'update cvs module' '
cd module-cvs &&
@@ -86,13 +93,21 @@ EOF
test_expect_success 'update git module' '
cd module-git &&
- git cvsimport -a -z 0 module &&
+ git cvsimport -a -R -z 0 module &&
git merge origin &&
cd .. &&
test_cmp module-cvs/o_fortuna module-git/o_fortuna
'
+test_expect_success 'update has correct .git/cvs-revisions' '
+
+ (cd module-git &&
+ git log --format="o_fortuna 1.1 %H" -1 HEAD^ &&
+ git log --format="o_fortuna 1.2 %H" -1 HEAD) > expected &&
+ test_cmp expected module-git/.git/cvs-revisions
+'
+
test_expect_success 'update cvs module' '
cd module-cvs &&
@@ -107,13 +122,22 @@ test_expect_success 'cvsimport.module config works' '
cd module-git &&
git config cvsimport.module module &&
- git cvsimport -a -z0 &&
+ git cvsimport -a -R -z0 &&
git merge origin &&
cd .. &&
test_cmp module-cvs/tick module-git/tick
'
+test_expect_success 'second update has correct .git/cvs-revisions' '
+
+ (cd module-git &&
+ git log --format="o_fortuna 1.1 %H" -1 HEAD^^ &&
+ git log --format="o_fortuna 1.2 %H" -1 HEAD^
+ git log --format="tick 1.1 %H" -1 HEAD) > expected &&
+ test_cmp expected module-git/.git/cvs-revisions
+'
+
test_expect_success 'import from a CVS working tree' '
$CVS co -d import-from-wt module &&
@@ -126,6 +150,12 @@ test_expect_success 'import from a CVS working tree' '
'
+test_expect_success 'no .git/cvs-revisions created by default' '
+
+ ! test -e import-from-wt/.git/cvs-revisions
+
+'
+
test_expect_success 'test entire HEAD' 'test_cmp_branch_tree master'
test_done
diff --git a/transport.c b/transport.c
index 08e4fa0354..f07bd33e86 100644
--- a/transport.c
+++ b/transport.c
@@ -573,7 +573,7 @@ static int push_had_errors(struct ref *ref)
return 0;
}
-static int refs_pushed(struct ref *ref)
+int transport_refs_pushed(struct ref *ref)
{
for (; ref; ref = ref->next) {
switch(ref->status) {
@@ -587,7 +587,7 @@ static int refs_pushed(struct ref *ref)
return 0;
}
-static void update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
+void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
{
struct refspec rs;
@@ -609,8 +609,6 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb
}
}
-#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
-
static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
{
if (porcelain) {
@@ -623,7 +621,7 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str
else
fprintf(stdout, "%s\n", summary);
} else {
- fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
+ fprintf(stderr, " %c %-*s ", flag, TRANSPORT_SUMMARY_WIDTH, summary);
if (from)
fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
else
@@ -711,8 +709,8 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
return 1;
}
-static void print_push_status(const char *dest, struct ref *refs,
- int verbose, int porcelain, int * nonfastforward)
+void transport_print_push_status(const char *dest, struct ref *refs,
+ int verbose, int porcelain, int *nonfastforward)
{
struct ref *ref;
int n = 0;
@@ -738,7 +736,7 @@ static void print_push_status(const char *dest, struct ref *refs,
}
}
-static void verify_remote_names(int nr_heads, const char **heads)
+void transport_verify_remote_names(int nr_heads, const char **heads)
{
int i;
@@ -872,6 +870,21 @@ static int is_file(const char *url)
return S_ISREG(buf.st_mode);
}
+static int isurlschemechar(int first_flag, int ch)
+{
+ /*
+ * The set of valid URL schemes, as per STD66 (RFC3986) is
+ * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check
+ * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
+ * of check used '[A-Za-z0-9]+' so not to break any remote
+ * helpers.
+ */
+ int alphanumeric, special;
+ alphanumeric = ch > 0 && isalnum(ch);
+ special = ch == '+' || ch == '-' || ch == '.';
+ return alphanumeric || (!first_flag && special);
+}
+
static int is_url(const char *url)
{
const char *url2, *first_slash;
@@ -896,7 +909,7 @@ static int is_url(const char *url)
*/
url2 = url;
while (url2 < first_slash - 1) {
- if (!isalnum((unsigned char)*url2))
+ if (!isurlschemechar(url2 == url, (unsigned char)*url2))
return 0;
url2++;
}
@@ -930,7 +943,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
if (url) {
const char *p = url;
- while (isalnum(*p))
+ while (isurlschemechar(p == url, *p))
p++;
if (!prefixcmp(p, "::"))
helper = xstrndup(url, p - url);
@@ -1019,7 +1032,7 @@ int transport_push(struct transport *transport,
int *nonfastforward)
{
*nonfastforward = 0;
- verify_remote_names(refspec_nr, refspec);
+ transport_verify_remote_names(refspec_nr, refspec);
if (transport->push) {
/* Maybe FIXME. But no important transport uses this case. */
@@ -1058,7 +1071,7 @@ int transport_push(struct transport *transport,
ret |= err;
if (!quiet || err)
- print_push_status(transport->url, remote_refs,
+ transport_print_push_status(transport->url, remote_refs,
verbose | porcelain, porcelain,
nonfastforward);
@@ -1068,10 +1081,10 @@ int transport_push(struct transport *transport,
if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next)
- update_tracking_ref(transport->remote, ref, verbose);
+ transport_update_tracking_ref(transport->remote, ref, verbose);
}
- if (!quiet && !ret && !refs_pushed(remote_refs))
+ if (!quiet && !ret && !transport_refs_pushed(remote_refs))
fprintf(stderr, "Everything up-to-date\n");
return ret;
}
diff --git a/transport.h b/transport.h
index 6dd9ae182f..096f6e9478 100644
--- a/transport.h
+++ b/transport.h
@@ -98,6 +98,7 @@ struct transport {
#define TRANSPORT_PUSH_PORCELAIN 32
#define TRANSPORT_PUSH_QUIET 64
#define TRANSPORT_PUSH_SET_UPSTREAM 128
+#define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
@@ -148,4 +149,14 @@ int transport_connect(struct transport *transport, const char *name,
/* Transport methods defined outside transport.c */
int transport_helper_init(struct transport *transport, const char *name);
+/* common methods used by transport.c and builtin-send-pack.c */
+void transport_verify_remote_names(int nr_heads, const char **heads);
+
+void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose);
+
+int transport_refs_pushed(struct ref *ref);
+
+void transport_print_push_status(const char *dest, struct ref *refs,
+ int verbose, int porcelain, int *nonfastforward);
+
#endif
diff --git a/xdiff-interface.c b/xdiff-interface.c
index 01f14fb50f..ca5e3fbae8 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -218,6 +218,23 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
return 0;
}
+void read_mmblob(mmfile_t *ptr, const unsigned char *sha1)
+{
+ unsigned long size;
+ enum object_type type;
+
+ if (!hashcmp(sha1, null_sha1)) {
+ ptr->ptr = xstrdup("");
+ ptr->size = 0;
+ return;
+ }
+
+ ptr->ptr = read_sha1_file(sha1, &type, &size);
+ if (!ptr->ptr || type != OBJ_BLOB)
+ die("unable to read blob object %s", sha1_to_hex(sha1));
+ ptr->size = size;
+}
+
#define FIRST_FEW_BYTES 8000
int buffer_is_binary(const char *ptr, unsigned long size)
{
diff --git a/xdiff-interface.h b/xdiff-interface.h
index 55572c39a1..abba70c16b 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -18,6 +18,7 @@ int parse_hunk_header(char *line, int len,
int *ob, int *on,
int *nb, int *nn);
int read_mmfile(mmfile_t *ptr, const char *filename);
+void read_mmblob(mmfile_t *ptr, const unsigned char *sha1);
int buffer_is_binary(const char *ptr, unsigned long size);
extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);