summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Documentation/Makefile7
-rw-r--r--Documentation/RelNotes-1.5.2.2.txt61
-rw-r--r--Documentation/asciidoc.conf3
-rwxr-xr-xDocumentation/cmd-list.perl2
-rw-r--r--Documentation/git-citool.txt32
-rw-r--r--Documentation/git-cvsexportcommit.txt2
-rw-r--r--Documentation/git-cvsserver.txt43
-rw-r--r--Documentation/git-gui.txt115
-rw-r--r--Documentation/git-log.txt9
-rw-r--r--Documentation/git-push.txt25
-rw-r--r--Documentation/git-read-tree.txt8
-rw-r--r--Documentation/git-reflog.txt13
-rw-r--r--Documentation/git-rev-list.txt13
-rw-r--r--Documentation/git-rev-parse.txt4
-rw-r--r--Documentation/git.txt4
-rw-r--r--Documentation/gitmodules.txt62
-rw-r--r--Documentation/pretty-options.txt9
-rw-r--r--Documentation/user-manual.txt4
-rw-r--r--INSTALL14
-rw-r--r--Makefile24
-rw-r--r--builtin-add.c69
-rw-r--r--builtin-branch.c9
-rw-r--r--builtin-read-tree.c2
-rw-r--r--builtin-revert.c4
-rw-r--r--cache-tree.c2
-rw-r--r--cache.h1
-rw-r--r--commit.c2
-rw-r--r--compat/hstrerror.c21
-rw-r--r--config.c2
-rw-r--r--connect.c6
-rwxr-xr-xcontrib/gitview/gitview21
-rw-r--r--csum-file.c55
-rw-r--r--csum-file.h2
-rw-r--r--diffcore-rename.c33
-rw-r--r--dir.c28
-rw-r--r--dir.h9
-rwxr-xr-xgenerate-cmdlist.sh2
-rwxr-xr-xgit-clone.sh20
-rw-r--r--git-compat-util.h5
-rwxr-xr-xgit-cvsimport.perl1
-rwxr-xr-xgit-cvsserver.perl91
-rw-r--r--git-filter-branch.sh441
-rwxr-xr-xgit-submodule.sh52
-rwxr-xr-xgit-svn.perl82
-rwxr-xr-xgit-svnimport.perl26
-rw-r--r--git.spec.in12
-rw-r--r--merge-recursive.c2
-rw-r--r--refs.c2
-rw-r--r--remote.c176
-rw-r--r--revision.c3
-rw-r--r--sha1_file.c4
-rwxr-xr-xt/t3200-branch.sh9
-rwxr-xr-xt/t4001-diff-rename.sh13
-rwxr-xr-xt/t5516-fetch-push.sh164
-rwxr-xr-xt/t7003-filter-branch.sh110
-rwxr-xr-xt/t7400-submodule-basic.sh22
-rwxr-xr-xt/t9113-git-svn-dcommit-new-file.sh40
-rwxr-xr-xt/t9400-git-cvsserver-server.sh45
-rw-r--r--tree-walk.h2
60 files changed, 1705 insertions, 341 deletions
diff --git a/.gitignore b/.gitignore
index bd49cd4627..e8b060cbe4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,7 +157,7 @@ common-cmds.h
*.tar.gz
*.dsc
*.deb
-git-core.spec
+git.spec
*.exe
*.[aos]
*.py[co]
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 9cef4806d1..f3a6c733b6 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -2,7 +2,7 @@ MAN1_TXT= \
$(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
$(wildcard git-*.txt)) \
gitk.txt
-MAN5_TXT=gitattributes.txt gitignore.txt
+MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt
MAN7_TXT=git.txt
DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT))
@@ -29,7 +29,7 @@ DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
prefix?=$(HOME)
bindir?=$(prefix)/bin
-mandir?=$(prefix)/man
+mandir?=$(prefix)/share/man
man1dir=$(mandir)/man1
man5dir=$(mandir)/man5
man7dir=$(mandir)/man7
@@ -37,6 +37,9 @@ man7dir=$(mandir)/man7
ASCIIDOC=asciidoc
ASCIIDOC_EXTRA =
+ifdef ASCIIDOC8
+ASCIIDOC_EXTRA += -a asciidoc7compatible
+endif
INSTALL?=install
DOC_REF = origin/man
diff --git a/Documentation/RelNotes-1.5.2.2.txt b/Documentation/RelNotes-1.5.2.2.txt
new file mode 100644
index 0000000000..f6393f8a94
--- /dev/null
+++ b/Documentation/RelNotes-1.5.2.2.txt
@@ -0,0 +1,61 @@
+GIT v1.5.2.2 Release Notes
+==========================
+
+Fixes since v1.5.2.1
+--------------------
+
+* Usability fix
+
+ - git-gui is shipped with its updated blame interface. It is
+ rumored that the older one was not just unusable but was
+ active health hazard, but this one is actually pretty.
+ Please see for yourself.
+
+* Bugfixes
+
+ - "git checkout fubar" was utterly confused when there is a
+ branch fubar and a tag fubar at the same time. It correctly
+ checks out the branch fubar now.
+
+ - "git clone /path/foo" to clone a local /path/foo.git
+ repository left an incorrect configuration.
+
+ - "git send-email" correctly unquotes RFC 2047 quoted names in
+ the patch-email before using their values.
+
+ - We did not accept number of seconds since epoch older than
+ year 2000 as a valid timestamp. We now interpret positive
+ integers more than 8 digits as such, which allows us to
+ express timestamps more recent than March 1973.
+
+ - git-cvsimport did not work when you have GIT_DIR to point
+ your repository at a nonstandard location.
+
+ - Some systems (notably, Solaris) lack hstrerror() to make
+ h_errno human readable; prepare a replacement
+ implementation.
+
+ - .gitignore file listed git-core.spec but what we generate is
+ git.spec, and nobody noticed for a long time.
+
+ - "git-merge-recursive" does not try to run file level merge
+ on binary files.
+
+ - "git-branch --track" did not create tracking configuration
+ correctly when the branch name had slash in it.
+
+ - The email address of the user specified with user.email
+ configuration was overriden by EMAIL environment variable.
+
+ - The tree parser did not warn about tree entries with
+ nonsense file modes, and assumed they must be blobs.
+
+ - "git log -z" without any other request to generate diff still
+ invoked the diff machinery, wasting cycles.
+
+* Documentation
+
+ - Many updates to fix stale or missing documentation.
+
+ - Although our documentation was primarily meant to be formatted
+ with AsciiDoc7, formatting with AsciiDoc8 is supported better.
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index 99302c5beb..6b6220dfdb 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -8,7 +8,8 @@
# the command.
[attributes]
-caret=^
+plus=+
+caret=^
startsb=[
endsb=]
tilde=~
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index a181f753e0..fcea1d74d5 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -86,6 +86,7 @@ git-check-attr purehelpers
git-check-ref-format purehelpers
git-cherry ancillaryinterrogators
git-cherry-pick mainporcelain
+git-citool mainporcelain
git-clean mainporcelain
git-clone mainporcelain
git-commit mainporcelain
@@ -111,6 +112,7 @@ git-fsck ancillaryinterrogators
git-gc mainporcelain
git-get-tar-commit-id ancillaryinterrogators
git-grep mainporcelain
+git-gui mainporcelain
git-hash-object plumbingmanipulators
git-http-fetch synchelpers
git-http-push synchelpers
diff --git a/Documentation/git-citool.txt b/Documentation/git-citool.txt
new file mode 100644
index 0000000000..5217ab2234
--- /dev/null
+++ b/Documentation/git-citool.txt
@@ -0,0 +1,32 @@
+git-citool(1)
+=============
+
+NAME
+----
+git-citool - Graphical alternative to git-commit
+
+SYNOPSIS
+--------
+'git citool'
+
+DESCRIPTION
+-----------
+A Tcl/Tk based graphical interface to review modified files, stage
+them into the index, enter a commit message and record the new
+commit onto the current branch. This interface is an alternative
+to the less interactive gitlink:git-commit[1] program.
+
+git-citool is actually a standard alias for 'git gui citool'.
+See gitlink:git-gui[1] for more details.
+
+Author
+------
+Written by Shawn O. Pearce <spearce@spearce.org>.
+
+Documentation
+--------------
+Documentation by Shawn O. Pearce <spearce@spearce.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt
index 827711c3c9..6c423e3a2f 100644
--- a/Documentation/git-cvsexportcommit.txt
+++ b/Documentation/git-cvsexportcommit.txt
@@ -76,7 +76,7 @@ $ git-cvsexportcommit -v <commit-sha1>
$ cvs commit -F .mgs <files>
------------
-Merge pending patches into CVS automatically -- only if you really know what you are doing ::
+Merge pending patches into CVS automatically -- only if you really know what you are doing::
+
------------
$ export GIT_DIR=~/project/.git
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index e5005f02f9..60d0bcf0f3 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -7,10 +7,53 @@ git-cvsserver - A CVS server emulator for git
SYNOPSIS
--------
+
+SSH:
+
[verse]
export CVS_SERVER=git-cvsserver
'cvs' -d :ext:user@server/path/repo.git co <HEAD_name>
+pserver (/etc/inetd.conf):
+
+[verse]
+cvspserver stream tcp nowait nobody /usr/bin/git-cvsserver git-cvsserver pserver
+
+Usage:
+
+[verse]
+'git-cvsserver' [options] [pserver|server] [<directory> ...]
+
+OPTIONS
+-------
+
+All these options obviously only make sense if enforced by the server side.
+They have been implemented to resemble the gitlink:git-daemon[1] options as
+closely as possible.
+
+--base-path <path>::
+Prepend 'path' to requested CVSROOT
+
+--strict-paths::
+Don't allow recursing into subdirectories
+
+--export-all::
+Don't check for `gitcvs.enabled` in config. You also have to specify a list
+of allowed directories (see below) if you want to use this option.
+
+--version, -V::
+Print version information and exit
+
+--help, -h, -H::
+Print usage information and exit
+
+<directory>::
+You can specify a list of allowed directories. If no directories
+are given, all are allowed. This is an additional restriction, gitcvs
+access still needs to be enabled by the `gitcvs.enabled` config option
+unless '--export-all' was given, too.
+
+
DESCRIPTION
-----------
diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt
new file mode 100644
index 0000000000..bd613b2fcf
--- /dev/null
+++ b/Documentation/git-gui.txt
@@ -0,0 +1,115 @@
+git-gui(1)
+==========
+
+NAME
+----
+git-gui - A portable graphical interface to Git
+
+SYNOPSIS
+--------
+'git gui' [<command>] [arguments]
+
+DESCRIPTION
+-----------
+A Tcl/Tk based graphical user interface to Git. git-gui focuses
+on allowing users to make changes to their repository by making
+new commits, amending existing ones, creating branches, performing
+local merges, and fetching/pushing to remote repositories.
+
+Unlike gitlink:gitk[1], git-gui focuses on commit generation
+and single file annotation, and does not show project history.
+It does however supply menu actions to start a gitk session from
+within git-gui.
+
+git-gui is known to work on all popular UNIX systems, Mac OS X,
+and Windows (under both Cygwin and MSYS). To the extent possible
+OS specific user interface guidelines are followed, making git-gui
+a fairly native interface for users.
+
+COMMANDS
+--------
+blame::
+ Start a blame viewer on the specified file on the given
+ version (or working directory if not specified).
+
+browser::
+ Start a tree browser showing all files in the specified
+ commit (or 'HEAD' by default). Files selected through the
+ browser are opened in the blame viewer.
+
+citool::
+ Start git-gui and arrange to make exactly one commit before
+ exiting and returning to the shell. The interface is limited
+ to only commit actions, slightly reducing the application's
+ startup time and simplifying the menubar.
+
+version::
+ Display the currently running version of git-gui.
+
+
+Examples
+--------
+git gui blame Makefile::
+
+ Show the contents of the file 'Makefile' in the current
+ working directory, and provide annotations for both the
+ original author of each line, and who moved the line to its
+ current location. The uncommitted file is annotated, and
+ uncommitted changes (if any) are explicitly attributed to
+ 'Not Yet Committed'.
+
+git gui blame v0.99.8 Makefile::
+
+ Show the contents of 'Makefile' in revision 'v0.99.8'
+ and provide annotations for each line. Unlike the above
+ example the file is read from the object database and not
+ the working directory.
+
+git gui citool::
+
+ Make one commit and return to the shell when it is complete.
+
+git citool::
+
+ Same as 'git gui citool' (above).
+
+git gui browser maint::
+
+ Show a browser for the tree of the 'maint' branch. Files
+ selected in the browser can be viewed with the internal
+ blame viewer.
+
+See Also
+--------
+'gitk(1)'::
+ The git repository browser. Shows branches, commit history
+ and file differences. gitk is the utility started by
+ git-gui's Repository Visualize actions.
+
+Other
+-----
+git-gui is actually maintained as an independent project, but stable
+versions are distributed as part of the Git suite for the convience
+of end users.
+
+A git-gui development repository can be obtained from:
+
+ git clone git://repo.or.cz/git-gui.git
+
+or
+
+ git clone http://repo.or.cz/r/git-gui.git
+
+or browsed online at http://repo.or.cz/w/git-gui.git/[].
+
+Author
+------
+Written by Shawn O. Pearce <spearce@spearce.org>.
+
+Documentation
+--------------
+Documentation by Shawn O. Pearce <spearce@spearce.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 6157edb404..7adcdefacf 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -52,7 +52,14 @@ include::pretty-options.txt[]
See also gitlink:git-reflog[1].
--decorate::
- Print out the ref names of any commits that are shown.
+ Print out the ref names of any commits that are shown.
+
+--full-diff::
+ Without this flag, "git log -p <paths>..." shows commits that
+ touch the specified paths, and diffs about the same specified
+ paths. With this, the full diff is shown for commits that touch
+ the specified paths; this means that "<paths>..." limits only
+ commits, and doesn't limit diff for those commits.
<paths>...::
Show only commits that affect the specified paths.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 366c5dbdce..665f6dc709 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -53,9 +53,8 @@ side are updated.
+
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
+
-A parameter <ref> without a colon is equivalent to
-<ref>`:`<ref>, hence updates <ref> in the destination from <ref>
-in the source.
+A parameter <ref> without a colon pushes the <ref> from the source
+repository to the destination repository under the same name.
+
Pushing an empty <src> allows you to delete the <dst> ref from
the remote repository.
@@ -98,6 +97,26 @@ the remote repository.
include::urls.txt[]
+
+Examples
+--------
+
+git push origin master::
+ Find a ref that matches `master` in the source repository
+ (most likely, it would find `refs/heads/master`), and update
+ the same ref (e.g. `refs/heads/master`) in `origin` repository
+ with it.
+
+git push origin :experimental::
+ Find a ref that matches `experimental` in the `origin` repository
+ (e.g. `refs/heads/experimental`), and delete it.
+
+git push origin master:satellite/master::
+ Find a ref that matches `master` in the source repository
+ (most likely, it would find `refs/heads/master`), and update
+ the ref that matches `satellite/master` (most likely, it would
+ be `refs/remotes/satellite/master`) in `origin` repository with it.
+
Author
------
Written by Junio C Hamano <junkio@cox.net>, later rewritten in C
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 84184d6294..74c5478ba1 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -8,7 +8,7 @@ git-read-tree - Reads tree information into the index
SYNOPSIS
--------
-'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
+'git-read-tree' (<tree-ish> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
DESCRIPTION
@@ -50,6 +50,12 @@ OPTIONS
trees that are not directly related to the current
working tree status into a temporary index file.
+--trivial::
+ Restrict three-way merge by `git-read-tree` to happen
+ only if there is no file-level merging required, instead
+ of resolving merge for trivial cases and leaving
+ conflicting files unresolved in the index.
+
--aggressive::
Usually a three-way merge by `git-read-tree` resolves
the merge for really trivial cases and leaves other
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index f717e1e30c..89bc9c51ea 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -39,6 +39,19 @@ the current branch. It is basically an alias for 'git log -g --abbrev-commit
OPTIONS
-------
+--stale-fix::
+ This revamps the logic -- the definition of "broken commit"
+ becomes: a commit that is not reachable from any of the refs and
+ there is a missing object among the commit, tree, or blob
+ objects reachable from it that is not reachable from any of the
+ refs.
++
+This computation involves traversing all the reachable objects, i.e. it
+has the same cost as 'git prune'. Fortunately, once this is run, we
+should not have to ever worry about missing objects, because the current
+prune and pack-objects know about reflogs and protect objects referred by
+them.
+
--expire=<time>::
Entries older than this time are pruned. Without the
option it is taken from configuration `gc.reflogExpire`,
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 0dba73f276..32cb13faec 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -16,11 +16,13 @@ SYNOPSIS
[ \--sparse ]
[ \--no-merges ]
[ \--remove-empty ]
+ [ \--full-history ]
[ \--not ]
[ \--all ]
[ \--stdin ]
[ \--topo-order ]
[ \--parents ]
+ [ \--timestamp ]
[ \--left-right ]
[ \--cherry-pick ]
[ \--encoding[=<encoding>] ]
@@ -116,6 +118,9 @@ e.g. "2 hours ago".
Print the parents of the commit.
+--timestamp::
+ Print the raw commit timestamp.
+
--left-right::
Mark which side of a symmetric diff a commit is reachable from.
@@ -228,6 +233,14 @@ limiting may be applied.
Stop when a given path disappears from the tree.
+--full-history::
+
+ Show also parts of history irrelevant to current state of a given
+ path. This turns off history simplification, which removed merges
+ which didn't change anything at all at some child. It will still actually
+ simplify away merges that didn't change anything at all into either
+ child.
+
--no-merges::
Do not print commits with more than one parent.
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index e1cb4ef856..87771b832b 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -89,6 +89,10 @@ OPTIONS
--git-dir::
Show `$GIT_DIR` if defined else show the path to the .git directory.
+--is-inside-git-dir::
+ Return "true" if we are in the git directory, otherwise "false".
+ Some commands require to be run in a working directory.
+
--short, --short=number::
Instead of outputting the full SHA1 values of object names try to
abbreviate them to a shorter unique name. When no length is specified
diff --git a/Documentation/git.txt b/Documentation/git.txt
index ba077c39c6..20b5b7bb48 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -41,9 +41,11 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.5.2/git.html[documentation for release 1.5.2]
+* link:v1.5.2.2/git.html[documentation for release 1.5.2.2]
* release notes for
+ link:RelNotes-1.5.2.2.txt[1.5.2.2],
+ link:RelNotes-1.5.2.1.txt[1.5.2.1],
link:RelNotes-1.5.2.txt[1.5.2].
* link:v1.5.1.6/git.html[documentation for release 1.5.1.6]
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
new file mode 100644
index 0000000000..035294e208
--- /dev/null
+++ b/Documentation/gitmodules.txt
@@ -0,0 +1,62 @@
+gitmodules(5)
+=============
+
+NAME
+----
+gitmodules - defining submodule properties
+
+SYNOPSIS
+--------
+gitmodules
+
+
+DESCRIPTION
+-----------
+
+The `.gitmodules` file, located in the top-level directory of a git
+working tree, is a text file with a syntax matching the requirements
+of gitlink:git-config[1].
+
+The file contains one subsection per submodule, and the subsection value
+is the name of the submodule. Each submodule section also contains the
+following required keys:
+
+submodule.<name>.path::
+ Defines the path, relative to the top-level directory of the git
+ working tree, where the submodule is expected to be checked out.
+ The path name must not end with a `/`. All submodule paths must
+ be unique within the .gitmodules file.
+
+submodule.<name>.url::
+ Defines an url from where the submodule repository can be cloned.
+
+
+EXAMPLES
+--------
+
+Consider the following .gitmodules file:
+
+ [submodule "libfoo"]
+ path = include/foo
+ url = git://foo.com/git/lib.git
+
+ [submodule "libbar"]
+ path = include/bar
+ url = git://bar.com/git/lib.git
+
+
+This defines two submodules, `libfoo` and `libbar`. These are expected to
+be checked out in the paths 'include/foo' and 'include/bar', and for both
+submodules an url is specified which can be used for cloning the submodules.
+
+SEE ALSO
+--------
+gitlink:git-submodule[1] gitlink:git-config[1]
+
+DOCUMENTATION
+-------------
+Documentation by Lars Hjemli <hjemli@gmail.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 6338def5a7..746bc5b7f9 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -5,6 +5,15 @@
'full', 'fuller', 'email', 'raw' and 'format:<string>'.
When left out the format default to 'medium'.
+--abbrev-commit::
+ Instead of showing the full 40-byte hexadecimal commit object
+ name, show only handful hexdigits prefix. Non default number of
+ digits can be specified with "--abbrev=<n>" (which also modifies
+ diff output, if it is displayed).
++
+This should make "--pretty=oneline" a whole lot more readable for
+people using 80-column terminals.
+
--encoding[=<encoding>]::
The commit objects record the encoding used for the log message
in their encoding header; this option can be used to tell the
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 0bfa21b3d2..ff7c71d4fb 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -2757,8 +2757,8 @@ As a result, the general consistency of an object can always be tested
independently of the contents or the type of the object: all objects can
be validated by verifying that (a) their hashes match the content of the
file and (b) the object successfully inflates to a stream of bytes that
-forms a sequence of <ascii type without space> + <space> + <ascii decimal
-size> + <byte\0> + <binary object data>.
+forms a sequence of <ascii type without space> {plus} <space> {plus} <ascii decimal
+size> {plus} <byte\0> {plus} <binary object data>.
The structured objects can further have their structure and
connectivity to other objects verified. This is generally done with
diff --git a/INSTALL b/INSTALL
index 95269cc513..63ba1480a6 100644
--- a/INSTALL
+++ b/INSTALL
@@ -89,10 +89,16 @@ Issues of note:
will include them. Note that config.mak is not distributed;
the name is reserved for local settings.
- - To build and install documentation suite, you need to have the
- asciidoc/xmlto toolchain. Alternatively, pre-formatted
- documentation are available in "html" and "man" branches of the git
- repository itself. For example, you could:
+ - To build and install documentation suite, you need to have
+ the asciidoc/xmlto toolchain. Because not many people are
+ inclined to install the tools, the default build target
+ ("make all") does _not_ build them. The documentation is
+ written for AsciiDoc 7, but "make ASCIIDOC8=YesPlease doc"
+ will let you format with AsciiDoc 8.
+
+ Alternatively, pre-formatted documentation are available in
+ "html" and "man" branches of the git repository itself. For
+ example, you could:
$ mkdir manual && cd manual
$ git init
diff --git a/Makefile b/Makefile
index 0f6540c6d8..0d904a93b9 100644
--- a/Makefile
+++ b/Makefile
@@ -107,6 +107,8 @@ all::
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-cache perspective.
#
+# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
+#
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
# MakeMaker (e.g. using ActiveState under Cygwin).
#
@@ -209,7 +211,8 @@ SCRIPT_SH = \
git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh \
- git-lost-found.sh git-quiltimport.sh git-submodule.sh
+ git-lost-found.sh git-quiltimport.sh git-submodule.sh \
+ git-filter-branch.sh
SCRIPT_PERL = \
git-add--interactive.perl \
@@ -410,6 +413,7 @@ ifeq ($(uname_S),SunOS)
NEEDS_NSL = YesPlease
SHELL_PATH = /bin/bash
NO_STRCASESTR = YesPlease
+ NO_HSTRERROR = YesPlease
ifeq ($(uname_R),5.8)
NEEDS_LIBICONV = YesPlease
NO_UNSETENV = YesPlease
@@ -654,6 +658,10 @@ endif
ifdef NO_PERL_MAKEMAKER
export NO_PERL_MAKEMAKER
endif
+ifdef NO_HSTRERROR
+ COMPAT_CFLAGS += -DNO_HSTRERROR
+ COMPAT_OBJS += compat/hstrerror.o
+endif
ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
@@ -684,6 +692,10 @@ ifndef V
endif
endif
+ifdef ASCIIDOC8
+ export ASCIIDOC8
+endif
+
# Shell quote (do not use $(call) to accommodate ancient setups);
SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
@@ -735,9 +747,13 @@ gitk-wish: gitk GIT-GUI-VARS
chmod +x $@+ && \
mv -f $@+ $@
-git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
+git.o: git.c common-cmds.h GIT-CFLAGS
+ $(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
+ $(ALL_CFLAGS) -c $(filter %.c,$^)
+
+git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
$(QUIET_LINK)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
- $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
+ $(ALL_CFLAGS) -o $@ $(filter %.c,$^) git.o \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
help.o: common-cmds.h
@@ -748,6 +764,8 @@ git-merge-subtree$X: git-merge-recursive$X
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)rm -f $@ && ln git$X $@
+common-cmds.h: ./generate-cmdlist.sh
+
common-cmds.h: $(wildcard Documentation/git-*.txt)
$(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
diff --git a/builtin-add.c b/builtin-add.c
index 159117106a..734547994f 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -40,42 +40,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
dir->nr = dst - dir->entries;
for (i = 0; i < specs; i++) {
- struct stat st;
- const char *match;
- if (seen[i])
- continue;
-
- match = pathspec[i];
- if (!match[0])
- continue;
-
- /* Existing file? We must have ignored it */
- if (!lstat(match, &st)) {
- struct dir_entry *ent;
-
- ent = dir_add_name(dir, match, strlen(match));
- ent->ignored = 1;
- if (S_ISDIR(st.st_mode))
- ent->ignored_dir = 1;
- continue;
- }
- die("pathspec '%s' did not match any files", match);
+ if (!seen[i] && !file_exists(pathspec[i]))
+ die("pathspec '%s' did not match any files",
+ pathspec[i]);
}
}
-static void fill_directory(struct dir_struct *dir, const char **pathspec)
+static void fill_directory(struct dir_struct *dir, const char **pathspec,
+ int ignored_too)
{
const char *path, *base;
int baselen;
/* Set up the default git porcelain excludes */
memset(dir, 0, sizeof(*dir));
- dir->exclude_per_dir = ".gitignore";
- path = git_path("info/exclude");
- if (!access(path, R_OK))
- add_excludes_from_file(dir, path);
- if (!access(excludes_file, R_OK))
- add_excludes_from_file(dir, excludes_file);
+ if (!ignored_too) {
+ dir->collect_ignored = 1;
+ dir->exclude_per_dir = ".gitignore";
+ path = git_path("info/exclude");
+ if (!access(path, R_OK))
+ add_excludes_from_file(dir, path);
+ if (!access(excludes_file, R_OK))
+ add_excludes_from_file(dir, excludes_file);
+ }
/*
* Calculate common prefix for the pathspec, and
@@ -219,13 +206,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
pathspec = get_pathspec(prefix, argv + i);
- fill_directory(&dir, pathspec);
+ fill_directory(&dir, pathspec, ignored_too);
if (show_only) {
const char *sep = "", *eof = "";
for (i = 0; i < dir.nr; i++) {
- if (!ignored_too && dir.entries[i]->ignored)
- continue;
printf("%s%s", sep, dir.entries[i]->name);
sep = " ";
eof = "\n";
@@ -237,25 +222,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die("index file corrupt");
- if (!ignored_too) {
- int has_ignored = 0;
- for (i = 0; i < dir.nr; i++)
- if (dir.entries[i]->ignored)
- has_ignored = 1;
- if (has_ignored) {
- fprintf(stderr, ignore_warning);
- for (i = 0; i < dir.nr; i++) {
- if (!dir.entries[i]->ignored)
- continue;
- fprintf(stderr, "%s", dir.entries[i]->name);
- if (dir.entries[i]->ignored_dir)
- fprintf(stderr, " (directory)");
- fputc('\n', stderr);
- }
- fprintf(stderr,
- "Use -f if you really want to add them.\n");
- exit(1);
+ if (dir.ignored_nr) {
+ fprintf(stderr, ignore_warning);
+ for (i = 0; i < dir.ignored_nr; i++) {
+ fprintf(stderr, "%s\n", dir.ignored[i]->name);
}
+ fprintf(stderr, "Use -f if you really want to add them.\n");
+ exit(1);
}
for (i = 0; i < dir.nr; i++)
diff --git a/builtin-branch.c b/builtin-branch.c
index d7c321af4f..77b85dde1f 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -85,6 +85,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
unsigned char sha1[20];
char *name = NULL;
const char *fmt, *remote;
+ char section[PATH_MAX];
int i;
int ret = 0;
@@ -152,9 +153,13 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
error("Error deleting %sbranch '%s'", remote,
argv[i]);
ret = 1;
- } else
+ } else {
printf("Deleted %sbranch %s.\n", remote, argv[i]);
-
+ snprintf(section, sizeof(section), "branch.%s",
+ argv[i]);
+ if (git_config_rename_section(section, NULL) < 0)
+ warning("Update of config-file failed");
+ }
}
if (name)
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 316fb0f8da..41f8110238 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -84,7 +84,7 @@ static void prime_cache_tree(void)
}
-static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
+static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
static struct lock_file lock_file;
diff --git a/builtin-revert.c b/builtin-revert.c
index 8f02ed7bd1..499bbe7343 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -25,7 +25,7 @@ static const char *cherry_pick_usage = "git-cherry-pick [--edit] [-n] [-r] [-x]
static int edit;
static int replay;
-enum { REVERT, CHERRY_PICK } action;
+static enum { REVERT, CHERRY_PICK } action;
static int no_commit;
static struct commit *commit;
static int needed_deref;
@@ -129,7 +129,7 @@ static char *get_encoding(const char *message)
return NULL;
}
-struct lock_file msg_file;
+static struct lock_file msg_file;
static int msg_fd;
static void add_to_msg(const char *string)
diff --git a/cache-tree.c b/cache-tree.c
index 350a79b768..077f034369 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -478,7 +478,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
if (0 <= it->entry_count) {
if (size < 20)
goto free_return;
- hashcpy(it->sha1, (unsigned char*)buf);
+ hashcpy(it->sha1, (const unsigned char*)buf);
buf += 20;
size -= 20;
}
diff --git a/cache.h b/cache.h
index aba7a5ec04..ed83d92c5a 100644
--- a/cache.h
+++ b/cache.h
@@ -372,7 +372,6 @@ extern int move_temp_to_file(const char *tmpfile, const char *filename);
extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
extern int has_sha1_file(const unsigned char *sha1);
-extern void *map_sha1_file(const unsigned char *sha1, unsigned long *);
extern int has_pack_file(const unsigned char *sha1);
extern int has_pack_index(const unsigned char *sha1);
diff --git a/commit.c b/commit.c
index dbb28b593f..03436b1b07 100644
--- a/commit.c
+++ b/commit.c
@@ -27,7 +27,7 @@ struct sort_node
const char *commit_type = "commit";
-struct cmt_fmt_map {
+static struct cmt_fmt_map {
const char *n;
size_t cmp_len;
enum cmit_fmt v;
diff --git a/compat/hstrerror.c b/compat/hstrerror.c
new file mode 100644
index 0000000000..069c555da4
--- /dev/null
+++ b/compat/hstrerror.c
@@ -0,0 +1,21 @@
+#include <string.h>
+#include <stdio.h>
+#include <netdb.h>
+
+const char *githstrerror(int err)
+{
+ static char buffer[48];
+ switch (err)
+ {
+ case HOST_NOT_FOUND:
+ return "Authoritative answer: host not found";
+ case NO_DATA:
+ return "Valid name, no data record of requested type";
+ case NO_RECOVERY:
+ return "Non recoverable errors, FORMERR, REFUSED, NOTIMP";
+ case TRY_AGAIN:
+ return "Non-authoritative \"host not found\", or SERVERFAIL";
+ }
+ sprintf(buffer, "Name resolution error %d", err);
+ return buffer;
+}
diff --git a/config.c b/config.c
index 58d3ed5d37..e323153ae4 100644
--- a/config.c
+++ b/config.c
@@ -523,7 +523,7 @@ static int store_aux(const char* key, const char* value)
return 0;
}
-static int write_error()
+static int write_error(void)
{
fprintf(stderr, "Failed to write new configuration file\n");
diff --git a/connect.c b/connect.c
index 7fab9c0fd9..a5afd2a536 100644
--- a/connect.c
+++ b/connect.c
@@ -224,11 +224,10 @@ static int git_tcp_connect_sock(char *host, int flags)
}
if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
saved_errno = errno;
- fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
+ fprintf(stderr, "%s[%d: %s]: errno=%s\n",
host,
cnt,
ai_name(ai),
- hstrerror(h_errno),
strerror(saved_errno));
close(sockfd);
sockfd = -1;
@@ -315,11 +314,10 @@ static int git_tcp_connect_sock(char *host, int flags)
if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
saved_errno = errno;
- fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
+ fprintf(stderr, "%s[%d: %s]: errno=%s\n",
host,
cnt,
inet_ntoa(*(struct in_addr *)&sa.sin_addr),
- hstrerror(h_errno),
strerror(saved_errno));
close(sockfd);
sockfd = -1;
diff --git a/contrib/gitview/gitview b/contrib/gitview/gitview
index 098cb01353..5931766620 100755
--- a/contrib/gitview/gitview
+++ b/contrib/gitview/gitview
@@ -352,6 +352,7 @@ class AnnotateWindow(object):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_border_width(0)
self.window.set_title("Git repository browser annotation window")
+ self.prev_read = ""
# Use two thirds of the screen by default
screen = self.window.get_screen()
@@ -401,7 +402,10 @@ class AnnotateWindow(object):
def data_ready(self, source, condition):
while (1):
try :
- buffer = source.read(8192)
+ # A simple readline doesn't work
+ # a readline bug ??
+ buffer = source.read(100)
+
except:
# resource temporary not available
return True
@@ -411,6 +415,19 @@ class AnnotateWindow(object):
source.close()
return False
+ if (self.prev_read != ""):
+ buffer = self.prev_read + buffer
+ self.prev_read = ""
+
+ if (buffer[len(buffer) -1] != '\n'):
+ try:
+ newline_index = buffer.rindex("\n")
+ except ValueError:
+ newline_index = 0
+
+ self.prev_read = buffer[newline_index:(len(buffer))]
+ buffer = buffer[0:newline_index]
+
for buff in buffer.split("\n"):
annotate_line = re.compile('^([0-9a-f]{40}) (.+) (.+) (.+)$')
m = annotate_line.match(buff)
@@ -516,7 +533,7 @@ class AnnotateWindow(object):
self.add_file_data(filename, commit_sha1, line_num)
- fp = os.popen("git blame --incremental -- " + filename + " " + commit_sha1)
+ fp = os.popen("git blame --incremental -C -C -- " + filename + " " + commit_sha1)
flags = fcntl.fcntl(fp.fileno(), fcntl.F_GETFL)
fcntl.fcntl(fp.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK)
self.io_watch_tag = gobject.io_add_watch(fp, gobject.IO_IN, self.data_ready)
diff --git a/csum-file.c b/csum-file.c
index 5109342624..9ab997120d 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -73,33 +73,6 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count)
return 0;
}
-struct sha1file *sha1create(const char *fmt, ...)
-{
- struct sha1file *f;
- unsigned len;
- va_list arg;
- int fd;
-
- f = xmalloc(sizeof(*f));
-
- va_start(arg, fmt);
- len = vsnprintf(f->name, sizeof(f->name), fmt, arg);
- va_end(arg);
- if (len >= PATH_MAX)
- die("you wascally wabbit, you");
- f->namelen = len;
-
- fd = open(f->name, O_CREAT | O_EXCL | O_WRONLY, 0666);
- if (fd < 0)
- die("unable to open %s (%s)", f->name, strerror(errno));
- f->fd = fd;
- f->error = 0;
- f->offset = 0;
- f->do_crc = 0;
- SHA1_Init(&f->ctx);
- return f;
-}
-
struct sha1file *sha1fd(int fd, const char *name)
{
struct sha1file *f;
@@ -121,34 +94,6 @@ struct sha1file *sha1fd(int fd, const char *name)
return f;
}
-int sha1write_compressed(struct sha1file *f, void *in, unsigned int size, int level)
-{
- z_stream stream;
- unsigned long maxsize;
- void *out;
-
- memset(&stream, 0, sizeof(stream));
- deflateInit(&stream, level);
- maxsize = deflateBound(&stream, size);
- out = xmalloc(maxsize);
-
- /* Compress it */
- stream.next_in = in;
- stream.avail_in = size;
-
- stream.next_out = out;
- stream.avail_out = maxsize;
-
- while (deflate(&stream, Z_FINISH) == Z_OK)
- /* nothing */;
- deflateEnd(&stream);
-
- size = stream.total_out;
- sha1write(f, out, size);
- free(out);
- return size;
-}
-
void crc32_begin(struct sha1file *f)
{
f->crc32 = crc32(0, Z_NULL, 0);
diff --git a/csum-file.h b/csum-file.h
index 4e8b83e093..c3c792f1b5 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -13,10 +13,8 @@ struct sha1file {
};
extern struct sha1file *sha1fd(int fd, const char *name);
-extern struct sha1file *sha1create(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern int sha1close(struct sha1file *, unsigned char *, int);
extern int sha1write(struct sha1file *, void *, unsigned int);
-extern int sha1write_compressed(struct sha1file *, void *, unsigned int, int);
extern void crc32_begin(struct sha1file *);
extern uint32_t crc32_end(struct sha1file *);
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 93c40d9e04..79c984c9cf 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -119,6 +119,21 @@ static int is_exact_match(struct diff_filespec *src,
return 0;
}
+static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
+{
+ int src_len = strlen(src->path), dst_len = strlen(dst->path);
+ while (src_len && dst_len) {
+ char c1 = src->path[--src_len];
+ char c2 = dst->path[--dst_len];
+ if (c1 != c2)
+ return 0;
+ if (c1 == '/')
+ return 1;
+ }
+ return (!src_len || src->path[src_len - 1] == '/') &&
+ (!dst_len || dst->path[dst_len - 1] == '/');
+}
+
struct diff_score {
int src; /* index in rename_src */
int dst; /* index in rename_dst */
@@ -186,8 +201,11 @@ static int estimate_similarity(struct diff_filespec *src,
*/
if (!dst->size)
score = 0; /* should not happen */
- else
+ else {
score = (int)(src_copied * MAX_SCORE / max_size);
+ if (basename_same(src, dst))
+ score++;
+ }
return score;
}
@@ -295,9 +313,22 @@ void diffcore_rename(struct diff_options *options)
if (rename_dst[i].pair)
continue; /* dealt with an earlier round */
for (j = 0; j < rename_src_nr; j++) {
+ int k;
struct diff_filespec *one = rename_src[j].one;
if (!is_exact_match(one, two, contents_too))
continue;
+
+ /* see if there is a basename match, too */
+ for (k = j; k < rename_src_nr; k++) {
+ one = rename_src[k].one;
+ if (basename_same(one, two) &&
+ is_exact_match(one, two,
+ contents_too)) {
+ j = k;
+ break;
+ }
+ }
+
record_rename_pair(i, j, (int)MAX_SCORE);
rename_count++;
break; /* we are done with this entry */
diff --git a/dir.c b/dir.c
index 5ba6030e9a..8d8faf5d78 100644
--- a/dir.c
+++ b/dir.c
@@ -275,7 +275,6 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len) {
struct dir_entry *ent;
ent = xmalloc(sizeof(*ent) + len + 1);
- ent->ignored = ent->ignored_dir = 0;
ent->len = len;
memcpy(ent->name, pathname, len);
ent->name[len] = 0;
@@ -287,10 +286,19 @@ struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int
if (cache_name_pos(pathname, len) >= 0)
return NULL;
- ALLOC_GROW(dir->entries, dir->nr, dir->alloc);
+ ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
}
+struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
+{
+ if (cache_name_pos(pathname, len) >= 0)
+ return NULL;
+
+ ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
+ return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);
+}
+
enum exist_status {
index_nonexistent = 0,
index_directory,
@@ -423,6 +431,18 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
return 0;
}
+static int in_pathspec(const char *path, int len, const struct path_simplify *simplify)
+{
+ if (simplify) {
+ for (; simplify->path; simplify++) {
+ if (len == simplify->len
+ && !memcmp(path, simplify->path, len))
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
* Read a directory tree. We currently ignore anything but
* directories, regular files and symlinks. That's because git
@@ -463,6 +483,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
continue;
exclude = excluded(dir, fullname);
+ if (exclude && dir->collect_ignored
+ && in_pathspec(fullname, baselen + len, simplify))
+ dir_add_ignored(dir, fullname, baselen + len);
if (exclude != dir->show_ignored) {
if (!dir->show_ignored || DTYPE(de) != DT_DIR) {
continue;
@@ -609,6 +632,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
read_directory_recursive(dir, path, base, baselen, 0, simplify);
free_simplify(simplify);
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
+ qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
return dir->nr;
}
diff --git a/dir.h b/dir.h
index 172147fd3d..ec0e8ababc 100644
--- a/dir.h
+++ b/dir.h
@@ -13,9 +13,7 @@
struct dir_entry {
- unsigned int ignored : 1;
- unsigned int ignored_dir : 1;
- unsigned int len : 30;
+ unsigned int len;
char name[FLEX_ARRAY]; /* more */
};
@@ -31,11 +29,14 @@ struct exclude_list {
struct dir_struct {
int nr, alloc;
+ int ignored_nr, ignored_alloc;
unsigned int show_ignored:1,
show_other_directories:1,
hide_empty_directories:1,
- no_gitlinks:1;
+ no_gitlinks:1,
+ collect_ignored:1;
struct dir_entry **entries;
+ struct dir_entry **ignored;
/* Exclude info */
const char *exclude_per_dir;
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index 975777f05e..17df47b950 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -7,7 +7,7 @@ struct cmdname_help
char help[80];
};
-struct cmdname_help common_cmds[] = {"
+static struct cmdname_help common_cmds[] = {"
sort <<\EOF |
add
diff --git a/git-clone.sh b/git-clone.sh
index 3a410624d3..bd44ce1c84 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -377,6 +377,13 @@ then
)
)
+ # Upstream URL
+ git-config remote."$origin".url "$repo" &&
+
+ # Set up the mappings to track the remote branches.
+ git-config remote."$origin".fetch \
+ "+refs/heads/*:$remote_top/*" '^$' &&
+
# Write out remote.$origin config, and update our "$head_points_at".
case "$head_points_at" in
?*)
@@ -384,21 +391,20 @@ then
git-symbolic-ref HEAD "refs/heads/$head_points_at" &&
# Tracking branch for the primary branch at the remote.
- origin_track="$remote_top/$head_points_at" &&
git-update-ref HEAD "$head_sha1" &&
- # Upstream URL
- git-config remote."$origin".url "$repo" &&
-
- # Set up the mappings to track the remote branches.
- git-config remote."$origin".fetch \
- "+refs/heads/*:$remote_top/*" '^$' &&
rm -f "refs/remotes/$origin/HEAD"
git-symbolic-ref "refs/remotes/$origin/HEAD" \
"refs/remotes/$origin/$head_points_at" &&
git-config branch."$head_points_at".remote "$origin" &&
git-config branch."$head_points_at".merge "refs/heads/$head_points_at"
+ ;;
+ '')
+ # Source had detached HEAD pointing nowhere
+ git-update-ref --no-deref HEAD "$head_sha1" &&
+ rm -f "refs/remotes/$origin/HEAD"
+ ;;
esac
case "$no_checkout" in
diff --git a/git-compat-util.h b/git-compat-util.h
index 6bd8987b27..b2ab3f8256 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -167,6 +167,11 @@ extern size_t gitstrlcpy(char *, const char *, size_t);
extern uintmax_t gitstrtoumax(const char *, char **, int);
#endif
+#ifdef NO_HSTRERROR
+#define hstrerror githstrerror
+extern const char *githstrerror(int herror);
+#endif
+
extern void release_pack_memory(size_t, int);
static inline char* xstrdup(const char *str)
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 433b7fd324..69ccb88dde 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -774,7 +774,6 @@ sub commit {
or die "Cannot write branch $branch for update: $!\n";
if ($tag) {
- my ($in, $out) = ('','');
my ($xtag) = $tag;
$xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
$xtag =~ tr/_/\./ if ( $opt_u );
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index d41b29f30b..5cbf27eebc 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -22,6 +22,9 @@ use bytes;
use Fcntl;
use File::Temp qw/tempdir tempfile/;
use File::Basename;
+use Getopt::Long qw(:config require_order no_ignore_case);
+
+my $VERSION = '@@GIT_VERSION@@';
my $log = GITCVS::log->new();
my $cfg;
@@ -85,15 +88,57 @@ my $methods = {
my $state = { prependdir => '' };
$log->info("--------------- STARTING -----------------");
+my $usage =
+ "Usage: git-cvsserver [options] [pserver|server] [<directory> ...]\n".
+ " --base-path <path> : Prepend to requested CVSROOT\n".
+ " --strict-paths : Don't allow recursing into subdirectories\n".
+ " --export-all : Don't check for gitcvs.enabled in config\n".
+ " --version, -V : Print version information and exit\n".
+ " --help, -h, -H : Print usage information and exit\n".
+ "\n".
+ "<directory> ... is a list of allowed directories. If no directories\n".
+ "are given, all are allowed. This is an additional restriction, gitcvs\n".
+ "access still needs to be enabled by the gitcvs.enabled config option.\n";
+
+my @opts = ( 'help|h|H', 'version|V',
+ 'base-path=s', 'strict-paths', 'export-all' );
+GetOptions( $state, @opts )
+ or die $usage;
+
+if ($state->{version}) {
+ print "git-cvsserver version $VERSION\n";
+ exit;
+}
+if ($state->{help}) {
+ print $usage;
+ exit;
+}
+
my $TEMP_DIR = tempdir( CLEANUP => 1 );
$log->debug("Temporary directory is '$TEMP_DIR'");
+$state->{method} = 'ext';
+if (@ARGV) {
+ if ($ARGV[0] eq 'pserver') {
+ $state->{method} = 'pserver';
+ shift @ARGV;
+ } elsif ($ARGV[0] eq 'server') {
+ shift @ARGV;
+ }
+}
+
+# everything else is a directory
+$state->{allowed_roots} = [ @ARGV ];
+
+# don't export the whole system unless the users requests it
+if ($state->{'export-all'} && !@{$state->{allowed_roots}}) {
+ die "--export-all can only be used together with an explicit whitelist\n";
+}
+
# if we are called with a pserver argument,
# deal with the authentication cat before entering the
# main loop
-$state->{method} = 'ext';
-if (@ARGV && $ARGV[0] eq 'pserver') {
- $state->{method} = 'pserver';
+if ($state->{method} eq 'pserver') {
my $line = <STDIN>; chomp $line;
unless( $line =~ /^BEGIN (AUTH|VERIFICATION) REQUEST$/) {
die "E Do not understand $line - expecting BEGIN AUTH REQUEST\n";
@@ -172,19 +217,48 @@ sub req_Root
return 0;
}
+ my $cvsroot = $state->{'base-path'} || '';
+ $cvsroot =~ s#/+$##;
+ $cvsroot .= $data;
+
if ($state->{CVSROOT}
- && ($state->{CVSROOT} ne $data)) {
+ && ($state->{CVSROOT} ne $cvsroot)) {
print "error 1 Conflicting roots specified\n";
return 0;
}
- $state->{CVSROOT} = $data;
+ $state->{CVSROOT} = $cvsroot;
$ENV{GIT_DIR} = $state->{CVSROOT} . "/";
+
+ if (@{$state->{allowed_roots}}) {
+ my $allowed = 0;
+ foreach my $dir (@{$state->{allowed_roots}}) {
+ next unless $dir =~ m#^/#;
+ $dir =~ s#/+$##;
+ if ($state->{'strict-paths'}) {
+ if ($ENV{GIT_DIR} =~ m#^\Q$dir\E/?$#) {
+ $allowed = 1;
+ last;
+ }
+ } elsif ($ENV{GIT_DIR} =~ m#^\Q$dir\E(/?$|/)#) {
+ $allowed = 1;
+ last;
+ }
+ }
+
+ unless ($allowed) {
+ print "E $ENV{GIT_DIR} does not seem to be a valid GIT repository\n";
+ print "E \n";
+ print "error 1 $ENV{GIT_DIR} is not a valid repository\n";
+ return 0;
+ }
+ }
+
unless (-d $ENV{GIT_DIR} && -e $ENV{GIT_DIR}.'HEAD') {
print "E $ENV{GIT_DIR} does not seem to be a valid GIT repository\n";
- print "E \n";
- print "error 1 $ENV{GIT_DIR} is not a valid repository\n";
+ print "E \n";
+ print "error 1 $ENV{GIT_DIR} is not a valid repository\n";
return 0;
}
@@ -207,7 +281,8 @@ sub req_Root
my $enabled = ($cfg->{gitcvs}{$state->{method}}{enabled}
|| $cfg->{gitcvs}{enabled});
- unless ($enabled && $enabled =~ /^\s*(1|true|yes)\s*$/i) {
+ unless ($state->{'export-all'} ||
+ ($enabled && $enabled =~ /^\s*(1|true|yes)\s*$/i)) {
print "E GITCVS emulation needs to be enabled on this repo\n";
print "E the repo config file needs a [gitcvs] section added, and the parameter 'enabled' set to 1\n";
print "E \n";
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
new file mode 100644
index 0000000000..8fa5ce6467
--- /dev/null
+++ b/git-filter-branch.sh
@@ -0,0 +1,441 @@
+#!/bin/sh
+#
+# Rewrite revision history
+# Copyright (c) Petr Baudis, 2006
+# Minimal changes to "port" it to core-git (c) Johannes Schindelin, 2007
+#
+# Lets you rewrite GIT revision history by creating a new branch from
+# your current branch by applying custom filters on each revision.
+# Those filters can modify each tree (e.g. removing a file or running
+# a perl rewrite on all files) or information about each commit.
+# Otherwise, all information (including original commit times or merge
+# information) will be preserved.
+#
+# The command takes the new branch name as a mandatory argument and
+# the filters as optional arguments. If you specify no filters, the
+# commits will be recommitted without any changes, which would normally
+# have no effect and result with the new branch pointing to the same
+# branch as your current branch. (Nevertheless, this may be useful in
+# the future for compensating for some Git bugs or such, therefore
+# such a usage is permitted.)
+#
+# WARNING! The rewritten history will have different ids for all the
+# objects and will not converge with the original branch. You will not
+# be able to easily push and distribute the rewritten branch. Please do
+# not use this command if you do not know the full implications, and
+# avoid using it anyway - do not do what a simple single commit on top
+# of the current version would fix.
+#
+# Always verify that the rewritten version is correct before disposing
+# the original branch.
+#
+# Note that since this operation is extensively I/O expensive, it might
+# be a good idea to do it off-disk, e.g. on tmpfs. Reportedly the speedup
+# is very noticeable.
+#
+# OPTIONS
+# -------
+# -d TEMPDIR:: The path to the temporary tree used for rewriting
+# When applying a tree filter, the command needs to temporary
+# checkout the tree to some directory, which may consume
+# considerable space in case of large projects. By default it
+# does this in the '.git-rewrite/' directory but you can override
+# that choice by this parameter.
+#
+# Filters
+# ~~~~~~~
+# The filters are applied in the order as listed below. The COMMAND
+# argument is always evaluated in shell using the 'eval' command.
+# The $GIT_COMMIT environment variable is permanently set to contain
+# the id of the commit being rewritten. The author/committer environment
+# variables are set before the first filter is run.
+#
+# A 'map' function is available that takes an "original sha1 id" argument
+# and outputs a "rewritten sha1 id" if the commit has been already
+# rewritten, fails otherwise; the 'map' function can return several
+# ids on separate lines if your commit filter emitted multiple commits
+# (see below).
+#
+# --env-filter COMMAND:: The filter for modifying environment
+# This is the filter for modifying the environment in which
+# the commit will be performed. Specifically, you might want
+# to rewrite the author/committer name/email/time environment
+# variables (see `git-commit` for details). Do not forget to
+# re-export the variables.
+#
+# --tree-filter COMMAND:: The filter for rewriting tree (and its contents)
+# This is the filter for rewriting the tree and its contents.
+# The COMMAND argument is evaluated in shell with the working
+# directory set to the root of the checked out tree. The new tree
+# is then used as-is (new files are auto-added, disappeared files
+# are auto-removed - .gitignore files nor any other ignore rules
+# HAVE NO EFFECT!).
+#
+# --index-filter COMMAND:: The filter for rewriting index
+# This is the filter for rewriting the Git's directory index.
+# It is similar to the tree filter but does not check out the
+# tree, which makes it much faster. However, you must use the
+# lowlevel Git index manipulation commands to do your work.
+#
+# --parent-filter COMMAND:: The filter for rewriting parents
+# This is the filter for rewriting the commit's parent list.
+# It will receive the parent string on stdin and shall output
+# the new parent string on stdout. The parent string is in
+# format accepted by `git-commit-tree`: empty for initial
+# commit, "-p parent" for a normal commit and "-p parent1
+# -p parent2 -p parent3 ..." for a merge commit.
+#
+# --msg-filter COMMAND:: The filter for rewriting commit message
+# This is the filter for rewriting the commit messages.
+# The COMMAND argument is evaluated in shell with the original
+# commit message on standard input; its standard output is
+# is used as the new commit message.
+#
+# --commit-filter COMMAND:: The filter for performing the commit
+# If this filter is passed, it will be called instead of the
+# `git-commit-tree` command, with those arguments:
+#
+# TREE_ID [-p PARENT_COMMIT_ID]...
+#
+# and the log message on stdin. The commit id is expected on
+# stdout. As a special extension, the commit filter may emit
+# multiple commit ids; in that case, all of them will be used
+# as parents instead of the original commit in further commits.
+#
+# --tag-name-filter COMMAND:: The filter for rewriting tag names.
+# If this filter is passed, it will be called for every tag ref
+# that points to a rewritten object (or to a tag object which
+# points to a rewritten object). The original tag name is passed
+# via standard input, and the new tag name is expected on standard
+# output.
+#
+# The original tags are not deleted, but can be overwritten;
+# use "--tag-name-filter=cat" to simply update the tags. In this
+# case, be very careful and make sure you have the old tags
+# backed up in case the conversion has run afoul.
+#
+# Note that there is currently no support for proper rewriting of
+# tag objects; in layman terms, if the tag has a message or signature
+# attached, the rewritten tag won't have it. Sorry. (It is by
+# definition impossible to preserve signatures at any rate, though.)
+#
+# --subdirectory-filter DIRECTORY:: Only regard the history, as seen by
+# the given subdirectory. The result will contain that directory as
+# its project root.
+#
+# EXAMPLE USAGE
+# -------------
+# Suppose you want to remove a file (containing confidential information
+# or copyright violation) from all commits:
+#
+# git-filter-branch --tree-filter 'rm filename' newbranch
+#
+# A significantly faster version:
+#
+# git-filter-branch --index-filter 'git-update-index --remove filename' newbranch
+#
+# Now, you will get the rewritten history saved in the branch 'newbranch'
+# (your current branch is left untouched).
+#
+# To "etch-graft" a commit to the revision history (set a commit to be
+# the parent of the current initial commit and propagate that):
+#
+# git-filter-branch --parent-filter sed\ 's/^$/-p graftcommitid/' newbranch
+#
+# (if the parent string is empty - therefore we are dealing with the
+# initial commit - add graftcommit as a parent). Note that this assumes
+# history with a single root (that is, no git-merge without common ancestors
+# happened). If this is not the case, use:
+#
+# git-filter-branch --parent-filter 'cat; [ "$GIT_COMMIT" = "COMMIT" ] && echo "-p GRAFTCOMMIT"' newbranch
+#
+# To remove commits authored by "Darl McBribe" from the history:
+#
+# git-filter-branch --commit-filter 'if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; then shift; while [ -n "$1" ]; do shift; echo "$1"; shift; done; else git-commit-tree "$@"; fi' newbranch
+#
+# (the shift magic first throws away the tree id and then the -p
+# parameters). Note that this handles merges properly! In case Darl
+# committed a merge between P1 and P2, it will be propagated properly
+# and all children of the merge will become merge commits with P1,P2
+# as their parents instead of the merge commit.
+#
+# To restrict rewriting to only part of the history, specify a revision
+# range in addition to the new branch name. The new branch name will
+# point to the top-most revision that a 'git rev-list' of this range
+# will print.
+#
+# Consider this history:
+#
+# D--E--F--G--H
+# / /
+# A--B-----C
+#
+# To rewrite commits D,E,F,G,H, use:
+#
+# git-filter-branch ... new-H C..H
+#
+# To rewrite commits E,F,G,H, use one of these:
+#
+# git-filter-branch ... new-H C..H --not D
+# git-filter-branch ... new-H D..H --not C
+#
+# To move the whole tree into a subdirectory, or remove it from there:
+#
+# git-filter-branch --index-filter \
+# 'git-ls-files -s | sed "s-\t-&newsubdir/-" |
+# GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
+# git-update-index --index-info &&
+# mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' directorymoved
+
+# Testsuite: TODO
+
+set -e
+
+USAGE="git-filter-branch [-d TEMPDIR] [FILTERS] DESTBRANCH [REV-RANGE]"
+. git-sh-setup
+
+map()
+{
+ # if it was not rewritten, take the original
+ test -r "$workdir/../map/$1" || echo "$1"
+ cat "$workdir/../map/$1"
+}
+
+# When piped a commit, output a script to set the ident of either
+# "author" or "committer
+
+set_ident () {
+ lid="$(echo "$1" | tr "A-Z" "a-z")"
+ uid="$(echo "$1" | tr "a-z" "A-Z")"
+ pick_id_script='
+ /^'$lid' /{
+ s/'\''/'\''\\'\'\''/g
+ h
+ s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/
+ s/'\''/'\''\'\'\''/g
+ s/.*/export GIT_'$uid'_NAME='\''&'\''/p
+
+ g
+ s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/
+ s/'\''/'\''\'\'\''/g
+ s/.*/export GIT_'$uid'_EMAIL='\''&'\''/p
+
+ g
+ s/^'$lid' [^<]* <[^>]*> \(.*\)$/\1/
+ s/'\''/'\''\'\'\''/g
+ s/.*/export GIT_'$uid'_DATE='\''&'\''/p
+
+ q
+ }
+ '
+
+ LANG=C LC_ALL=C sed -ne "$pick_id_script"
+ # Ensure non-empty id name.
+ echo "[ -n \"\$GIT_${uid}_NAME\" ] || export GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\""
+}
+
+tempdir=.git-rewrite
+filter_env=
+filter_tree=
+filter_index=
+filter_parent=
+filter_msg=cat
+filter_commit='git-commit-tree "$@"'
+filter_tag_name=
+filter_subdir=
+while case "$#" in 0) usage;; esac
+do
+ case "$1" in
+ --)
+ shift
+ break
+ ;;
+ -*)
+ ;;
+ *)
+ break;
+ esac
+
+ # all switches take one argument
+ ARG="$1"
+ case "$#" in 1) usage ;; esac
+ shift
+ OPTARG="$1"
+ shift
+
+ case "$ARG" in
+ -d)
+ tempdir="$OPTARG"
+ ;;
+ --env-filter)
+ filter_env="$OPTARG"
+ ;;
+ --tree-filter)
+ filter_tree="$OPTARG"
+ ;;
+ --index-filter)
+ filter_index="$OPTARG"
+ ;;
+ --parent-filter)
+ filter_parent="$OPTARG"
+ ;;
+ --msg-filter)
+ filter_msg="$OPTARG"
+ ;;
+ --commit-filter)
+ filter_commit="$OPTARG"
+ ;;
+ --tag-name-filter)
+ filter_tag_name="$OPTARG"
+ ;;
+ --subdirectory-filter)
+ filter_subdir="$OPTARG"
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+
+dstbranch="$1"
+shift
+test -n "$dstbranch" || die "missing branch name"
+git-show-ref "refs/heads/$dstbranch" 2> /dev/null &&
+ die "branch $dstbranch already exists"
+
+test ! -e "$tempdir" || die "$tempdir already exists, please remove it"
+mkdir -p "$tempdir/t"
+cd "$tempdir/t"
+workdir="$(pwd)"
+
+case "$GIT_DIR" in
+/*)
+ ;;
+*)
+ export GIT_DIR="$(pwd)/../../$GIT_DIR"
+ ;;
+esac
+
+export GIT_INDEX_FILE="$(pwd)/../index"
+git-read-tree # seed the index file
+
+ret=0
+
+
+mkdir ../map # map old->new commit ids for rewriting parents
+
+case "$filter_subdir" in
+"")
+ git-rev-list --reverse --topo-order --default HEAD \
+ --parents "$@"
+ ;;
+*)
+ git-rev-list --reverse --topo-order --default HEAD \
+ --parents --full-history "$@" -- "$filter_subdir"
+esac > ../revs
+commits=$(cat ../revs | wc -l | tr -d " ")
+
+test $commits -eq 0 && die "Found nothing to rewrite"
+
+i=0
+while read commit parents; do
+ i=$(($i+1))
+ printf "$commit ($i/$commits) "
+
+ case "$filter_subdir" in
+ "")
+ git-read-tree -i -m $commit
+ ;;
+ *)
+ git-read-tree -i -m $commit:"$filter_subdir"
+ esac
+
+ export GIT_COMMIT=$commit
+ git-cat-file commit "$commit" >../commit
+
+ eval "$(set_ident AUTHOR <../commit)"
+ eval "$(set_ident COMMITTER <../commit)"
+ eval "$filter_env" < /dev/null
+
+ if [ "$filter_tree" ]; then
+ git-checkout-index -f -u -a
+ # files that $commit removed are now still in the working tree;
+ # remove them, else they would be added again
+ git-ls-files -z --others | xargs -0 rm -f
+ eval "$filter_tree" < /dev/null
+ git-diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \
+ xargs -0 git-update-index --add --replace --remove
+ git-ls-files -z --others | \
+ xargs -0 git-update-index --add --replace --remove
+ fi
+
+ eval "$filter_index" < /dev/null
+
+ parentstr=
+ for parent in $parents; do
+ for reparent in $(map "$parent"); do
+ parentstr="$parentstr -p $reparent"
+ done
+ done
+ if [ "$filter_parent" ]; then
+ parentstr="$(echo "$parentstr" | eval "$filter_parent")"
+ fi
+
+ sed -e '1,/^$/d' <../commit | \
+ eval "$filter_msg" | \
+ sh -c "$filter_commit" git-commit-tree $(git-write-tree) $parentstr | \
+ tee ../map/$commit
+done <../revs
+
+src_head=$(tail -n 1 ../revs | sed -e 's/ .*//')
+target_head=$(head -n 1 ../map/$src_head)
+case "$target_head" in
+'')
+ echo Nothing rewritten
+ ;;
+*)
+ git-update-ref refs/heads/"$dstbranch" $target_head
+ if [ $(cat ../map/$src_head | wc -l) -gt 1 ]; then
+ echo "WARNING: Your commit filter caused the head commit to expand to several rewritten commits. Only the first such commit was recorded as the current $dstbranch head but you will need to resolve the situation now (probably by manually merging the other commits). These are all the commits:" >&2
+ sed 's/^/ /' ../map/$src_head >&2
+ ret=1
+ fi
+ ;;
+esac
+
+if [ "$filter_tag_name" ]; then
+ git-for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |
+ while read sha1 type ref; do
+ ref="${ref#refs/tags/}"
+ # XXX: Rewrite tagged trees as well?
+ if [ "$type" != "commit" -a "$type" != "tag" ]; then
+ continue;
+ fi
+
+ if [ "$type" = "tag" ]; then
+ # Dereference to a commit
+ sha1t="$sha1"
+ sha1="$(git-rev-parse "$sha1"^{commit} 2>/dev/null)" || continue
+ fi
+
+ [ -f "../map/$sha1" ] || continue
+ new_sha1="$(cat "../map/$sha1")"
+ export GIT_COMMIT="$sha1"
+ new_ref="$(echo "$ref" | eval "$filter_tag_name")"
+
+ echo "$ref -> $new_ref ($sha1 -> $new_sha1)"
+
+ if [ "$type" = "tag" ]; then
+ # Warn that we are not rewriting the tag object itself.
+ warn "unreferencing tag object $sha1t"
+ fi
+
+ git-update-ref "refs/tags/$new_ref" "$new_sha1"
+ done
+fi
+
+cd ../..
+rm -rf "$tempdir"
+echo "Rewritten history saved to the $dstbranch branch"
+
+exit $ret
diff --git a/git-submodule.sh b/git-submodule.sh
index 8bdd99a2f3..89a3885350 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -25,6 +25,19 @@ say()
fi
}
+#
+# Map submodule path to submodule name
+#
+# $1 = path
+#
+module_name()
+{
+ name=$(GIT_CONFIG=.gitmodules git-config --get-regexp '^submodule\..*\.path$' "$1" |
+ sed -nre 's/^submodule\.(.+)\.path .+$/\1/p')
+ test -z "$name" &&
+ die "No submodule mapping found in .gitmodules for path '$path'"
+ echo "$name"
+}
#
# Clone a submodule
@@ -49,7 +62,7 @@ module_clone()
die "A file already exist at path '$path'"
git-clone -n "$url" "$path" ||
- die "Clone of submodule '$path' failed"
+ die "Clone of '$url' into submodule path '$path' failed"
}
#
@@ -63,17 +76,18 @@ modules_init()
while read mode sha1 stage path
do
# Skip already registered paths
- url=$(git-config submodule."$path".url)
+ name=$(module_name "$path") || exit
+ url=$(git-config submodule."$name".url)
test -z "$url" || continue
- url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
+ url=$(GIT_CONFIG=.gitmodules git-config submodule."$name".url)
test -z "$url" &&
- die "No url found for submodule '$path' in .gitmodules"
+ die "No url found for submodule path '$path' in .gitmodules"
- git-config submodule."$path".url "$url" ||
- die "Failed to register url for submodule '$path'"
+ git-config submodule."$name".url "$url" ||
+ die "Failed to register url for submodule path '$path'"
- say "Submodule '$path' registered with url '$url'"
+ say "Submodule '$name' ($url) registered for path '$path'"
done
}
@@ -87,38 +101,40 @@ modules_update()
git ls-files --stage -- "$@" | grep -e '^160000 ' |
while read mode sha1 stage path
do
- url=$(git-config submodule."$path".url)
+ name=$(module_name "$path") || exit
+ url=$(git-config submodule."$name".url)
if test -z "$url"
then
# Only mention uninitialized submodules when its
# path have been specified
test "$#" != "0" &&
- say "Submodule '$path' not initialized"
+ say "Submodule path '$path' not initialized"
continue
fi
if ! test -d "$path"/.git
then
module_clone "$path" "$url" || exit
+ subsha1=
+ else
+ subsha1=$(unset GIT_DIR && cd "$path" &&
+ git-rev-parse --verify HEAD) ||
+ die "Unable to find current revision in submodule path '$path'"
fi
- subsha1=$(unset GIT_DIR && cd "$path" &&
- git-rev-parse --verify HEAD) ||
- die "Unable to find current revision of submodule '$path'"
-
if test "$subsha1" != "$sha1"
then
(unset GIT_DIR && cd "$path" && git-fetch &&
git-checkout -q "$sha1") ||
- die "Unable to checkout '$sha1' in submodule '$path'"
+ die "Unable to checkout '$sha1' in submodule path '$path'"
- say "Submodule '$path': checked out '$sha1'"
+ say "Submodule path '$path': checked out '$sha1'"
fi
done
}
#
-# List all registered submodules, prefixed with:
+# List all submodules, prefixed with:
# - submodule not initialized
# + different revision checked out
#
@@ -132,7 +148,9 @@ modules_list()
git ls-files --stage -- "$@" | grep -e '^160000 ' |
while read mode sha1 stage path
do
- if ! test -d "$path"/.git
+ name=$(module_name "$path") || exit
+ url=$(git-config submodule."$name".url)
+ if test -z "url" || ! test -d "$path"/.git
then
say "-$sha1 $path"
continue;
diff --git a/git-svn.perl b/git-svn.perl
index e35006142a..50128d7285 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -38,14 +38,16 @@ use IPC::Open3;
use Git;
BEGIN {
- my $s;
+ # import functions from Git into our packages, en masse
+ no strict 'refs';
foreach (qw/command command_oneline command_noisy command_output_pipe
command_input_pipe command_close_pipe/) {
- $s .= "*SVN::Git::Editor::$_ = *SVN::Git::Fetcher::$_ = ".
- "*Git::SVN::Migration::$_ = ".
- "*Git::SVN::Log::$_ = *Git::SVN::$_ = *$_ = *Git::$_; ";
+ for my $package ( qw(SVN::Git::Editor SVN::Git::Fetcher
+ Git::SVN::Migration Git::SVN::Log Git::SVN),
+ __PACKAGE__) {
+ *{"${package}::$_"} = \&{"Git::$_"};
+ }
}
- eval $s;
}
my ($SVN);
@@ -846,26 +848,26 @@ BEGIN {
# some options are read globally, but can be overridden locally
# per [svn-remote "..."] section. Command-line options will *NOT*
# override options set in an [svn-remote "..."] section
- my $e;
- foreach (qw/follow_parent no_metadata use_svm_props
- use_svnsync_props/) {
- my $key = $_;
+ no strict 'refs';
+ for my $option (qw/follow_parent no_metadata use_svm_props
+ use_svnsync_props/) {
+ my $key = $option;
$key =~ tr/_//d;
- $e .= "sub $_ {
- my (\$self) = \@_;
- return \$self->{-$_} if exists \$self->{-$_};
- my \$k = \"svn-remote.\$self->{repo_id}\.$key\";
- eval { command_oneline(qw/config --get/, \$k) };
- if (\$@) {
- \$self->{-$_} = \$Git::SVN::_$_;
+ my $prop = "-$option";
+ *$option = sub {
+ my ($self) = @_;
+ return $self->{$prop} if exists $self->{$prop};
+ my $k = "svn-remote.$self->{repo_id}.$key";
+ eval { command_oneline(qw/config --get/, $k) };
+ if ($@) {
+ $self->{$prop} = ${"Git::SVN::_$option"};
} else {
- my \$v = command_oneline(qw/config --bool/,\$k);
- \$self->{-$_} = \$v eq 'false' ? 0 : 1;
+ my $v = command_oneline(qw/config --bool/,$k);
+ $self->{$prop} = $v eq 'false' ? 0 : 1;
}
- return \$self->{-$_} }\n";
+ return $self->{$prop};
+ }
}
- $e .= "1;\n";
- eval $e or die $@;
}
my %LOCKFILES;
@@ -1457,7 +1459,7 @@ sub tmp_config {
my (@args) = @_;
my $old_def_config = "$ENV{GIT_DIR}/svn/config";
my $config = "$ENV{GIT_DIR}/svn/.metadata";
- if (-e $old_def_config && ! -e $config) {
+ if (! -f $config && -f $old_def_config) {
rename $old_def_config, $config or
die "Failed rename $old_def_config => $config: $!\n";
}
@@ -2899,17 +2901,17 @@ my ($can_do_switch, %ignored_err, $RA);
BEGIN {
# enforce temporary pool usage for some simple functions
- my $e;
- foreach (qw/rev_proplist get_latest_revnum get_uuid get_repos_root/) {
- $e .= "sub $_ {
- my \$self = shift;
- my \$pool = SVN::Pool->new;
- my \@ret = \$self->SUPER::$_(\@_,\$pool);
- \$pool->clear;
- wantarray ? \@ret : \$ret[0]; }\n";
+ no strict 'refs';
+ for my $f (qw/rev_proplist get_latest_revnum get_uuid get_repos_root/) {
+ my $SUPER = "SUPER::$f";
+ *$f = sub {
+ my $self = shift;
+ my $pool = SVN::Pool->new;
+ my @ret = $self->$SUPER(@_,$pool);
+ $pool->clear;
+ wantarray ? @ret : $ret[0];
+ };
}
-
- eval "$e; 1;" or die $@;
}
sub new {
@@ -3072,11 +3074,8 @@ sub gs_do_switch {
$editor->{git_commit_ok};
}
-sub gs_fetch_loop_common {
- my ($self, $base, $head, $gsv, $globs) = @_;
- return if ($base > $head);
- my $inc = $_log_window_size;
- my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
+sub longest_common_path {
+ my ($gsv, $globs) = @_;
my %common;
my $common_max = scalar @$gsv;
@@ -3108,6 +3107,15 @@ sub gs_fetch_loop_common {
last;
}
}
+ $longest_path;
+}
+
+sub gs_fetch_loop_common {
+ my ($self, $base, $head, $gsv, $globs) = @_;
+ return if ($base > $head);
+ my $inc = $_log_window_size;
+ my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
+ my $longest_path = longest_common_path($gsv, $globs);
while (1) {
my %revs;
my $err;
diff --git a/git-svnimport.perl b/git-svnimport.perl
index f4597626b9..b73d6494d8 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -867,34 +867,14 @@ sub commit {
or die "Cannot write branch $dest for update: $!\n";
}
- if($tag) {
- my($in, $out) = ('','');
+ if ($tag) {
$last_rev = "-" if %$changed_paths;
# the tag was 'complex', i.e. did not refer to a "real" revision
$dest =~ tr/_/\./ if $opt_u;
- $branch = $dest;
-
- my $pid = open2($in, $out, 'git-mktag');
- print $out ("object $cid\n".
- "type commit\n".
- "tag $dest\n".
- "tagger $committer_name <$committer_email> 0 +0000\n") and
- close($out)
- or die "Cannot create tag object $dest: $!\n";
-
- my $tagobj = <$in>;
- chomp $tagobj;
-
- if ( !close($in) or waitpid($pid, 0) != $pid or
- $? != 0 or $tagobj !~ /^[0123456789abcdef]{40}$/ ) {
- die "Cannot create tag object $dest: $!\n";
- }
- open(C,">$git_dir/refs/tags/$dest") and
- print C ("$tagobj\n") and
- close(C)
- or die "Cannot create tag $branch: $!\n";
+ system('git-tag', $dest, $cid) == 0
+ or die "Cannot create tag $dest: $!\n";
print "Created tag '$dest' on '$branch'\n" if $opt_v;
}
diff --git a/git.spec.in b/git.spec.in
index b9dc1d59eb..287057e816 100644
--- a/git.spec.in
+++ b/git.spec.in
@@ -164,11 +164,10 @@ rm -rf $RPM_BUILD_ROOT
%{_bindir}/git-gui
%{_bindir}/git-citool
%{_datadir}/git-gui/
-# Not Yet...
-# %{!?_without_docs: %{_mandir}/man1/git-gui.1}
-# %{!?_without_docs: %doc Documentation/git-gui.html}
-# %{!?_without_docs: %{_mandir}/man1/git-citool.1}
-# %{!?_without_docs: %doc Documentation/git-citool.html}
+%{!?_without_docs: %{_mandir}/man1/git-gui.1}
+%{!?_without_docs: %doc Documentation/git-gui.html}
+%{!?_without_docs: %{_mandir}/man1/git-citool.1}
+%{!?_without_docs: %doc Documentation/git-citool.html}
%files -n gitk
%defattr(-,root,root)
@@ -188,6 +187,9 @@ rm -rf $RPM_BUILD_ROOT
%{!?_without_docs: %doc Documentation/technical}
%changelog
+* Thu Jun 21 2007 Shawn O. Pearce <spearce@spearce.org>
+- Added documentation files for git-gui
+
* Tue May 13 2007 Quy Tonthat <qtonthat@gmail.com>
- Added lib files for git-gui
- Added Documentation/technical (As needed by Git Users Manual)
diff --git a/merge-recursive.c b/merge-recursive.c
index 4a82b741ae..c8539ec0ba 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -127,7 +127,7 @@ static void output(int v, const char *fmt, ...)
va_end(args);
}
-static void flush_output()
+static void flush_output(void)
{
struct output_buffer *b, *n;
for (b = output_list; b; b = n) {
diff --git a/refs.c b/refs.c
index ef4484d293..67ac97c713 100644
--- a/refs.c
+++ b/refs.c
@@ -150,7 +150,7 @@ static struct ref_list *sort_ref_list(struct ref_list *list)
* Future: need to be in "struct repository"
* when doing a full libification.
*/
-struct cached_refs {
+static struct cached_refs {
char did_loose;
char did_packed;
struct ref_list *loose;
diff --git a/remote.c b/remote.c
index ed62a62fa0..500ca4d968 100644
--- a/remote.c
+++ b/remote.c
@@ -333,7 +333,6 @@ static int count_refspec_match(const char *pattern,
for (weak_match = match = 0; refs; refs = refs->next) {
char *name = refs->name;
int namelen = strlen(name);
- int weak_match;
if (namelen < patlen ||
memcmp(name + namelen - patlen, pattern, patlen))
@@ -406,90 +405,96 @@ static struct ref *try_explicit_object_name(const char *name)
return ref;
}
-static int match_explicit_refs(struct ref *src, struct ref *dst,
- struct ref ***dst_tail, struct refspec *rs,
- int rs_nr)
+static struct ref *make_dst(const char *name, struct ref ***dst_tail)
{
- int i, errs;
- for (i = errs = 0; i < rs_nr; i++) {
- struct ref *matched_src, *matched_dst;
+ struct ref *dst;
+ size_t len;
- const char *dst_value = rs[i].dst;
+ len = strlen(name) + 1;
+ dst = xcalloc(1, sizeof(*dst) + len);
+ memcpy(dst->name, name, len);
+ link_dst_tail(dst, dst_tail);
+ return dst;
+}
- if (rs[i].pattern)
- continue;
+static int match_explicit(struct ref *src, struct ref *dst,
+ struct ref ***dst_tail,
+ struct refspec *rs,
+ int errs)
+{
+ struct ref *matched_src, *matched_dst;
- if (dst_value == NULL)
- dst_value = rs[i].src;
+ const char *dst_value = rs->dst;
- matched_src = matched_dst = NULL;
- switch (count_refspec_match(rs[i].src, src, &matched_src)) {
- case 1:
- break;
- case 0:
- /* The source could be in the get_sha1() format
- * not a reference name. :refs/other is a
- * way to delete 'other' ref at the remote end.
- */
- matched_src = try_explicit_object_name(rs[i].src);
- if (matched_src)
- break;
- errs = 1;
- error("src refspec %s does not match any.",
- rs[i].src);
- break;
- default:
- errs = 1;
- error("src refspec %s matches more than one.",
- rs[i].src);
- break;
- }
- switch (count_refspec_match(dst_value, dst, &matched_dst)) {
- case 1:
- break;
- case 0:
- if (!memcmp(dst_value, "refs/", 5)) {
- int len = strlen(dst_value) + 1;
- matched_dst = xcalloc(1, sizeof(*dst) + len);
- memcpy(matched_dst->name, dst_value, len);
- link_dst_tail(matched_dst, dst_tail);
- }
- else if (!strcmp(rs[i].src, dst_value) &&
- matched_src) {
- /* pushing "master:master" when
- * remote does not have master yet.
- */
- int len = strlen(matched_src->name) + 1;
- matched_dst = xcalloc(1, sizeof(*dst) + len);
- memcpy(matched_dst->name, matched_src->name,
- len);
- link_dst_tail(matched_dst, dst_tail);
- }
- else {
- errs = 1;
- error("dst refspec %s does not match any "
- "existing ref on the remote and does "
- "not start with refs/.", dst_value);
- }
- break;
- default:
- errs = 1;
- error("dst refspec %s matches more than one.",
- dst_value);
+ if (rs->pattern)
+ return errs;
+
+ matched_src = matched_dst = NULL;
+ switch (count_refspec_match(rs->src, src, &matched_src)) {
+ case 1:
+ break;
+ case 0:
+ /* The source could be in the get_sha1() format
+ * not a reference name. :refs/other is a
+ * way to delete 'other' ref at the remote end.
+ */
+ matched_src = try_explicit_object_name(rs->src);
+ if (matched_src)
break;
- }
- if (errs)
- continue;
- if (matched_dst->peer_ref) {
- errs = 1;
- error("dst ref %s receives from more than one src.",
- matched_dst->name);
- }
- else {
- matched_dst->peer_ref = matched_src;
- matched_dst->force = rs[i].force;
- }
+ error("src refspec %s does not match any.",
+ rs->src);
+ break;
+ default:
+ matched_src = NULL;
+ error("src refspec %s matches more than one.",
+ rs->src);
+ break;
+ }
+
+ if (!matched_src)
+ errs = 1;
+
+ if (dst_value == NULL)
+ dst_value = matched_src->name;
+
+ switch (count_refspec_match(dst_value, dst, &matched_dst)) {
+ case 1:
+ break;
+ case 0:
+ if (!memcmp(dst_value, "refs/", 5))
+ matched_dst = make_dst(dst_value, dst_tail);
+ else
+ error("dst refspec %s does not match any "
+ "existing ref on the remote and does "
+ "not start with refs/.", dst_value);
+ break;
+ default:
+ matched_dst = NULL;
+ error("dst refspec %s matches more than one.",
+ dst_value);
+ break;
+ }
+ if (errs || matched_dst == NULL)
+ return 1;
+ if (matched_dst->peer_ref) {
+ errs = 1;
+ error("dst ref %s receives from more than one src.",
+ matched_dst->name);
+ }
+ else {
+ matched_dst->peer_ref = matched_src;
+ matched_dst->force = rs->force;
}
+ return errs;
+}
+
+static int match_explicit_refs(struct ref *src, struct ref *dst,
+ struct ref ***dst_tail, struct refspec *rs,
+ int rs_nr)
+{
+ int i, errs;
+ for (i = errs = 0; i < rs_nr; i++)
+ errs |= match_explicit(src, dst, dst_tail, &rs[i], errs);
return -errs;
}
@@ -513,6 +518,11 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
return NULL;
}
+/*
+ * Note. This is used only by "push"; refspec matching rules for
+ * push and fetch are subtly different, so do not try to reuse it
+ * without thinking.
+ */
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
int nr_refspec, char **refspec, int all)
{
@@ -536,10 +546,11 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
}
if (pat) {
- dst_name = xmalloc(strlen(pat->dst) +
+ const char *dst_side = pat->dst ? pat->dst : pat->src;
+ dst_name = xmalloc(strlen(dst_side) +
strlen(src->name) -
strlen(pat->src) + 2);
- strcpy(dst_name, pat->dst);
+ strcpy(dst_name, dst_side);
strcat(dst_name, src->name + strlen(pat->src));
} else
dst_name = xstrdup(src->name);
@@ -554,11 +565,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
goto free_name;
if (!dst_peer) {
/* Create a new one and link it */
- int len = strlen(dst_name) + 1;
- dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
- memcpy(dst_peer->name, dst_name, len);
+ dst_peer = make_dst(dst_name, dst_tail);
hashcpy(dst_peer->new_sha1, src->new_sha1);
- link_dst_tail(dst_peer, dst_tail);
}
dst_peer->peer_ref = src;
free_name:
diff --git a/revision.c b/revision.c
index b12c25e2b0..1f4590b896 100644
--- a/revision.c
+++ b/revision.c
@@ -1180,7 +1180,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
if (opts > 0) {
- revs->diff = 1;
+ if (strcmp(argv[i], "-z"))
+ revs->diff = 1;
i += opts - 1;
continue;
}
diff --git a/sha1_file.c b/sha1_file.c
index 2b860868f5..7628ee97d9 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -413,7 +413,7 @@ static size_t peak_pack_mapped;
static size_t pack_mapped;
struct packed_git *packed_git;
-void pack_report()
+void pack_report(void)
{
fprintf(stderr,
"pack_report: getpagesize() = %10" SZ_FMT "\n"
@@ -959,7 +959,7 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz
return hashcmp(sha1, real_sha1) ? -1 : 0;
}
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+static void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
{
struct stat st;
void *map;
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 6f6d8844e8..f1793d0b9a 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -171,6 +171,15 @@ test_expect_success 'test tracking setup via --track but deeper' \
test "$(git-config branch.my7.remote)" = local &&
test "$(git-config branch.my7.merge)" = refs/heads/o/o'
+test_expect_success 'test deleting branch deletes branch config' \
+ 'git-branch -d my7 &&
+ test "$(git-config branch.my7.remote)" = "" &&
+ test "$(git-config branch.my7.merge)" = ""'
+
+test_expect_success 'test deleting branch without config' \
+ 'git-branch my7 s &&
+ test "$(git-branch -d my7 2>&1)" = "Deleted branch my7."'
+
# Keep this test last, as it changes the current branch
cat >expect <<EOF
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index 2e3c20d6b9..90c085f828 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -64,4 +64,17 @@ test_expect_success \
'validate the output.' \
'compare_diff_patch current expected'
+test_expect_success 'favour same basenames over different ones' '
+ cp path1 another-path &&
+ git add another-path &&
+ git commit -m 1 &&
+ git rm path1 &&
+ mkdir subdir &&
+ git mv another-path subdir/path1 &&
+ git runstatus | grep "renamed: .*path1 -> subdir/path1"'
+
+test_expect_success 'favour same basenames even with minor differences' '
+ git show HEAD:path1 | sed "s/15/16/" > subdir/path1 &&
+ git runstatus | grep "renamed: .*path1 -> subdir/path1"'
+
test_done
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index dba018f667..08d58e1c8c 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -15,12 +15,58 @@ mk_empty () {
)
}
+mk_test () {
+ mk_empty &&
+ (
+ for ref in "$@"
+ do
+ git push testrepo $the_first_commit:refs/$ref || {
+ echo "Oops, push refs/$ref failure"
+ exit 1
+ }
+ done &&
+ cd testrepo &&
+ for ref in "$@"
+ do
+ r=$(git show-ref -s --verify refs/$ref) &&
+ test "z$r" = "z$the_first_commit" || {
+ echo "Oops, refs/$ref is wrong"
+ exit 1
+ }
+ done &&
+ git fsck --full
+ )
+}
+
+check_push_result () {
+ (
+ cd testrepo &&
+ it="$1" &&
+ shift
+ for ref in "$@"
+ do
+ r=$(git show-ref -s --verify refs/$ref) &&
+ test "z$r" = "z$it" || {
+ echo "Oops, refs/$ref is wrong"
+ exit 1
+ }
+ done &&
+ git fsck --full
+ )
+}
+
test_expect_success setup '
: >path1 &&
git add path1 &&
test_tick &&
git commit -a -m repo &&
+ the_first_commit=$(git show-ref -s --verify refs/heads/master) &&
+
+ : >path2 &&
+ git add path2 &&
+ test_tick &&
+ git commit -a -m second &&
the_commit=$(git show-ref -s --verify refs/heads/master)
'
@@ -79,4 +125,122 @@ test_expect_success 'push with wildcard' '
)
'
+test_expect_success 'push with matching heads' '
+
+ mk_test heads/master &&
+ git push testrepo &&
+ check_push_result $the_commit heads/master
+
+'
+
+test_expect_success 'push with no ambiguity (1)' '
+
+ mk_test heads/master &&
+ git push testrepo master:master &&
+ check_push_result $the_commit heads/master
+
+'
+
+test_expect_success 'push with no ambiguity (2)' '
+
+ mk_test remotes/origin/master &&
+ git push testrepo master:master &&
+ check_push_result $the_commit remotes/origin/master
+
+'
+
+test_expect_success 'push with weak ambiguity (1)' '
+
+ mk_test heads/master remotes/origin/master &&
+ git push testrepo master:master &&
+ check_push_result $the_commit heads/master &&
+ check_push_result $the_first_commit remotes/origin/master
+
+'
+
+test_expect_success 'push with weak ambiguity (2)' '
+
+ mk_test heads/master remotes/origin/master remotes/another/master &&
+ git push testrepo master:master &&
+ check_push_result $the_commit heads/master &&
+ check_push_result $the_first_commit remotes/origin/master remotes/another/master
+
+'
+
+test_expect_success 'push with ambiguity (1)' '
+
+ mk_test remotes/origin/master remotes/frotz/master &&
+ if git push testrepo master:master
+ then
+ echo "Oops, should have failed"
+ false
+ else
+ check_push_result $the_first_commit remotes/origin/master remotes/frotz/master
+ fi
+'
+
+test_expect_success 'push with ambiguity (2)' '
+
+ mk_test heads/frotz tags/frotz &&
+ if git push testrepo master:frotz
+ then
+ echo "Oops, should have failed"
+ false
+ else
+ check_push_result $the_first_commit heads/frotz tags/frotz
+ fi
+
+'
+
+test_expect_success 'push with colon-less refspec (1)' '
+
+ mk_test heads/frotz tags/frotz &&
+ git branch -f frotz master &&
+ git push testrepo frotz &&
+ check_push_result $the_commit heads/frotz &&
+ check_push_result $the_first_commit tags/frotz
+
+'
+
+test_expect_success 'push with colon-less refspec (2)' '
+
+ mk_test heads/frotz tags/frotz &&
+ if git show-ref --verify -q refs/heads/frotz
+ then
+ git branch -D frotz
+ fi &&
+ git tag -f frotz &&
+ git push testrepo frotz &&
+ check_push_result $the_commit tags/frotz &&
+ check_push_result $the_first_commit heads/frotz
+
+'
+
+test_expect_success 'push with colon-less refspec (3)' '
+
+ mk_test &&
+ if git show-ref --verify -q refs/tags/frotz
+ then
+ git tag -d frotz
+ fi &&
+ git branch -f frotz master &&
+ git push testrepo frotz &&
+ check_push_result $the_commit heads/frotz &&
+ test "$( cd testrepo && git show-ref | wc -l )" = 1
+'
+
+test_expect_success 'push with colon-less refspec (4)' '
+
+ mk_test &&
+ if git show-ref --verify -q refs/heads/frotz
+ then
+ git branch -D frotz
+ fi &&
+ git tag -f frotz &&
+ git push testrepo frotz &&
+ check_push_result $the_commit tags/frotz &&
+ test "$( cd testrepo && git show-ref | wc -l )" = 1
+
+'
+
test_done
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
new file mode 100755
index 0000000000..f00c262e45
--- /dev/null
+++ b/t/t7003-filter-branch.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+test_description='git-filter-branch'
+. ./test-lib.sh
+
+make_commit () {
+ lower=$(echo $1 | tr A-Z a-z)
+ echo $lower > $lower
+ git add $lower
+ test_tick
+ git commit -m $1
+ git tag $1
+}
+
+test_expect_success 'setup' '
+ make_commit A
+ make_commit B
+ git checkout -b branch B
+ make_commit D
+ make_commit E
+ git checkout master
+ make_commit C
+ git checkout branch
+ git merge C
+ git tag F
+ make_commit G
+ make_commit H
+'
+
+H=$(git-rev-parse H)
+
+test_expect_success 'rewrite identically' '
+ git-filter-branch H2
+'
+
+test_expect_success 'result is really identical' '
+ test $H = $(git-rev-parse H2)
+'
+
+test_expect_success 'rewrite, renaming a specific file' '
+ git-filter-branch --tree-filter "mv d doh || :" H3
+'
+
+test_expect_success 'test that the file was renamed' '
+ test d = $(git show H3:doh)
+'
+
+git tag oldD H3~4
+test_expect_success 'rewrite one branch, keeping a side branch' '
+ git-filter-branch --tree-filter "mv b boh || :" modD D..oldD
+'
+
+test_expect_success 'common ancestor is still common (unchanged)' '
+ test "$(git-merge-base modD D)" = "$(git-rev-parse B)"
+'
+
+test_expect_success 'filter subdirectory only' '
+ mkdir subdir &&
+ touch subdir/new &&
+ git add subdir/new &&
+ test_tick &&
+ git commit -m "subdir" &&
+ echo H > a &&
+ test_tick &&
+ git commit -m "not subdir" a &&
+ echo A > subdir/new &&
+ test_tick &&
+ git commit -m "again subdir" subdir/new &&
+ git rm a &&
+ test_tick &&
+ git commit -m "again not subdir" &&
+ git-filter-branch --subdirectory-filter subdir sub
+'
+
+test_expect_success 'subdirectory filter result looks okay' '
+ test 2 = $(git-rev-list sub | wc -l) &&
+ git show sub:new &&
+ ! git show sub:subdir
+'
+
+test_expect_success 'setup and filter history that requires --full-history' '
+ git checkout master &&
+ mkdir subdir &&
+ echo A > subdir/new &&
+ git add subdir/new &&
+ test_tick &&
+ git commit -m "subdir on master" subdir/new &&
+ git rm a &&
+ test_tick &&
+ git commit -m "again subdir on master" &&
+ git merge branch &&
+ git-filter-branch --subdirectory-filter subdir sub-master
+'
+
+test_expect_success 'subdirectory filter result looks okay' '
+ test 3 = $(git-rev-list -1 --parents sub-master | wc -w) &&
+ git show sub-master^:new &&
+ git show sub-master^2:new &&
+ ! git show sub:subdir
+'
+
+test_expect_success 'use index-filter to move into a subdirectory' '
+ git-filter-branch --index-filter \
+ "git-ls-files -s | sed \"s-\\t-&newsubdir/-\" |
+ GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
+ git-update-index --index-info &&
+ mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+ test -z "$(git diff HEAD directorymoved:newsubdir)"'
+
+test_done
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 3940433b8f..7a9b505b13 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -18,7 +18,7 @@ subcommands of git-submodule.
# -add directory lib to 'superproject', this creates a DIRLINK entry
# -add a couple of regular files to enable testing of submodule filtering
# -mv lib subrepo
-# -add an entry to .gitmodules for path 'lib'
+# -add an entry to .gitmodules for submodule 'example'
#
test_expect_success 'Prepare submodule testing' '
mkdir lib &&
@@ -40,7 +40,19 @@ test_expect_success 'Prepare submodule testing' '
git-add a lib z &&
git-commit -m "super commit 1" &&
mv lib .subrepo &&
- GIT_CONFIG=.gitmodules git-config module.lib.url git://example.com/lib.git
+ GIT_CONFIG=.gitmodules git-config submodule.example.url git://example.com/lib.git
+'
+
+test_expect_success 'status should fail for unmapped paths' '
+ if git-submodule status
+ then
+ echo "[OOPS] submodule status succeeded"
+ false
+ elif ! GIT_CONFIG=.gitmodules git-config submodule.example.path lib
+ then
+ echo "[OOPS] git-config failed to update .gitmodules"
+ false
+ fi
'
test_expect_success 'status should only print one line' '
@@ -54,12 +66,12 @@ test_expect_success 'status should initially be "missing"' '
test_expect_success 'init should register submodule url in .git/config' '
git-submodule init &&
- url=$(git-config submodule.lib.url) &&
+ url=$(git-config submodule.example.url) &&
if test "$url" != "git://example.com/lib.git"
then
echo "[OOPS] init succeeded but submodule url is wrong"
false
- elif ! git-config submodule.lib.url ./.subrepo
+ elif ! git-config submodule.example.url ./.subrepo
then
echo "[OOPS] init succeeded but update of url failed"
false
@@ -72,7 +84,7 @@ test_expect_success 'update should fail when path is used by a file' '
then
echo "[OOPS] update should have failed"
false
- elif test -f lib && test "$(cat lib)" != "hello"
+ elif test "$(cat lib)" != "hello"
then
echo "[OOPS] update failed but lib file was molested"
false
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
new file mode 100755
index 0000000000..9ef0db9044
--- /dev/null
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+#
+
+# Don't run this test by default unless the user really wants it
+# I don't like the idea of taking a port and possibly leaving a
+# daemon running on a users system if the test fails.
+# Not all git users will need to interact with SVN.
+test -z "$SVNSERVE_PORT" && exit 0
+
+test_description='git-svn dcommit new files over svn:// test'
+
+. ./lib-git-svn.sh
+
+start_svnserve () {
+ svnserve --listen-port $SVNSERVE_PORT \
+ --root $rawsvnrepo \
+ --listen-once \
+ --listen-host 127.0.0.1 &
+}
+
+test_expect_success 'start tracking an empty repo' "
+ svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
+ echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+ start_svnserve &&
+ git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
+ git svn fetch
+ "
+
+test_expect_success 'create files in new directory with dcommit' "
+ mkdir git-new-dir &&
+ echo hello > git-new-dir/world &&
+ git update-index --add git-new-dir/world &&
+ git commit -m hello &&
+ start_svnserve &&
+ git svn dcommit
+ "
+
+test_done
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 41dcf646d1..0331770686 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -143,6 +143,51 @@ test_expect_success 'req_Root failure (conflicting roots)' \
'cat request-conflict | git-cvsserver pserver >log 2>&1 &&
tail log | grep -q "^error 1 Conflicting roots specified$"'
+test_expect_success 'req_Root (strict paths)' \
+ 'cat request-anonymous | git-cvsserver --strict-paths pserver $SERVERDIR >log 2>&1 &&
+ tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (strict-paths)' \
+ 'cat request-anonymous | git-cvsserver --strict-paths pserver $WORKDIR >log 2>&1'
+
+test_expect_success 'req_Root (w/o strict-paths)' \
+ 'cat request-anonymous | git-cvsserver pserver $WORKDIR/ >log 2>&1 &&
+ tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (w/o strict-paths)' \
+ 'cat request-anonymous | git-cvsserver pserver $WORKDIR/gitcvs >log 2>&1'
+
+cat >request-base <<EOF
+BEGIN AUTH REQUEST
+/gitcvs.git
+anonymous
+
+END AUTH REQUEST
+Root /gitcvs.git
+EOF
+
+test_expect_success 'req_Root (base-path)' \
+ 'cat request-base | git-cvsserver --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+ tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (base-path)' \
+ 'cat request-anonymous | git-cvsserver --strict-paths --base-path $WORKDIR pserver $SERVERDIR >log 2>&1'
+
+GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1
+
+test_expect_success 'req_Root (export-all)' \
+ 'cat request-anonymous | git-cvsserver --export-all pserver $WORKDIR >log 2>&1 &&
+ tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (export-all w/o whitelist)' \
+ 'cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 ||
+ false'
+
+test_expect_success 'req_Root (everything together)' \
+ 'cat request-base | git-cvsserver --export-all --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+ tail -n1 log | grep -q "^I LOVE YOU$"'
+
+GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true || exit 1
#--------------
# CONFIG TESTS
diff --git a/tree-walk.h b/tree-walk.h
index ee747aba0b..db0fbdc701 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -22,7 +22,7 @@ static inline const unsigned char *tree_entry_extract(struct tree_desc *desc, co
static inline int tree_entry_len(const char *name, const unsigned char *sha1)
{
- return (char *)sha1 - (char *)name - 1;
+ return (const char *)sha1 - name - 1;
}
void update_tree_entry(struct tree_desc *);