summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--Documentation/RelNotes-1.6.3.3.txt38
-rw-r--r--Documentation/asciidoc.conf1
-rw-r--r--Documentation/git-am.txt6
-rw-r--r--Documentation/git-bisect.txt5
-rw-r--r--Documentation/git-rebase.txt4
-rw-r--r--Documentation/git-rev-parse.txt5
-rw-r--r--Documentation/git-stash.txt15
-rw-r--r--Documentation/git-submodule.txt5
-rw-r--r--Documentation/git-svn.txt108
-rw-r--r--Documentation/git.txt3
-rw-r--r--Documentation/gittutorial.txt24
-rw-r--r--Makefile16
-rw-r--r--attr.c2
-rw-r--r--bisect.c50
-rw-r--r--builtin-mv.c10
-rw-r--r--builtin-receive-pack.c53
-rw-r--r--builtin-remote.c18
-rw-r--r--builtin-rev-parse.c8
-rw-r--r--commit.c6
-rwxr-xr-xcontrib/completion/git-completion.bash7
-rw-r--r--daemon.c56
-rw-r--r--fsck.c2
-rwxr-xr-xgit-am.sh166
-rwxr-xr-xgit-cvsexportcommit.perl5
-rwxr-xr-xgit-rebase.sh48
-rwxr-xr-xgit-repack.sh12
-rwxr-xr-xgit-request-pull.sh7
-rwxr-xr-xgit-sh-setup.sh9
-rwxr-xr-xgit-stash.sh78
-rwxr-xr-xgit-submodule.sh24
-rwxr-xr-xgit-svn.perl173
-rw-r--r--git.c3
-rw-r--r--gitweb/README10
-rw-r--r--http-push.c2
-rw-r--r--ll-merge.c8
-rw-r--r--log-tree.c3
-rw-r--r--merge-recursive.c9
-rw-r--r--revision.c4
-rw-r--r--revision.h1
-rw-r--r--strbuf.c2
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh43
-rwxr-xr-xt/t3400-rebase.sh19
-rwxr-xr-xt/t3404-rebase-interactive.sh4
-rwxr-xr-xt/t3505-cherry-pick-empty.sh10
-rwxr-xr-xt/t3700-add.sh2
-rwxr-xr-xt/t3903-stash.sh23
-rwxr-xr-xt/t4037-diff-r-t-dirs.sh53
-rwxr-xr-xt/t4150-am.sh26
-rwxr-xr-xt/t5000-tar-tree.sh4
-rwxr-xr-xt/t6024-recursive-merge.sh9
-rwxr-xr-xt/t6030-bisect-porcelain.sh4
-rwxr-xr-xt/t7002-grep.sh30
-rwxr-xr-xt/t9001-send-email.sh5
-rwxr-xr-xt/t9100-git-svn-basic.sh19
-rwxr-xr-xt/t9138-git-svn-multiple-branches.sh122
-rwxr-xr-xt/t9139-git-svn-reset.sh66
-rw-r--r--tree-diff.c6
-rw-r--r--upload-pack.c7
-rw-r--r--ws.c12
60 files changed, 1211 insertions, 261 deletions
diff --git a/.gitattributes b/.gitattributes
index 6b9c715d21..0636deea93 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,2 @@
* whitespace=!indent,trail,space
-*.[ch] whitespace
+*.[ch] whitespace=indent,trail,space
diff --git a/Documentation/RelNotes-1.6.3.3.txt b/Documentation/RelNotes-1.6.3.3.txt
new file mode 100644
index 0000000000..1c28398bb6
--- /dev/null
+++ b/Documentation/RelNotes-1.6.3.3.txt
@@ -0,0 +1,38 @@
+GIT v1.6.3.3 Release Notes
+==========================
+
+Fixes since v1.6.3.2
+--------------------
+
+ * "git archive" running on Cygwin can get stuck in an infinite loop.
+
+ * "git daemon" did not correctly parse the initial line that carries
+ virtual host request information.
+
+ * "git diff --textconv" leaked memory badly when the textconv filter
+ errored out.
+
+ * The built-in regular expressions to pick function names to put on
+ hunk header lines for java and objc were very inefficiently written.
+
+ * in certain error situations git-fetch (and git-clone) on Windows didn't
+ detect connection abort and ended up waiting indefinitely.
+
+ * import-tars script (in contrib) did not import symbolic links correctly.
+
+ * http.c used CURLOPT_SSLKEY even on libcURL version 7.9.2, even though
+ it was only available starting 7.9.3.
+
+ * low-level filelevel merge driver used return value from strdup()
+ without checking if we ran out of memory.
+
+ * "git rebase -i" left stray closing parenthesis in its reflog message.
+
+ * "git remote show" did not show all the URLs associated with the named
+ remote, even though "git remote -v" did. Made them consistent by
+ making the former show all URLs.
+
+ * "whitespace" attribute that is set was meant to detect all errors known
+ to git, but it told git to ignore trailing carriage-returns.
+
+Includes other documentation fixes.
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index dc76e7f073..87a90f2c3f 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -17,6 +17,7 @@ caret=^
startsb=[
endsb=]
tilde=~
+backtick=`
ifdef::backend-docbook[]
[linkgit-inlinemacro]
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 6d92cbee64..32e689b2bf 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[--3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
- [--reject]
+ [--reject] [-q | --quiet]
[<mbox> | <Maildir>...]
'git am' (--skip | --resolved | --abort)
@@ -39,6 +39,10 @@ OPTIONS
--keep::
Pass `-k` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).
+-q::
+--quiet::
+ Be quiet. Only print error messages.
+
-u::
--utf8::
Pass `-u` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index ffc02c737c..63e7a42cb3 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -164,9 +164,8 @@ to do it for you by issuing the command:
$ git bisect skip # Current version cannot be tested
------------
-But computing the commit to test may be slower afterwards and git may
-eventually not be able to tell the first bad commit among a bad commit
-and one or more skipped commits.
+But git may eventually be unable to tell the first bad commit among
+a bad commit and one or more skipped commits.
You can even skip a range of commits, instead of just one commit,
using the "'<commit1>'..'<commit2>'" notation. For example:
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 26f3b7b2b0..db1b71d248 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -236,6 +236,10 @@ OPTIONS
is used instead ('git-merge-recursive' when merging a single
head, 'git-merge-octopus' otherwise). This implies --merge.
+-q::
+--quiet::
+ Be quiet. Implies --no-stat.
+
-v::
--verbose::
Be verbose. Implies --stat.
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 4bbdd056da..82045a2522 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -30,6 +30,11 @@ OPTIONS
Only meaningful in `--parseopt` mode. Tells the option parser to echo
out the first `--` met instead of skipping it.
+--stop-at-non-option::
+ Only meaningful in `--parseopt` mode. Lets the option parser stop at
+ the first non-option argument. This can be used to parse sub-commands
+ that take options themself.
+
--sq-quote::
Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE
section below). In contrast to the `--sq` option below, this
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index a42d4c85bd..1c64a02fe5 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -9,10 +9,11 @@ SYNOPSIS
--------
[verse]
'git stash' list [<options>]
-'git stash' ( show | drop ) [<stash>]
-'git stash' ( pop | apply ) [--index] [<stash>]
+'git stash' show [<stash>]
+'git stash' drop [-q|--quiet] [<stash>]
+'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
'git stash' branch <branchname> [<stash>]
-'git stash' [save [--keep-index] [<message>]]
+'git stash' [save [--keep-index] [-q|--quiet] [<message>]]
'git stash' clear
'git stash' create
@@ -41,7 +42,7 @@ is also possible).
OPTIONS
-------
-save [--keep-index] [<message>]::
+save [--keep-index] [-q|--quiet] [<message>]::
Save your local modifications to a new 'stash', and run `git reset
--hard` to revert them. This is the default action when no
@@ -75,7 +76,7 @@ show [<stash>]::
it will accept any format known to 'git-diff' (e.g., `git stash show
-p stash@\{1}` to view the second most recent stash in patch form).
-pop [<stash>]::
+pop [--index] [-q|--quiet] [<stash>]::
Remove a single stashed state from the stash list and apply it
on top of the current working tree state, i.e., do the inverse
@@ -93,7 +94,7 @@ longer apply the changes as they were originally).
+
When no `<stash>` is given, `stash@\{0}` is assumed.
-apply [--index] [<stash>]::
+apply [--index] [-q|--quiet] [<stash>]::
Like `pop`, but do not remove the state from the stash list.
@@ -115,7 +116,7 @@ clear::
Remove all the stashed states. Note that those states will then
be subject to pruning, and may be difficult or impossible to recover.
-drop [<stash>]::
+drop [-q|--quiet] [<stash>]::
Remove a single stashed state from the stash list. When no `<stash>`
is given, it removes the latest one. i.e. `stash@\{0}`
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 470bd75ad9..683ba1a1eb 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -141,8 +141,9 @@ foreach::
the processing to terminate. This can be overridden by adding '|| :'
to the end of the command.
+
-As an example, "git submodule foreach 'echo $path `git rev-parse HEAD`' will
-show the path and currently checked out commit for each submodule.
+As an example, +git submodule foreach \'echo $path {backtick}git
+rev-parse HEAD{backtick}'+ will show the path and currently checked out
+commit for each submodule.
sync::
Synchronizes submodules' remote URL configuration setting
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index bb22d8e712..7e9b9a0423 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -3,7 +3,7 @@ git-svn(1)
NAME
----
-git-svn - Bidirectional operation between a single Subversion branch and git
+git-svn - Bidirectional operation between a Subversion repository and git
SYNOPSIS
--------
@@ -15,13 +15,12 @@ DESCRIPTION
It provides a bidirectional flow of changes between a Subversion and a git
repository.
-'git-svn' can track a single Subversion branch simply by using a
-URL to the branch, follow branches laid out in the Subversion recommended
-method (trunk, branches, tags directories) with the --stdlayout option, or
-follow branches in any layout with the -T/-t/-b options (see options to
-'init' below, and also the 'clone' command).
+'git-svn' can track a standard Subversion repository,
+following the common "trunk/branches/tags" layout, with the --stdlayout option.
+It can also follow branches and tags in any layout with the -T/-t/-b options
+(see options to 'init' below, and also the 'clone' command).
-Once tracking a Subversion branch (with any of the above methods), the git
+Once tracking a Subversion repository (with any of the above methods), the git
repository can be updated from Subversion by the 'fetch' command and
Subversion updated from git by the 'dcommit' command.
@@ -48,8 +47,11 @@ COMMANDS
--stdlayout;;
These are optional command-line options for init. Each of
these flags can point to a relative repository path
- (--tags=project/tags') or a full url
- (--tags=https://foo.org/project/tags). The option --stdlayout is
+ (--tags=project/tags) or a full url
+ (--tags=https://foo.org/project/tags).
+ You can specify more than one --tags and/or --branches options, in case
+ your Subversion repository places tags or branches under multiple paths.
+ The option --stdlayout is
a shorthand way of setting trunk,tags,branches as the relative paths,
which is the Subversion default. If any of the other options are given
as well, they take precedence.
@@ -170,8 +172,9 @@ and have no uncommitted changes.
It is recommended that you run 'git-svn' fetch and rebase (not
pull or merge) your commits against the latest changes in the
SVN repository.
- An optional command-line argument may be specified as an
- alternative to HEAD.
+ An optional revision or branch argument may be specified, and
+ causes 'git-svn' to do all work on that revision/branch
+ instead of HEAD.
This is advantageous over 'set-tree' (below) because it produces
cleaner, more linear history.
+
@@ -204,6 +207,20 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
Create a tag by using the tags_subdir instead of the branches_subdir
specified during git svn init.
+-d;;
+--destination;;
+ If more than one --branches (or --tags) option was given to the 'init'
+ or 'clone' command, you must provide the location of the branch (or
+ tag) you wish to create in the SVN repository. The value of this
+ option must match one of the paths specified by a --branches (or
+ --tags) option. You can see these paths with the commands
++
+ git config --get-all svn-remote.<name>.branches
+ git config --get-all svn-remote.<name>.tags
++
+where <name> is the name of the SVN repository as specified by the -R option to
+'init' (or "svn" by default).
+
'tag'::
Create a tag in the SVN repository. This is a shorthand for
'branch -t'.
@@ -215,7 +232,7 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
The following features from `svn log' are supported:
+
--
---revision=<n>[:<n>];;
+-r/--revision=<n>[:<n>];;
is supported, non-numeric args are not:
HEAD, NEXT, BASE, PREV, etc ...
-v/--verbose;;
@@ -313,6 +330,63 @@ Any other arguments are passed directly to 'git-log'
Shows the Subversion externals. Use -r/--revision to specify a
specific revision.
+'reset'::
+ Undoes the effects of 'fetch' back to the specified revision.
+ This allows you to re-'fetch' an SVN revision. Normally the
+ contents of an SVN revision should never change and 'reset'
+ should not be necessary. However, if SVN permissions change,
+ or if you alter your --ignore-paths option, a 'fetch' may fail
+ with "not found in commit" (file not previously visible) or
+ "checksum mismatch" (missed a modification). If the problem
+ file cannot be ignored forever (with --ignore-paths) the only
+ way to repair the repo is to use 'reset'.
+
+Only the rev_map and refs/remotes/git-svn are changed. Follow 'reset'
+with a 'fetch' and then 'git-reset' or 'git-rebase' to move local
+branches onto the new tree.
+
+-r/--revision=<n>;;
+ Specify the most recent revision to keep. All later revisions
+ are discarded.
+-p/--parent;;
+ Discard the specified revision as well, keeping the nearest
+ parent instead.
+Example:;;
+Assume you have local changes in "master", but you need to refetch "r2".
+
+------------
+ r1---r2---r3 remotes/git-svn
+ \
+ A---B master
+------------
+
+Fix the ignore-paths or SVN permissions problem that caused "r2" to
+be incomplete in the first place. Then:
+
+[verse]
+git svn reset -r2 -p
+git svn fetch
+
+------------
+ r1---r2'--r3' remotes/git-svn
+ \
+ r2---r3---A---B master
+------------
+
+Then fixup "master" with 'git-rebase'.
+Do NOT use 'git-merge' or your history will not be compatible with a
+future 'dcommit'!
+
+[verse]
+git rebase --onto remotes/git-svn A^ master
+
+------------
+ r1---r2'--r3' remotes/git-svn
+ \
+ A'--B' master
+------------
+
+
--
OPTIONS
@@ -669,6 +743,16 @@ already dcommitted. It is considered bad practice to --amend commits
you've already pushed to a remote repository for other users, and
dcommit with SVN is analogous to that.
+When using multiple --branches or --tags, 'git-svn' does not automatically
+handle name collisions (for example, if two branches from different paths have
+the same name, or if a branch and a tag have the same name). In these cases,
+use 'init' to set up your git repository then, before your first 'fetch', edit
+the .git/config file so that the branches and tags are associated with
+different name spaces. For example:
+
+ branches = stable/*:refs/remotes/svn/stable/*
+ branches = debug/*:refs/remotes/svn/debug/*
+
BUGS
----
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 56d47709ac..6fa0310e05 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.6.3.2/git.html[documentation for release 1.6.3.2]
+* link:v1.6.3.3/git.html[documentation for release 1.6.3.3]
* release notes for
+ link:RelNotes-1.6.3.3.txt[1.6.3.3],
link:RelNotes-1.6.3.2.txt[1.6.3.2],
link:RelNotes-1.6.3.1.txt[1.6.3.1],
link:RelNotes-1.6.3.txt[1.6.3].
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index c7fa949c28..cf0689cfeb 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -332,11 +332,11 @@ alice$ git log -p HEAD..FETCH_HEAD
------------------------------------------------
This operation is safe even if Alice has uncommitted local changes.
-The range notation HEAD..FETCH_HEAD" means "show everything that is reachable
-from the FETCH_HEAD but exclude anything that is reachable from HEAD.
+The range notation "HEAD..FETCH_HEAD" means "show everything that is reachable
+from the FETCH_HEAD but exclude anything that is reachable from HEAD".
Alice already knows everything that leads to her current state (HEAD),
-and reviewing what Bob has in his state (FETCH_HEAD) that she has not
-seen with this command
+and reviews what Bob has in his state (FETCH_HEAD) that she has not
+seen with this command.
If Alice wants to visualize what Bob did since their histories forked
she can issue the following command:
@@ -375,9 +375,9 @@ it easier:
alice$ git remote add bob /home/bob/myrepo
------------------------------------------------
-With this, Alice can perform the first part of the "pull" operation alone using the
-'git-fetch' command without merging them with her own branch,
-using:
+With this, Alice can perform the first part of the "pull" operation
+alone using the 'git-fetch' command without merging them with her own
+branch, using:
-------------------------------------
alice$ git fetch bob
@@ -566,22 +566,22 @@ $ git log v2.5.. Makefile # commits since v2.5 which modify
You can also give 'git-log' a "range" of commits where the first is not
necessarily an ancestor of the second; for example, if the tips of
-the branches "stable-release" and "master" diverged from a common
+the branches "stable" and "master" diverged from a common
commit some time ago, then
-------------------------------------
-$ git log stable..experimental
+$ git log stable..master
-------------------------------------
-will list commits made in the experimental branch but not in the
+will list commits made in the master branch but not in the
stable branch, while
-------------------------------------
-$ git log experimental..stable
+$ git log master..stable
-------------------------------------
will show the list of commits made on the stable branch but not
-the experimental branch.
+the master branch.
The 'git-log' command has a weakness: it must present commits in a
list. When the history has lines of development that diverged and
diff --git a/Makefile b/Makefile
index 41ab8e9e0d..78cc11382a 100644
--- a/Makefile
+++ b/Makefile
@@ -194,6 +194,8 @@ all::
#
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
+#
+# Define NO_REGEX if you have no or inferior regex support in your C library.
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -723,6 +725,7 @@ ifeq ($(uname_S),SunOS)
NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease
NO_MKSTEMPS = YesPlease
+ NO_REGEX = YesPlease
ifeq ($(uname_R),5.7)
NEEDS_RESOLV = YesPlease
NO_IPV6 = YesPlease
@@ -750,7 +753,7 @@ ifeq ($(uname_S),SunOS)
endif
INSTALL = /usr/ucb/install
TAR = gtar
- BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__
+ BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
endif
ifeq ($(uname_O),Cygwin)
NO_D_TYPE_IN_DIRENT = YesPlease
@@ -884,9 +887,10 @@ ifneq (,$(findstring MINGW,$(uname_S)))
USE_NED_ALLOCATOR = YesPlease
UNRELIABLE_FSTAT = UnfortunatelyYes
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
- COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
+ NO_REGEX = YesPlease
+ COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
- COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o
+ COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o
EXTLIBS += -lws2_32
X = .exe
ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
@@ -1200,6 +1204,10 @@ endif
ifdef UNRELIABLE_FSTAT
BASIC_CFLAGS += -DUNRELIABLE_FSTAT
endif
+ifdef NO_REGEX
+ COMPAT_CFLAGS += -Icompat/regex
+ COMPAT_OBJS += compat/regex/regex.o
+endif
ifdef USE_NED_ALLOCATOR
COMPAT_CFLAGS += -DUSE_NED_ALLOCATOR -DOVERRIDE_STRDUP -DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR -Icompat/nedmalloc
@@ -1464,7 +1472,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
-$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.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)
diff --git a/attr.c b/attr.c
index f8f6faa94f..55bdb7cdeb 100644
--- a/attr.c
+++ b/attr.c
@@ -555,6 +555,8 @@ static void prepare_attr_stack(const char *path, int dirlen)
}
}
+ strbuf_release(&pathbuf);
+
/*
* Finally push the "info" one at the top of the stack.
*/
diff --git a/bisect.c b/bisect.c
index dbeb28752a..52220df751 100644
--- a/bisect.c
+++ b/bisect.c
@@ -585,16 +585,49 @@ struct commit_list *filter_skipped(struct commit_list *list,
return filtered;
}
-static struct commit_list *apply_skip_ratio(struct commit_list *list,
- int count,
- int skip_num, int skip_denom)
+#define PRN_MODULO 32768
+
+/*
+ * This is a pseudo random number generator based on "man 3 rand".
+ * It is not used properly because the seed is the argument and it
+ * is increased by one between each call, but that should not matter
+ * for this application.
+ */
+int get_prn(int count) {
+ count = count * 1103515245 + 12345;
+ return ((unsigned)(count/65536) % PRN_MODULO);
+}
+
+/*
+ * Custom integer square root from
+ * http://en.wikipedia.org/wiki/Integer_square_root
+ */
+static int sqrti(int val)
+{
+ float d, x = val;
+
+ if (val == 0)
+ return 0;
+
+ do {
+ float y = (x + (float)val / x) / 2;
+ d = (y > x) ? y - x : x - y;
+ x = y;
+ } while (d >= 0.5);
+
+ return (int)x;
+}
+
+static struct commit_list *skip_away(struct commit_list *list, int count)
{
- int index, i;
struct commit_list *cur, *previous;
+ int prn, index, i;
+
+ prn = get_prn(count);
+ index = (count * prn / PRN_MODULO) * sqrti(prn) / sqrti(PRN_MODULO);
cur = list;
previous = NULL;
- index = count * skip_num / skip_denom;
for (i = 0; cur; cur = cur->next, i++) {
if (i == index) {
@@ -614,7 +647,6 @@ static struct commit_list *managed_skipped(struct commit_list *list,
struct commit_list **tried)
{
int count, skipped_first;
- int skip_num, skip_denom;
*tried = NULL;
@@ -626,11 +658,7 @@ static struct commit_list *managed_skipped(struct commit_list *list,
if (!skipped_first)
return list;
- /* Use alternatively 1/5, 2/5 and 3/5 as skip ratio. */
- skip_num = count % 3 + 1;
- skip_denom = 5;
-
- return apply_skip_ratio(list, count, skip_num, skip_denom);
+ return skip_away(list, count);
}
static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
diff --git a/builtin-mv.c b/builtin-mv.c
index 8b81d4b51d..68f47384dc 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -24,14 +24,10 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
result[count] = NULL;
for (i = 0; i < count; i++) {
int length = strlen(result[i]);
- if (length > 0 && result[i][length - 1] == '/') {
+ if (length > 0 && is_dir_sep(result[i][length - 1]))
result[i] = xmemdupz(result[i], length - 1);
- }
- if (base_name) {
- const char *last_slash = strrchr(result[i], '/');
- if (last_slash)
- result[i] = last_slash + 1;
- }
+ if (base_name)
+ result[i] = basename((char *)result[i]);
}
return get_pathspec(prefix, result);
}
diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c
index 33d345dc39..6ec1d056e6 100644
--- a/builtin-receive-pack.c
+++ b/builtin-receive-pack.c
@@ -123,27 +123,27 @@ static struct command *commands;
static const char pre_receive_hook[] = "hooks/pre-receive";
static const char post_receive_hook[] = "hooks/post-receive";
-static int hook_status(int code, const char *hook_name)
+static int run_status(int code, const char *cmd_name)
{
switch (code) {
case 0:
return 0;
case -ERR_RUN_COMMAND_FORK:
- return error("hook fork failed");
+ return error("fork of %s failed", cmd_name);
case -ERR_RUN_COMMAND_EXEC:
- return error("hook execute failed");
+ return error("execute of %s failed", cmd_name);
case -ERR_RUN_COMMAND_PIPE:
- return error("hook pipe failed");
+ return error("pipe failed");
case -ERR_RUN_COMMAND_WAITPID:
return error("waitpid failed");
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
return error("waitpid is confused");
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
- return error("%s died of signal", hook_name);
+ return error("%s died of signal", cmd_name);
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
- return error("%s died strangely", hook_name);
+ return error("%s died strangely", cmd_name);
default:
- error("%s exited with error code %d", hook_name, -code);
+ error("%s exited with error code %d", cmd_name, -code);
return -code;
}
}
@@ -174,7 +174,7 @@ static int run_receive_hook(const char *hook_name)
code = start_command(&proc);
if (code)
- return hook_status(code, hook_name);
+ return run_status(code, hook_name);
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string) {
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
@@ -186,7 +186,7 @@ static int run_receive_hook(const char *hook_name)
}
}
close(proc.in);
- return hook_status(finish_command(&proc), hook_name);
+ return run_status(finish_command(&proc), hook_name);
}
static int run_update_hook(struct command *cmd)
@@ -203,7 +203,7 @@ static int run_update_hook(struct command *cmd)
argv[3] = sha1_to_hex(cmd->new_sha1);
argv[4] = NULL;
- return hook_status(run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
+ return run_status(run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
RUN_COMMAND_STDOUT_TO_STDERR),
update_hook);
}
@@ -394,7 +394,7 @@ static char update_post_hook[] = "hooks/post-update";
static void run_update_post_hook(struct command *cmd)
{
struct command *cmd_p;
- int argc;
+ int argc, status;
const char **argv;
for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
@@ -417,8 +417,9 @@ static void run_update_post_hook(struct command *cmd)
argc++;
}
argv[argc] = NULL;
- run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
- | RUN_COMMAND_STDOUT_TO_STDERR);
+ status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
+ | RUN_COMMAND_STDOUT_TO_STDERR);
+ run_status(status, update_post_hook);
}
static void execute_commands(const char *unpacker_error)
@@ -534,24 +535,10 @@ static const char *unpack(void)
unpacker[i++] = hdr_arg;
unpacker[i++] = NULL;
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
- switch (code) {
- case 0:
+ if (!code)
return NULL;
- case -ERR_RUN_COMMAND_FORK:
- return "unpack fork failed";
- case -ERR_RUN_COMMAND_EXEC:
- return "unpack execute failed";
- case -ERR_RUN_COMMAND_WAITPID:
- return "waitpid failed";
- case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
- return "waitpid is confused";
- case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
- return "unpacker died of signal";
- case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
- return "unpacker died strangely";
- default:
- return "unpacker exited with error code";
- }
+ run_status(code, unpacker[0]);
+ return "unpack-objects abnormal exit";
} else {
const char *keeper[7];
int s, status, i = 0;
@@ -574,8 +561,11 @@ static const char *unpack(void)
ip.argv = keeper;
ip.out = -1;
ip.git_cmd = 1;
- if (start_command(&ip))
+ status = start_command(&ip);
+ if (status) {
+ run_status(status, keeper[0]);
return "index-pack fork failed";
+ }
pack_lockfile = index_pack_lockfile(ip.out);
close(ip.out);
status = finish_command(&ip);
@@ -583,6 +573,7 @@ static const char *unpack(void)
reprepare_packed_git();
return NULL;
}
+ run_status(status, keeper[0]);
return "index-pack abnormal exit";
}
}
diff --git a/builtin-remote.c b/builtin-remote.c
index 658d578588..008abfe092 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -787,7 +787,7 @@ static int get_remote_ref_states(const char *name,
read_branches();
if (query) {
- transport = transport_get(NULL, states->remote->url_nr > 0 ?
+ transport = transport_get(states->remote, states->remote->url_nr > 0 ?
states->remote->url[0] : NULL);
remote_refs = transport_get_remote_refs(transport);
transport_disconnect(transport);
@@ -1276,15 +1276,14 @@ static int update(int argc, const char **argv)
static int get_one_entry(struct remote *remote, void *priv)
{
struct string_list *list = priv;
+ struct strbuf url_buf = STRBUF_INIT;
const char **url;
int i, url_nr;
- void **utilp;
if (remote->url_nr > 0) {
- utilp = &(string_list_append(remote->name, list)->util);
- *utilp = xmalloc(strlen(remote->url[0])+strlen(" (fetch)")+1);
- strcpy((char *) *utilp, remote->url[0]);
- strcat((char *) *utilp, " (fetch)");
+ strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
+ string_list_append(remote->name, list)->util =
+ strbuf_detach(&url_buf, NULL);
} else
string_list_append(remote->name, list)->util = NULL;
if (remote->pushurl_nr) {
@@ -1296,10 +1295,9 @@ static int get_one_entry(struct remote *remote, void *priv)
}
for (i = 0; i < url_nr; i++)
{
- utilp = &(string_list_append(remote->name, list)->util);
- *utilp = xmalloc(strlen(url[i])+strlen(" (push)")+1);
- strcpy((char *) *utilp, url[i]);
- strcat((char *) *utilp, " (push)");
+ strbuf_addf(&url_buf, "%s (push)", url[i]);
+ string_list_append(remote->name, list)->util =
+ strbuf_detach(&url_buf, NULL);
}
return 0;
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 112d622cda..5ea7518b0f 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -301,7 +301,7 @@ static const char *skipspaces(const char *s)
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
- static int keep_dashdash = 0;
+ static int keep_dashdash = 0, stop_at_non_option = 0;
static char const * const parseopt_usage[] = {
"git rev-parse --parseopt [options] -- [<args>...]",
NULL
@@ -309,6 +309,9 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
static struct option parseopt_opts[] = {
OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
"keep the `--` passed as an arg"),
+ OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
+ "stop parsing after the "
+ "first non-option argument"),
OPT_END(),
};
@@ -394,7 +397,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
ALLOC_GROW(opts, onb + 1, osz);
memset(opts + onb, 0, sizeof(opts[onb]));
argc = parse_options(argc, argv, prefix, opts, usage,
- keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
+ keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0 |
+ stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0);
strbuf_addf(&parsed, " --");
sq_quote_argv(&parsed, argv, 0);
diff --git a/commit.c b/commit.c
index aa3b35b6a8..a47fb4da27 100644
--- a/commit.c
+++ b/commit.c
@@ -50,7 +50,6 @@ struct commit *lookup_commit(const unsigned char *sha1)
static unsigned long parse_commit_date(const char *buf, const char *tail)
{
- unsigned long date;
const char *dateptr;
if (buf + 6 >= tail)
@@ -73,10 +72,7 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)
if (buf >= tail)
return 0;
/* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
- date = strtoul(dateptr, NULL, 10);
- if (date == ULONG_MAX)
- date = 0;
- return date;
+ return strtoul(dateptr, NULL, 10);
}
static struct commit_graft **commit_graft;
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index b60cb68a8b..1f44ec2092 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1165,7 +1165,7 @@ _git_log ()
$__git_log_shortlog_options
$__git_log_gitk_options
--root --topo-order --date-order --reverse
- --follow
+ --follow --full-diff
--abbrev-commit --abbrev=
--relative-date --date=
--pretty= --format= --oneline
@@ -1457,7 +1457,7 @@ _git_config ()
branch.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
- __gitcomp "remote merge mergeoptions" "$pfx" "$cur"
+ __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur"
return
;;
branch.*)
@@ -1504,7 +1504,7 @@ _git_config ()
cur="${cur##*.}"
__gitcomp "
url proxy fetch push mirror skipDefaultUpdate
- receivepack uploadpack tagopt
+ receivepack uploadpack tagopt pushurl
" "$pfx" "$cur"
return
;;
@@ -1522,6 +1522,7 @@ _git_config ()
;;
esac
__gitcomp "
+ add.ignore-errors
alias.
apply.whitespace
branch.autosetupmerge
diff --git a/daemon.c b/daemon.c
index 366db37b39..76a400557d 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1,6 +1,8 @@
#include "cache.h"
#include "pkt-line.h"
#include "exec_cmd.h"
+#include "run-command.h"
+#include "strbuf.h"
#include <syslog.h>
@@ -343,28 +345,66 @@ static int run_service(char *dir, struct daemon_service *service)
return service->fn();
}
+static void copy_to_log(int fd)
+{
+ struct strbuf line = STRBUF_INIT;
+ FILE *fp;
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ logerror("fdopen of error channel failed");
+ close(fd);
+ return;
+ }
+
+ while (strbuf_getline(&line, fp, '\n') != EOF) {
+ logerror("%s", line.buf);
+ strbuf_setlen(&line, 0);
+ }
+
+ strbuf_release(&line);
+ fclose(fp);
+}
+
+static int run_service_command(const char **argv)
+{
+ struct child_process cld;
+
+ memset(&cld, 0, sizeof(cld));
+ cld.argv = argv;
+ cld.git_cmd = 1;
+ cld.err = -1;
+ if (start_command(&cld))
+ return -1;
+
+ close(0);
+ close(1);
+
+ copy_to_log(cld.err);
+
+ return finish_command(&cld);
+}
+
static int upload_pack(void)
{
/* Timeout as string */
char timeout_buf[64];
+ const char *argv[] = { "upload-pack", "--strict", timeout_buf, ".", NULL };
snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
-
- /* git-upload-pack only ever reads stuff, so this is safe */
- execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
- return -1;
+ return run_service_command(argv);
}
static int upload_archive(void)
{
- execl_git_cmd("upload-archive", ".", NULL);
- return -1;
+ static const char *argv[] = { "upload-archive", ".", NULL };
+ return run_service_command(argv);
}
static int receive_pack(void)
{
- execl_git_cmd("receive-pack", ".", NULL);
- return -1;
+ static const char *argv[] = { "receive-pack", ".", NULL };
+ return run_service_command(argv);
}
static struct daemon_service daemon_service[] = {
diff --git a/fsck.c b/fsck.c
index 511b82cba9..89278c1459 100644
--- a/fsck.c
+++ b/fsck.c
@@ -229,7 +229,7 @@ static int fsck_commit(struct commit *commit, fsck_error error_func)
struct commit_graft *graft;
int parents = 0;
- if (!commit->date)
+ if (commit->date == ULONG_MAX)
return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line");
if (memcmp(buffer, "tree ", 5))
diff --git a/git-am.sh b/git-am.sh
index 578780be13..d64d997535 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -11,6 +11,7 @@ git am [options] (--resolved | --skip | --abort)
i,interactive run interactively
b,binary* (historical option -- no-op)
3,3way allow fall back on 3way merging if needed
+q,quiet be quiet
s,signoff add a Signed-off-by line to the commit message
u,utf8 recode into utf8 (default)
k,keep pass -k flag to git-mailinfo
@@ -18,6 +19,7 @@ whitespace= pass it through git-apply
directory= pass it through git-apply
C= pass it through git-apply
p= pass it through git-apply
+patch-format= format the patch(es) are in
reject pass it through git-apply
resolvemsg= override error message when patch failure occurs
r,resolved to be used after a patch failure
@@ -99,7 +101,7 @@ fall_back_3way () {
git write-tree >"$dotest/patch-merge-base+" ||
cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge."
- echo Using index info to reconstruct a base tree...
+ say Using index info to reconstruct a base tree...
if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
git apply --cached <"$dotest/patch"
then
@@ -115,7 +117,7 @@ It does not apply to blobs recorded in its index."
orig_tree=$(cat "$dotest/patch-merge-base") &&
rm -fr "$dotest"/patch-merge-* || exit 1
- echo Falling back to patching base and 3-way merge...
+ say Falling back to patching base and 3-way merge...
# This is not so wrong. Depending on which base we picked,
# orig_tree may be wildly different from ours, but his_tree
@@ -125,6 +127,10 @@ It does not apply to blobs recorded in its index."
eval GITHEAD_$his_tree='"$FIRSTLINE"'
export GITHEAD_$his_tree
+ if test -n "$GIT_QUIET"
+ then
+ export GIT_MERGE_VERBOSITY=0
+ fi
git-merge-recursive $orig_tree -- HEAD $his_tree || {
git rerere
echo Failed to merge in the changes.
@@ -133,6 +139,126 @@ It does not apply to blobs recorded in its index."
unset GITHEAD_$his_tree
}
+clean_abort () {
+ test $# = 0 || echo >&2 "$@"
+ rm -fr "$dotest"
+ exit 1
+}
+
+patch_format=
+
+check_patch_format () {
+ # early return if patch_format was set from the command line
+ if test -n "$patch_format"
+ then
+ return 0
+ fi
+
+ # we default to mbox format if input is from stdin and for
+ # directories
+ if test $# = 0 || test "x$1" = "x-" || test -d "$1"
+ then
+ patch_format=mbox
+ return 0
+ fi
+
+ # otherwise, check the first few lines of the first patch to try
+ # to detect its format
+ {
+ read l1
+ read l2
+ read l3
+ case "$l1" in
+ "From "* | "From: "*)
+ patch_format=mbox
+ ;;
+ '# This series applies on GIT commit'*)
+ patch_format=stgit-series
+ ;;
+ "# HG changeset patch")
+ patch_format=hg
+ ;;
+ *)
+ # if the second line is empty and the third is
+ # a From, Author or Date entry, this is very
+ # likely an StGIT patch
+ case "$l2,$l3" in
+ ,"From: "* | ,"Author: "* | ,"Date: "*)
+ patch_format=stgit
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ esac
+ } < "$1" || clean_abort
+}
+
+split_patches () {
+ case "$patch_format" in
+ mbox)
+ git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" ||
+ clean_abort
+ ;;
+ stgit-series)
+ if test $# -ne 1
+ then
+ clean_abort "Only one StGIT patch series can be applied at once"
+ fi
+ series_dir=`dirname "$1"`
+ series_file="$1"
+ shift
+ {
+ set x
+ while read filename
+ do
+ set "$@" "$series_dir/$filename"
+ done
+ # remove the safety x
+ shift
+ # remove the arg coming from the first-line comment
+ shift
+ } < "$series_file" || clean_abort
+ # set the patch format appropriately
+ patch_format=stgit
+ # now handle the actual StGIT patches
+ split_patches "$@"
+ ;;
+ stgit)
+ this=0
+ for stgit in "$@"
+ do
+ this=`expr "$this" + 1`
+ msgnum=`printf "%0${prec}d" $this`
+ # Perl version of StGIT parse_patch. The first nonemptyline
+ # not starting with Author, From or Date is the
+ # subject, and the body starts with the next nonempty
+ # line not starting with Author, From or Date
+ perl -ne 'BEGIN { $subject = 0 }
+ if ($subject > 1) { print ; }
+ elsif (/^\s+$/) { next ; }
+ elsif (/^Author:/) { print s/Author/From/ ; }
+ elsif (/^(From|Date)/) { print ; }
+ elsif ($subject) {
+ $subject = 2 ;
+ print "\n" ;
+ print ;
+ } else {
+ print "Subject: ", $_ ;
+ $subject = 1;
+ }
+ ' < "$stgit" > "$dotest/$msgnum" || clean_abort
+ done
+ echo "$this" > "$dotest/last"
+ this=
+ msgnum=
+ ;;
+ *)
+ clean_abort "Patch format $patch_format is not supported."
+ ;;
+ esac
+}
+
prec=4
dotest="$GIT_DIR/rebase-apply"
sign= utf8=t keep= skip= interactive= resolved= rebasing= abort=
@@ -175,12 +301,16 @@ do
git_apply_opt="$git_apply_opt $(sq "$1=$2")"; shift ;;
-C|-p)
git_apply_opt="$git_apply_opt $(sq "$1$2")"; shift ;;
+ --patch-format)
+ shift ; patch_format="$1" ;;
--reject)
git_apply_opt="$git_apply_opt $1" ;;
--committer-date-is-author-date)
committer_date_is_author_date=t ;;
--ignore-date)
ignore_date=t ;;
+ -q|--quiet)
+ GIT_QUIET=t ;;
--)
shift; break ;;
*)
@@ -274,12 +404,12 @@ else
done
shift
fi
- git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || {
- rm -fr "$dotest"
- exit 1
- }
- # -s, -u, -k, --whitespace, -3, -C and -p flags are kept
+ check_patch_format "$@"
+
+ split_patches "$@"
+
+ # -s, -u, -k, --whitespace, -3, -C, -q and -p flags are kept
# for the resuming session after a patch failure.
# -i can and must be given when resuming.
echo " $git_apply_opt" >"$dotest/apply-opt"
@@ -287,6 +417,7 @@ else
echo "$sign" >"$dotest/sign"
echo "$utf8" >"$dotest/utf8"
echo "$keep" >"$dotest/keep"
+ echo "$GIT_QUIET" >"$dotest/quiet"
echo 1 >"$dotest/next"
if test -n "$rebasing"
then
@@ -327,6 +458,10 @@ if test "$(cat "$dotest/keep")" = t
then
keep=-k
fi
+if test "$(cat "$dotest/quiet")" = t
+then
+ GIT_QUIET=t
+fi
if test "$(cat "$dotest/threeway")" = t
then
threeway=t
@@ -352,7 +487,7 @@ fi
if test "$this" -gt "$last"
then
- echo Nothing to do.
+ say Nothing to do.
rm -fr "$dotest"
exit
fi
@@ -498,11 +633,18 @@ do
stop_here $this
fi
- printf 'Applying: %s\n' "$FIRSTLINE"
+ say "Applying: $FIRSTLINE"
case "$resolved" in
'')
- eval 'git apply '"$git_apply_opt"' --index "$dotest/patch"'
+ # When we are allowed to fall back to 3-way later, don't give
+ # false errors during the initial attempt.
+ squelch=
+ if test "$threeway" = t
+ then
+ squelch='>/dev/null 2>&1 '
+ fi
+ eval "git apply $squelch$git_apply_opt"' --index "$dotest/patch"'
apply_status=$?
;;
t)
@@ -534,7 +676,7 @@ do
# Applying the patch to an earlier tree and merging the
# result may have produced the same tree as ours.
git diff-index --quiet --cached HEAD -- && {
- echo No changes -- Patch already applied.
+ say No changes -- Patch already applied.
go_next
continue
}
@@ -560,7 +702,7 @@ do
GIT_AUTHOR_DATE=
fi
parent=$(git rev-parse --verify -q HEAD) ||
- echo >&2 "applying to an empty history"
+ say >&2 "applying to an empty history"
if test -n "$committer_date_is_author_date"
then
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index a36df33926..59b672213b 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -259,7 +259,8 @@ if (@canstatusfiles) {
if $file =~ /^no file /
&& $status eq 'Up-to-date';
- $cvsstat{$fullname{$file}} = $status;
+ $cvsstat{$fullname{$file}} = $status
+ if defined $fullname{$file};
}
}
}
@@ -299,7 +300,7 @@ foreach my $f (@files) {
while (<FILTER_IN>)
{
my $line = $_;
- $line =~ s/\$([A-Z][a-z]+):[^\$]+\$/\$\1\$/g;
+ $line =~ s/\$([A-Z][a-z]+):[^\$]+\$/\$$1\$/g;
print FILTER_OUT $line;
}
close FILTER_IN;
diff --git a/git-rebase.sh b/git-rebase.sh
index 334629fc97..18bc6946cf 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--onto <newbase>] [<upstream>|--root] [<branch>]'
+USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -72,11 +72,20 @@ continue_merge () {
echo "directly, but instead do one of the following: "
die "$RESOLVEMSG"
fi
- printf "Committed: %0${prec}d " $msgnum
+ if test -z "$GIT_QUIET"
+ then
+ printf "Committed: %0${prec}d " $msgnum
+ fi
else
- printf "Already applied: %0${prec}d " $msgnum
+ if test -z "$GIT_QUIET"
+ then
+ printf "Already applied: %0${prec}d " $msgnum
+ fi
+ fi
+ if test -z "$GIT_QUIET"
+ then
+ git rev-list --pretty=oneline -1 "$cmt" | sed -e 's/^[^ ]* //'
fi
- git rev-list --pretty=oneline -1 "$cmt" | sed -e 's/^[^ ]* //'
prev_head=`git rev-parse HEAD^0`
# save the resulting commit so we can read-tree on it later
@@ -97,6 +106,10 @@ call_merge () {
eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
eval GITHEAD_$hd='$(cat "$dotest/onto_name")'
export GITHEAD_$cmt GITHEAD_$hd
+ if test -n "$GIT_QUIET"
+ then
+ export GIT_MERGE_VERBOSITY=1
+ fi
git-merge-$strategy "$cmt^" -- "$hd" "$cmt"
rv=$?
case "$rv" in
@@ -138,7 +151,7 @@ move_to_original_branch () {
finish_rb_merge () {
move_to_original_branch
rm -r "$dotest"
- echo "All done."
+ say All done.
}
is_interactive () {
@@ -207,6 +220,7 @@ do
end=$(cat "$dotest/end")
msgnum=$(cat "$dotest/msgnum")
onto=$(cat "$dotest/onto")
+ GIT_QUIET=$(cat "$dotest/quiet")
continue_merge
while test "$msgnum" -le "$end"
do
@@ -219,6 +233,7 @@ do
head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
+ GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
@@ -236,6 +251,7 @@ do
msgnum=$(cat "$dotest/msgnum")
msgnum=$(($msgnum + 1))
onto=$(cat "$dotest/onto")
+ GIT_QUIET=$(cat "$dotest/quiet")
while test "$msgnum" -le "$end"
do
call_merge "$msgnum"
@@ -247,6 +263,7 @@ do
head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
+ GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
@@ -258,9 +275,11 @@ do
git rerere clear
if test -d "$dotest"
then
+ GIT_QUIET=$(cat "$dotest/quiet")
move_to_original_branch
else
dotest="$GIT_DIR"/rebase-apply
+ GIT_QUIET=$(cat "$dotest/quiet")
move_to_original_branch
fi
git reset --hard $(cat "$dotest/orig-head")
@@ -298,6 +317,13 @@ do
-v|--verbose)
verbose=t
diffstat=t
+ GIT_QUIET=
+ ;;
+ -q|--quiet)
+ GIT_QUIET=t
+ git_am_opt="$git_am_opt -q"
+ verbose=
+ diffstat=
;;
--whitespace=*)
git_am_opt="$git_am_opt $1"
@@ -442,15 +468,15 @@ then
then
# Lazily switch to the target branch if needed...
test -z "$switch_to" || git checkout "$switch_to"
- echo >&2 "Current branch $branch_name is up to date."
+ say "Current branch $branch_name is up to date."
exit 0
else
- echo "Current branch $branch_name is up to date, rebase forced."
+ say "Current branch $branch_name is up to date, rebase forced."
fi
fi
# Detach HEAD and reset the tree
-echo "First, rewinding head to replay your work on top of it..."
+say "First, rewinding head to replay your work on top of it..."
git checkout -q "$onto^0" || die "could not detach HEAD"
git update-ref ORIG_HEAD $branch
@@ -468,7 +494,7 @@ fi
# we just fast forwarded.
if test "$mb" = "$branch"
then
- echo >&2 "Fast-forwarded $branch_name to $onto_name."
+ say "Fast-forwarded $branch_name to $onto_name."
move_to_original_branch
exit 0
fi
@@ -490,7 +516,8 @@ then
test 0 != $ret -a -d "$GIT_DIR"/rebase-apply &&
echo $head_name > "$GIT_DIR"/rebase-apply/head-name &&
echo $onto > "$GIT_DIR"/rebase-apply/onto &&
- echo $orig_head > "$GIT_DIR"/rebase-apply/orig-head
+ echo $orig_head > "$GIT_DIR"/rebase-apply/orig-head &&
+ echo "$GIT_QUIET" > "$GIT_DIR"/rebase-apply/quiet
exit $ret
fi
@@ -504,6 +531,7 @@ prev_head=$orig_head
echo "$prev_head" > "$dotest/prev_head"
echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
+echo "$GIT_QUIET" > "$dotest/quiet"
msgnum=0
for cmt in `git rev-list --reverse --no-merges "$revisions"`
diff --git a/git-repack.sh b/git-repack.sh
index 0868734723..1bf239499c 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -24,7 +24,7 @@ SUBDIRECTORY_OK='Yes'
. git-sh-setup
no_update_info= all_into_one= remove_redundant= unpack_unreachable=
-local= quiet= no_reuse= extra=
+local= no_reuse= extra=
while test $# != 0
do
case "$1" in
@@ -33,7 +33,7 @@ do
-A) all_into_one=t
unpack_unreachable=--unpack-unreachable ;;
-d) remove_redundant=t ;;
- -q) quiet=-q ;;
+ -q) GIT_QUIET=t ;;
-f) no_reuse=--no-reuse-object ;;
-l) local=--local ;;
--max-pack-size|--window|--window-memory|--depth)
@@ -80,13 +80,11 @@ case ",$all_into_one," in
;;
esac
-args="$args $local $quiet $no_reuse$extra"
+args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra"
names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
exit 1
if [ -z "$names" ]; then
- if test -z "$quiet"; then
- echo Nothing new to pack.
- fi
+ say Nothing new to pack.
fi
# Ok we have prepared all new packfiles.
@@ -176,7 +174,7 @@ then
done
)
fi
- git prune-packed $quiet
+ git prune-packed ${GIT_QUIET:+-q}
fi
case "$no_update_info" in
diff --git a/git-request-pull.sh b/git-request-pull.sh
index a2cf5b8215..5917773240 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -12,6 +12,9 @@ OPTIONS_SPEC=
. git-sh-setup
. git-parse-remote
+GIT_PAGER=
+export GIT_PAGER
+
base=$1
url=$2
head=${3-HEAD}
@@ -34,7 +37,7 @@ branch=$(git ls-remote "$url" \
}")
if [ -z "$branch" ]; then
echo "warn: No branch of $url is at:" >&2
- git log --max-count=1 --pretty='format:warn: %h: %s' $headrev >&2
+ git log --max-count=1 --pretty='tformat:warn: %h: %s' $headrev >&2
echo "warn: Are you sure you pushed $head there?" >&2
echo >&2
echo >&2
@@ -42,8 +45,6 @@ if [ -z "$branch" ]; then
status=1
fi
-PAGER=
-export PAGER
echo "The following changes since commit $baserev:"
git shortlog --max-count=1 $baserev | sed -e 's/^\(.\)/ \1/'
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 80acb7de72..c41c2f7439 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -44,6 +44,15 @@ die() {
exit 1
}
+GIT_QUIET=
+
+say () {
+ if test -z "$GIT_QUIET"
+ then
+ printf '%s\n' "$*"
+ fi
+}
+
if test -n "$OPTIONS_SPEC"; then
usage() {
"$0" -h
diff --git a/git-stash.sh b/git-stash.sh
index e6a5867209..531c7c31ac 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -3,10 +3,11 @@
dashless=$(basename "$0" | sed -e 's/-/ /')
USAGE="list [<options>]
- or: $dashless ( show | drop ) [<stash>]
- or: $dashless ( pop | apply ) [--index] [<stash>]
+ or: $dashless show [<stash>]
+ or: $dashless drop [-q|--quiet] [<stash>]
+ or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
or: $dashless branch <branchname> [<stash>]
- or: $dashless [save [--keep-index] [<message>]]
+ or: $dashless [save [--keep-index] [-q|--quiet] [<message>]]
or: $dashless clear"
SUBDIRECTORY_OK=Yes
@@ -94,18 +95,28 @@ create_stash () {
save_stash () {
keep_index=
- case "$1" in
- --keep-index)
- keep_index=t
+ while test $# != 0
+ do
+ case "$1" in
+ --keep-index)
+ keep_index=t
+ ;;
+ -q|--quiet)
+ GIT_QUIET=t
+ ;;
+ *)
+ break
+ ;;
+ esac
shift
- esac
+ done
stash_msg="$*"
git update-index -q --refresh
if no_changes
then
- echo 'No local changes to save'
+ say 'No local changes to save'
exit 0
fi
test -f "$GIT_DIR/logs/$ref_stash" ||
@@ -118,9 +129,9 @@ save_stash () {
git update-ref -m "$stash_msg" $ref_stash $w_commit ||
die "Cannot save the current status"
- printf 'Saved working directory and index state "%s"\n' "$stash_msg"
+ say Saved working directory and index state "$stash_msg"
- git reset --hard
+ git reset --hard ${GIT_QUIET:+-q}
if test -n "$keep_index" && test -n $i_tree
then
@@ -156,11 +167,22 @@ apply_stash () {
die 'Cannot apply to a dirty working tree, please stage your changes'
unstash_index=
- case "$1" in
- --index)
- unstash_index=t
+
+ while test $# != 0
+ do
+ case "$1" in
+ --index)
+ unstash_index=t
+ ;;
+ -q|--quiet)
+ GIT_QUIET=t
+ ;;
+ *)
+ break
+ ;;
+ esac
shift
- esac
+ done
# current index state
c_tree=$(git write-tree) ||
@@ -193,6 +215,10 @@ apply_stash () {
export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree
"
+ if test -n "$GIT_QUIET"
+ then
+ export GIT_MERGE_VERBOSITY=0
+ fi
if git-merge-recursive $b_tree -- $c_tree $w_tree
then
# No conflict
@@ -207,7 +233,12 @@ apply_stash () {
die "Cannot unstage modified files"
rm -f "$a"
fi
- git status || :
+ squelch=
+ if test -n "$GIT_QUIET"
+ then
+ squelch='>/dev/null 2>&1'
+ fi
+ eval "git status $squelch" || :
else
# Merge conflict; keep the exit status from merge-recursive
status=$?
@@ -222,6 +253,19 @@ apply_stash () {
drop_stash () {
have_stash || die 'No stash entries to drop'
+ while test $# != 0
+ do
+ case "$1" in
+ -q|--quiet)
+ GIT_QUIET=t
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
if test $# = 0
then
set x "$ref_stash@{0}"
@@ -235,7 +279,7 @@ drop_stash () {
die "$*: not a valid stashed state"
git reflog delete --updateref --rewrite "$@" &&
- echo "Dropped $* ($s)" || die "$*: Could not drop stash entry"
+ say "Dropped $* ($s)" || die "$*: Could not drop stash entry"
# clear_stash if we just dropped the last stash entry
git rev-parse --verify "$ref_stash@{0}" > /dev/null 2>&1 || clear_stash
@@ -312,7 +356,7 @@ branch)
if test $# -eq 0
then
save_stash &&
- echo '(To restore them type "git stash apply")'
+ say '(To restore them type "git stash apply")'
else
usage
fi
diff --git a/git-submodule.sh b/git-submodule.sh
index f4f3562671..ebed711da4 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -14,23 +14,11 @@ require_work_tree
command=
branch=
-quiet=
reference=
cached=
nofetch=
update=
-#
-# print stuff on stdout unless -q was specified
-#
-say()
-{
- if test -z "$quiet"
- then
- echo "$@"
- fi
-}
-
# Resolve relative url by appending to parent's url
resolve_relative_url ()
{
@@ -137,7 +125,7 @@ cmd_add()
shift
;;
-q|--quiet)
- quiet=1
+ GIT_QUIET=1
;;
--reference)
case "$2" in '') usage ;; esac
@@ -273,7 +261,7 @@ cmd_init()
do
case "$1" in
-q|--quiet)
- quiet=1
+ GIT_QUIET=1
;;
--)
shift
@@ -333,7 +321,7 @@ cmd_update()
case "$1" in
-q|--quiet)
shift
- quiet=1
+ GIT_QUIET=1
;;
-i|--init)
init=1
@@ -659,7 +647,7 @@ cmd_status()
do
case "$1" in
-q|--quiet)
- quiet=1
+ GIT_QUIET=1
;;
--cached)
cached=1
@@ -713,7 +701,7 @@ cmd_sync()
do
case "$1" in
-q|--quiet)
- quiet=1
+ GIT_QUIET=1
shift
;;
--)
@@ -768,7 +756,7 @@ do
command=$1
;;
-q|--quiet)
- quiet=1
+ GIT_QUIET=1
;;
-b|--branch)
case "$2" in
diff --git a/git-svn.perl b/git-svn.perl
index 33017974d0..d1af1a3d2f 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -63,7 +63,7 @@ my ($SVN);
$sha1 = qr/[a-f\d]{40}/;
$sha1_short = qr/[a-f\d]{4,40}/;
my ($_stdin, $_help, $_edit,
- $_message, $_file,
+ $_message, $_file, $_branch_dest,
$_template, $_shared,
$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
$_merge, $_strategy, $_dry_run, $_local,
@@ -92,11 +92,11 @@ my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
'localtime' => \$Git::SVN::_localtime,
%remote_opts );
-my ($_trunk, $_tags, $_branches, $_stdlayout);
+my ($_trunk, @_tags, @_branches, $_stdlayout);
my %icv;
my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
- 'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
- 'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
+ 'trunk|T=s' => \$_trunk, 'tags|t=s@' => \@_tags,
+ 'branches|b=s@' => \@_branches, 'prefix=s' => \$_prefix,
'stdlayout|s' => \$_stdlayout,
'minimize-url|m' => \$Git::SVN::_minimize_url,
'no-metadata' => sub { $icv{noMetadata} = 1 },
@@ -141,11 +141,13 @@ my %cmd = (
branch => [ \&cmd_branch,
'Create a branch in the SVN repository',
{ 'message|m=s' => \$_message,
+ 'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run,
'tag|t' => \$_tag } ],
tag => [ sub { $_tag = 1; cmd_branch(@_) },
'Create a tag in the SVN repository',
{ 'message|m=s' => \$_message,
+ 'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run } ],
'set-tree' => [ \&cmd_set_tree,
"Set an SVN repository to a git tree-ish",
@@ -211,6 +213,10 @@ my %cmd = (
'blame' => [ \&Git::SVN::Log::cmd_blame,
"Show what revision and author last modified each line of a file",
{ 'git-format' => \$_git_format } ],
+ 'reset' => [ \&cmd_reset,
+ "Undo fetches back to the specified SVN revision",
+ { 'revision|r=s' => \$_revision,
+ 'parent|p' => \$_fetch_parent } ],
);
my $cmd;
@@ -219,6 +225,9 @@ for (my $i = 0; $i < @ARGV; $i++) {
$cmd = $ARGV[$i];
splice @ARGV, $i, 1;
last;
+ } elsif ($ARGV[$i] eq 'help') {
+ $cmd = $ARGV[$i+1];
+ usage(0);
}
};
@@ -358,7 +367,7 @@ sub init_subdir {
sub cmd_clone {
my ($url, $path) = @_;
if (!defined $path &&
- (defined $_trunk || defined $_branches || defined $_tags ||
+ (defined $_trunk || @_branches || @_tags ||
defined $_stdlayout) &&
$url !~ m#^[a-z\+]+://#) {
$path = $url;
@@ -372,14 +381,15 @@ sub cmd_clone {
sub cmd_init {
if (defined $_stdlayout) {
$_trunk = 'trunk' if (!defined $_trunk);
- $_tags = 'tags' if (!defined $_tags);
- $_branches = 'branches' if (!defined $_branches);
+ @_tags = 'tags' if (! @_tags);
+ @_branches = 'branches' if (! @_branches);
}
- if (defined $_trunk || defined $_branches || defined $_tags) {
+ if (defined $_trunk || @_branches || @_tags) {
return cmd_multi_init(@_);
}
my $url = shift or die "SVN repository location required ",
"as a command-line argument\n";
+ $url = canonicalize_url($url);
init_subdir(@_);
do_git_init_db();
@@ -454,8 +464,22 @@ sub cmd_dcommit {
'Cannot dcommit with a dirty index. Commit your changes first, '
. "or stash them with `git stash'.\n";
$head ||= 'HEAD';
+
+ my $old_head;
+ if ($head ne 'HEAD') {
+ $old_head = eval {
+ command_oneline([qw/symbolic-ref -q HEAD/])
+ };
+ if ($old_head) {
+ $old_head =~ s{^refs/heads/}{};
+ } else {
+ $old_head = eval { command_oneline(qw/rev-parse HEAD/) };
+ }
+ command(['checkout', $head], STDERR => 0);
+ }
+
my @refs;
- my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
+ my ($url, $rev, $uuid, $gs) = working_head_info('HEAD', \@refs);
unless ($gs) {
die "Unable to determine upstream SVN information from ",
"$head history.\nPerhaps the repository is empty.";
@@ -541,7 +565,7 @@ sub cmd_dcommit {
if (@diff) {
@refs = ();
my ($url_, $rev_, $uuid_, $gs_) =
- working_head_info($head, \@refs);
+ working_head_info('HEAD', \@refs);
my ($linear_refs_, $parents_) =
linearize_history($gs_, \@refs);
if (scalar(@$linear_refs) !=
@@ -579,6 +603,22 @@ sub cmd_dcommit {
}
}
}
+
+ if ($old_head) {
+ my $new_head = command_oneline(qw/rev-parse HEAD/);
+ my $new_is_symbolic = eval {
+ command_oneline(qw/symbolic-ref -q HEAD/);
+ };
+ if ($new_is_symbolic) {
+ print "dcommitted the branch ", $head, "\n";
+ } else {
+ print "dcommitted on a detached HEAD because you gave ",
+ "a revision argument.\n",
+ "The rewritten commit is: ", $new_head, "\n";
+ }
+ command(['checkout', $old_head], STDERR => 0);
+ }
+
unlink $gs->{index};
}
@@ -593,7 +633,33 @@ sub cmd_branch {
my ($src, $rev, undef, $gs) = working_head_info($head);
my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
- my $glob = $remote->{ $_tag ? 'tags' : 'branches' };
+ my $allglobs = $remote->{ $_tag ? 'tags' : 'branches' };
+ my $glob;
+ if ($#{$allglobs} == 0) {
+ $glob = $allglobs->[0];
+ } else {
+ unless(defined $_branch_dest) {
+ die "Multiple ",
+ $_tag ? "tag" : "branch",
+ " paths defined for Subversion repository.\n",
+ "You must specify where you want to create the ",
+ $_tag ? "tag" : "branch",
+ " with the --destination argument.\n";
+ }
+ foreach my $g (@{$allglobs}) {
+ # SVN::Git::Editor could probably be moved to Git.pm..
+ my $re = SVN::Git::Editor::glob2pat($g->{path}->{left});
+ if ($_branch_dest =~ /$re/) {
+ $glob = $g;
+ last;
+ }
+ }
+ unless (defined $glob) {
+ die "Unknown ",
+ $_tag ? "tag" : "branch",
+ " destination $_branch_dest\n";
+ }
+ }
my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/};
my $dst = join '/', $remote->{url}, $lft, $branch_name, ($rgt || ());
@@ -741,6 +807,12 @@ sub canonicalize_path {
return $path;
}
+sub canonicalize_url {
+ my ($url) = @_;
+ $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e;
+ return $url;
+}
+
# get_svnprops(PATH)
# ------------------
# Helper for cmd_propget and cmd_proplist below.
@@ -800,7 +872,7 @@ sub cmd_proplist {
sub cmd_multi_init {
my $url = shift;
- unless (defined $_trunk || defined $_branches || defined $_tags) {
+ unless (defined $_trunk || @_branches || @_tags) {
usage(1);
}
@@ -810,7 +882,7 @@ sub cmd_multi_init {
$_prefix = '' unless defined $_prefix;
if (defined $url) {
- $url =~ s#/+$##;
+ $url = canonicalize_url($url);
init_subdir(@_);
}
do_git_init_db();
@@ -825,10 +897,14 @@ sub cmd_multi_init {
undef, $trunk_ref);
}
}
- return unless defined $_branches || defined $_tags;
+ return unless @_branches || @_tags;
my $ra = $url ? Git::SVN::Ra->new($url) : undef;
- complete_url_ls_init($ra, $_branches, '--branches/-b', $_prefix);
- complete_url_ls_init($ra, $_tags, '--tags/-t', $_prefix . 'tags/');
+ foreach my $path (@_branches) {
+ complete_url_ls_init($ra, $path, '--branches/-b', $_prefix);
+ }
+ foreach my $path (@_tags) {
+ complete_url_ls_init($ra, $path, '--tags/-t', $_prefix.'tags/');
+ }
}
sub cmd_multi_fetch {
@@ -1021,6 +1097,20 @@ sub cmd_info {
print $result, "\n";
}
+sub cmd_reset {
+ my $target = shift || $_revision or die "SVN revision required\n";
+ $target = $1 if $target =~ /^r(\d+)$/;
+ $target =~ /^\d+$/ or die "Numeric SVN revision expected\n";
+ my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
+ unless ($gs) {
+ die "Unable to determine upstream SVN information from ".
+ "history\n";
+ }
+ my ($r, $c) = $gs->find_rev_before($target, not $_fetch_parent);
+ $gs->rev_map_set($r, $c, 'reset', $uuid);
+ print "r$r = $c ($gs->{ref_id})\n";
+}
+
########################### utility functions #########################
sub rebase_cmd {
@@ -1099,6 +1189,7 @@ sub complete_url_ls_init {
die "--prefix='$pfx' must have a trailing slash '/'\n";
}
command_noisy('config',
+ '--add',
"svn-remote.$gs->{repo_id}.$n",
"$remote_path:refs/remotes/$pfx*" .
('/*' x (($remote_path =~ tr/*/*/) - 1)) );
@@ -1565,7 +1656,8 @@ sub fetch_all {
# read the max revs for wildcard expansion (branches/*, tags/*)
foreach my $t (qw/branches tags/) {
defined $remote->{$t} or next;
- push @globs, $remote->{$t};
+ push @globs, @{$remote->{$t}};
+
my $max_rev = eval { tmp_config(qw/--int --get/,
"svn-remote.$repo_id.${t}-maxRev") };
if (defined $max_rev && ($max_rev < $base)) {
@@ -1612,15 +1704,16 @@ sub read_all_remotes {
} elsif (m!^(.+)\.(branches|tags)=
(.*):refs/remotes/(.+)\s*$/!x) {
my ($p, $g) = ($3, $4);
- my $rs = $r->{$1}->{$2} = {
- t => $2,
- remote => $1,
- path => Git::SVN::GlobSpec->new($p),
- ref => Git::SVN::GlobSpec->new($g) };
+ my $rs = {
+ t => $2,
+ remote => $1,
+ path => Git::SVN::GlobSpec->new($p),
+ ref => Git::SVN::GlobSpec->new($g) };
if (length($rs->{ref}->{right}) != 0) {
die "The '*' glob character must be the last ",
"character of '$g'\n";
}
+ push @{ $r->{$1}->{$2} }, $rs;
}
}
@@ -1760,9 +1853,10 @@ sub find_by_url { # repos_root and, path are optional
next if defined $repos_root && $repos_root ne $u;
my $fetch = $remotes->{$repo_id}->{fetch} || {};
- foreach (qw/branches tags/) {
- resolve_local_globs($u, $fetch,
- $remotes->{$repo_id}->{$_});
+ foreach my $t (qw/branches tags/) {
+ foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
+ resolve_local_globs($u, $fetch, $globspec);
+ }
}
my $p = $path;
my $rwr = rewrite_root({repo_id => $repo_id});
@@ -2990,6 +3084,14 @@ sub _rev_map_set {
croak "write: $!";
}
+sub _rev_map_reset {
+ my ($fh, $rev, $commit) = @_;
+ my $c = _rev_map_get($fh, $rev);
+ $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n";
+ my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!";
+ truncate $fh, $offset or croak "truncate: $!";
+}
+
sub mkfile {
my ($path) = @_;
unless (-e $path) {
@@ -3006,6 +3108,7 @@ sub rev_map_set {
my $db = $self->map_path($uuid);
my $db_lock = "$db.lock";
my $sig;
+ $update_ref ||= 0;
if ($update_ref) {
$SIG{INT} = $SIG{HUP} = $SIG{TERM} = $SIG{ALRM} = $SIG{PIPE} =
$SIG{USR1} = $SIG{USR2} = sub { $sig = $_[0] };
@@ -3029,7 +3132,8 @@ sub rev_map_set {
sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
or croak "Couldn't open $db_lock: $!\n";
- _rev_map_set($fh, $rev, $commit);
+ $update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) :
+ _rev_map_set($fh, $rev, $commit);
if ($sync) {
$fh->flush or die "Couldn't flush $db_lock: $!\n";
$fh->sync or die "Couldn't sync $db_lock: $!\n";
@@ -3037,7 +3141,9 @@ sub rev_map_set {
close $fh or croak $!;
if ($update_ref) {
$_head = $self;
- command_noisy('update-ref', '-m', "r$rev",
+ my $note = "";
+ $note = " ($update_ref)" if ($update_ref !~ /^\d*$/);
+ command_noisy('update-ref', '-m', "r$rev$note",
$self->refname, $commit);
}
rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
@@ -3099,12 +3205,19 @@ sub rev_map_get {
return undef unless -e $map_path;
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+ my $c = _rev_map_get($fh, $rev);
+ close($fh) or croak "close: $!";
+ $c
+}
+
+sub _rev_map_get {
+ my ($fh, $rev) = @_;
+
binmode $fh or croak "binmode: $!";
my $size = (stat($fh))[7];
($size % 24) == 0 or croak "inconsistent size: $size";
if ($size == 0) {
- close $fh or croak "close: $fh";
return undef;
}
@@ -3122,11 +3235,9 @@ sub rev_map_get {
} elsif ($r > $rev) {
$u = $i - 24;
} else { # $r == $rev
- close($fh) or croak "close: $!";
return $c eq ('0' x 40) ? undef : $c;
}
}
- close($fh) or croak "close: $!";
undef;
}
@@ -3138,6 +3249,8 @@ sub find_rev_before {
my ($self, $rev, $eq_ok, $min_rev) = @_;
--$rev unless $eq_ok;
$min_rev ||= 1;
+ my $max_rev = $self->rev_map_max;
+ $rev = $max_rev if ($rev > $max_rev);
while ($rev >= $min_rev) {
if (my $c = $self->rev_map_get($rev)) {
return ($rev, $c);
diff --git a/git.c b/git.c
index 7d7f949f0d..f4d53f40de 100644
--- a/git.c
+++ b/git.c
@@ -188,10 +188,9 @@ static int handle_alias(int *argcp, const char ***argv)
alias_command);
new_argv = xrealloc(new_argv, sizeof(char *) *
- (count + *argcp + 1));
+ (count + *argcp));
/* insert after command name */
memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
- new_argv[count+*argcp] = NULL;
*argv = new_argv;
*argcp += count - 1;
diff --git a/gitweb/README b/gitweb/README
index ccda890c0e..9056d1e090 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -377,7 +377,7 @@ named without a .git extension (e.g. /pub/git/project instead of
DocumentRoot /var/www/gitweb
- AliasMatch ^(/.*?)(\.git)(/.*)? /pub/git$1$3
+ AliasMatch ^(/.*?)(\.git)(/.*)?$ /pub/git$1$3
<Directory /var/www/gitweb>
Options ExecCGI
AddHandler cgi-script cgi
@@ -402,6 +402,14 @@ http://git.example.com/project
will provide human-friendly gitweb access.
+This solution is not 100% bulletproof, in the sense that if some project
+has a named ref (branch, tag) starting with 'git/', then paths such as
+
+http://git.example.com/project/command/abranch..git/abranch
+
+will fail with a 404 error.
+
+
Originally written by:
Kay Sievers <kay.sievers@vrfy.org>
diff --git a/http-push.c b/http-push.c
index 8cc8ee0dfd..00e83dcec1 100644
--- a/http-push.c
+++ b/http-push.c
@@ -193,6 +193,8 @@ static char *xml_entities(char *s)
case '&':
strbuf_addstr(&buf, "&amp;");
break;
+ case 0:
+ return strbuf_detach(&buf, NULL);
}
s++;
}
diff --git a/ll-merge.c b/ll-merge.c
index 9168958e86..a2c13c4c08 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -55,7 +55,7 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
mmbuffer_t *result,
- const char *path_unused,
+ const char *path,
mmfile_t *orig,
mmfile_t *src1, const char *name1,
mmfile_t *src2, const char *name2,
@@ -67,10 +67,10 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
if (buffer_is_binary(orig->ptr, orig->size) ||
buffer_is_binary(src1->ptr, src1->size) ||
buffer_is_binary(src2->ptr, src2->size)) {
- warning("Cannot merge binary files: %s vs. %s\n",
- name1, name2);
+ warning("Cannot merge binary files: %s (%s vs. %s)\n",
+ path, name1, name2);
return ll_binary_merge(drv_unused, result,
- path_unused,
+ path,
orig, src1, name1,
src2, name2,
virtual_ancestor);
diff --git a/log-tree.c b/log-tree.c
index 59d63eb67e..6f73c17d74 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -321,7 +321,8 @@ void show_log(struct rev_info *opt)
}
/*
- * If use_terminator is set, add a newline at the end of the entry.
+ * If use_terminator is set, we already handled any record termination
+ * at the end of the last record.
* Otherwise, add a diffopt.line_termination character before all
* entries but the first. (IOW, as a separator between entries)
*/
diff --git a/merge-recursive.c b/merge-recursive.c
index c703445a9c..53cad9605b 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -622,8 +622,13 @@ static int merge_3way(struct merge_options *o,
char *name1, *name2;
int merge_status;
- name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
- name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
+ if (strcmp(a->path, b->path)) {
+ name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
+ name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
+ } else {
+ name1 = xstrdup(mkpath("%s", branch1));
+ name2 = xstrdup(mkpath("%s", branch2));
+ }
fill_mm(one->sha1, &orig);
fill_mm(a->sha1, &src1);
diff --git a/revision.c b/revision.c
index bf58448367..a31434bdc8 100644
--- a/revision.c
+++ b/revision.c
@@ -1077,6 +1077,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->show_all = 1;
} else if (!strcmp(arg, "--remove-empty")) {
revs->remove_empty_trees = 1;
+ } else if (!strcmp(arg, "--merges")) {
+ revs->merges_only = 1;
} else if (!strcmp(arg, "--no-merges")) {
revs->no_merges = 1;
} else if (!strcmp(arg, "--boundary")) {
@@ -1676,6 +1678,8 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
return commit_ignore;
if (revs->no_merges && commit->parents && commit->parents->next)
return commit_ignore;
+ if (revs->merges_only && !(commit->parents && commit->parents->next))
+ return commit_ignore;
if (!commit_match(commit, revs))
return commit_ignore;
if (revs->prune && revs->dense) {
diff --git a/revision.h b/revision.h
index 227164cf70..fb74492714 100644
--- a/revision.h
+++ b/revision.h
@@ -36,6 +36,7 @@ struct rev_info {
unsigned int dense:1,
prune:1,
no_merges:1,
+ merges_only:1,
no_walk:1,
show_all:1,
remove_empty_trees:1,
diff --git a/strbuf.c b/strbuf.c
index a88496030b..f03d11702b 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -260,7 +260,7 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
res = fread(sb->buf + sb->len, 1, size, f);
if (res > 0)
strbuf_setlen(sb, sb->len + res);
- else if (res < 0 && oldalloc == 0)
+ else if (oldalloc == 0)
strbuf_release(sb);
return res;
}
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index 997002d4c4..e504058062 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -20,8 +20,7 @@ Extras
EOF
-test_expect_success 'test --parseopt help output' '
- git rev-parse --parseopt -- -h 2> output.err <<EOF
+cat > optionspec << EOF
some-command [options] <args>...
some-command does foo and bar!
@@ -37,7 +36,47 @@ C? option C with an optional argument
Extras
extra1 line above used to cause a segfault but no longer does
EOF
+
+test_expect_success 'test --parseopt help output' '
+ git rev-parse --parseopt -- -h 2> output.err < optionspec
test_cmp expect.err output.err
'
+cat > expect <<EOF
+set -- --foo --bar 'ham' -- 'arg'
+EOF
+
+test_expect_success 'test --parseopt' '
+ git rev-parse --parseopt -- --foo --bar=ham arg < optionspec > output &&
+ test_cmp expect output
+'
+
+test_expect_success 'test --parseopt with mixed options and arguments' '
+ git rev-parse --parseopt -- --foo arg --bar=ham < optionspec > output &&
+ test_cmp expect output
+'
+
+cat > expect <<EOF
+set -- --foo -- 'arg' '--bar=ham'
+EOF
+
+test_expect_success 'test --parseopt with --' '
+ git rev-parse --parseopt -- --foo -- arg --bar=ham < optionspec > output &&
+ test_cmp expect output
+'
+
+test_expect_success 'test --parseopt --stop-at-non-option' '
+ git rev-parse --parseopt --stop-at-non-option -- --foo arg --bar=ham < optionspec > output &&
+ test_cmp expect output
+'
+
+cat > expect <<EOF
+set -- --foo -- '--' 'arg' '--bar=ham'
+EOF
+
+test_expect_success 'test --parseopt --keep-dashdash' '
+ git rev-parse --parseopt --keep-dashdash -- --foo -- arg --bar=ham < optionspec > output &&
+ test_cmp expect output
+'
+
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 7f62bfb9dd..c5c29ccc4f 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -54,8 +54,8 @@ test_expect_success 'rebase against master' '
git rebase master'
test_expect_success 'rebase against master twice' '
- git rebase master 2>err &&
- grep "Current branch my-topic-branch is up to date" err
+ git rebase master >out &&
+ grep "Current branch my-topic-branch is up to date" out
'
test_expect_success 'rebase against master twice with --force' '
@@ -65,14 +65,14 @@ test_expect_success 'rebase against master twice with --force' '
test_expect_success 'rebase against master twice from another branch' '
git checkout my-topic-branch^ &&
- git rebase master my-topic-branch 2>err &&
- grep "Current branch my-topic-branch is up to date" err
+ git rebase master my-topic-branch >out &&
+ grep "Current branch my-topic-branch is up to date" out
'
test_expect_success 'rebase fast-forward to master' '
git checkout my-topic-branch^ &&
- git rebase my-topic-branch 2>err &&
- grep "Fast-forwarded HEAD to my-topic-branch" err
+ git rebase my-topic-branch >out &&
+ grep "Fast-forwarded HEAD to my-topic-branch" out
'
test_expect_success \
@@ -126,4 +126,11 @@ test_expect_success 'Show verbose error when HEAD could not be detached' '
grep "Untracked working tree file .B. would be overwritten" output.err
'
+test_expect_success 'rebase -q is quiet' '
+ rm B &&
+ git checkout -b quiet topic &&
+ git rebase -q master > output.out 2>&1 &&
+ test ! -s output.out
+'
+
test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index c32ff6682b..a973628e8e 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -119,11 +119,11 @@ index e69de29..00750ed 100644
EOF
cat > expect2 << EOF
-<<<<<<< HEAD:file1
+<<<<<<< HEAD
2
=======
3
->>>>>>> b7ca976... G:file1
+>>>>>>> b7ca976... G
EOF
test_expect_success 'stop on conflicting pick' '
diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index 9aaeabd972..e51e505a9f 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -17,11 +17,11 @@ test_expect_success setup '
'
-test_expect_code 1 'cherry-pick an empty commit' '
-
- git checkout master &&
- git cherry-pick empty-branch
-
+test_expect_success 'cherry-pick an empty commit' '
+ git checkout master && {
+ git cherry-pick empty-branch
+ test "$?" = 1
+ }
'
test_expect_success 'index lockfile was removed' '
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 6ae5a2cd95..85eb0fbf96 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -223,7 +223,7 @@ test_expect_success POSIXPERM 'git add (add.ignore-errors = false)' '
'
rm -f foo2
-test_expect_success '--no-ignore-errors overrides config' '
+test_expect_success POSIXPERM '--no-ignore-errors overrides config' '
git config add.ignore-errors 1 &&
git reset --hard &&
date >foo1 &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 7484cbede6..7a3fb67957 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -177,4 +177,27 @@ test_expect_success 'stash branch' '
test 0 = $(git stash list | wc -l)
'
+test_expect_success 'apply -q is quiet' '
+ echo foo > file &&
+ git stash &&
+ git stash apply -q > output.out 2>&1 &&
+ test ! -s output.out
+'
+
+test_expect_success 'save -q is quiet' '
+ git stash save --quiet > output.out 2>&1 &&
+ test ! -s output.out
+'
+
+test_expect_success 'pop -q is quiet' '
+ git stash pop -q > output.out 2>&1 &&
+ test ! -s output.out
+'
+
+test_expect_success 'drop -q is quiet' '
+ git stash &&
+ git stash drop -q > output.out 2>&1 &&
+ test ! -s output.out
+'
+
test_done
diff --git a/t/t4037-diff-r-t-dirs.sh b/t/t4037-diff-r-t-dirs.sh
new file mode 100755
index 0000000000..f5ce3b29a2
--- /dev/null
+++ b/t/t4037-diff-r-t-dirs.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+test_description='diff -r -t shows directory additions and deletions'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ mkdir dc dr dt &&
+ >dc/1 &&
+ >dr/2 &&
+ >dt/3 &&
+ >fc &&
+ >fr &&
+ >ft &&
+ git add . &&
+ test_tick &&
+ git commit -m initial &&
+
+ rm -fr dt dr ft fr &&
+ mkdir da ft &&
+ for p in dc/1 da/4 dt ft/5 fc
+ do
+ echo hello >$p || exit
+ done &&
+ git add -u &&
+ git add . &&
+ test_tick &&
+ git commit -m second
+'
+
+cat >expect <<\EOF
+A da
+A da/4
+M dc
+M dc/1
+D dr
+D dr/2
+A dt
+D dt
+D dt/3
+M fc
+D fr
+D ft
+A ft
+A ft/5
+EOF
+
+test_expect_success verify '
+ git diff-tree -r -t --name-status HEAD^ HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index d6ebbaebe2..a12bf84623 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -180,6 +180,17 @@ test_expect_success 'am -3 falls back to 3-way merge' '
test -z "$(git diff lorem)"
'
+test_expect_success 'am -3 -q is quiet' '
+ git reset master2 --hard &&
+ sed -n -e "3,\$p" msg >file &&
+ head -n 9 msg >>file &&
+ git add file &&
+ test_tick &&
+ git commit -m "copied stuff" &&
+ git am -3 -q lorem-move.patch > output.out 2>&1 &&
+ ! test -s output.out
+'
+
test_expect_success 'am pauses on conflict' '
git checkout lorem2^^ &&
test_must_fail git am lorem-move.patch &&
@@ -305,4 +316,19 @@ test_expect_success 'am into an unborn branch' '
test "z$result" = "z$(git rev-parse first^{tree})"
'
+test_expect_success 'am newline in subject' '
+ git checkout first &&
+ test_tick &&
+ sed -e "s/second/second \\\n foo/" patch1 > patchnl &&
+ git am < patchnl > output.out 2>&1 &&
+ grep "^Applying: second \\\n foo$" output.out
+'
+
+test_expect_success 'am -q is quiet' '
+ git checkout first &&
+ test_tick &&
+ git am -q < patch1 > output.out 2>&1 &&
+ ! test -s output.out
+'
+
test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index abb41b07ef..5f84b18fa5 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -94,6 +94,10 @@ test_expect_success 'git archive with --output' \
'git archive --output=b4.tar HEAD &&
test_cmp b.tar b4.tar'
+test_expect_success 'git archive --remote' \
+ 'git archive --remote=. HEAD >b5.tar &&
+ test_cmp b.tar b5.tar'
+
test_expect_success \
'validate file modification time' \
'mkdir extract &&
diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 129fa3000c..b3fbf659c0 100755
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -65,18 +65,18 @@ test_expect_success "combined merge conflicts" "
"
cat > expect << EOF
-<<<<<<< HEAD:a1
+<<<<<<< HEAD
F
=======
G
->>>>>>> G:a1
+>>>>>>> G
EOF
test_expect_success "result contains a conflict" "test_cmp expect a1"
git ls-files --stage > out
cat > expect << EOF
-100644 da056ce14a2241509897fa68bb2b3b6e6194ef9e 1 a1
+100644 439cc46de773d8a83c77799b7cc9191c128bfcff 1 a1
100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2 a1
100644 fd7923529855d0b274795ae3349c5e0438333979 3 a1
EOF
@@ -93,8 +93,7 @@ test_expect_success 'refuse to merge binary files' '
git add binary-file &&
git commit -m binary2 &&
test_must_fail git merge F > merge.out 2> merge.err &&
- grep "Cannot merge binary files: HEAD:binary-file vs. F:binary-file" \
- merge.err
+ grep "Cannot merge binary files: binary-file (HEAD vs. F)" merge.err
'
test_expect_success 'mark rename/delete as unmerged' '
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 4556cdd8d2..1315bab595 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -563,8 +563,8 @@ test_expect_success 'skipping away from skipped commit' '
hash7=$(git rev-parse --verify HEAD) &&
test "$hash7" = "$HASH7" &&
git bisect skip &&
- hash3=$(git rev-parse --verify HEAD) &&
- test "$hash3" = "$HASH3"
+ para3=$(git rev-parse --verify HEAD) &&
+ test "$para3" = "$PARA_HASH3"
'
#
diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh
index f275af8240..7868af8f18 100755
--- a/t/t7002-grep.sh
+++ b/t/t7002-grep.sh
@@ -125,6 +125,36 @@ do
done
+cat >expected <<EOF
+file:foo mmap bar_mmap
+EOF
+
+test_expect_success 'grep -e A --and -e B' '
+ git grep -e "foo mmap" --and -e bar_mmap >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+file:foo_mmap bar mmap
+file:foo_mmap bar mmap baz
+EOF
+
+
+test_expect_success 'grep ( -e A --or -e B ) --and -e B' '
+ git grep \( -e foo_ --or -e baz \) \
+ --and -e " mmap" >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+file:foo mmap bar
+EOF
+
+test_expect_success 'grep -e A --and --not -e B' '
+ git grep -e "foo mmap" --and --not -e bar_mmap >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'log grep setup' '
echo a >>file &&
test_tick &&
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index fb7d9f3e4a..fb606a9f05 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -152,7 +152,10 @@ test_expect_success 'cccmd works' '
clean_fake_sendmail &&
cp $patches cccmd.patch &&
echo cccmd--cccmd@example.com >>cccmd.patch &&
- echo sed -n s/^cccmd--//p \"\$1\" > cccmd-sed &&
+ {
+ echo "#!$SHELL_PATH"
+ echo sed -n -e s/^cccmd--//p \"\$1\"
+ } > cccmd-sed &&
chmod +x cccmd-sed &&
git send-email \
--from="Example <nobody@example.com>" \
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 64aa7e2f10..570e0359e4 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -231,6 +231,25 @@ test_expect_success \
"^:refs/${remotes_git_svn}$"
'
+test_expect_success 'dcommit $rev does not clobber current branch' '
+ git svn fetch -i bar &&
+ git checkout -b my-bar refs/remotes/bar &&
+ echo 1 > foo &&
+ git add foo &&
+ git commit -m "change 1" &&
+ echo 2 > foo &&
+ git add foo &&
+ git commit -m "change 2" &&
+ old_head=$(git rev-parse HEAD) &&
+ git svn dcommit -i bar HEAD^ &&
+ test $old_head = $(git rev-parse HEAD) &&
+ test refs/heads/my-bar = $(git symbolic-ref HEAD) &&
+ git log refs/remotes/bar | grep "change 1" &&
+ ! git log refs/remotes/bar | grep "change 2" &&
+ git checkout master &&
+ git branch -D my-bar
+ '
+
test_expect_success 'able to dcommit to a subdirectory' "
git svn fetch -i bar &&
git checkout -b my-bar refs/remotes/bar &&
diff --git a/t/t9138-git-svn-multiple-branches.sh b/t/t9138-git-svn-multiple-branches.sh
new file mode 100755
index 0000000000..cb9a6d229d
--- /dev/null
+++ b/t/t9138-git-svn-multiple-branches.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Marc Branchaud
+#
+
+test_description='git svn multiple branch and tag paths in the svn repo'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup svnrepo' '
+ mkdir project \
+ project/trunk \
+ project/b_one \
+ project/b_two \
+ project/tags_A \
+ project/tags_B &&
+ echo 1 > project/trunk/a.file &&
+ svn_cmd import -m "$test_description" project "$svnrepo/project" &&
+ rm -rf project &&
+ svn_cmd cp -m "Branch 1" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_one/first" &&
+ svn_cmd cp -m "Tag 1" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/1.0" &&
+ svn_cmd co "$svnrepo/project" svn_project &&
+ ( cd svn_project &&
+ echo 2 > trunk/a.file &&
+ svn_cmd ci -m "Change 1" trunk/a.file &&
+ svn_cmd cp -m "Branch 2" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_one/second" &&
+ svn_cmd cp -m "Tag 2" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/2.0" &&
+ echo 3 > trunk/a.file &&
+ svn_cmd ci -m "Change 2" trunk/a.file &&
+ svn_cmd cp -m "Branch 3" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_two/1" &&
+ svn_cmd cp -m "Tag 3" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/3.0" &&
+ echo 4 > trunk/a.file &&
+ svn_cmd ci -m "Change 3" trunk/a.file &&
+ svn_cmd cp -m "Branch 4" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_two/2" &&
+ svn_cmd cp -m "Tag 4" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/4.0" &&
+ svn_cmd up &&
+ echo 5 > b_one/first/a.file &&
+ svn_cmd ci -m "Change 4" b_one/first/a.file &&
+ svn_cmd cp -m "Tag 5" "$svnrepo/project/b_one/first" \
+ "$svnrepo/project/tags_B/v5" &&
+ echo 6 > b_one/second/a.file &&
+ svn_cmd ci -m "Change 5" b_one/second/a.file &&
+ svn_cmd cp -m "Tag 6" "$svnrepo/project/b_one/second" \
+ "$svnrepo/project/tags_B/v6" &&
+ echo 7 > b_two/1/a.file &&
+ svn_cmd ci -m "Change 6" b_two/1/a.file &&
+ svn_cmd cp -m "Tag 7" "$svnrepo/project/b_two/1" \
+ "$svnrepo/project/tags_B/v7" &&
+ echo 8 > b_two/2/a.file &&
+ svn_cmd ci -m "Change 7" b_two/2/a.file &&
+ svn_cmd cp -m "Tag 8" "$svnrepo/project/b_two/2" \
+ "$svnrepo/project/tags_B/v8"
+ )
+'
+
+test_expect_success 'clone multiple branch and tag paths' '
+ git svn clone -T trunk \
+ -b b_one/* --branches b_two/* \
+ -t tags_A/* --tags tags_B \
+ "$svnrepo/project" git_project &&
+ ( cd git_project &&
+ git rev-parse refs/remotes/first &&
+ git rev-parse refs/remotes/second &&
+ git rev-parse refs/remotes/1 &&
+ git rev-parse refs/remotes/2 &&
+ git rev-parse refs/remotes/tags/1.0 &&
+ git rev-parse refs/remotes/tags/2.0 &&
+ git rev-parse refs/remotes/tags/3.0 &&
+ git rev-parse refs/remotes/tags/4.0 &&
+ git rev-parse refs/remotes/tags/v5 &&
+ git rev-parse refs/remotes/tags/v6 &&
+ git rev-parse refs/remotes/tags/v7 &&
+ git rev-parse refs/remotes/tags/v8
+ )
+'
+
+test_expect_success 'Multiple branch or tag paths require -d' '
+ ( cd git_project &&
+ test_must_fail git svn branch -m "No new branch" Nope &&
+ test_must_fail git svn tag -m "No new tag" Tagless &&
+ test_must_fail git rev-parse refs/remotes/Nope &&
+ test_must_fail git rev-parse refs/remotes/tags/Tagless
+ ) &&
+ ( cd svn_project &&
+ svn_cmd up &&
+ test_must_fail test -d b_one/Nope &&
+ test_must_fail test -d b_two/Nope &&
+ test_must_fail test -d tags_A/Tagless &&
+ test_must_fail test -d tags_B/Tagless
+ )
+'
+
+test_expect_success 'create new branches and tags' '
+ ( cd git_project &&
+ git svn branch -m "New branch 1" -d project/b_one New1 ) &&
+ ( cd svn_project &&
+ svn_cmd up && test -e b_one/New1/a.file ) &&
+
+ ( cd git_project &&
+ git svn branch -m "New branch 2" -d project/b_two New2 ) &&
+ ( cd svn_project &&
+ svn_cmd up && test -e b_two/New2/a.file ) &&
+
+ ( cd git_project &&
+ git svn branch -t -m "New tag 1" -d project/tags_A Tag1 ) &&
+ ( cd svn_project &&
+ svn_cmd up && test -e tags_A/Tag1/a.file ) &&
+
+ ( cd git_project &&
+ git svn tag -m "New tag 2" -d project/tags_B Tag2 ) &&
+ ( cd svn_project &&
+ svn_cmd up && test -e tags_B/Tag2/a.file )
+'
+
+test_done
diff --git a/t/t9139-git-svn-reset.sh b/t/t9139-git-svn-reset.sh
new file mode 100755
index 0000000000..0735526d4b
--- /dev/null
+++ b/t/t9139-git-svn-reset.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Ben Jackson
+#
+
+test_description='git svn reset'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup test repository' '
+ svn_cmd co "$svnrepo" s &&
+ (
+ cd s &&
+ mkdir vis &&
+ echo always visible > vis/vis.txt &&
+ svn_cmd add vis &&
+ svn_cmd commit -m "create visible files" &&
+ mkdir hid &&
+ echo initially hidden > hid/hid.txt &&
+ svn_cmd add hid &&
+ svn_cmd commit -m "create initially hidden files" &&
+ svn_cmd up &&
+ echo mod >> vis/vis.txt &&
+ svn_cmd commit -m "modify vis" &&
+ svn_cmd up
+ )
+'
+
+test_expect_success 'clone SVN repository with hidden directory' '
+ git svn init "$svnrepo" g &&
+ ( cd g && git svn fetch --ignore-paths="^hid" )
+'
+
+test_expect_success 'modify hidden file in SVN repo' '
+ ( cd s &&
+ echo mod hidden >> hid/hid.txt &&
+ svn_cmd commit -m "modify hid" &&
+ svn_cmd up
+ )
+'
+
+test_expect_success 'fetch fails on modified hidden file' '
+ ( cd g &&
+ git svn find-rev refs/remotes/git-svn > ../expect &&
+ ! git svn fetch 2> ../errors &&
+ git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
+ fgrep "not found in commit" errors &&
+ test_cmp expect expect2
+'
+
+test_expect_success 'reset unwinds back to r1' '
+ ( cd g &&
+ git svn reset -r1 &&
+ git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
+ echo 1 >expect &&
+ test_cmp expect expect2
+'
+
+test_expect_success 'refetch succeeds not ignoring any files' '
+ ( cd g &&
+ git svn fetch &&
+ git svn rebase &&
+ fgrep "mod hidden" hid/hid.txt
+ )
+'
+
+test_done
diff --git a/tree-diff.c b/tree-diff.c
index edd83949bf..0459e54d3d 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -239,6 +239,12 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
if (!tree || type != OBJ_TREE)
die("corrupt tree sha %s", sha1_to_hex(sha1));
+ if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
+ newbase[baselen + pathlen] = 0;
+ opt->add_remove(opt, *prefix, mode, sha1, newbase);
+ newbase[baselen + pathlen] = '/';
+ }
+
init_tree_desc(&inner, tree, size);
show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);
diff --git a/upload-pack.c b/upload-pack.c
index edc7861228..841ebb534a 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -28,7 +28,7 @@ static unsigned long oldest_have;
static int multi_ack, nr_our_refs;
static int use_thin_pack, use_ofs_delta, use_include_tag;
-static int no_progress;
+static int no_progress, daemon_mode;
static struct object_array have_obj;
static struct object_array want_obj;
static unsigned int timeout;
@@ -521,6 +521,10 @@ static void receive_needs(void)
}
if (debug_fd)
write_in_full(debug_fd, "#E\n", 3);
+
+ if (!use_sideband && daemon_mode)
+ no_progress = 1;
+
if (depth == 0 && shallows.nr == 0)
return;
if (depth > 0) {
@@ -630,6 +634,7 @@ int main(int argc, char **argv)
}
if (!prefixcmp(arg, "--timeout=")) {
timeout = atoi(arg+10);
+ daemon_mode = 1;
continue;
}
if (!strcmp(arg, "--")) {
diff --git a/ws.c b/ws.c
index b1efcd9d75..819c797cf6 100644
--- a/ws.c
+++ b/ws.c
@@ -10,11 +10,12 @@
static struct whitespace_rule {
const char *rule_name;
unsigned rule_bits;
+ unsigned loosens_error;
} whitespace_rule_names[] = {
- { "trailing-space", WS_TRAILING_SPACE },
- { "space-before-tab", WS_SPACE_BEFORE_TAB },
- { "indent-with-non-tab", WS_INDENT_WITH_NON_TAB },
- { "cr-at-eol", WS_CR_AT_EOL },
+ { "trailing-space", WS_TRAILING_SPACE, 0 },
+ { "space-before-tab", WS_SPACE_BEFORE_TAB, 0 },
+ { "indent-with-non-tab", WS_INDENT_WITH_NON_TAB, 0 },
+ { "cr-at-eol", WS_CR_AT_EOL, 1 },
};
unsigned parse_whitespace_rule(const char *string)
@@ -79,7 +80,8 @@ unsigned whitespace_rule(const char *pathname)
unsigned all_rule = 0;
int i;
for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
- all_rule |= whitespace_rule_names[i].rule_bits;
+ if (!whitespace_rule_names[i].loosens_error)
+ all_rule |= whitespace_rule_names[i].rule_bits;
return all_rule;
} else if (ATTR_FALSE(value)) {
/* false (-whitespace) */