Merge branch 'jc/oneline'
authorJunio C Hamano <gitster@pobox.com>
Sat, 23 Jun 2007 06:33:08 +0000 (23:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 23 Jun 2007 06:33:08 +0000 (23:33 -0700)
* jc/oneline:
pp_header(): work around possible memory corruption

60 files changed:
.gitignore
Documentation/Makefile
Documentation/RelNotes-1.5.2.2.txt [new file with mode: 0644]
Documentation/asciidoc.conf
Documentation/cmd-list.perl
Documentation/git-citool.txt [new file with mode: 0644]
Documentation/git-cvsexportcommit.txt
Documentation/git-cvsserver.txt
Documentation/git-gui.txt [new file with mode: 0644]
Documentation/git-log.txt
Documentation/git-push.txt
Documentation/git-read-tree.txt
Documentation/git-reflog.txt
Documentation/git-rev-list.txt
Documentation/git-rev-parse.txt
Documentation/git.txt
Documentation/gitmodules.txt [new file with mode: 0644]
Documentation/pretty-options.txt
Documentation/user-manual.txt
INSTALL
Makefile
builtin-add.c
builtin-branch.c
builtin-read-tree.c
builtin-revert.c
cache-tree.c
cache.h
commit.c
compat/hstrerror.c [new file with mode: 0644]
config.c
connect.c
contrib/gitview/gitview
csum-file.c
csum-file.h
diffcore-rename.c
dir.c
dir.h
generate-cmdlist.sh
git-clone.sh
git-compat-util.h
git-cvsimport.perl
git-cvsserver.perl
git-filter-branch.sh [new file with mode: 0644]
git-submodule.sh
git-svn.perl
git-svnimport.perl
git.spec.in
merge-recursive.c
refs.c
remote.c
revision.c
sha1_file.c
t/t3200-branch.sh
t/t4001-diff-rename.sh
t/t5516-fetch-push.sh
t/t7003-filter-branch.sh [new file with mode: 0755]
t/t7400-submodule-basic.sh
t/t9113-git-svn-dcommit-new-file.sh [new file with mode: 0755]
t/t9400-git-cvsserver-server.sh
tree-walk.h
index bd49cd4627a786d6dbcd7f0d17f0fddc2add7014..e8b060cbe43d13b82ad8686f7676a26ef559a609 100644 (file)
@@ -157,7 +157,7 @@ common-cmds.h
 *.tar.gz
 *.dsc
 *.deb
-git-core.spec
+git.spec
 *.exe
 *.[aos]
 *.py[co]
index 9cef4806d1a51bac670ebe192a4482fde95c9013..f3a6c733b662f4e9d06bc69cadc2201ea34f41ce 100644 (file)
@@ -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 (file)
index 0000000..f6393f8
--- /dev/null
@@ -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.
index 99302c5bebb6017e34371bf12dafeab97447bda5..6b6220dfdbd6cacb8a05be4995279bbd0487fada 100644 (file)
@@ -8,7 +8,8 @@
 # the command.
 
 [attributes]
-caret=^
+plus=&#43;
+caret=&#94;
 startsb=&#91;
 endsb=&#93;
 tilde=&#126;
index a181f753e0fefdeb036a826b8c0d0a5b54d0ae25..fcea1d74d597c84eeb535935fd5d881d7788f931 100755 (executable)
@@ -86,6 +86,7 @@ sub format_one {
 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 @@ sub format_one {
 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 (file)
index 0000000..5217ab2
--- /dev/null
@@ -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
index 827711c3c9b8ad8c7ecb074c5ec1a9b887992526..6c423e3a2f1c69e523eeb9cc092126adc2691803 100644 (file)
@@ -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
index e5005f02f997437da3251f6c52c6efbdf06557b4..60d0bcf0f31e6b4da6e56d7726ed942744704cbb 100644 (file)
@@ -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 (file)
index 0000000..bd613b2
--- /dev/null
@@ -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
index 6157edb404db3ff0db0bb21e826e140037acb6af..7adcdefacfd681729317c59ebacfd4a27db1effd 100644 (file)
@@ -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.
index 366c5dbdce69854e7cc1e085cdf53e0e88f7bcb2..665f6dc709207725daa9e7dd81d150a9aac0f7cb 100644 (file)
@@ -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
index 84184d6294df83c3229a8035d934b23c598578d1..74c5478ba18763de1703f0c8c08c20f1aac02ac0 100644 (file)
@@ -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
index f717e1e30c1b2a99d1d32b86d7d3eedfe6d88d40..89bc9c51ea13630f6556b12637ce8b1cc483d2fd 100644 (file)
@@ -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`,
index 0dba73f27607560d3e868306af78bad83dc3bfff..32cb13faec8abc08d72912dbaf6bfc668ac4abd9 100644 (file)
@@ -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.
index e1cb4ef8568d05ad7bacfb391227bb88560fd448..87771b832bdc71a9b18535f0ab21e68478891e46 100644 (file)
@@ -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
index ba077c39c6a34584da306cce51da34537b0d1e0f..20b5b7bb48f75cea066857c6967a08203957d927 100644 (file)
@@ -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 (file)
index 0000000..035294e
--- /dev/null
@@ -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
index 6338def5a795a8171286626752a96f8ac88842c8..746bc5b7f9a3f96ea321586e095a4fc8ccb6e73f 100644 (file)
@@ -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
index 0bfa21b3d2eddf2783890d880e3d5abc951b62fa..ff7c71d4fb73932dd0925cf9dd19c74544f68055 100644 (file)
@@ -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 95269cc513fab071d96a044b32aec7abb8b3fe7c..63ba1480a697ddeb98c5665106352fd2bb0ceb5a 100644 (file)
--- 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
index 0f6540c6d84b95616965330e1d198e976fa1c9f4..0d904a93b9e9c6ef58edd96f189fa8a4a9c5f9b8 100644 (file)
--- 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 $@+ $@
 
index 159117106a3db52b430cb1bf82d094e54693f690..734547994f3a35e04fc7fdea10396c0c87bc6f0d 100644 (file)
@@ -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++)
index d7c321af4f14eeafae1e34072a304835836dbe66..77b85dde1f661069d2e07314a1d6bf80f0b27efc 100644 (file)
@@ -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)
index 316fb0f8dae022b35a89b71c94a22331a77a500a..41f81102380bf0ec86e223d393d0ab61b3f854ed 100644 (file)
@@ -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;
 
index 8f02ed7bd1b7d4aecb8611ac1c0ebf3978b34ca5..499bbe7343a635f1c7fc024ed6a1436042dcb8ac 100644 (file)
@@ -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)
index 350a79b768e7c032e1b4815f7201c9ce5f88bc8d..077f03436941e9c0bf31d3bb2002c1e36b8817b9 100644 (file)
@@ -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 aba7a5ec0438466d593c7cffb081a24f0e71722a..ed83d92c5a2735b2b7f8a7fc06276acbf0df8b18 100644 (file)
--- 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);
index dbb28b593f3b3b723a619882f1a0b11f124c1807..03436b1b077f3f83cebceb697f97c3ba5b26265c 100644 (file)
--- 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 (file)
index 0000000..069c555
--- /dev/null
@@ -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;
+}
index 58d3ed5d371b6d7548f6677e65135bd3f01851d0..e323153ae4f91c661cf35fdeea3041a2a621b34e 100644 (file)
--- 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");
 
index 7fab9c0fd961af54a5758e8452391ff7a5e2e9bd..a5afd2a5361d840347eb64a3a73db9d8dcbd1057 100644 (file)
--- 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;
index 098cb01353d4adbfd32bdd4f70183b4b474f2158..593176662050f0c84897759ab7d80f31aabfae53 100755 (executable)
@@ -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)
index 510934262437cf48c2b732bc2a392dd8167bee45..9ab997120d04c5be0aa9d3ff3ba090ba12b7bec8 100644 (file)
@@ -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);
index 4e8b83e0936f255e0fff57127da56288a988a5fe..c3c792f1b56026b6a4d9d10b6ba63947c7f383cf 100644 (file)
@@ -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 *);
 
index 93c40d9e04f35897b1ac2ad578db0c0972aacbc1..79c984c9cf5489d22f359b7a2ad3464ffc271c35 100644 (file)
@@ -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 5ba6030e9a89102a8fcf0e7311d80082841de67b..8d8faf5d788b402d5fd4f5d724954fd2ee178fdb 100644 (file)
--- 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 172147fd3d4711c9ea95cd76048b7188bf9a1e2c..ec0e8ababc7fa00d9bf039e0ad97d8639b70450f 100644 (file)
--- 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;
index 975777f05ed69ef78f1fd91ac512f5b92a384141..17df47b95067449f03039b8ecd7715701302fa68 100755 (executable)
@@ -7,7 +7,7 @@ struct cmdname_help
     char help[80];
 };
 
-struct cmdname_help common_cmds[] = {"
+static struct cmdname_help common_cmds[] = {"
 
 sort <<\EOF |
 add
index 3a410624d374e9d02b305a25469176e4d4e725e6..bd44ce1c84175e9cce97489a363fe340b74b7f23 100755 (executable)
@@ -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
index 6bd8987b2774774fbbd3747a2b571b66ad78727b..b2ab3f82567d54607a07f4061153adae86854fa9 100644 (file)
@@ -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)
index 433b7fd3246cf1ab29f3d74befbf6db5adfc8d2c..69ccb88dde188a5a73eadf3bb8f778afce833b2f 100755 (executable)
@@ -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 );
index d41b29f30b6f07429b227fc4e07fffdcb292bbee..5cbf27eebc0f090c0d7e45e82064344b30d326fc 100755 (executable)
@@ -22,6 +22,9 @@
 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;
 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 (file)
index 0000000..8fa5ce6
--- /dev/null
@@ -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
index 8bdd99a2f37a8c76fd4b08e6736d7a67da47be1e..89a388535026258d65ecba3c0dd6de68e2b06cb4 100755 (executable)
@@ -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;
index e35006142af766080b3bafe0cdcd39bf2ccf3f04..50128d72850714b80a765ad9c5ffa9588b8da505 100755 (executable)
 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 @@ package Git::SVN::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;
index f4597626b955252fa7cfc092d8bb041cc3887345..b73d6494d80fe5ee19e1d95971e2e4e64e980dea 100755 (executable)
@@ -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;
        }
index b9dc1d59ebc14e94d2b81bdfaf68c10d97820e83..287057e816a5b0674a38a1676700110cb5a642f7 100644 (file)
@@ -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)
index 4a82b741ae020376ac67b34d5fce86e8a87a3b5d..c8539ec0bafce5e238d97d6397a9d08c2c92a09c 100644 (file)
@@ -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 ef4484d2937727b131eade1c6b62180cd9722976..67ac97c713d071790f2d627f4c0435af23430fb8 100644 (file)
--- 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;
index ed62a62fa0d5eab7d154233f94e4dad1fc9fbe2f..500ca4d968753485ac38d44e238e93ab86372c1c 100644 (file)
--- 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:
index b12c25e2b0c8e2c1d3bb097739f3c132a296c964..1f4590b89649a9d1397af2f35af142cc6ab36847 100644 (file)
@@ -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;
                        }
index 2b860868f55a83ed599f39d7820a9fb227946912..7628ee97d9137c3cc2eae2e626fc708a88dc444a 100644 (file)
@@ -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;
index 6f6d8844e8628d006b1d4c11eb02a5ee14a8fd35..f1793d0b9ab6cf6e5c24abaf3aaa0892ea4f9631 100755 (executable)
@@ -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
index 2e3c20d6b9468bf413e97d422e7dbe13ac4238cd..90c085f82814fc973ec7f0732b419cd631e9dc43 100755 (executable)
@@ -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
index dba018f667048d7bd5233136dfe70ee0f1305a9a..08d58e1c8c8d61d50c97b48d795ac1a574d56035 100755 (executable)
@@ -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 (executable)
index 0000000..f00c262
--- /dev/null
@@ -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
index 3940433b8f59196eff06dd24be24c9f54e7254ac..7a9b505b13f60ebbca188439b24f7a20b30b66cf 100755 (executable)
@@ -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 (executable)
index 0000000..9ef0db9
--- /dev/null
@@ -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
index 41dcf646d132e35ca37ab6cc75fc2a7e70cc765e..033177068670199aa8b5efc2bd970f8426b2f13e 100755 (executable)
@@ -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
index ee747aba0bec914bd8f5c7a5285c8395ba5f489b..db0fbdc701f1ef63cdc1a8b7d5c5e72322f91426 100644 (file)
@@ -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 *);