GIT 0.99.9j aka 1.0rc3 v0.99.9j v1.0rc3
authorJunio C Hamano <junkio@cox.net>
Thu, 17 Nov 2005 05:32:44 +0000 (21:32 -0800)
committerJunio C Hamano <junkio@cox.net>
Thu, 17 Nov 2005 05:32:44 +0000 (21:32 -0800)
Signed-off-by: Junio C Hamano <junkio@cox.net>
47 files changed:
Documentation/diff-format.txt
Documentation/diff-options.txt
Documentation/git-apply.txt
Documentation/git-commit-tree.txt
Documentation/git-daemon.txt
Documentation/git-diff-index.txt
Documentation/git-fsck-objects.txt
Documentation/git-log.txt
Documentation/git-read-tree.txt
Documentation/git-symbolic-ref.txt
Documentation/git.txt
Makefile
README
apply.c
cache.h
commit.c
config.c
daemon.c
debian/changelog
diff.c
diff.h
diffcore-rename.c
environment.c
fsck-objects.c
git-am.sh
git-archimport.perl
git-core.spec.in [deleted file]
git-cvsexportcommit.perl
git-cvsimport.perl
git-grep.sh
git-merge-recursive.py
git-svnimport.perl
git.c [new file with mode: 0644]
git.sh [deleted file]
git.spec.in [new file with mode: 0644]
http-fetch.c
object.c
object.h
pack-redundant.c
refs.c
server-info.c
sha1_file.c
symbolic-ref.c
t/t4103-apply-binary.sh [new file with mode: 0644]
t/test-lib.sh
tag.c
tree.c

index b426a14..97756ec 100644 (file)
@@ -81,7 +81,7 @@ The "diff" formatting options can be customized via the
 environment variable 'GIT_DIFF_OPTS'.  For example, if you
 prefer context diff:
 
 environment variable 'GIT_DIFF_OPTS'.  For example, if you
 prefer context diff:
 
-      GIT_DIFF_OPTS=-c git-diff-index -p $(cat .git/HEAD)
+      GIT_DIFF_OPTS=-c git-diff-index -p HEAD
 
 
 2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the
 
 
 2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the
index 8eef86e..6b496ed 100644 (file)
 --name-status::
        Show only names and status of changed files.
 
 --name-status::
        Show only names and status of changed files.
 
+--full-index::
+       Instead of the first handful characters, show full
+       object name of pre- and post-image blob on the "index"
+       line when generating a patch format output.     
+
 -B::
        Break complete rewrite changes into pairs of delete and create.
 
 -B::
        Break complete rewrite changes into pairs of delete and create.
 
index 6702a18..626e281 100644 (file)
@@ -8,7 +8,7 @@ git-apply - Apply patch on a git index file and a work tree
 
 SYNOPSIS
 --------
 
 SYNOPSIS
 --------
-'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] [<patch>...]
+'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [<patch>...]
 
 DESCRIPTION
 -----------
 
 DESCRIPTION
 -----------
@@ -79,6 +79,17 @@ OPTIONS
        the result with this option, which would apply the
        deletion part but not addition part.
 
        the result with this option, which would apply the
        deletion part but not addition part.
 
+--allow-binary-replacement::
+       When applying a patch, which is a git-enhanced patch
+       that was prepared to record the pre- and post-image object
+       name in full, and the path being patched exactly matches
+       the object the patch applies to (i.e. "index" line's
+       pre-image object name is what is in the working tree),
+       and the post-image object is available in the object
+       database, use the post-image object as the patch
+       result.  This allows binary files to be patched in a
+       very limited way.
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
index 5cf6bd3..a794192 100644 (file)
@@ -26,8 +26,9 @@ to get there.
 
 Normally a commit would identify a new "HEAD" state, and while git
 doesn't care where you save the note about that state, in practice we
 
 Normally a commit would identify a new "HEAD" state, and while git
 doesn't care where you save the note about that state, in practice we
-tend to just write the result to the file `.git/HEAD`, so that we can
-always see what the last committed state was.
+tend to just write the result to the file that is pointed at by
+`.git/HEAD`, so that we can always see what the last committed
+state was.
 
 OPTIONS
 -------
 
 OPTIONS
 -------
index 67c5f22..3783858 100644 (file)
@@ -35,7 +35,7 @@ OPTIONS
        do not have the 'git-daemon-export-ok' file.
 
 --inetd::
        do not have the 'git-daemon-export-ok' file.
 
 --inetd::
-       Have the server run as an inetd service.
+       Have the server run as an inetd service. Implies --syslog.
 
 --port::
        Listen on an alternative port.
 
 --port::
        Listen on an alternative port.
index d8fc78f..dba6d30 100644 (file)
@@ -57,14 +57,14 @@ some files in the index and are ready to commit. You want to see eactly
 *what* you are going to commit is without having to write a new tree
 object and compare it that way, and to do that, you just do
 
 *what* you are going to commit is without having to write a new tree
 object and compare it that way, and to do that, you just do
 
-       git-diff-index --cached $(cat .git/HEAD)
+       git-diff-index --cached HEAD
 
 Example: let's say I had renamed `commit.c` to `git-commit.c`, and I had
 done an "git-update-index" to make that effective in the index file.
 "git-diff-files" wouldn't show anything at all, since the index file
 matches my working directory. But doing a "git-diff-index" does:
 
 
 Example: let's say I had renamed `commit.c` to `git-commit.c`, and I had
 done an "git-update-index" to make that effective in the index file.
 "git-diff-files" wouldn't show anything at all, since the index file
 matches my working directory. But doing a "git-diff-index" does:
 
-  torvalds@ppc970:~/git> git-diff-index --cached $(cat .git/HEAD)
+  torvalds@ppc970:~/git> git-diff-index --cached HEAD
   -100644 blob    4161aecc6700a2eb579e842af0b7f22b98443f74        commit.c
   +100644 blob    4161aecc6700a2eb579e842af0b7f22b98443f74        git-commit.c
 
   -100644 blob    4161aecc6700a2eb579e842af0b7f22b98443f74        commit.c
   +100644 blob    4161aecc6700a2eb579e842af0b7f22b98443f74        git-commit.c
 
@@ -98,7 +98,7 @@ show that. So let's say that you have edited `kernel/sched.c`, but
 have not actually done a "git-update-index" on it yet - there is no
 "object" associated with the new state, and you get:
 
 have not actually done a "git-update-index" on it yet - there is no
 "object" associated with the new state, and you get:
 
-  torvalds@ppc970:~/v2.6/linux> git-diff-index $(cat .git/HEAD )
+  torvalds@ppc970:~/v2.6/linux> git-diff-index HEAD
   *100644->100664 blob    7476bb......->000000......      kernel/sched.c
 
 ie it shows that the tree has changed, and that `kernel/sched.c` has is
   *100644->100664 blob    7476bb......->000000......      kernel/sched.c
 
 ie it shows that the tree has changed, and that `kernel/sched.c` has is
index 37e8055..bab1f60 100644 (file)
@@ -68,7 +68,7 @@ that aren't readable from any of the specified head nodes.
 
 So for example
 
 
 So for example
 
-       git-fsck-objects --unreachable $(cat .git/HEAD .git/refs/heads/*)
+       git-fsck-objects --unreachable HEAD $(cat .git/refs/heads/*)
 
 will do quite a _lot_ of verification on the tree. There are a few
 extra validity tests to be added (make sure that tree objects are
 
 will do quite a _lot_ of verification on the tree. There are a few
 extra validity tests to be added (make sure that tree objects are
index 9cac088..e995d1b 100644 (file)
@@ -20,7 +20,7 @@ This manual page describes only the most frequently used options.
 
 OPTIONS
 -------
 
 OPTIONS
 -------
---pretty=<format>:
+--pretty=<format>::
        Controls the way the commit log is formatted.
 
 --max-count=<n>::
        Controls the way the commit log is formatted.
 
 --max-count=<n>::
index 7be0cbd..8b91847 100644 (file)
@@ -237,7 +237,7 @@ This is done to prevent you from losing your work-in-progress
 changes.  To illustrate, suppose you start from what has been
 commited last to your repository:
 
 changes.  To illustrate, suppose you start from what has been
 commited last to your repository:
 
-    $ JC=`cat .git/HEAD`
+    $ JC=`git-rev-parse --verify "HEAD^0"`
     $ git-checkout-index -f -u -a $JC
 
 You do random edits, without running git-update-index.  And then
     $ git-checkout-index -f -u -a $JC
 
 You do random edits, without running git-update-index.  And then
index a851ae2..68ac6a6 100644 (file)
@@ -24,8 +24,8 @@ Traditionally, `.git/HEAD` is a symlink pointing at
 we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we want
 to find out which branch we are on, we did `readlink .git/HEAD`.
 This was fine, and internally that is what still happens by
 we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we want
 to find out which branch we are on, we did `readlink .git/HEAD`.
 This was fine, and internally that is what still happens by
-default, but on platforms that does not have working symlinks,
-or that does not have the `readlink(1)` command, this was a bit
+default, but on platforms that do not have working symlinks,
+or that do not have the `readlink(1)` command, this was a bit
 cumbersome.  On some platforms, `ln -sf` does not even work as
 advertised (horrors).
 
 cumbersome.  On some platforms, `ln -sf` does not even work as
 advertised (horrors).
 
index 7045f3f..338e5ac 100644 (file)
@@ -8,13 +8,33 @@ git - the stupid content tracker
 
 SYNOPSIS
 --------
 
 SYNOPSIS
 --------
-'git-<command>' <args>
+'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ARGS]
 
 DESCRIPTION
 -----------
 
 DESCRIPTION
 -----------
-
-This is reference information for the core git commands.
-
+'git' is both a program and a directory content tracker system.
+The program 'git' is just a wrapper to reach the core git programs
+(or a potty if you like, as it's not exactly porcelain but still
+brings your stuff to the plumbing).
+
+OPTIONS
+-------
+--version::
+       prints the git suite version that the 'git' program came from.
+
+--help::
+       prints the synopsis and a list of available commands.
+       If a git command is named this option will bring up the
+       man-page for that command.
+
+--exec-path::
+       path to wherever your core git programs are installed.
+       This can also be controlled by setting the GIT_EXEC_PATH
+       environment variable. If no path is given 'git' will print
+       the current setting and then exit.
+
+CORE GIT COMMANDS
+-----------------
 Before reading this cover to cover, you may want to take a look
 at the link:tutorial.html[tutorial] document.
 
 Before reading this cover to cover, you may want to take a look
 at the link:tutorial.html[tutorial] document.
 
@@ -67,7 +87,7 @@ gitlink:git-commit-tree[1]::
 gitlink:git-hash-object[1]::
        Computes the object ID from a file.
 
 gitlink:git-hash-object[1]::
        Computes the object ID from a file.
 
-gitlink:git-index-pack.html[1]::
+gitlink:git-index-pack[1]::
        Build pack index file for an existing packed archive.
 
 gitlink:git-init-db[1]::
        Build pack index file for an existing packed archive.
 
 gitlink:git-init-db[1]::
@@ -533,9 +553,12 @@ Discussion[[Discussion]]
 ------------------------
 include::../README[]
 
 ------------------------
 include::../README[]
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and the git-list <git@vger.kernel.org>.
+Authors
+-------
+       git's founding father is Linus Torvalds <torvalds@osdl.org>.
+       The current git nurse is Junio C. Hamano <junkio@cox.net>.
+       The git potty was written by Andres Ericsson <ae@op5.se>.
+       General upbringing is handled by the git-list <git@vger.kernel.org>.
 
 Documentation
 --------------
 
 Documentation
 --------------
index f4a3a33..e5cf5ef 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,7 @@
 # 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 USE_STDEV below if you want git to care about the underlying device
 # change being considered an inode change from the update-cache perspective.
 
-GIT_VERSION = 0.99.9i
+GIT_VERSION = 0.99.9j
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
@@ -88,7 +88,7 @@ SCRIPT_SH = \
        git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
        git-repack.sh git-request-pull.sh git-reset.sh \
        git-resolve.sh git-revert.sh git-sh-setup.sh git-status.sh \
        git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
        git-repack.sh git-request-pull.sh git-reset.sh \
        git-resolve.sh git-revert.sh git-sh-setup.sh git-status.sh \
-       git-tag.sh git-verify-tag.sh git-whatchanged.sh git.sh \
+       git-tag.sh git-verify-tag.sh git-whatchanged.sh \
        git-applymbox.sh git-applypatch.sh git-am.sh \
        git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
        git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
        git-applymbox.sh git-applypatch.sh git-am.sh \
        git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
        git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
@@ -105,7 +105,7 @@ SCRIPT_PYTHON = \
 # The ones that do not have to link with lcrypto nor lz.
 SIMPLE_PROGRAMS = \
        git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
 # The ones that do not have to link with lcrypto nor lz.
 SIMPLE_PROGRAMS = \
        git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
-       git-stripspace$X git-var$X git-daemon$X
+       git-stripspace$X git-daemon$X
 
 # ... and all the rest
 PROGRAMS = \
 
 # ... and all the rest
 PROGRAMS = \
@@ -125,7 +125,7 @@ PROGRAMS = \
        git-unpack-objects$X git-update-index$X git-update-server-info$X \
        git-upload-pack$X git-verify-pack$X git-write-tree$X \
        git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
        git-unpack-objects$X git-update-index$X git-update-server-info$X \
        git-upload-pack$X git-verify-pack$X git-write-tree$X \
        git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
-       git-name-rev$X git-pack-redundant$X $(SIMPLE_PROGRAMS)
+       git-name-rev$X git-pack-redundant$X git-var$X $(SIMPLE_PROGRAMS)
 
 # Backward compatibility -- to be removed after 1.0
 PROGRAMS += git-ssh-pull$X git-ssh-push$X
 
 # Backward compatibility -- to be removed after 1.0
 PROGRAMS += git-ssh-pull$X git-ssh-push$X
@@ -334,19 +334,15 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
 export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
 ### Build rules
 
 export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
 ### Build rules
 
-all: $(PROGRAMS) $(SCRIPTS)
+all: $(PROGRAMS) $(SCRIPTS) git
 
 all:
        $(MAKE) -C templates
 
 
 all:
        $(MAKE) -C templates
 
-git: git.sh Makefile
-       rm -f $@+ $@
-       sed -e '1s|#!.*/sh|#!$(call shq,$(SHELL_PATH))|' \
-           -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-           -e 's/@@X@@/$(X)/g' \
-           $(GIT_LIST_TWEAK) <$@.sh >$@+
-       chmod +x $@+
-       mv $@+ $@
+# Only use $(CFLAGS). We don't need anything else.
+git: git.c Makefile
+       $(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
+               $(CFLAGS) $@.c -o $@
 
 $(filter-out git,$(patsubst %.sh,%,$(SCRIPT_SH))) : % : %.sh
        rm -f $@
 
 $(filter-out git,$(patsubst %.sh,%,$(SCRIPT_SH))) : % : %.sh
        rm -f $@
@@ -431,9 +427,9 @@ check:
 
 ### Installation rules
 
 
 ### Installation rules
 
-install: $(PROGRAMS) $(SCRIPTS)
+install: $(PROGRAMS) $(SCRIPTS) git
        $(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
        $(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
-       $(INSTALL) $(PROGRAMS) $(SCRIPTS) $(call shellquote,$(DESTDIR)$(bindir))
+       $(INSTALL) git $(PROGRAMS) $(SCRIPTS) $(call shellquote,$(DESTDIR)$(bindir))
        $(MAKE) -C templates install
        $(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
        $(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
        $(MAKE) -C templates install
        $(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
        $(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
@@ -446,20 +442,20 @@ install-doc:
 
 ### Maintainer's dist rules
 
 
 ### Maintainer's dist rules
 
-git-core.spec: git-core.spec.in Makefile
+git.spec: git.spec.in Makefile
        sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@
 
        sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@
 
-GIT_TARNAME=git-core-$(GIT_VERSION)
-dist: git-core.spec git-tar-tree
+GIT_TARNAME=git-$(GIT_VERSION)
+dist: git.spec git-tar-tree
        ./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar
        @mkdir -p $(GIT_TARNAME)
        ./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar
        @mkdir -p $(GIT_TARNAME)
-       @cp git-core.spec $(GIT_TARNAME)
-       $(TAR) rf $(GIT_TARNAME).tar $(GIT_TARNAME)/git-core.spec
+       @cp git.spec $(GIT_TARNAME)
+       $(TAR) rf $(GIT_TARNAME).tar $(GIT_TARNAME)/git.spec
        @rm -rf $(GIT_TARNAME)
        gzip -f -9 $(GIT_TARNAME).tar
 
 rpm: dist
        @rm -rf $(GIT_TARNAME)
        gzip -f -9 $(GIT_TARNAME).tar
 
 rpm: dist
-       $(RPMBUILD) -ta git-core-$(GIT_VERSION).tar.gz
+       $(RPMBUILD) -ta $(GIT_TARNAME).tar.gz
 
 deb: dist
        rm -rf $(GIT_TARNAME)
 
 deb: dist
        rm -rf $(GIT_TARNAME)
@@ -472,7 +468,7 @@ deb: dist
 clean:
        rm -f *.o mozilla-sha1/*.o ppc/*.o compat/*.o $(PROGRAMS) $(LIB_FILE)
        rm -f $(filter-out gitk,$(SCRIPTS))
 clean:
        rm -f *.o mozilla-sha1/*.o ppc/*.o compat/*.o $(PROGRAMS) $(LIB_FILE)
        rm -f $(filter-out gitk,$(SCRIPTS))
-       rm -f git-core.spec *.pyc *.pyo
+       rm -f *.spec *.pyc *.pyo
        rm -rf $(GIT_TARNAME)
        rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        rm -f git-core_$(GIT_VERSION)-*.dsc
        rm -rf $(GIT_TARNAME)
        rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        rm -f git-core_$(GIT_VERSION)-*.dsc
diff --git a/README b/README
index 4a2616b..36fef6e 100644 (file)
--- a/README
+++ b/README
@@ -396,8 +396,8 @@ git-commit-tree will return the name of the object that represents
 that commit, and you should save it away for later use. Normally,
 you'd commit a new `HEAD` state, and while git doesn't care where you
 save the note about that state, in practice we tend to just write the
 that commit, and you should save it away for later use. Normally,
 you'd commit a new `HEAD` state, and while git doesn't care where you
 save the note about that state, in practice we tend to just write the
-result to the file `.git/HEAD`, so that we can always see what the
-last committed state was.
+result to the file pointed at by `.git/HEAD`, so that we can always see
+what the last committed state was.
 
 Here is an ASCII art by Jon Loeliger that illustrates how
 various pieces fit together.
 
 Here is an ASCII art by Jon Loeliger that illustrates how
 various pieces fit together.
@@ -464,7 +464,7 @@ tend to be small and fairly self-explanatory. In particular, if you
 follow the convention of having the top commit name in `.git/HEAD`,
 you can do
 
 follow the convention of having the top commit name in `.git/HEAD`,
 you can do
 
-               git-cat-file commit $(cat .git/HEAD)
+               git-cat-file commit HEAD
 
 to see what the top commit was.
 
 
 to see what the top commit was.
 
diff --git a/apply.c b/apply.c
index 590adc6..129edb1 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -16,6 +16,7 @@
 //  --numstat does numeric diffstat, and doesn't actually apply
 //  --index-info shows the old and new index info for paths if available.
 //
 //  --numstat does numeric diffstat, and doesn't actually apply
 //  --index-info shows the old and new index info for paths if available.
 //
+static int allow_binary_replacement = 0;
 static int check_index = 0;
 static int write_index = 0;
 static int diffstat = 0;
 static int check_index = 0;
 static int write_index = 0;
 static int diffstat = 0;
@@ -27,7 +28,7 @@ static int no_add = 0;
 static int show_index_info = 0;
 static int line_termination = '\n';
 static const char apply_usage[] =
 static int show_index_info = 0;
 static int line_termination = '\n';
 static const char apply_usage[] =
-"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] <patch>...";
+"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] <patch>...";
 
 /*
  * For "diff-stat" like behaviour, we keep track of the biggest change
 
 /*
  * For "diff-stat" like behaviour, we keep track of the biggest change
@@ -891,7 +892,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
 
        patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
 
 
        patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
 
-       if (!patchsize && !metadata_changes(patch)) {
+       if (!patchsize) {
                static const char binhdr[] = "Binary files ";
 
                if (sizeof(binhdr) - 1 < size - offset - hdrsize &&
                static const char binhdr[] = "Binary files ";
 
                if (sizeof(binhdr) - 1 < size - offset - hdrsize &&
@@ -899,9 +900,14 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
                            sizeof(binhdr)-1))
                        patch->is_binary = 1;
 
                            sizeof(binhdr)-1))
                        patch->is_binary = 1;
 
-               if (patch->is_binary && !apply && !check)
-                       ;
-               else
+               /* Empty patch cannot be applied if:
+                * - it is a binary patch and we do not do binary_replace, or
+                * - text patch without metadata change
+                */
+               if ((apply || check) &&
+                   (patch->is_binary
+                    ? !allow_binary_replacement
+                    : !metadata_changes(patch)))
                        die("patch with only garbage at line %d", linenr);
        }
 
                        die("patch with only garbage at line %d", linenr);
        }
 
@@ -1155,10 +1161,77 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
 static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
 {
        struct fragment *frag = patch->fragments;
 static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
 {
        struct fragment *frag = patch->fragments;
+       const char *name = patch->old_name ? patch->old_name : patch->new_name;
+
+       if (patch->is_binary) {
+               unsigned char sha1[20];
+
+               if (!allow_binary_replacement)
+                       return error("cannot apply binary patch to '%s' "
+                                    "without --allow-binary-replacement",
+                                    name);
+
+               /* For safety, we require patch index line to contain
+                * full 40-byte textual SHA1 for old and new, at least for now.
+                */
+               if (strlen(patch->old_sha1_prefix) != 40 ||
+                   strlen(patch->new_sha1_prefix) != 40 ||
+                   get_sha1_hex(patch->old_sha1_prefix, sha1) ||
+                   get_sha1_hex(patch->new_sha1_prefix, sha1))
+                       return error("cannot apply binary patch to '%s' "
+                                    "without full index line", name);
+
+               if (patch->old_name) {
+                       unsigned char hdr[50];
+                       int hdrlen;
+
+                       /* See if the old one matches what the patch
+                        * applies to.
+                        */
+                       write_sha1_file_prepare(desc->buffer, desc->size,
+                                               "blob", sha1, hdr, &hdrlen);
+                       if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
+                               return error("the patch applies to '%s' (%s), "
+                                            "which does not match the "
+                                            "current contents.",
+                                            name, sha1_to_hex(sha1));
+               }
+               else {
+                       /* Otherwise, the old one must be empty. */
+                       if (desc->size)
+                               return error("the patch applies to an empty "
+                                            "'%s' but it is not empty", name);
+               }
+
+               /* For now, we do not record post-image data in the patch,
+                * and require the object already present in the recipient's
+                * object database.
+                */
+               if (desc->buffer) {
+                       free(desc->buffer);
+                       desc->alloc = desc->size = 0;
+               }
+               get_sha1_hex(patch->new_sha1_prefix, sha1);
+
+               if (memcmp(sha1, null_sha1, 20)) {
+                       char type[10];
+                       unsigned long size;
+
+                       desc->buffer = read_sha1_file(sha1, type, &size);
+                       if (!desc->buffer)
+                               return error("the necessary postimage %s for "
+                                            "'%s' does not exist",
+                                            patch->new_sha1_prefix, name);
+                       desc->alloc = desc->size = size;
+               }
+
+               return 0;
+       }
 
        while (frag) {
                if (apply_one_fragment(desc, frag) < 0)
 
        while (frag) {
                if (apply_one_fragment(desc, frag) < 0)
-                       return error("patch failed: %s:%ld", patch->old_name, frag->oldpos);
+                       return error("patch failed: %s:%ld",
+                                    name, frag->oldpos);
                frag = frag->next;
        }
        return 0;
                frag = frag->next;
        }
        return 0;
@@ -1200,6 +1273,7 @@ static int check_patch(struct patch *patch)
        struct stat st;
        const char *old_name = patch->old_name;
        const char *new_name = patch->new_name;
        struct stat st;
        const char *old_name = patch->old_name;
        const char *new_name = patch->new_name;
+       const char *name = old_name ? old_name : new_name;
 
        if (old_name) {
                int changed;
 
        if (old_name) {
                int changed;
@@ -1274,7 +1348,7 @@ static int check_patch(struct patch *patch)
        }       
 
        if (apply_data(patch, &st) < 0)
        }       
 
        if (apply_data(patch, &st) < 0)
-               return error("%s: patch does not apply", old_name);
+               return error("%s: patch does not apply", name);
        return 0;
 }
 
        return 0;
 }
 
@@ -1723,6 +1797,10 @@ int main(int argc, char **argv)
                        diffstat = 1;
                        continue;
                }
                        diffstat = 1;
                        continue;
                }
+               if (!strcmp(arg, "--allow-binary-replacement")) {
+                       allow_binary_replacement = 1;
+                       continue;
+               }
                if (!strcmp(arg, "--numstat")) {
                        apply = 0;
                        numstat = 1;
                if (!strcmp(arg, "--numstat")) {
                        apply = 0;
                        numstat = 1;
diff --git a/cache.h b/cache.h
index 677c6ac..08461cf 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -179,6 +179,8 @@ extern int commit_index_file(struct cache_file *);
 extern void rollback_index_file(struct cache_file *);
 
 extern int trust_executable_bit;
 extern void rollback_index_file(struct cache_file *);
 
 extern int trust_executable_bit;
+extern int only_use_symrefs;
+extern int diff_rename_limit_default;
 
 #define MTIME_CHANGED  0x0001
 #define CTIME_CHANGED  0x0002
 
 #define MTIME_CHANGED  0x0001
 #define CTIME_CHANGED  0x0002
index ebf4db6..e867b86 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -204,6 +204,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
        unsigned char parent[20];
        struct commit_list **pptr;
        struct commit_graft *graft;
        unsigned char parent[20];
        struct commit_list **pptr;
        struct commit_graft *graft;
+       unsigned n_refs = 0;
 
        if (item->object.parsed)
                return 0;
 
        if (item->object.parsed)
                return 0;
@@ -214,7 +215,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
                return error("bad tree pointer in commit %s\n", sha1_to_hex(item->object.sha1));
        item->tree = lookup_tree(parent);
        if (item->tree)
                return error("bad tree pointer in commit %s\n", sha1_to_hex(item->object.sha1));
        item->tree = lookup_tree(parent);
        if (item->tree)
-               add_ref(&item->object, &item->tree->object);
+               n_refs++;
        bufptr += 46; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
 
        bufptr += 46; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
 
@@ -230,7 +231,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
                new_parent = lookup_commit(parent);
                if (new_parent) {
                        pptr = &commit_list_insert(new_parent, pptr)->next;
                new_parent = lookup_commit(parent);
                if (new_parent) {
                        pptr = &commit_list_insert(new_parent, pptr)->next;
-                       add_ref(&item->object, &new_parent->object);
+                       n_refs++;
                }
        }
        if (graft) {
                }
        }
        if (graft) {
@@ -241,10 +242,22 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
                        if (!new_parent)
                                continue;
                        pptr = &commit_list_insert(new_parent, pptr)->next;
                        if (!new_parent)
                                continue;
                        pptr = &commit_list_insert(new_parent, pptr)->next;
-                       add_ref(&item->object, &new_parent->object);
+                       n_refs++;
                }
        }
        item->date = parse_commit_date(bufptr);
                }
        }
        item->date = parse_commit_date(bufptr);
+
+       if (track_object_refs) {
+               unsigned i = 0;
+               struct commit_list *p;
+               struct object_refs *refs = alloc_object_refs(n_refs);
+               if (item->tree)
+                       refs->ref[i++] = &item->tree->object;
+               for (p = item->parents; p; p = p->next)
+                       refs->ref[i++] = &p->item->object;
+               set_object_refs(&item->object, refs);
+       }
+
        return 0;
 }
 
        return 0;
 }
 
index e89bab2..915bb97 100644 (file)
--- a/config.c
+++ b/config.c
@@ -214,6 +214,11 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
                return 0;
        }
 
+       if (!strcmp(var, "core.symrefsonly")) {
+               only_use_symrefs = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "user.name")) {
                strncpy(git_default_name, value, sizeof(git_default_name));
                return 0;
        if (!strcmp(var, "user.name")) {
                strncpy(git_default_name, value, sizeof(git_default_name));
                return 0;
@@ -224,6 +229,11 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
                return 0;
        }
 
+       if (!strcmp(var, "diff.renamelimit")) {
+               diff_rename_limit_default = git_config_int(var, value);
+               return 0;
+       }
+
        /* Add other config variables here.. */
        return 0;
 }
        /* Add other config variables here.. */
        return 0;
 }
index c3f8641..2b81152 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -594,6 +594,7 @@ int main(int argc, char **argv)
                }
                if (!strcmp(arg, "--inetd")) {
                        inetd_mode = 1;
                }
                if (!strcmp(arg, "--inetd")) {
                        inetd_mode = 1;
+                       log_syslog = 1;
                        continue;
                }
                if (!strcmp(arg, "--verbose")) {
                        continue;
                }
                if (!strcmp(arg, "--verbose")) {
@@ -602,7 +603,6 @@ int main(int argc, char **argv)
                }
                if (!strcmp(arg, "--syslog")) {
                        log_syslog = 1;
                }
                if (!strcmp(arg, "--syslog")) {
                        log_syslog = 1;
-                       openlog("git-daemon", 0, LOG_DAEMON);
                        continue;
                }
                if (!strcmp(arg, "--export-all")) {
                        continue;
                }
                if (!strcmp(arg, "--export-all")) {
@@ -611,9 +611,11 @@ int main(int argc, char **argv)
                }
                if (!strncmp(arg, "--timeout=", 10)) {
                        timeout = atoi(arg+10);
                }
                if (!strncmp(arg, "--timeout=", 10)) {
                        timeout = atoi(arg+10);
+                       continue;
                }
                if (!strncmp(arg, "--init-timeout=", 15)) {
                        init_timeout = atoi(arg+15);
                }
                if (!strncmp(arg, "--init-timeout=", 15)) {
                        init_timeout = atoi(arg+15);
+                       continue;
                }
                if (!strcmp(arg, "--")) {
                        ok_paths = &argv[i+1];
                }
                if (!strcmp(arg, "--")) {
                        ok_paths = &argv[i+1];
@@ -626,10 +628,13 @@ int main(int argc, char **argv)
                usage(daemon_usage);
        }
 
                usage(daemon_usage);
        }
 
+       if (log_syslog)
+               openlog("git-daemon", 0, LOG_DAEMON);
+
        if (inetd_mode) {
                fclose(stderr); //FIXME: workaround
                return execute();
        if (inetd_mode) {
                fclose(stderr); //FIXME: workaround
                return execute();
-       } else {
-               return serve(port);
        }
        }
+
+       return serve(port);
 }
 }
index 3d90d93..1eda61f 100644 (file)
@@ -1,3 +1,9 @@
+git-core (0.99.9j-0) unstable; urgency=low
+
+  * GIT 0.99.9j aka 1.0rc3
+
+ -- Junio C Hamano <junkio@cox.net>  Wed, 16 Nov 2005 20:39:55 -0800
+
 git-core (0.99.9i-0) unstable; urgency=low
 
   * GIT 0.99.9i aka 1.0rc2
 git-core (0.99.9i-0) unstable; urgency=low
 
   * GIT 0.99.9i aka 1.0rc2
diff --git a/diff.c b/diff.c
index ec94a96..0391e8c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -13,6 +13,8 @@ static const char *diff_opts = "-pu";
 
 static int use_size_cache;
 
 
 static int use_size_cache;
 
+int diff_rename_limit_default = -1;
+
 static char *quote_one(const char *str)
 {
        int needlen;
 static char *quote_one(const char *str)
 {
        int needlen;
@@ -648,7 +650,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
                memset(one->sha1, 0, 20);
 }
 
                memset(one->sha1, 0, 20);
 }
 
-static void run_diff(struct diff_filepair *p)
+static void run_diff(struct diff_filepair *p, struct diff_options *o)
 {
        const char *pgm = external_diff();
        char msg[PATH_MAX*2+300], *xfrm_msg;
 {
        const char *pgm = external_diff();
        char msg[PATH_MAX*2+300], *xfrm_msg;
@@ -711,11 +713,11 @@ static void run_diff(struct diff_filepair *p)
 
        if (memcmp(one->sha1, two->sha1, 20)) {
                char one_sha1[41];
 
        if (memcmp(one->sha1, two->sha1, 20)) {
                char one_sha1[41];
+               const char *index_fmt = o->full_index ? "index %s..%s" : "index %.7s..%.7s";
                memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
 
                len += snprintf(msg + len, sizeof(msg) - len,
                memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
 
                len += snprintf(msg + len, sizeof(msg) - len,
-                               "index %.7s..%.7s", one_sha1,
-                               sha1_to_hex(two->sha1));
+                               index_fmt, one_sha1, sha1_to_hex(two->sha1));
                if (one->mode == two->mode)
                        len += snprintf(msg + len, sizeof(msg) - len,
                                        " %06o", one->mode);
                if (one->mode == two->mode)
                        len += snprintf(msg + len, sizeof(msg) - len,
                                        " %06o", one->mode);
@@ -761,9 +763,12 @@ void diff_setup(struct diff_options *options)
 
 int diff_setup_done(struct diff_options *options)
 {
 
 int diff_setup_done(struct diff_options *options)
 {
-       if ((options->find_copies_harder || 0 <= options->rename_limit) &&
-           options->detect_rename != DIFF_DETECT_COPY)
+       if ((options->find_copies_harder &&
+            options->detect_rename != DIFF_DETECT_COPY) ||
+           (0 <= options->rename_limit && !options->detect_rename))
                return -1;
                return -1;
+       if (options->detect_rename && options->rename_limit < 0)
+               options->rename_limit = diff_rename_limit_default;
        if (options->setup & DIFF_SETUP_USE_CACHE) {
                if (!active_cache)
                        /* read-cache does not die even when it fails
        if (options->setup & DIFF_SETUP_USE_CACHE) {
                if (!active_cache)
                        /* read-cache does not die even when it fails
@@ -789,6 +794,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->line_termination = 0;
        else if (!strncmp(arg, "-l", 2))
                options->rename_limit = strtoul(arg+2, NULL, 10);
                options->line_termination = 0;
        else if (!strncmp(arg, "-l", 2))
                options->rename_limit = strtoul(arg+2, NULL, 10);
+       else if (!strcmp(arg, "--full-index"))
+               options->full_index = 1;
        else if (!strcmp(arg, "--name-only"))
                options->output_format = DIFF_FORMAT_NAME;
        else if (!strcmp(arg, "--name-status"))
        else if (!strcmp(arg, "--name-only"))
                options->output_format = DIFF_FORMAT_NAME;
        else if (!strcmp(arg, "--name-status"))
@@ -1017,7 +1024,7 @@ int diff_unmodified_pair(struct diff_filepair *p)
        return 0;
 }
 
        return 0;
 }
 
-static void diff_flush_patch(struct diff_filepair *p)
+static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
 {
        if (diff_unmodified_pair(p))
                return;
 {
        if (diff_unmodified_pair(p))
                return;
@@ -1026,7 +1033,7 @@ static void diff_flush_patch(struct diff_filepair *p)
            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
                return; /* no tree diffs in patch format */ 
 
            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
                return; /* no tree diffs in patch format */ 
 
-       run_diff(p);
+       run_diff(p, o);
 }
 
 int diff_queue_is_empty(void)
 }
 
 int diff_queue_is_empty(void)
@@ -1158,7 +1165,7 @@ void diff_flush(struct diff_options *options)
                        die("internal error in diff-resolve-rename-copy");
                switch (diff_output_format) {
                case DIFF_FORMAT_PATCH:
                        die("internal error in diff-resolve-rename-copy");
                switch (diff_output_format) {
                case DIFF_FORMAT_PATCH:
-                       diff_flush_patch(p);
+                       diff_flush_patch(p, options);
                        break;
                case DIFF_FORMAT_RAW:
                case DIFF_FORMAT_NAME_STATUS:
                        break;
                case DIFF_FORMAT_RAW:
                case DIFF_FORMAT_NAME_STATUS:
diff --git a/diff.h b/diff.h
index 1259079..9b2e1e6 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -32,7 +32,8 @@ struct diff_options {
        const char *orderfile;
        const char *pickaxe;
        unsigned recursive:1,
        const char *orderfile;
        const char *pickaxe;
        unsigned recursive:1,
-                tree_in_recursive:1;
+                tree_in_recursive:1,
+                full_index:1;
        int break_opt;
        int detect_rename;
        int find_copies_harder;
        int break_opt;
        int detect_rename;
        int find_copies_harder;
@@ -96,6 +97,7 @@ extern void diffcore_std_no_resolve(struct diff_options *);
 "  -u            synonym for -p.\n" \
 "  --name-only   show only names of changed files.\n" \
 "  --name-status show names and status of changed files.\n" \
 "  -u            synonym for -p.\n" \
 "  --name-only   show only names of changed files.\n" \
 "  --name-status show names and status of changed files.\n" \
+"  --full-index  show full object name on index ines.\n" \
 "  -R            swap input file pairs.\n" \
 "  -B            detect complete rewrites.\n" \
 "  -M            detect renames.\n" \
 "  -R            swap input file pairs.\n" \
 "  -B            detect complete rewrites.\n" \
 "  -M            detect renames.\n" \
index e17dd90..6a9d95d 100644 (file)
@@ -283,7 +283,7 @@ void diffcore_rename(struct diff_options *options)
                        register_rename_src(p->one, 1);
        }
        if (rename_dst_nr == 0 ||
                        register_rename_src(p->one, 1);
        }
        if (rename_dst_nr == 0 ||
-           (0 <= rename_limit && rename_limit < rename_dst_nr))
+           (0 < rename_limit && rename_limit < rename_dst_nr))
                goto cleanup; /* nothing to do */
 
        /* We really want to cull the candidates list early
                goto cleanup; /* nothing to do */
 
        /* We really want to cull the candidates list early
index 1dc7af5..b5026f1 100644 (file)
@@ -12,6 +12,7 @@
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
+int only_use_symrefs = 0;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
        *git_graft_file;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
        *git_graft_file;
index 17d0536..0433a1d 100644 (file)
@@ -56,7 +56,6 @@ static void check_connectivity(void)
        /* Look up all the requirements, warn about missing objects.. */
        for (i = 0; i < nr_objs; i++) {
                struct object *obj = objs[i];
        /* Look up all the requirements, warn about missing objects.. */
        for (i = 0; i < nr_objs; i++) {
                struct object *obj = objs[i];
-               struct object_list *refs;
 
                if (!obj->parsed) {
                        if (!standalone && has_sha1_file(obj->sha1))
 
                if (!obj->parsed) {
                        if (!standalone && has_sha1_file(obj->sha1))
@@ -67,14 +66,19 @@ static void check_connectivity(void)
                        continue;
                }
 
                        continue;
                }
 
-               for (refs = obj->refs; refs; refs = refs->next) {
-                       if (refs->item->parsed ||
-                           (!standalone && has_sha1_file(refs->item->sha1)))
-                               continue;
-                       printf("broken link from %7s %s\n",
-                              obj->type, sha1_to_hex(obj->sha1));
-                       printf("              to %7s %s\n",
-                              refs->item->type, sha1_to_hex(refs->item->sha1));
+               if (obj->refs) {
+                       const struct object_refs *refs = obj->refs;
+                       unsigned j;
+                       for (j = 0; j < refs->count; j++) {
+                               struct object *ref = refs->ref[j];
+                               if (ref->parsed ||
+                                   (!standalone && has_sha1_file(ref->sha1)))
+                                       continue;
+                               printf("broken link from %7s %s\n",
+                                      obj->type, sha1_to_hex(obj->sha1));
+                               printf("              to %7s %s\n",
+                                      ref->type, sha1_to_hex(ref->sha1));
+                       }
                }
 
                if (show_unreachable && !(obj->flags & REACHABLE)) {
                }
 
                if (show_unreachable && !(obj->flags & REACHABLE)) {
@@ -184,10 +188,17 @@ static int fsck_tree(struct tree *item)
                        default:
                                break;
                        }
                        default:
                                break;
                        }
+                       free(last->name);
+                       free(last);
                }
 
                last = entry;
        }
                }
 
                last = entry;
        }
+       if (last) {
+               free(last->name);
+               free(last);
+       }
+       item->entries = NULL;
 
        retval = 0;
        if (has_full_path) {
 
        retval = 0;
        if (has_full_path) {
index 38841d9..98a390a 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -3,16 +3,10 @@
 #
 . git-sh-setup || die "Not a git archive"
 
 #
 . git-sh-setup || die "Not a git archive"
 
-files=$(git-diff-index --cached --name-only HEAD) || exit
-if [ "$files" ]; then
-   echo "Dirty index: cannot apply patches (dirty: $files)" >&2
-   exit 1
-fi
-
 usage () {
     echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--3way] <mbox>"
     echo >&2 " or, when resuming"
 usage () {
     echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--3way] <mbox>"
     echo >&2 " or, when resuming"
-    echo >&2 " $0 [--skip]"
+    echo >&2 " $0 [--skip | --resolved]"
     exit 1;
 }
 
     exit 1;
 }
 
@@ -104,7 +98,7 @@ fall_back_3way () {
 }
 
 prec=4
 }
 
 prec=4
-dotest=.dotest sign= utf8= keep= skip= interactive=
+dotest=.dotest sign= utf8= keep= skip= interactive= resolved=
 
 while case "$#" in 0) break;; esac
 do
 
 while case "$#" in 0) break;; esac
 do
@@ -128,6 +122,9 @@ do
        -k|--k|--ke|--kee|--keep)
        keep=t; shift ;;
 
        -k|--k|--ke|--kee|--keep)
        keep=t; shift ;;
 
+       -r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
+       resolved=t; shift ;;
+
        --sk|--ski|--skip)
        skip=t; shift ;;
 
        --sk|--ski|--skip)
        skip=t; shift ;;
 
@@ -140,6 +137,8 @@ do
        esac
 done
 
        esac
 done
 
+# If the dotest directory exists, but we have finished applying all the
+# patches in them, clear it out.
 if test -d "$dotest" &&
    last=$(cat "$dotest/last") &&
    next=$(cat "$dotest/next") &&
 if test -d "$dotest" &&
    last=$(cat "$dotest/last") &&
    next=$(cat "$dotest/next") &&
@@ -155,9 +154,9 @@ then
        die "previous dotest directory $dotest still exists but mbox given."
        resume=yes
 else
        die "previous dotest directory $dotest still exists but mbox given."
        resume=yes
 else
-       # Make sure we are not given --skip
-       test ",$skip," = ,, ||
-       die "we are not resuming."
+       # Make sure we are not given --skip nor --resolved
+       test ",$skip,$resolved," = ,,, ||
+               die "we are not resuming."
 
        # Start afresh.
        mkdir -p "$dotest" || exit
 
        # Start afresh.
        mkdir -p "$dotest" || exit
@@ -170,12 +169,24 @@ else
                exit 1
        }
 
                exit 1
        }
 
+       # -s, -u and -k flags are kept for the resuming session after
+       # a patch failure.
+       # -3 and -i can and must be given when resuming.
        echo "$sign" >"$dotest/sign"
        echo "$utf8" >"$dotest/utf8"
        echo "$keep" >"$dotest/keep"
        echo 1 >"$dotest/next"
 fi
 
        echo "$sign" >"$dotest/sign"
        echo "$utf8" >"$dotest/utf8"
        echo "$keep" >"$dotest/keep"
        echo 1 >"$dotest/next"
 fi
 
+case "$resolved" in
+'')
+       files=$(git-diff-index --cached --name-only HEAD) || exit
+       if [ "$files" ]; then
+          echo "Dirty index: cannot apply patches (dirty: $files)" >&2
+          exit 1
+       fi
+esac
+
 if test "$(cat "$dotest/utf8")" = t
 then
        utf8=-u
 if test "$(cat "$dotest/utf8")" = t
 then
        utf8=-u
@@ -216,6 +227,15 @@ do
                go_next
                continue
        }
                go_next
                continue
        }
+
+       # If we are not resuming, parse and extract the patch information
+       # into separate files:
+       #  - info records the authorship and title
+       #  - msg is the rest of commit log message
+       #  - patch is the patch body.
+       #
+       # When we are resuming, these files are either already prepared
+       # by the user, or the user can tell us to do so by --resolved flag.
        case "$resume" in
        '')
                git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
        case "$resume" in
        '')
                git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
@@ -263,6 +283,13 @@ do
                fi
            } >"$dotest/final-commit"
            ;;
                fi
            } >"$dotest/final-commit"
            ;;
+       *)
+               case "$resolved,$interactive" in
+               tt)
+                       # This is used only for interactive view option.
+                       git-diff-index -p --cached HEAD >"$dotest/patch"
+                       ;;
+               esac
        esac
 
        resume=
        esac
 
        resume=
@@ -310,7 +337,21 @@ do
        echo "Applying '$SUBJECT'"
        echo
 
        echo "Applying '$SUBJECT'"
        echo
 
-       git-apply --index "$dotest/patch"; apply_status=$?
+       case "$resolved" in
+       '')
+               git-apply --index "$dotest/patch"
+               apply_status=$?
+               ;;
+       t)
+               # Resolved means the user did all the hard work, and
+               # we do not have to do any patch application.  Just
+               # trust what the user has in the index file and the
+               # working tree.
+               resolved=
+               apply_status=0
+               ;;
+       esac
+
        if test $apply_status = 1 && test "$threeway" = t
        then
                if (fall_back_3way)
        if test $apply_status = 1 && test "$threeway" = t
        then
                if (fall_back_3way)
index e22c816..23becb7 100755 (executable)
@@ -410,8 +410,7 @@ foreach my $ps (@psets) {
     open  HEAD, ">$git_dir/refs/heads/$ps->{branch}";
     print HEAD $commitid;
     close HEAD;
     open  HEAD, ">$git_dir/refs/heads/$ps->{branch}";
     print HEAD $commitid;
     close HEAD;
-    unlink ("$git_dir/HEAD");
-    symlink("refs/heads/$ps->{branch}","$git_dir/HEAD");
+    system('git-update-ref', 'HEAD', "$ps->{branch}");
 
     # tag accordingly
     ptag($ps->{id}, $commitid); # private tag
 
     # tag accordingly
     ptag($ps->{id}, $commitid); # private tag
diff --git a/git-core.spec.in b/git-core.spec.in
deleted file mode 100644 (file)
index 16c6269..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-# Pass --without docs to rpmbuild if you don't want the documentation
-Name:          git-core
-Version:       @@VERSION@@
-Release:       1%{?dist}
-Summary:       Git core and tools
-License:       GPL
-Group:                 Development/Tools
-URL:           http://kernel.org/pub/software/scm/git/
-Source:        http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
-BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
-BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-Requires:      zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, python >= 2.3, expat
-
-%description
-This is a stupid (but extremely fast) directory content manager.  It
-doesn't do a whole lot, but what it _does_ do is track directory
-contents efficiently. It is intended to be the base of an efficient,
-distributed source code management system. This package includes
-rudimentary tools that can be used as a SCM, but you should look
-elsewhere for tools for ordinary humans layered on top of this.
-
-%package svn
-Summary:        Git tools for importing Subversion repositories
-Group:          Development/Tools
-Requires:       git-core = %{version}-%{release}, subversion
-%description svn
-Git tools for importing Subversion repositories.
-
-%package cvs
-Summary:        Git tools for importing CVS repositories
-Group:          Development/Tools
-Requires:       git-core = %{version}-%{release}, cvs, cvsps
-%description cvs
-Git tools for importing CVS repositories.
-
-%package arch
-Summary:        Git tools for importing Arch repositories
-Group:          Development/Tools
-Requires:       git-core = %{version}-%{release}, tla
-%description arch
-Git tools for importing Arch repositories.
-
-%package email
-Summary:        Git tools for sending email
-Group:          Development/Tools
-Requires:      git-core = %{version}-%{release} 
-%description email
-Git tools for sending email.
-
-%package tk
-Summary:        Git revision tree visualiser ('gitk')
-Group:          Development/Tools
-Requires:       git-core = %{version}-%{release}, tk >= 8.4
-%description tk
-Git revision tree visualiser ('gitk')
-
-%prep
-%setup -q
-
-%build
-make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" WITH_OWN_SUBPROCESS_PY=YesPlease WITH_SEND_EMAIL=1 \
-     prefix=%{_prefix} all %{!?_without_docs: doc}
-
-%install
-rm -rf $RPM_BUILD_ROOT
-make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease WITH_SEND_EMAIL=1 \
-     prefix=%{_prefix} mandir=%{_mandir} \
-     install %{!?_without_docs: install-doc}
-
-(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "arch|svn|cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@)               > bin-man-doc-files
-%if %{!?_without_docs:1}0
-(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "arch|svn|git-cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files
-%endif
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files svn
-%defattr(-,root,root)
-%{_bindir}/*svn*
-%doc Documentation/*svn*.txt
-%{!?_without_docs: %{_mandir}/man1/*svn*.1*}
-%{!?_without_docs: %doc Documentation/*svn*.html }
-
-%files cvs
-%defattr(-,root,root)
-%doc Documentation/*git-cvs*.txt
-%{_bindir}/*cvs*
-%{!?_without_docs: %{_mandir}/man1/*cvs*.1*}
-%{!?_without_docs: %doc Documentation/*git-cvs*.html }
-
-%files arch
-%defattr(-,root,root)
-%doc Documentation/*arch*.txt
-%{_bindir}/*arch*
-%{!?_without_docs: %{_mandir}/man1/*arch*.1*}
-%{!?_without_docs: %doc Documentation/*arch*.html }
-
-%files email
-%defattr(-,root,root)
-%doc Documentation/*email*.txt
-%{_bindir}/*email*
-%{!?_without_docs: %{_mandir}/man1/*email*.1*}
-%{!?_without_docs: %doc Documentation/*email*.html }
-
-%files tk
-%defattr(-,root,root)
-%doc Documentation/*gitk*.txt
-%{_bindir}/*gitk*
-%{!?_without_docs: %{_mandir}/man1/*gitk*.1*}
-%{!?_without_docs: %doc Documentation/*gitk*.html }
-
-%files -f bin-man-doc-files
-%defattr(-,root,root)
-%{_datadir}/git-core/
-%doc README COPYING Documentation/*.txt
-%{!?_without_docs: %doc Documentation/*.html }
-
-%changelog
-* Thu Nov 10 2005 Chris Wright <chrisw@osdl.org> 0.99.9g-1
-- zlib dependency fix
-- Minor cleanups from split
-- Move arch import to separate package as well
-
-* Tue Sep 27 2005 Jim Radford <radford@blackbean.org>
-- Move programs with non-standard dependencies (svn, cvs, email)
-  into separate packages
-
-* Tue Sep 27 2005 H. Peter Anvin <hpa@zytor.com>
-- parallelize build
-- COPTS -> CFLAGS
-
-* Fri Sep 16 2005 Chris Wright <chrisw@osdl.org> 0.99.6-1
-- update to 0.99.6
-
-* Fri Sep 16 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
-- Linus noticed that less is required, added to the dependencies
-
-* Sun Sep 11 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
-- Updated dependencies
-- Don't assume manpages are gzipped
-
-* Thu Aug 18 2005 Chris Wright <chrisw@osdl.org> 0.99.4-4
-- drop sh_utils, sh-utils, diffutils, mktemp, and openssl Requires
-- use RPM_OPT_FLAGS in spec file, drop patch0
-
-* Wed Aug 17 2005 Tom "spot" Callaway <tcallawa@redhat.com> 0.99.4-3
-- use dist tag to differentiate between branches
-- use rpm optflags by default (patch0)
-- own %{_datadir}/git-core/
-
-* Mon Aug 15 2005 Chris Wright <chrisw@osdl.org>
-- update spec file to fix Buildroot, Requires, and drop Vendor
-
-* Sun Aug 07 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
-- Redid the description
-- Cut overlong make line, loosened changelog a bit
-- I think Junio (or perhaps OSDL?) should be vendor...
-
-* Thu Jul 14 2005 Eric Biederman <ebiederm@xmission.com>
-- Add the man pages, and the --without docs build option
-
-* Wed Jul 7 2005 Chris Wright <chris@osdl.org>
-- initial git spec file
index 50b041c..5a8c011 100755 (executable)
@@ -4,6 +4,7 @@ use strict;
 use Getopt::Std;
 use File::Temp qw(tempdir);
 use Data::Dumper;
 use Getopt::Std;
 use File::Temp qw(tempdir);
 use Data::Dumper;
+use File::Basename qw(basename);
 
 unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
     die "GIT_DIR is not defined or is unreadable";
 
 unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
     die "GIT_DIR is not defined or is unreadable";
@@ -11,7 +12,7 @@ unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
 
 our ($opt_h, $opt_p, $opt_v, $opt_c );
 
 
 our ($opt_h, $opt_p, $opt_v, $opt_c );
 
-getopt('hpvc');
+getopts('hpvc');
 
 $opt_h && usage();
 
 
 $opt_h && usage();
 
@@ -77,7 +78,7 @@ $opt_v && print "Applying to CVS commit $commit from parent $parent\n";
 
 # grab the commit message
 `git-cat-file commit $commit | sed -e '1,/^\$/d' > .msg`;
 
 # grab the commit message
 `git-cat-file commit $commit | sed -e '1,/^\$/d' > .msg`;
-$? && die "Error extraction the commit message";
+$? && die "Error extracting the commit message";
 
 my (@afiles, @dfiles, @mfiles);
 my @files = `git-diff-tree -r $parent $commit`;
 
 my (@afiles, @dfiles, @mfiles);
 my @files = `git-diff-tree -r $parent $commit`;
@@ -187,9 +188,9 @@ my $cmd = "cvs commit -F .msg $commitfiles";
 
 if ($dirtypatch) {
     print "NOTE: One or more hunks failed to apply cleanly.\n";
 
 if ($dirtypatch) {
     print "NOTE: One or more hunks failed to apply cleanly.\n";
-    print "Resolve the conflicts and then commit using:n";
+    print "Resolve the conflicts and then commit using:\n";
     print "\n    $cmd\n\n";
     print "\n    $cmd\n\n";
-    exit;
+    exit(1);
 }
 
 
 }
 
 
@@ -206,8 +207,7 @@ if ($opt_c) {
 }
 sub usage {
        print STDERR <<END;
 }
 sub usage {
        print STDERR <<END;
-Usage: GIT_DIR=/path/to/.gi ${\basename $0}      # fetch/update GIT from CVS
-       [-h] [-p] [ parent ] commit
+Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [ parent ] commit
 END
        exit(1);
 }
 END
        exit(1);
 }
index 7bd9136..efe1934 100755 (executable)
@@ -437,7 +437,11 @@ unless(-d $git_dir) {
                       "Either use the correct '-o branch' option,\n".
                       "or import to a new repository.\n";
 
                       "Either use the correct '-o branch' option,\n".
                       "or import to a new repository.\n";
 
-       $last_branch = basename(readlink("$git_dir/HEAD"));
+       open(F, "git-symbolic-ref HEAD |") or
+               die "Cannot run git-symbolic-ref: $!\n";
+       chomp ($last_branch = <F>);
+       $last_branch = basename($last_branch);
+       close(F);
        unless($last_branch) {
                warn "Cannot read the last branch name: $! -- assuming 'master'\n";
                $last_branch = "master";
        unless($last_branch) {
                warn "Cannot read the last branch name: $! -- assuming 'master'\n";
                $last_branch = "master";
@@ -829,8 +833,7 @@ if($orig_branch) {
        print "DONE; creating $orig_branch branch\n" if $opt_v;
        system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
                unless -f "$git_dir/refs/heads/master";
        print "DONE; creating $orig_branch branch\n" if $opt_v;
        system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
                unless -f "$git_dir/refs/heads/master";
-       unlink("$git_dir/HEAD");
-       symlink("refs/heads/$orig_branch","$git_dir/HEAD");
+       system('git-update-ref', 'HEAD', "$orig_branch");
        unless ($opt_i) {
                system('git checkout');
                die "checkout failed: $?\n" if $?;
        unless ($opt_i) {
                system('git checkout');
                die "checkout failed: $?\n" if $?;
index e7a35eb..44c1613 100755 (executable)
@@ -39,5 +39,9 @@ while : ; do
        esac
        shift
 done
        esac
        shift
 done
+[ "$pattern" ] || {
+       echo >&2 "usage: 'git grep <pattern> [pathspec*]'"
+       exit 1
+}
 git-ls-files -z "${git_flags[@]}" "$@" |
        xargs -0 grep "${flags[@]}" -e "$pattern"
 git-ls-files -z "${git_flags[@]}" "$@" |
        xargs -0 grep "${flags[@]}" -e "$pattern"
index 1bf73f3..d7d36aa 100755 (executable)
@@ -3,11 +3,13 @@
 # Copyright (C) 2005 Fredrik Kuivinen
 #
 
 # Copyright (C) 2005 Fredrik Kuivinen
 #
 
-import sys, math, random, os, re, signal, tempfile, stat, errno, traceback
+import sys
+sys.path.append('''@@GIT_PYTHON_PATH@@''')
+
+import math, random, os, re, signal, tempfile, stat, errno, traceback
 from heapq import heappush, heappop
 from sets import Set
 
 from heapq import heappush, heappop
 from sets import Set
 
-sys.path.append('''@@GIT_PYTHON_PATH@@''')
 from gitMergeCommon import *
 
 outputIndent = 0
 from gitMergeCommon import *
 
 outputIndent = 0
index af13fdd..45d77c5 100755 (executable)
@@ -216,7 +216,11 @@ unless(-d $git_dir) {
        -f "$git_dir/svn2git"
                or die "'$git_dir/svn2git' does not exist.\n".
                       "You need that file for incremental imports.\n";
        -f "$git_dir/svn2git"
                or die "'$git_dir/svn2git' does not exist.\n".
                       "You need that file for incremental imports.\n";
-       $last_branch = basename(readlink("$git_dir/HEAD"));
+       open(F, "git-symbolic-ref HEAD |") or
+               die "Cannot run git-symbolic-ref: $!\n";
+       chomp ($last_branch = <F>);
+       $last_branch = basename($last_branch);
+       close(F);
        unless($last_branch) {
                warn "Cannot read the last branch name: $! -- assuming 'master'\n";
                $last_branch = "master";
        unless($last_branch) {
                warn "Cannot read the last branch name: $! -- assuming 'master'\n";
                $last_branch = "master";
@@ -766,8 +770,7 @@ if($orig_branch) {
        print "DONE; creating $orig_branch branch\n" if $opt_v and (not defined $opt_l or $opt_l > 0);
        system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
                unless -f "$git_dir/refs/heads/master";
        print "DONE; creating $orig_branch branch\n" if $opt_v and (not defined $opt_l or $opt_l > 0);
        system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
                unless -f "$git_dir/refs/heads/master";
-       unlink("$git_dir/HEAD");
-       symlink("refs/heads/$orig_branch","$git_dir/HEAD");
+       system('git-update-ref', 'HEAD', "$orig_branch");
        unless ($opt_i) {
                system('git checkout');
                die "checkout failed: $?\n" if $?;
        unless ($opt_i) {
                system('git checkout');
                die "checkout failed: $?\n" if $?;
diff --git a/git.c b/git.c
new file mode 100644 (file)
index 0000000..b9b8c62
--- /dev/null
+++ b/git.c
@@ -0,0 +1,295 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+static const char git_usage[] =
+       "Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
+
+/* most gui terms set COLUMNS (although some don't export it) */
+static int term_columns(void)
+{
+       char *col_string = getenv("COLUMNS");
+       int n_cols = 0;
+
+       if (col_string && (n_cols = atoi(col_string)) > 0)
+               return n_cols;
+
+       return 80;
+}
+
+static void oom(void)
+{
+       fprintf(stderr, "git: out of memory\n");
+       exit(1);
+}
+
+static inline void mput_char(char c, unsigned int num)
+{
+       while(num--)
+               putchar(c);
+}
+
+static struct cmdname {
+       size_t len;
+       char name[1];
+} **cmdname;
+static int cmdname_alloc, cmdname_cnt;
+
+static void add_cmdname(const char *name, int len)
+{
+       struct cmdname *ent;
+       if (cmdname_alloc <= cmdname_cnt) {
+               cmdname_alloc = cmdname_alloc + 200;
+               cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname));
+               if (!cmdname)
+                       oom();
+       }
+       ent = malloc(sizeof(*ent) + len);
+       if (!ent)
+               oom();
+       ent->len = len;
+       memcpy(ent->name, name, len+1);
+       cmdname[cmdname_cnt++] = ent;
+}
+
+static int cmdname_compare(const void *a_, const void *b_)
+{
+       struct cmdname *a = *(struct cmdname **)a_;
+       struct cmdname *b = *(struct cmdname **)b_;
+       return strcmp(a->name, b->name);
+}
+
+static void pretty_print_string_list(struct cmdname **cmdname, int longest)
+{
+       int cols = 1;
+       int space = longest + 1; /* min 1 SP between words */
+       int max_cols = term_columns() - 1; /* don't print *on* the edge */
+       int i;
+
+       if (space < max_cols)
+               cols = max_cols / space;
+
+       qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
+
+       for (i = 0; i < cmdname_cnt; ) {
+               int c;
+               printf("  ");
+
+               for (c = cols; c && i < cmdname_cnt; i++) {
+                       printf("%s", cmdname[i]->name);
+
+                       if (--c)
+                               mput_char(' ', space - cmdname[i]->len);
+               }
+               putchar('\n');
+       }
+}
+
+static void list_commands(const char *exec_path, const char *pattern)
+{
+       unsigned int longest = 0;
+       char path[PATH_MAX];
+       int dirlen;
+       DIR *dir = opendir(exec_path);
+       struct dirent *de;
+
+       if (!dir) {
+               fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno));
+               exit(1);
+       }
+
+       dirlen = strlen(exec_path);
+       if (PATH_MAX - 20 < dirlen) {
+               fprintf(stderr, "git: insanely long exec-path '%s'\n",
+                       exec_path);
+               exit(1);
+       }
+
+       memcpy(path, exec_path, dirlen);
+       path[dirlen++] = '/';
+
+       while ((de = readdir(dir)) != NULL) {
+               struct stat st;
+               int entlen;
+
+               if (strncmp(de->d_name, "git-", 4))
+                       continue;
+               strcpy(path+dirlen, de->d_name);
+               if (stat(path, &st) || /* stat, not lstat */
+                   !S_ISREG(st.st_mode) ||
+                   !(st.st_mode & S_IXUSR))
+                       continue;
+
+               entlen = strlen(de->d_name);
+
+               if (longest < entlen)
+                       longest = entlen;
+
+               add_cmdname(de->d_name + 4, entlen-4);
+       }
+       closedir(dir);
+
+       printf("git commands available in '%s'\n", exec_path);
+       printf("----------------------------");
+       mput_char('-', strlen(exec_path));
+       putchar('\n');
+       pretty_print_string_list(cmdname, longest - 4);
+       putchar('\n');
+}
+
+#ifdef __GNUC__
+static void usage(const char *exec_path, const char *fmt, ...)
+       __attribute__((__format__(__printf__, 2, 3), __noreturn__));
+#endif
+static void usage(const char *exec_path, const char *fmt, ...)
+{
+       if (fmt) {
+               va_list ap;
+
+               va_start(ap, fmt);
+               printf("git: ");
+               vprintf(fmt, ap);
+               va_end(ap);
+               putchar('\n');
+       }
+       else
+               puts(git_usage);
+
+       putchar('\n');
+
+       if(exec_path)
+               list_commands(exec_path, "git-*");
+
+       exit(1);
+}
+
+static void prepend_to_path(const char *dir, int len)
+{
+       char *path, *old_path = getenv("PATH");
+       int path_len = len;
+
+       if (!old_path)
+               old_path = "/usr/local/bin:/usr/bin:/bin";
+
+       path_len = len + strlen(old_path) + 1;
+
+       path = malloc(path_len + 1);
+       path[path_len + 1] = '\0';
+
+       memcpy(path, dir, len);
+       path[len] = ':';
+       memcpy(path + len + 1, old_path, path_len - len);
+
+       setenv("PATH", path, 1);
+}
+
+static void show_man_page(char *git_cmd)
+{
+       char *page;
+
+       if (!strncmp(git_cmd, "git", 3))
+               page = git_cmd;
+       else {
+               int page_len = strlen(git_cmd) + 4;
+
+               page = malloc(page_len + 1);
+               strcpy(page, "git-");
+               strcpy(page + 4, git_cmd);
+               page[page_len] = 0;
+       }
+
+       execlp("man", "man", page, NULL);
+}
+
+int main(int argc, char **argv, char **envp)
+{
+       char git_command[PATH_MAX + 1];
+       char wd[PATH_MAX + 1];
+       int i, len, show_help = 0;
+       char *exec_path = getenv("GIT_EXEC_PATH");
+
+       getcwd(wd, PATH_MAX);
+
+       if (!exec_path)
+               exec_path = GIT_EXEC_PATH;
+
+       for (i = 1; i < argc; i++) {
+               char *arg = argv[i];
+
+               if (strncmp(arg, "--", 2))
+                       break;
+
+               arg += 2;
+
+               if (!strncmp(arg, "exec-path", 9)) {
+                       arg += 9;
+                       if (*arg == '=')
+                               exec_path = arg + 1;
+                       else {
+                               puts(exec_path);
+                               exit(0);
+                       }
+               }
+               else if (!strcmp(arg, "version")) {
+                       printf("git version %s\n", GIT_VERSION);
+                       exit(0);
+               }
+               else if (!strcmp(arg, "help"))
+                       show_help = 1;
+               else if (!show_help)
+                       usage(NULL, NULL);
+       }
+
+       if (i >= argc || show_help) {
+               if (i >= argc)
+                       usage(exec_path, NULL);
+
+               show_man_page(argv[i]);
+       }
+
+       if (*exec_path != '/') {
+               if (!getcwd(git_command, sizeof(git_command))) {
+                       fprintf(stderr,
+                               "git: cannot determine current directory");
+                       exit(1);
+               }
+               len = strlen(git_command);
+
+               /* Trivial cleanup */
+               while (!strncmp(exec_path, "./", 2)) {
+                       exec_path += 2;
+                       while (*exec_path == '/')
+                               *exec_path++;
+               }
+               snprintf(git_command + len, sizeof(git_command) - len,
+                        "/%s", exec_path);
+       }
+       else
+               strcpy(git_command, exec_path);
+       len = strlen(git_command);
+       prepend_to_path(git_command, len);
+
+       strncat(&git_command[len], "/git-", sizeof(git_command) - len);
+       len += 5;
+       strncat(&git_command[len], argv[i], sizeof(git_command) - len);
+
+       if (access(git_command, X_OK))
+               usage(exec_path, "'%s' is not a git-command", argv[i]);
+
+       /* execve() can only ever return if it fails */
+       execve(git_command, &argv[i], envp);
+       printf("Failed to run command '%s': %s\n", git_command, strerror(errno));
+
+       return 1;
+}
diff --git a/git.sh b/git.sh
deleted file mode 100755 (executable)
index 94940ae..0000000
--- a/git.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/bin/sh
-
-cmd=
-path=$(dirname "$0")
-case "$#" in
-0)     ;;
-*)     cmd="$1"
-       shift
-       case "$cmd" in
-       -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
-               echo "git version @@GIT_VERSION@@"
-               exit 0 ;;
-       esac
-       
-       test -x "$path/git-$cmd" && exec "$path/git-$cmd" "$@"
-       
-       case '@@X@@' in
-           '')
-               ;;
-           *)
-               test -x "$path/git-$cmd@@X@@" &&
-               exec "$path/git-$cmd@@X@@" "$@"
-               ;;
-       esac
-       ;;
-esac
-
-echo "Usage: git COMMAND [OPTIONS] [TARGET]"
-if [ -n "$cmd" ]; then
-    echo "git command '$cmd' not found."
-fi
-echo "git commands are:"
-
-fmt <<\EOF | sed -e 's/^/    /'
-add
-apply
-archimport
-bisect
-branch
-checkout
-cherry
-clone
-commit
-count-objects
-cvsimport
-diff
-fetch
-format-patch
-fsck-objects
-get-tar-commit-id
-init-db
-log
-ls-remote
-octopus
-pack-objects
-parse-remote
-patch-id
-prune
-pull
-push
-rebase
-relink
-rename
-repack
-request-pull
-reset
-resolve
-revert
-send-email
-shortlog
-show-branch
-status
-tag
-verify-tag
-whatchanged
-EOF
diff --git a/git.spec.in b/git.spec.in
new file mode 100644 (file)
index 0000000..96dfc1d
--- /dev/null
@@ -0,0 +1,188 @@
+# Pass --without docs to rpmbuild if you don't want the documentation
+Name:          git
+Version:       @@VERSION@@
+Release:       1%{?dist}
+Summary:       Git core and tools
+License:       GPL
+Group:                 Development/Tools
+URL:           http://kernel.org/pub/software/scm/git/
+Source:        http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
+BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
+BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Requires:      git-core, git-svn, git-cvs, git-arch, git-email, gitk
+
+%description
+This is a stupid (but extremely fast) directory content manager.  It
+doesn't do a whole lot, but what it _does_ do is track directory
+contents efficiently. It is intended to be the base of an efficient,
+distributed source code management system. This package includes
+rudimentary tools that can be used as a SCM, but you should look
+elsewhere for tools for ordinary humans layered on top of this.
+
+This is a dummy package which brings in all subpackages.
+
+%package core
+Summary:       Core git tools
+Group:         Development/Tools
+Requires:      zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, python >= 2.3, expat
+%description core
+This is a stupid (but extremely fast) directory content manager.  It
+doesn't do a whole lot, but what it _does_ do is track directory
+contents efficiently. It is intended to be the base of an efficient,
+distributed source code management system. This package includes
+rudimentary tools that can be used as a SCM, but you should look
+elsewhere for tools for ordinary humans layered on top of this.
+
+These are the core tools with minimal dependencies.
+
+%package svn
+Summary:        Git tools for importing Subversion repositories
+Group:          Development/Tools
+Requires:       git-core = %{version}-%{release}, subversion
+%description svn
+Git tools for importing Subversion repositories.
+
+%package cvs
+Summary:        Git tools for importing CVS repositories
+Group:          Development/Tools
+Requires:       git-core = %{version}-%{release}, cvs, cvsps
+%description cvs
+Git tools for importing CVS repositories.
+
+%package arch
+Summary:        Git tools for importing Arch repositories
+Group:          Development/Tools
+Requires:       git-core = %{version}-%{release}, tla
+%description arch
+Git tools for importing Arch repositories.
+
+%package email
+Summary:        Git tools for sending email
+Group:          Development/Tools
+Requires:      git-core = %{version}-%{release} 
+%description email
+Git tools for sending email.
+
+%package -n gitk
+Summary:        Git revision tree visualiser ('gitk')
+Group:          Development/Tools
+Requires:       git-core = %{version}-%{release}, tk >= 8.4
+%description -n gitk
+Git revision tree visualiser ('gitk')
+
+%prep
+%setup -q
+
+%build
+make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" WITH_OWN_SUBPROCESS_PY=YesPlease WITH_SEND_EMAIL=1 \
+     prefix=%{_prefix} all %{!?_without_docs: doc}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease WITH_SEND_EMAIL=1 \
+     prefix=%{_prefix} mandir=%{_mandir} \
+     install %{!?_without_docs: install-doc}
+
+(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "arch|svn|cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@)               > bin-man-doc-files
+%if %{!?_without_docs:1}0
+(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "arch|svn|git-cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+# These are no files in the root package
+
+%files svn
+%defattr(-,root,root)
+%{_bindir}/*svn*
+%doc Documentation/*svn*.txt
+%{!?_without_docs: %{_mandir}/man1/*svn*.1*}
+%{!?_without_docs: %doc Documentation/*svn*.html }
+
+%files cvs
+%defattr(-,root,root)
+%doc Documentation/*git-cvs*.txt
+%{_bindir}/*cvs*
+%{!?_without_docs: %{_mandir}/man1/*cvs*.1*}
+%{!?_without_docs: %doc Documentation/*git-cvs*.html }
+
+%files arch
+%defattr(-,root,root)
+%doc Documentation/*arch*.txt
+%{_bindir}/*arch*
+%{!?_without_docs: %{_mandir}/man1/*arch*.1*}
+%{!?_without_docs: %doc Documentation/*arch*.html }
+
+%files email
+%defattr(-,root,root)
+%doc Documentation/*email*.txt
+%{_bindir}/*email*
+%{!?_without_docs: %{_mandir}/man1/*email*.1*}
+%{!?_without_docs: %doc Documentation/*email*.html }
+
+%files -n gitk
+%defattr(-,root,root)
+%doc Documentation/*gitk*.txt
+%{_bindir}/*gitk*
+%{!?_without_docs: %{_mandir}/man1/*gitk*.1*}
+%{!?_without_docs: %doc Documentation/*gitk*.html }
+
+%files core -f bin-man-doc-files
+%defattr(-,root,root)
+%{_datadir}/git-core/
+%doc README COPYING Documentation/*.txt
+%{!?_without_docs: %doc Documentation/*.html }
+
+%changelog
+* Mon Nov 14 2005 H. Peter Anvin <hpa@zytor.com> 0.99.9j-1
+- Change subpackage names to git-<name> instead of git-core-<name>
+- Create empty root package which brings in all subpackages
+- Rename git-tk -> gitk
+
+* Thu Nov 10 2005 Chris Wright <chrisw@osdl.org> 0.99.9g-1
+- zlib dependency fix
+- Minor cleanups from split
+- Move arch import to separate package as well
+
+* Tue Sep 27 2005 Jim Radford <radford@blackbean.org>
+- Move programs with non-standard dependencies (svn, cvs, email)
+  into separate packages
+
+* Tue Sep 27 2005 H. Peter Anvin <hpa@zytor.com>
+- parallelize build
+- COPTS -> CFLAGS
+
+* Fri Sep 16 2005 Chris Wright <chrisw@osdl.org> 0.99.6-1
+- update to 0.99.6
+
+* Fri Sep 16 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
+- Linus noticed that less is required, added to the dependencies
+
+* Sun Sep 11 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
+- Updated dependencies
+- Don't assume manpages are gzipped
+
+* Thu Aug 18 2005 Chris Wright <chrisw@osdl.org> 0.99.4-4
+- drop sh_utils, sh-utils, diffutils, mktemp, and openssl Requires
+- use RPM_OPT_FLAGS in spec file, drop patch0
+
+* Wed Aug 17 2005 Tom "spot" Callaway <tcallawa@redhat.com> 0.99.4-3
+- use dist tag to differentiate between branches
+- use rpm optflags by default (patch0)
+- own %{_datadir}/git-core/
+
+* Mon Aug 15 2005 Chris Wright <chrisw@osdl.org>
+- update spec file to fix Buildroot, Requires, and drop Vendor
+
+* Sun Aug 07 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
+- Redid the description
+- Cut overlong make line, loosened changelog a bit
+- I think Junio (or perhaps OSDL?) should be vendor...
+
+* Thu Jul 14 2005 Eric Biederman <ebiederm@xmission.com>
+- Add the man pages, and the --without docs build option
+
+* Wed Jul 7 2005 Chris Wright <chris@osdl.org>
+- initial git spec file
index b8aa965..21cc1b9 100644 (file)
@@ -425,6 +425,8 @@ static void start_request(struct transfer_request *request)
        rename(request->tmpfile, prevfile);
        unlink(request->tmpfile);
 
        rename(request->tmpfile, prevfile);
        unlink(request->tmpfile);
 
+       if (request->local != -1)
+               error("fd leakage in start: %d", request->local);
        request->local = open(request->tmpfile,
                              O_WRONLY | O_CREAT | O_EXCL, 0666);
        /* This could have failed due to the "lazy directory creation";
        request->local = open(request->tmpfile,
                              O_WRONLY | O_CREAT | O_EXCL, 0666);
        /* This could have failed due to the "lazy directory creation";
@@ -523,7 +525,7 @@ static void start_request(struct transfer_request *request)
        /* Try to get the request started, abort the request on error */
        if (!start_active_slot(slot)) {
                request->state = ABORTED;
        /* Try to get the request started, abort the request on error */
        if (!start_active_slot(slot)) {
                request->state = ABORTED;
-               close(request->local);
+               close(request->local); request->local = -1;
                free(request->url);
                return;
        }
                free(request->url);
                return;
        }
@@ -537,7 +539,7 @@ static void finish_request(struct transfer_request *request)
        struct stat st;
 
        fchmod(request->local, 0444);
        struct stat st;
 
        fchmod(request->local, 0444);
-       close(request->local);
+       close(request->local); request->local = -1;
 
        if (request->http_code == 416) {
                fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
 
        if (request->http_code == 416) {
                fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
@@ -569,6 +571,8 @@ static void release_request(struct transfer_request *request)
 {
        struct transfer_request *entry = request_queue_head;
 
 {
        struct transfer_request *entry = request_queue_head;
 
+       if (request->local != -1)
+               error("fd leakage in release: %d", request->local);
        if (request == request_queue_head) {
                request_queue_head = request->next;
        } else {
        if (request == request_queue_head) {
                request_queue_head = request->next;
        } else {
@@ -631,6 +635,8 @@ static void process_curl_messages(void)
                                        if (request->repo->next != NULL) {
                                                request->repo =
                                                        request->repo->next;
                                        if (request->repo->next != NULL) {
                                                request->repo =
                                                        request->repo->next;
+                                               close(request->local);
+                                                       request->local = -1;
                                                start_request(request);
                                        } else {
                                                finish_request(request);
                                                start_request(request);
                                        } else {
                                                finish_request(request);
@@ -763,6 +769,7 @@ static int fetch_index(struct alt_base *repo, unsigned char *sha1)
                                     curl_errorstr);
                }
        } else {
                                     curl_errorstr);
                }
        } else {
+               fclose(indexfile);
                return error("Unable to start request");
        }
 
                return error("Unable to start request");
        }
 
@@ -1083,6 +1090,7 @@ static int fetch_pack(struct alt_base *repo, unsigned char *sha1)
                                     curl_errorstr);
                }
        } else {
                                     curl_errorstr);
                }
        } else {
+               fclose(packfile);
                return error("Unable to start request");
        }
 
                return error("Unable to start request");
        }
 
@@ -1145,6 +1153,7 @@ static int fetch_object(struct alt_base *repo, unsigned char *sha1)
                        fetch_alternates(alt->base);
                        if (request->repo->next != NULL) {
                                request->repo = request->repo->next;
                        fetch_alternates(alt->base);
                        if (request->repo->next != NULL) {
                                request->repo = request->repo->next;
+                               close(request->local); request->local = -1;
                                start_request(request);
                        }
                } else {
                                start_request(request);
                        }
                } else {
@@ -1153,6 +1162,9 @@ static int fetch_object(struct alt_base *repo, unsigned char *sha1)
                }
 #endif
        }
                }
 #endif
        }
+       if (request->local != -1) {
+               close(request->local); request->local = -1;
+       }
 
        if (request->state == ABORTED) {
                release_request(request);
 
        if (request->state == ABORTED) {
                release_request(request);
index 1fdebe0..427e14c 100644 (file)
--- a/object.c
+++ b/object.c
@@ -67,40 +67,66 @@ void created_object(const unsigned char *sha1, struct object *obj)
        nr_objs++;
 }
 
        nr_objs++;
 }
 
-void add_ref(struct object *refer, struct object *target)
+struct object_refs *alloc_object_refs(unsigned count)
 {
 {
-       struct object_list **pp, *p;
+       struct object_refs *refs;
+       size_t size = sizeof(*refs) + count*sizeof(struct object *);
 
 
-       if (!track_object_refs)
+       refs = xmalloc(size);
+       memset(refs, 0, size);
+       refs->count = count;
+       return refs;
+}
+
+static int compare_object_pointers(const void *a, const void *b)
+{
+       const struct object * const *pa = a;
+       const struct object * const *pb = b;
+       return *pa - *pb;
+}
+
+void set_object_refs(struct object *obj, struct object_refs *refs)
+{
+       unsigned int i, j;
+
+       /* Do not install empty list of references */
+       if (refs->count < 1) {
+               free(refs);
                return;
                return;
+       }
 
 
-       pp = &refer->refs;
-       while ((p = *pp) != NULL) {
-               if (p->item == target)
-                       return;
-               pp = &p->next;
+       /* Sort the list and filter out duplicates */
+       qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
+             compare_object_pointers);
+       for (i = j = 1; i < refs->count; i++) {
+               if (refs->ref[i] != refs->ref[i - 1])
+                       refs->ref[j++] = refs->ref[i];
+       }
+       if (j < refs->count) {
+               /* Duplicates were found - reallocate list */
+               size_t size = sizeof(*refs) + j*sizeof(struct object *);
+               refs->count = j;
+               refs = xrealloc(refs, size);
        }
 
        }
 
-       target->used = 1;
-       p = xmalloc(sizeof(*p));
-       p->item = target;
-       p->next = NULL;
-       *pp = p;
+       for (i = 0; i < refs->count; i++)
+               refs->ref[i]->used = 1;
+       obj->refs = refs;
 }
 
 void mark_reachable(struct object *obj, unsigned int mask)
 {
 }
 
 void mark_reachable(struct object *obj, unsigned int mask)
 {
-       struct object_list *p = obj->refs;
-
        if (!track_object_refs)
                die("cannot do reachability with object refs turned off");
        /* If we've been here already, don't bother */
        if (obj->flags & mask)
                return;
        obj->flags |= mask;
        if (!track_object_refs)
                die("cannot do reachability with object refs turned off");
        /* If we've been here already, don't bother */
        if (obj->flags & mask)
                return;
        obj->flags |= mask;
-       while (p) {
-               mark_reachable(p->item, mask);
-               p = p->next;
+       if (obj->refs) {
+               const struct object_refs *refs = obj->refs;
+               unsigned i;
+               for (i = 0; i < refs->count; i++)
+                       mark_reachable(refs->ref[i], mask);
        }
 }
 
        }
 }
 
index 6accda3..336d986 100644 (file)
--- a/object.h
+++ b/object.h
@@ -7,13 +7,18 @@ struct object_list {
        const char *name;
 };
 
        const char *name;
 };
 
+struct object_refs {
+       unsigned count;
+       struct object *ref[0];
+};
+
 struct object {
        unsigned parsed : 1;
        unsigned used : 1;
        unsigned int flags;
        unsigned char sha1[20];
        const char *type;
 struct object {
        unsigned parsed : 1;
        unsigned used : 1;
        unsigned int flags;
        unsigned char sha1[20];
        const char *type;
-       struct object_list *refs;
+       struct object_refs *refs;
        void *util;
 };
 
        void *util;
 };
 
@@ -35,7 +40,8 @@ struct object *parse_object(const unsigned char *sha1);
 /** Returns the object, with potentially excess memory allocated. **/
 struct object *lookup_unknown_object(const unsigned  char *sha1);
 
 /** Returns the object, with potentially excess memory allocated. **/
 struct object *lookup_unknown_object(const unsigned  char *sha1);
 
-void add_ref(struct object *refer, struct object *target);
+struct object_refs *alloc_object_refs(unsigned count);
+void set_object_refs(struct object *obj, struct object_refs *refs);
 
 void mark_reachable(struct object *obj, unsigned int mask);
 
 
 void mark_reachable(struct object *obj, unsigned int mask);
 
index 28b82ee..fcb36ff 100644 (file)
@@ -127,38 +127,6 @@ inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
        return llist_insert_back(list, sha1);
 }
 
        return llist_insert_back(list, sha1);
 }
 
-/* computes A\B */
-void llist_sorted_difference_inplace(struct llist *A,
-                                    struct llist *B)
-{
-       struct llist_item *prev, *a, *b, *x;
-
-       prev = a = A->front;
-       b = B->front;
-
-       while (a != NULL && b != NULL) {
-               int cmp = memcmp(a->sha1, b->sha1, 20);
-               if (!cmp) {
-                       x = a;
-                       if (a == A->front)
-                               A->front = a->next;
-                       a = prev->next = a->next;
-
-                       if (a == NULL) /* end of list */
-                               A->back = prev;
-                       A->size--;
-                       free(x);
-                       b = b->next;
-               } else
-                       if (cmp > 0)
-                               b = b->next;
-                       else {
-                               prev = a;
-                               a = a->next;
-                       }
-       }
-}
-
 /* returns a pointer to an item in front of sha1 */
 inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
                                               struct llist_item *hint)
 /* returns a pointer to an item in front of sha1 */
 inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
                                               struct llist_item *hint)
@@ -194,6 +162,21 @@ redo_from_start:
        return prev;
 }
 
        return prev;
 }
 
+/* computes A\B */
+void llist_sorted_difference_inplace(struct llist *A,
+                                    struct llist *B)
+{
+       struct llist_item *hint, *b;
+
+       hint = NULL;
+       b = B->front;
+
+       while (b) {
+               hint = llist_sorted_remove(A, b->sha1, hint);
+               b = b->next;
+       }
+}
+
 inline struct pack_list * pack_list_insert(struct pack_list **pl,
                                           struct pack_list *entry)
 {
 inline struct pack_list * pack_list_insert(struct pack_list **pl,
                                           struct pack_list *entry)
 {
diff --git a/refs.c b/refs.c
index a52b038..f324be5 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -121,10 +121,12 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master)
        int fd, len, written;
 
 #if USE_SYMLINK_HEAD
        int fd, len, written;
 
 #if USE_SYMLINK_HEAD
-       unlink(git_HEAD);
-       if (!symlink(refs_heads_master, git_HEAD))
-               return 0;
-       fprintf(stderr, "no symlink - falling back to symbolic ref\n");
+       if (!only_use_symrefs) {
+               unlink(git_HEAD);
+               if (!symlink(refs_heads_master, git_HEAD))
+                       return 0;
+               fprintf(stderr, "no symlink - falling back to symbolic ref\n");
+       }
 #endif
 
        len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
 #endif
 
        len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
index 0cba8e1..e4006f0 100644 (file)
@@ -424,7 +424,6 @@ static void find_pack_info_one(int pack_ix)
 {
        unsigned char sha1[20];
        struct object *o;
 {
        unsigned char sha1[20];
        struct object *o;
-       struct object_list *ref;
        int i;
        struct packed_git *p = info[pack_ix]->p;
        int num = num_packed_objects(p);
        int i;
        struct packed_git *p = info[pack_ix]->p;
        int num = num_packed_objects(p);
@@ -437,8 +436,12 @@ static void find_pack_info_one(int pack_ix)
                        die("corrupt pack file %s?", p->pack_name);
                if ((o = lookup_object(sha1)) == NULL)
                        die("cannot parse %s", sha1_to_hex(sha1));
                        die("corrupt pack file %s?", p->pack_name);
                if ((o = lookup_object(sha1)) == NULL)
                        die("cannot parse %s", sha1_to_hex(sha1));
-               for (ref = o->refs; ref; ref = ref->next)
-                       ref->item->flags = 0;
+               if (o->refs) {
+                       struct object_refs *refs = o->refs;
+                       int j;
+                       for (j = 0; j < refs->count; j++)
+                               refs->ref[j]->flags = 0;
+               }
                o->flags = 0;
        }
 
                o->flags = 0;
        }
 
@@ -448,8 +451,12 @@ static void find_pack_info_one(int pack_ix)
                        die("corrupt pack file %s?", p->pack_name);
                if ((o = lookup_object(sha1)) == NULL)
                        die("cannot find %s", sha1_to_hex(sha1));
                        die("corrupt pack file %s?", p->pack_name);
                if ((o = lookup_object(sha1)) == NULL)
                        die("cannot find %s", sha1_to_hex(sha1));
-               for (ref = o->refs; ref; ref = ref->next)
-                       ref->item->flags |= REFERENCED;
+               if (o->refs) {
+                       struct object_refs *refs = o->refs;
+                       int j;
+                       for (j = 0; j < refs->count; j++)
+                               refs->ref[j]->flags |= REFERENCED;
+               }
                o->flags |= INTERNAL;
        }
 
                o->flags |= INTERNAL;
        }
 
@@ -460,8 +467,12 @@ static void find_pack_info_one(int pack_ix)
                        die("cannot find %s", sha1_to_hex(sha1));
 
                show(o, pack_ix);
                        die("cannot find %s", sha1_to_hex(sha1));
 
                show(o, pack_ix);
-               for (ref = o->refs; ref; ref = ref->next)
-                       show(ref->item, pack_ix);
+               if (o->refs) {
+                       struct object_refs *refs = o->refs;
+                       int j;
+                       for (j = 0; j < refs->count; j++)
+                               show(refs->ref[j], pack_ix);
+               }
        }
 
 }
        }
 
 }
index cd814d7..82a0188 100644 (file)
@@ -424,7 +424,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
        struct packed_git *p;
        unsigned long idx_size;
        void *idx_map;
        struct packed_git *p;
        unsigned long idx_size;
        void *idx_map;
-       char sha1[20];
+       unsigned char sha1[20];
 
        if (check_packed_git_idx(path, &idx_size, &idx_map))
                return NULL;
 
        if (check_packed_git_idx(path, &idx_size, &idx_map))
                return NULL;
index a72d7ac..193c87c 100644 (file)
@@ -20,6 +20,7 @@ static void check_symref(const char *HEAD)
 int main(int argc, const char **argv)
 {
        setup_git_directory();
 int main(int argc, const char **argv)
 {
        setup_git_directory();
+       git_config(git_default_config);
        switch (argc) {
        case 2:
                check_symref(argv[1]);
        switch (argc) {
        case 2:
                check_symref(argv[1]);
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
new file mode 100644 (file)
index 0000000..00bd8b1
--- /dev/null
@@ -0,0 +1,115 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='git-apply handling binary patches
+
+'
+. ./test-lib.sh
+
+# setup
+
+cat >file1 <<EOF
+A quick brown fox jumps over the lazy dog.
+A tiny little penguin runs around in circles.
+There is a flag with Linux written on it.
+A slow black-and-white panda just sits there,
+munching on his bamboo.
+EOF
+cat file1 >file2
+cat file1 >file4
+
+git-update-index --add --remove file1 file2 file4
+git-commit -m 'Initial Version' 2>/dev/null
+
+git-checkout -b binary
+tr 'x' '\0' <file1 >file3
+cat file3 >file4
+git-add file2
+tr '\0' 'v' <file3 >file1
+rm -f file2
+git-update-index --add --remove file1 file2 file3 file4
+git-commit -m 'Second Version'
+
+git-diff-tree -p master binary >B.diff
+git-diff-tree -p -C master binary >C.diff
+
+git-diff-tree -p --full-index master binary >BF.diff
+git-diff-tree -p --full-index -C master binary >CF.diff
+
+test_expect_success 'stat binary diff -- should not fail.' \
+       'git-checkout master
+        git-apply --stat --summary B.diff'
+
+test_expect_success 'stat binary diff (copy) -- should not fail.' \
+       'git-checkout master
+        git-apply --stat --summary C.diff'
+
+test_expect_failure 'check binary diff -- should fail.' \
+       'git-checkout master
+        git-apply --check B.diff'
+
+test_expect_failure 'check binary diff (copy) -- should fail.' \
+       'git-checkout master
+        git-apply --check C.diff'
+
+test_expect_failure 'check incomplete binary diff with replacement -- should fail.' \
+       'git-checkout master
+        git-apply --check --allow-binary-replacement B.diff'
+
+test_expect_failure 'check incomplete binary diff with replacement (copy) -- should fail.' \
+       'git-checkout master
+        git-apply --check --allow-binary-replacement C.diff'
+
+test_expect_success 'check binary diff with replacement.' \
+       'git-checkout master
+        git-apply --check --allow-binary-replacement BF.diff'
+
+test_expect_success 'check binary diff with replacement (copy).' \
+       'git-checkout master
+        git-apply --check --allow-binary-replacement CF.diff'
+
+# Now we start applying them.
+
+do_reset () {
+       rm -f file?
+       git-reset --hard
+       git-checkout -f master
+}
+
+test_expect_failure 'apply binary diff -- should fail.' \
+       'do_reset
+        git-apply B.diff'
+
+test_expect_failure 'apply binary diff -- should fail.' \
+       'do_reset
+        git-apply --index B.diff'
+
+test_expect_failure 'apply binary diff (copy) -- should fail.' \
+       'do_reset
+        git-apply C.diff'
+
+test_expect_failure 'apply binary diff (copy) -- should fail.' \
+       'do_reset
+        git-apply --index C.diff'
+
+test_expect_failure 'apply binary diff without replacement -- should fail.' \
+       'do_reset
+        git-apply BF.diff'
+
+test_expect_failure 'apply binary diff without replacement (copy) -- should fail.' \
+       'do_reset
+        git-apply CF.diff'
+
+test_expect_success 'apply binary diff.' \
+       'do_reset
+        git-apply --allow-binary-replacement --index BF.diff &&
+        test -z "$(git-diff --name-status binary)"'
+
+test_expect_success 'apply binary diff (copy).' \
+       'do_reset
+        git-apply --allow-binary-replacement --index CF.diff &&
+        test -z "$(git-diff --name-status binary)"'
+
+test_done
index a8f239d..e654155 100755 (executable)
@@ -158,6 +158,8 @@ test_done () {
 # Test the binaries we have just built.  The tests are kept in
 # t/ subdirectory and are run in trash subdirectory.
 PATH=$(pwd)/..:$PATH
 # Test the binaries we have just built.  The tests are kept in
 # t/ subdirectory and are run in trash subdirectory.
 PATH=$(pwd)/..:$PATH
+GIT_EXEC_PATH=$(pwd)/..
+export GIT_EXEC_PATH
 
 # Test repository
 test=trash
 
 # Test repository
 test=trash
diff --git a/tag.c b/tag.c
index e574c4b..61ac434 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -75,8 +75,11 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
        item->tag[taglen] = '\0';
 
        item->tagged = lookup_object_type(object, type);
        item->tag[taglen] = '\0';
 
        item->tagged = lookup_object_type(object, type);
-       if (item->tagged)
-               add_ref(&item->object, item->tagged);
+       if (item->tagged && track_object_refs) {
+               struct object_refs *refs = alloc_object_refs(1);
+               refs->ref[0] = item->tagged;
+               set_object_refs(&item->object, refs);
+       }
 
        return 0;
 }
 
        return 0;
 }
diff --git a/tree.c b/tree.c
index 315b6a5..8b42a07 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -148,6 +148,7 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
 {
        void *bufptr = buffer;
        struct tree_entry_list **list_p;
 {
        void *bufptr = buffer;
        struct tree_entry_list **list_p;
+       int n_refs = 0;
 
        if (item->object.parsed)
                return 0;
 
        if (item->object.parsed)
                return 0;
@@ -184,11 +185,21 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
                        obj = &entry->item.blob->object;
                }
                if (obj)
                        obj = &entry->item.blob->object;
                }
                if (obj)
-                       add_ref(&item->object, obj);
+                       n_refs++;
                entry->parent = NULL; /* needs to be filled by the user */
                *list_p = entry;
                list_p = &entry->next;
        }
                entry->parent = NULL; /* needs to be filled by the user */
                *list_p = entry;
                list_p = &entry->next;
        }
+
+       if (track_object_refs) {
+               struct tree_entry_list *entry;
+               unsigned i = 0;
+               struct object_refs *refs = alloc_object_refs(n_refs);
+               for (entry = item->entries; entry; entry = entry->next)
+                       refs->ref[i++] = entry->item.any;
+               set_object_refs(&item->object, refs);
+       }
+
        return 0;
 }
 
        return 0;
 }