Merge early parts of branch 'js/diff'
authorJunio C Hamano <junkio@cox.net>
Thu, 22 Jun 2006 17:32:58 +0000 (10:32 -0700)
committerJunio C Hamano <junkio@cox.net>
Thu, 22 Jun 2006 17:32:58 +0000 (10:32 -0700)
94 files changed:
.gitignore
Documentation/git-clone-pack.txt [deleted file]
Documentation/git-clone.txt
Documentation/git-read-tree.txt
Documentation/git-receive-pack.txt
Documentation/git-repo-config.txt
Documentation/git-send-email.txt
Documentation/git-tar-tree.txt
Documentation/git-upload-pack.txt
Documentation/git-write-tree.txt
Documentation/git.txt
INSTALL
Makefile
alloc.c [new file with mode: 0644]
blame.c
blob.c
builtin-apply.c
builtin-diff-files.c
builtin-diff-index.c
builtin-diff-tree.c
builtin-diff.c
builtin-grep.c
builtin-init-db.c
builtin-log.c
builtin-read-tree.c
builtin-rev-list.c
builtin-show-branch.c
builtin-tar-tree.c
cache-tree.c
cache-tree.h
cache.h
clone-pack.c [deleted file]
commit.c
commit.h
config.c
connect.c
contrib/git-svn/Makefile
contrib/git-svn/git-svn.perl
contrib/git-svn/t/t0002-deep-rmdir.sh [new file with mode: 0644]
convert-objects.c
csum-file.c
daemon.c
date.c
describe.c
diff-delta.c
diff-lib.c
diff.c
diffcore-order.c
environment.c
fetch-clone.c
fetch-pack.c
fetch.c
fsck-objects.c
git-checkout.sh
git-send-email.perl
http-fetch.c
http-push.c
http.c
imap-send.c
merge-index.c
name-rev.c
object-refs.c [new file with mode: 0644]
object.c
object.h
pack-check.c
pack-objects.c
pack-redundant.c
patch-delta.c
path.c
pkt-line.c
pkt-line.h
ppc/sha1.c
quote.c
read-cache.c
repo-config.c
revision.c
revision.h
send-pack.c
server-info.c
setup.c
sha1_file.c
sha1_name.c
ssh-fetch.c
t/Makefile
t/annotate-tests.sh
t/t0000-basic.sh
t/t1300-repo-config.sh
tag.c
tree-walk.c
tree.c
upload-pack.c
write-tree.c
xdiff/xutils.c
xdiff/xutils.h
index afd0876218686c14834ff27b3ad6f0da307da601..65aa939f6b2bafe5bf7c55bf38456eb28b4df0a3 100644 (file)
@@ -17,7 +17,6 @@ git-cherry
 git-cherry-pick
 git-clean
 git-clone
-git-clone-pack
 git-commit
 git-commit-tree
 git-convert-objects
diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt
deleted file mode 100644 (file)
index 09f43ee..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-git-clone-pack(1)
-=================
-
-NAME
-----
-git-clone-pack - Clones a repository by receiving packed objects
-
-
-SYNOPSIS
---------
-'git-clone-pack' [--exec=<git-upload-pack>] [<host>:]<directory> [<head>...]
-
-DESCRIPTION
------------
-Clones a repository into the current repository by invoking
-'git-upload-pack', possibly on the remote host via ssh, in
-the named repository, and stores the sent pack in the local
-repository.
-
-OPTIONS
--------
---exec=<git-upload-pack>::
-       Use this to specify the path to 'git-upload-pack' on the
-       remote side, if it is not found on your $PATH.
-       Installations of sshd ignore the user's environment
-       setup scripts for login shells (e.g. .bash_profile) and
-       your privately installed git may not be found on the system
-       default $PATH.  Another workaround suggested is to set
-       up your $PATH in ".bashrc", but this flag is for people
-       who do not want to pay the overhead for non-interactive
-       shells by having a lean .bashrc file (they set most of
-       the things up in .bash_profile).
-
-<host>::
-       A remote host that houses the repository.  When this
-       part is specified, 'git-upload-pack' is invoked via
-       ssh.
-
-<directory>::
-       The repository to sync from.
-
-<head>...::
-       The heads to update.  This is relative to $GIT_DIR
-       (e.g. "HEAD", "refs/heads/master").  When unspecified,
-       all heads are updated to match the remote repository.
-+
-Usually all the refs from existing repository are stored
-under the same name in the new repository.  Giving explicit
-<head> arguments instead writes the object names and refs to
-the standard output, just like get-fetch-pack does.
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
-
-GIT
----
-Part of the gitlink:git[7] suite
-
index a90521e5139b264d1a37289966da64ea53c862cd..f973c64313699713100ba63822d80fd86979ff78 100644 (file)
@@ -62,7 +62,7 @@ OPTIONS
 --quiet::
 -q::
        Operate quietly.  This flag is passed to "rsync" and
-       "git-clone-pack" commands when given.
+       "git-fetch-pack" commands when given.
 
 -n::
        No checkout of HEAD is performed after the clone is complete.
@@ -85,7 +85,7 @@ OPTIONS
 --upload-pack <upload-pack>::
 -u <upload-pack>::
        When given, and the repository to clone from is handled
-       by 'git-clone-pack', '--exec=<upload-pack>' is passed to
+       by 'git-fetch-pack', '--exec=<upload-pack>' is passed to
        the command to specify non-default path for the command
        run on the other end.
 
index d894f537ba2634ed2719ee746b170a22f0173f56..11bd9c0adc5517ef1aadc76abdb8dfb0827c27b0 100644 (file)
@@ -8,7 +8,7 @@ git-read-tree - Reads tree information into the index
 
 SYNOPSIS
 --------
-'git-read-tree' (<tree-ish> | [[-m [--aggressive]| --reset] [-u | -i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
+'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
 
 
 DESCRIPTION
@@ -63,6 +63,15 @@ OPTIONS
 * when both sides adds a path identically.  The resolution
   is to add that path.
 
+--prefix=<prefix>/::
+       Keep the current index contents, and read the contents
+       of named tree-ish under directory at `<prefix>`.  The
+       original index file cannot have anything at the path
+       `<prefix>` itself, and have nothing in `<prefix>/`
+       directory.  Note that the `<prefix>/` value must end
+       with a slash.
+
+
 <tree-ish#>::
        The id of the tree object(s) to be read/merged.
 
index 60debca48720ad54766287e8770254f57fad9d7b..f9457d45ed684597769124af945c184a7d03a948 100644 (file)
@@ -18,8 +18,7 @@ information fed from the remote end.
 This command is usually not invoked directly by the end user.
 The UI for the protocol is on the 'git-send-pack' side, and the
 program pair is meant to be used to push updates to remote
-repository.  For pull operations, see 'git-fetch-pack' and
-'git-clone-pack'.
+repository.  For pull operations, see 'git-fetch-pack'.
 
 The command allows for creation and fast forwarding of sha1 refs
 (heads/tags) on the remote end (strictly speaking, it is the
index d5142e0dcd6799b8a94c9cd5a3f2bd17c3cb7289..803c0d5cae6db0a953380adc6ee3980a0afa72e0 100644 (file)
@@ -73,6 +73,18 @@ OPTIONS
        List all variables set in .git/config.
 
 
+ENVIRONMENT
+-----------
+
+GIT_CONFIG::
+       Take the configuration from the given file instead of .git/config.
+
+GIT_CONFIG_LOCAL::
+       Currently the same as $GIT_CONFIG; when Git will support global
+       configuration files, this will cause it to take the configuration
+       from the global configuration file in addition to the given file.
+
+
 EXAMPLE
 -------
 
index ad1b9cf2e9b2532c02c0abd3450ecf6272673472..481b3f50e3d690f5cd47ffa2c2d8bb645114e315 100644 (file)
@@ -24,9 +24,16 @@ OPTIONS
 -------
 The options available are:
 
+--bcc::
+       Specify a "Bcc:" value for each email.
+
+       The --bcc option must be repeated for each user you want on the bcc list.
+
 --cc::
        Specify a starting "Cc:" value for each email.
 
+       The --cc option must be repeated for each user you want on the cc list.
+
 --chain-reply-to, --no-chain-reply-to::
        If this is set, each email will be sent as a reply to the previous
        email sent.  If disabled with "--no-chain-reply-to", all emails after
@@ -76,6 +83,8 @@ The options available are:
        Generally, this will be the upstream maintainer of the
        project involved.
 
+       The --to option must be repeated for each user you want on the to list.
+
 
 Author
 ------
index 831537b6ffe5c53b8b1955fe7b4f8bac9a3df60d..f2675c41933fc4f824f871cc9185a6a1bf010d2b 100644 (file)
@@ -39,19 +39,24 @@ OPTIONS
 
 Examples
 --------
-git tar-tree HEAD | (cd /var/tmp/ && mkdir junk && tar Cxf junk -)::
+git tar-tree HEAD junk | (cd /var/tmp/ && tar xf -)::
 
        Create a tar archive that contains the contents of the
        latest commit on the current branch, and extracts it in
        `/var/tmp/junk` directory.
 
-git tar-tree v2.6.17 linux-2.6.17 | gzip >linux-2.6.17.tar.gz
+git tar-tree v1.4.0 git-1.4.0 | gzip >git-1.4.0.tar.gz::
 
-       Create a tarball for v2.6.17 release.
+       Create a tarball for v1.4.0 release.
 
-git tar-tree --remote=example.com:git.git v0.99 >git-0.99.tar
+git tar-tree v1.4.0{caret}\{tree\} git-1.4.0 | gzip >git-1.4.0.tar.gz::
 
-       Get a tarball v0.99 from example.com.
+       Create a tarball for v1.4.0 release, but without a
+       global extended pax header.
+
+git tar-tree --remote=example.com:git.git v1.4.0 >git-1.4.0.tar::
+
+       Get a tarball v1.4.0 from example.com.
 
 Author
 ------
index 4795e9875441a498e225b3aec6223ab4a7a597d3..b2c9307661ebff26269cf3802a06490e0f1ba165 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Invoked by 'git-clone-pack' and/or 'git-fetch-pack', learns what
+Invoked by 'git-fetch-pack', learns what
 objects the other side is missing, and sends them after packing.
 
 This command is usually not invoked directly by the end user.
index 77e12cb949201445ab33992f9ff155f647ce167c..c85fa89c30e25ed026d2e95a2b537798f878e50f 100644 (file)
@@ -8,7 +8,7 @@ git-write-tree - Creates a tree object from the current index
 
 SYNOPSIS
 --------
-'git-write-tree' [--missing-ok]
+'git-write-tree' [--missing-ok] [--prefix=<prefix>/]
 
 DESCRIPTION
 -----------
@@ -30,6 +30,12 @@ OPTIONS
        directory exist in the object database.  This option disables this
        check.
 
+--prefix=<prefix>/::
+       Writes a tree object that represents a subdirectory
+       `<prefix>`.  This can be used to write the tree object
+       for a subproject that is in the named subdirectory.
+
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
index d4472b56d1b11227bc20b8ad3f69a3d42278dd42..51f20c6e67acb8c7eb526fac544992eaec321623 100644 (file)
@@ -192,10 +192,6 @@ the working tree.
 Synching repositories
 ~~~~~~~~~~~~~~~~~~~~~
 
-gitlink:git-clone-pack[1]::
-       Clones a repository into the current repository (engine
-       for ssh and local transport).
-
 gitlink:git-fetch-pack[1]::
        Updates from a remote repository (engine for ssh and
        local transport).
@@ -237,7 +233,7 @@ gitlink:git-update-server-info[1]::
        clients discover references and packs on it.
 
 gitlink:git-upload-pack[1]::
-       Invoked by 'git-clone-pack' and 'git-fetch-pack' to push
+       Invoked by 'git-fetch-pack' to push
        what are asked for.
 
 gitlink:git-upload-tar[1]::
diff --git a/INSTALL b/INSTALL
index 63af8eccf3ce115a992cc3f1dc812e5842e3f75f..f8337e2a4d154157ed805eeb10f52d01513f7adb 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -96,7 +96,7 @@ Issues of note:
 
        $ mkdir manual && cd manual
        $ git init-db
-       $ git clone-pack git://git.kernel.org/pub/scm/git/git.git man html |
+       $ git fetch-pack git://git.kernel.org/pub/scm/git/git.git man html |
          while read a b
          do
            echo $a >.git/$b
index 2a1e6392dddeac520b90e5bccfb841f58018f858..69b5500f3fd5b42d92e981e0add0dae2264fdf16 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -149,7 +149,7 @@ SIMPLE_PROGRAMS = \
 
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS = \
-       git-checkout-index$X git-clone-pack$X \
+       git-checkout-index$X \
        git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
        git-hash-object$X git-index-pack$X git-local-fetch$X \
        git-mailinfo$X git-merge-base$X \
@@ -212,11 +212,11 @@ LIB_OBJS = \
        blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
        date.o diff-delta.o entry.o exec_cmd.o ident.o lockfile.o \
        object.o pack-check.o patch-delta.o path.o pkt-line.o \
-       quote.o read-cache.o refs.o run-command.o dir.o \
+       quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
        server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
        tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
        fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
-       $(DIFF_OBJS)
+       alloc.o $(DIFF_OBJS)
 
 BUILTIN_OBJS = \
        builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
@@ -464,6 +464,7 @@ DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 bindir_SQ = $(subst ','\'',$(bindir))
 gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
 template_dir_SQ = $(subst ','\'',$(template_dir))
+prefix_SQ = $(subst ','\'',$(prefix))
 
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
@@ -471,7 +472,6 @@ PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
 GIT_PYTHON_DIR_SQ = $(subst ','\'',$(GIT_PYTHON_DIR))
 
 ALL_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' $(COMPAT_CFLAGS)
-ALL_CFLAGS += -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
 LIB_OBJS += $(COMPAT_OBJS)
 export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
 ### Build rules
@@ -484,7 +484,7 @@ all:
 strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
 
-git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS)
+git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
        $(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
                $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
@@ -516,7 +516,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) : % : %.perl
        chmod +x $@+
        mv $@+ $@
 
-$(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py
+$(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py GIT-CFLAGS
        rm -f $@ $@+
        sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
            -e 's|@@GIT_PYTHON_PATH@@|$(GIT_PYTHON_DIR_SQ)|g' \
@@ -540,19 +540,21 @@ git$X git.spec \
        $(patsubst %.py,%,$(SCRIPT_PYTHON)) \
        : GIT-VERSION-FILE
 
-%.o: %.c
+%.o: %.c GIT-CFLAGS
        $(CC) -o $*.o -c $(ALL_CFLAGS) $<
 %.o: %.S
        $(CC) -o $*.o -c $(ALL_CFLAGS) $<
 
-exec_cmd.o: exec_cmd.c
+exec_cmd.o: exec_cmd.c GIT-CFLAGS
        $(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $<
+builtin-init-db.o: builtin-init-db.c GIT-CFLAGS
+       $(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
 
-http.o: http.c
+http.o: http.c GIT-CFLAGS
        $(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
 
 ifdef NO_EXPAT
-http-fetch.o: http-fetch.c http.h
+http-fetch.o: http-fetch.c http.h GIT-CFLAGS
        $(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $<
 endif
 
@@ -609,6 +611,17 @@ tags:
        rm -f tags
        find . -name '*.[hcS]' -print | xargs ctags -a
 
+### Detect prefix changes
+TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):$(GIT_PYTHON_DIR_SQ):\
+             $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
+
+GIT-CFLAGS: .FORCE-GIT-CFLAGS
+       @FLAGS='$(TRACK_CFLAGS)'; \
+           if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
+               echo 1>&2 "    * new build flags or prefix"; \
+               echo "$$FLAGS" >GIT-CFLAGS; \
+            fi
+
 ### Testing rules
 
 # GNU make supports exporting all variables by "export" without parameters.
@@ -667,7 +680,7 @@ git.spec: git.spec.in
 
 GIT_TARNAME=git-$(GIT_VERSION)
 dist: git.spec git-tar-tree
-       ./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar
+       ./git-tar-tree HEAD^{tree} $(GIT_TARNAME) > $(GIT_TARNAME).tar
        @mkdir -p $(GIT_TARNAME)
        @cp git.spec $(GIT_TARNAME)
        @echo $(GIT_VERSION) > $(GIT_TARNAME)/version
@@ -711,10 +724,10 @@ clean:
        $(MAKE) -C Documentation/ clean
        $(MAKE) -C templates clean
        $(MAKE) -C t/ clean
-       rm -f GIT-VERSION-FILE
+       rm -f GIT-VERSION-FILE GIT-CFLAGS
 
 .PHONY: all install clean strip
-.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags
+.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags .FORCE-GIT-CFLAGS
 
 ### Check documentation
 #
diff --git a/alloc.c b/alloc.c
new file mode 100644 (file)
index 0000000..e3b22f4
--- /dev/null
+++ b/alloc.c
@@ -0,0 +1,51 @@
+/*
+ * alloc.c  - specialized allocator for internal objects
+ *
+ * Copyright (C) 2006 Linus Torvalds
+ *
+ * The standard malloc/free wastes too much space for objects, partly because
+ * it maintains all the allocation infrastructure (which isn't needed, since
+ * we never free an object descriptor anyway), but even more because it ends
+ * up with maximal alignment because it doesn't know what the object alignment
+ * for the new allocation is.
+ */
+#include "cache.h"
+#include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "tag.h"
+
+#define BLOCKING 1024
+
+#define DEFINE_ALLOCATOR(name)                                 \
+static unsigned int name##_allocs;                             \
+struct name *alloc_##name##_node(void)                         \
+{                                                              \
+       static int nr;                                          \
+       static struct name *block;                              \
+                                                               \
+       if (!nr) {                                              \
+               nr = BLOCKING;                                  \
+               block = xcalloc(BLOCKING, sizeof(struct name)); \
+       }                                                       \
+       nr--;                                                   \
+       name##_allocs++;                                        \
+       return block++;                                         \
+}
+
+DEFINE_ALLOCATOR(blob)
+DEFINE_ALLOCATOR(tree)
+DEFINE_ALLOCATOR(commit)
+DEFINE_ALLOCATOR(tag)
+
+#define REPORT(name)   \
+       fprintf(stderr, "%10s: %8u (%zu kB)\n", #name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
+
+void alloc_report(void)
+{
+       REPORT(blob);
+       REPORT(tree);
+       REPORT(commit);
+       REPORT(tag);
+}
diff --git a/blame.c b/blame.c
index 25d3bcf647f44bbaed1c273d5886df6a7cfe6e03..c86e2fd4b31fc75adf1c315fda166aabc38f0f43 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -110,8 +110,8 @@ static struct patch *get_patch(struct commit *commit, struct commit *other)
        xdemitconf_t xecfg;
        mmfile_t file_c, file_o;
        xdemitcb_t ecb;
-       struct util_info *info_c = (struct util_info *)commit->object.util;
-       struct util_info *info_o = (struct util_info *)other->object.util;
+       struct util_info *info_c = (struct util_info *)commit->util;
+       struct util_info *info_o = (struct util_info *)other->util;
        struct timeval tv_start, tv_end;
 
        get_blob(commit);
@@ -197,7 +197,7 @@ static int get_blob_sha1_internal(const unsigned char *sha1, const char *base,
 
 static void get_blob(struct commit *commit)
 {
-       struct util_info *info = commit->object.util;
+       struct util_info *info = commit->util;
        char type[20];
 
        if (info->buf)
@@ -223,8 +223,8 @@ static void print_patch(struct patch *p)
 /* For debugging only */
 static void print_map(struct commit *cmit, struct commit *other)
 {
-       struct util_info *util = cmit->object.util;
-       struct util_info *util2 = other->object.util;
+       struct util_info *util = cmit->util;
+       struct util_info *util2 = other->util;
 
        int i;
        int max =
@@ -259,8 +259,8 @@ static void print_map(struct commit *cmit, struct commit *other)
 static void fill_line_map(struct commit *commit, struct commit *other,
                          struct patch *p)
 {
-       struct util_info *util = commit->object.util;
-       struct util_info *util2 = other->object.util;
+       struct util_info *util = commit->util;
+       struct util_info *util2 = other->util;
        int *map = util->line_map;
        int *map2 = util2->line_map;
        int cur_chunk = 0;
@@ -301,9 +301,9 @@ static void fill_line_map(struct commit *commit, struct commit *other,
                                if (DEBUG)
                                        printf("map: i1: %d %d %p i2: %d %d %p\n",
                                               i1, map[i1],
-                                              i1 != -1 ? blame_lines[map[i1]] : NULL,
+                                              (void *) (i1 != -1 ? blame_lines[map[i1]] : NULL),
                                               i2, map2[i2],
-                                              i2 != -1 ? blame_lines[map2[i2]] : NULL);
+                                              (void *) (i2 != -1 ? blame_lines[map2[i2]] : NULL));
                                if (map2[i2] != -1 &&
                                    blame_lines[map[i1]] &&
                                    !blame_lines[map2[i2]])
@@ -322,14 +322,14 @@ static void fill_line_map(struct commit *commit, struct commit *other,
 
 static int map_line(struct commit *commit, int line)
 {
-       struct util_info *info = commit->object.util;
+       struct util_info *info = commit->util;
        assert(line >= 0 && line < info->num_lines);
        return info->line_map[line];
 }
 
 static struct util_info* get_util(struct commit *commit)
 {
-       struct util_info *util = commit->object.util;
+       struct util_info *util = commit->util;
 
        if (util)
                return util;
@@ -340,13 +340,13 @@ static struct util_info* get_util(struct commit *commit)
        util->line_map = NULL;
        util->num_lines = -1;
        util->pathname = NULL;
-       commit->object.util = util;
+       commit->util = util;
        return util;
 }
 
 static int fill_util_info(struct commit *commit)
 {
-       struct util_info *util = commit->object.util;
+       struct util_info *util = commit->util;
 
        assert(util);
        assert(util->pathname);
@@ -359,7 +359,7 @@ static int fill_util_info(struct commit *commit)
 
 static void alloc_line_map(struct commit *commit)
 {
-       struct util_info *util = commit->object.util;
+       struct util_info *util = commit->util;
        int i;
 
        if (util->line_map)
@@ -383,7 +383,7 @@ static void alloc_line_map(struct commit *commit)
 
 static void init_first_commit(struct commit* commit, const char* filename)
 {
-       struct util_info* util = commit->object.util;
+       struct util_info* util = commit->util;
        int i;
 
        util->pathname = filename;
@@ -392,7 +392,7 @@ static void init_first_commit(struct commit* commit, const char* filename)
 
        alloc_line_map(commit);
 
-       util = commit->object.util;
+       util = commit->util;
 
        for (i = 0; i < util->num_lines; i++)
                util->line_map[i] = i;
@@ -413,7 +413,7 @@ static void process_commits(struct rev_info *rev, const char *path,
        assert(commit);
        init_first_commit(commit, path);
 
-       util = commit->object.util;
+       util = commit->util;
        num_blame_lines = util->num_lines;
        blame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);
        blame_contents = util->buf;
@@ -452,7 +452,7 @@ static void process_commits(struct rev_info *rev, const char *path,
                        continue;
 
                alloc_line_map(commit);
-               util = commit->object.util;
+               util = commit->util;
 
                for (parents = commit->parents;
                     parents != NULL; parents = parents->next) {
@@ -512,7 +512,7 @@ static int compare_tree_path(struct rev_info* revs,
 {
        int ret;
        const char* paths[2];
-       struct util_info* util = c2->object.util;
+       struct util_info* util = c2->util;
        paths[0] = util->pathname;
        paths[1] = NULL;
 
@@ -541,7 +541,7 @@ static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
 
 static const char* find_rename(struct commit* commit, struct commit* parent)
 {
-       struct util_info* cutil = commit->object.util;
+       struct util_info* cutil = commit->util;
        struct diff_options diff_opts;
        const char *paths[1];
        int i;
@@ -585,7 +585,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit)
                return;
 
        if (!commit->parents) {
-               struct util_info* util = commit->object.util;
+               struct util_info* util = commit->util;
                if (!same_tree_as_empty_path(revs, commit->tree,
                                             util->pathname))
                        commit->object.flags |= TREECHANGE;
@@ -612,7 +612,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit)
                case REV_TREE_NEW:
                {
 
-                       struct util_info* util = commit->object.util;
+                       struct util_info* util = commit->util;
                        if (revs->remove_empty_trees &&
                            same_tree_as_empty_path(revs, p->tree,
                                                    util->pathname)) {
@@ -709,13 +709,13 @@ static const char* format_time(unsigned long time, const char* tz_str,
 
 static void topo_setter(struct commit* c, void* data)
 {
-       struct util_info* util = c->object.util;
+       struct util_info* util = c->util;
        util->topo_data = data;
 }
 
 static void* topo_getter(struct commit* c)
 {
-       struct util_info* util = c->object.util;
+       struct util_info* util = c->util;
        return util->topo_data;
 }
 
@@ -863,7 +863,7 @@ int main(int argc, const char **argv)
                struct util_info* u;
                if (!c)
                        c = initial;
-               u = c->object.util;
+               u = c->util;
 
                if (!found_rename && strcmp(filename, u->pathname))
                        found_rename = 1;
@@ -881,7 +881,7 @@ int main(int argc, const char **argv)
                if (!c)
                        c = initial;
 
-               u = c->object.util;
+               u = c->util;
                get_commit_info(c, &ci);
                fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
                if(compability) {
diff --git a/blob.c b/blob.c
index c1fdd861c3dedbbd670fcf07989501fd0f9b5fda..496f270043a617242efa9d27285853feb2597484 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -8,16 +8,16 @@ struct blob *lookup_blob(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj) {
-               struct blob *ret = xcalloc(1, sizeof(struct blob));
+               struct blob *ret = alloc_blob_node();
                created_object(sha1, &ret->object);
-               ret->object.type = blob_type;
+               ret->object.type = TYPE_BLOB;
                return ret;
        }
        if (!obj->type)
-               obj->type = blob_type;
-       if (obj->type != blob_type) {
-               error("Object %s is a %s, not a blob", 
-                     sha1_to_hex(sha1), obj->type);
+               obj->type = TYPE_BLOB;
+       if (obj->type != TYPE_BLOB) {
+               error("Object %s is a %s, not a blob",
+                     sha1_to_hex(sha1), typename(obj->type));
                return NULL;
        }
        return (struct blob *) obj;
index e113c74dd80d458116788500baca2740cfaa9a00..6dd0472ae07cac291d26b9e547a92c7c51d569df 100644 (file)
@@ -148,7 +148,7 @@ static void *read_patch_file(int fd, unsigned long *sizep)
                        buffer = xrealloc(buffer, alloc);
                        nr = alloc - size;
                }
-               nr = xread(fd, buffer + size, nr);
+               nr = xread(fd, (char *) buffer + size, nr);
                if (!nr)
                        break;
                if (nr < 0)
@@ -164,7 +164,7 @@ static void *read_patch_file(int fd, unsigned long *sizep)
         */
        if (alloc < size + SLOP)
                buffer = xrealloc(buffer, size + SLOP);
-       memset(buffer + size, 0, SLOP);
+       memset((char *) buffer + size, 0, SLOP);
        return buffer;
 }
 
@@ -1194,7 +1194,7 @@ static int read_old_data(struct stat *st, const char *path, void *buf, unsigned
                        return error("unable to open %s", path);
                got = 0;
                for (;;) {
-                       int ret = xread(fd, buf + got, size - got);
+                       int ret = xread(fd, (char *) buf + got, size - got);
                        if (ret <= 0)
                                break;
                        got += ret;
index cebda828eec4e90f3d0af050e07a53071b39d5b7..5afc1d7208f8a13b7363be2127cad3b43baa95dd 100644 (file)
@@ -41,7 +41,7 @@ int cmd_diff_files(int argc, const char **argv, char **envp)
         * rev.max_count is reasonable (0 <= n <= 3),
         * there is no other revision filtering parameters.
         */
-       if (rev.pending_objects ||
+       if (rev.pending.nr ||
            rev.min_age != -1 || rev.max_age != -1)
                usage(diff_files_usage);
        /*
index 1958580d82e54ab5a5b1e054263eab7264c4bcb2..c42ef9a7a76e7d8f6bc25d593865b9343d4e74b5 100644 (file)
@@ -32,7 +32,7 @@ int cmd_diff_index(int argc, const char **argv, char **envp)
         * Make sure there is one revision (i.e. pending object),
         * and there is no revision filtering parameters.
         */
-       if (!rev.pending_objects || rev.pending_objects->next ||
+       if (rev.pending.nr != 1 ||
            rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
                usage(diff_cache_usage);
        return run_diff_index(&rev, cached);
index 58cf65856d1e9e0ab088dab2c051058cf48cb840..3409a39a9f73f9ed67547f5cc79619c1e402f47b 100644 (file)
@@ -65,7 +65,6 @@ int cmd_diff_tree(int argc, const char **argv, char **envp)
        char line[1000];
        struct object *tree1, *tree2;
        static struct rev_info *opt = &log_tree_opt;
-       struct object_list *list;
        int read_stdin = 0;
 
        git_config(git_diff_config);
@@ -86,45 +85,28 @@ int cmd_diff_tree(int argc, const char **argv, char **envp)
        }
 
        /*
-        * NOTE! "setup_revisions()" will have inserted the revisions
-        * it parsed in reverse order. So if you do
-        *
-        *      git-diff-tree a b
-        *
-        * the commit list will be "b" -> "a" -> NULL, so we reverse
-        * the order of the objects if the first one is not marked
-        * UNINTERESTING.
+        * NOTE! We expect "a ^b" to be equal to "a..b", so we
+        * reverse the order of the objects if the second one
+        * is marked UNINTERESTING.
         */
-       nr_sha1 = 0;
-       list = opt->pending_objects;
-       if (list) {
-               nr_sha1++;
-               tree1 = list->item;
-               list = list->next;
-               if (list) {
-                       nr_sha1++;
-                       tree2 = tree1;
-                       tree1 = list->item;
-                       if (list->next)
-                               usage(diff_tree_usage);
-                       /* Switch them around if the second one was uninteresting.. */
-                       if (tree2->flags & UNINTERESTING) {
-                               struct object *tmp = tree2;
-                               tree2 = tree1;
-                               tree1 = tmp;
-                       }
-               }
-       }
-
+       nr_sha1 = opt->pending.nr;
        switch (nr_sha1) {
        case 0:
                if (!read_stdin)
                        usage(diff_tree_usage);
                break;
        case 1:
+               tree1 = opt->pending.objects[0].item;
                diff_tree_commit_sha1(tree1->sha1);
                break;
        case 2:
+               tree1 = opt->pending.objects[0].item;
+               tree2 = opt->pending.objects[1].item;
+               if (tree2->flags & UNINTERESTING) {
+                       struct object *tmp = tree2;
+                       tree2 = tree1;
+                       tree1 = tmp;
+               }
                diff_tree_sha1(tree1->sha1,
                               tree2->sha1,
                               "", &opt->diffopt);
index 27451d56134e08364c33c26d5074693dd4437d31..99a2f766055d6c8c3231e38bd369169d3c742782 100644 (file)
@@ -50,7 +50,7 @@ static int builtin_diff_files(struct rev_info *revs,
         * specified rev.max_count is reasonable (0 <= n <= 3), and
         * there is no other revision filtering parameter.
         */
-       if (revs->pending_objects ||
+       if (revs->pending.nr ||
            revs->min_age != -1 ||
            revs->max_age != -1 ||
            3 < revs->max_count)
@@ -172,7 +172,7 @@ static int builtin_diff_index(struct rev_info *revs,
         * Make sure there is one revision (i.e. pending object),
         * and there is no revision filtering parameters.
         */
-       if (!revs->pending_objects || revs->pending_objects->next ||
+       if (revs->pending.nr != 1 ||
            revs->max_count != -1 || revs->min_age != -1 ||
            revs->max_age != -1)
                usage(builtin_diff_usage);
@@ -181,10 +181,10 @@ static int builtin_diff_index(struct rev_info *revs,
 
 static int builtin_diff_tree(struct rev_info *revs,
                             int argc, const char **argv,
-                            struct object_list *ent)
+                            struct object_array_entry *ent)
 {
        const unsigned char *(sha1[2]);
-       int swap = 1;
+       int swap = 0;
        while (1 < argc) {
                const char *arg = argv[1];
                if (!strcmp(arg, "--raw"))
@@ -195,10 +195,10 @@ static int builtin_diff_tree(struct rev_info *revs,
        }
 
        /* We saw two trees, ent[0] and ent[1].
-        * unless ent[0] is unintesting, they are swapped
+        * if ent[1] is unintesting, they are swapped
         */
-       if (ent[0].item->flags & UNINTERESTING)
-               swap = 0;
+       if (ent[1].item->flags & UNINTERESTING)
+               swap = 1;
        sha1[swap] = ent[0].item->sha1;
        sha1[1-swap] = ent[1].item->sha1;
        diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
@@ -208,7 +208,7 @@ static int builtin_diff_tree(struct rev_info *revs,
 
 static int builtin_diff_combined(struct rev_info *revs,
                                 int argc, const char **argv,
-                                struct object_list *ent,
+                                struct object_array_entry *ent,
                                 int ents)
 {
        const unsigned char (*parent)[20];
@@ -242,13 +242,14 @@ void add_head(struct rev_info *revs)
        obj = parse_object(sha1);
        if (!obj)
                return;
-       add_object(obj, &revs->pending_objects, NULL, "HEAD");
+       add_pending_object(revs, obj, "HEAD");
 }
 
 int cmd_diff(int argc, const char **argv, char **envp)
 {
+       int i;
        struct rev_info rev;
-       struct object_list *list, ent[100];
+       struct object_array_entry ent[100];
        int ents = 0, blobs = 0, paths = 0;
        const char *path = NULL;
        struct blobinfo blob[2];
@@ -281,7 +282,7 @@ int cmd_diff(int argc, const char **argv, char **envp)
        /* Do we have --cached and not have a pending object, then
         * default to HEAD by hand.  Eek.
         */
-       if (!rev.pending_objects) {
+       if (!rev.pending.nr) {
                int i;
                for (i = 1; i < argc; i++) {
                        const char *arg = argv[i];
@@ -294,7 +295,8 @@ int cmd_diff(int argc, const char **argv, char **envp)
                }
        }
 
-       for (list = rev.pending_objects; list; list = list->next) {
+       for (i = 0; i < rev.pending.nr; i++) {
+               struct object_array_entry *list = rev.pending.objects+i;
                struct object *obj = list->item;
                const char *name = list->name;
                int flags = (obj->flags & UNINTERESTING);
@@ -303,9 +305,9 @@ int cmd_diff(int argc, const char **argv, char **envp)
                obj = deref_tag(obj, NULL, 0);
                if (!obj)
                        die("invalid object '%s' given.", name);
-               if (!strcmp(obj->type, commit_type))
+               if (obj->type == TYPE_COMMIT)
                        obj = &((struct commit *)obj)->tree->object;
-               if (!strcmp(obj->type, tree_type)) {
+               if (obj->type == TYPE_TREE) {
                        if (ARRAY_SIZE(ent) <= ents)
                                die("more than %d trees given: '%s'",
                                    (int) ARRAY_SIZE(ent), name);
@@ -315,7 +317,7 @@ int cmd_diff(int argc, const char **argv, char **envp)
                        ents++;
                        continue;
                }
-               if (!strcmp(obj->type, blob_type)) {
+               if (obj->type == TYPE_BLOB) {
                        if (2 <= blobs)
                                die("more than two blobs given: '%s'", name);
                        memcpy(blob[blobs].sha1, obj->sha1, 20);
index 5fac5701e6ccebdbe83b00d2e2df19343d3aea0e..2e7986cecefc964f665b10d363569951c1f40293 100644 (file)
@@ -29,10 +29,11 @@ static int pathspec_matches(const char **paths, const char *name)
                int matchlen = strlen(match);
                const char *cp, *meta;
 
-               if ((matchlen <= namelen) &&
-                   !strncmp(name, match, matchlen) &&
-                   (match[matchlen-1] == '/' ||
-                    name[matchlen] == '\0' || name[matchlen] == '/'))
+               if (!matchlen ||
+                   ((matchlen <= namelen) &&
+                    !strncmp(name, match, matchlen) &&
+                    (match[matchlen-1] == '/' ||
+                     name[matchlen] == '\0' || name[matchlen] == '/')))
                        return 1;
                if (!fnmatch(match, name, 0))
                        return 1;
@@ -630,10 +631,9 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
 static int grep_object(struct grep_opt *opt, const char **paths,
                       struct object *obj, const char *name)
 {
-       if (!strcmp(obj->type, blob_type))
+       if (obj->type == TYPE_BLOB)
                return grep_sha1(opt, obj->sha1, name);
-       if (!strcmp(obj->type, commit_type) ||
-           !strcmp(obj->type, tree_type)) {
+       if (obj->type == TYPE_COMMIT || obj->type == TYPE_TREE) {
                struct tree_desc tree;
                void *data;
                int hit;
@@ -646,7 +646,7 @@ static int grep_object(struct grep_opt *opt, const char **paths,
                free(data);
                return hit;
        }
-       die("unable to grep from object of type %s", obj->type);
+       die("unable to grep from object of type %s", typename(obj->type));
 }
 
 static const char builtin_grep_usage[] =
@@ -658,7 +658,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
        int cached = 0;
        int seen_dashdash = 0;
        struct grep_opt opt;
-       struct object_list *list, **tail, *object_list = NULL;
+       struct object_array list = { 0, 0, NULL };
        const char *prefix = setup_git_directory();
        const char **paths = NULL;
        int i;
@@ -678,7 +678,6 @@ int cmd_grep(int argc, const char **argv, char **envp)
         * that continues up to the -- (if exists), and then paths.
         */
 
-       tail = &object_list;
        while (1 < argc) {
                const char *arg = argv[1];
                argc--; argv++;
@@ -852,12 +851,9 @@ int cmd_grep(int argc, const char **argv, char **envp)
                /* Is it a rev? */
                if (!get_sha1(arg, sha1)) {
                        struct object *object = parse_object(sha1);
-                       struct object_list *elem;
                        if (!object)
                                die("bad object %s", arg);
-                       elem = object_list_insert(object, tail);
-                       elem->name = arg;
-                       tail = &elem->next;
+                       add_object_array(object, arg, &list);
                        continue;
                }
                if (!strcmp(arg, "--")) {
@@ -882,16 +878,16 @@ int cmd_grep(int argc, const char **argv, char **envp)
                paths[1] = NULL;
        }
 
-       if (!object_list)
+       if (!list.nr)
                return !grep_cache(&opt, paths, cached);
 
        if (cached)
                die("both --cached and trees are given.");
 
-       for (list = object_list; list; list = list->next) {
+       for (i = 0; i < list.nr; i++) {
                struct object *real_obj;
-               real_obj = deref_tag(list->item, NULL, 0);
-               if (grep_object(&opt, paths, real_obj, list->name))
+               real_obj = deref_tag(list.objects[i].item, NULL, 0);
+               if (grep_object(&opt, paths, real_obj, list.objects[i].name))
                        hit = 1;
        }
        return !hit;
index 6a24e9bcab4a7b364b69f9ccf2ae822c40873895..7fdd2fa9f9f7fb2801c6e1fc398f78b414a269e1 100644 (file)
@@ -263,7 +263,9 @@ int cmd_init_db(int argc, const char **argv, char **envp)
                if (!strncmp(arg, "--template=", 11))
                        template_dir = arg+11;
                else if (!strcmp(arg, "--shared"))
-                       shared_repository = 1;
+                       shared_repository = PERM_GROUP;
+               else if (!strncmp(arg, "--shared=", 9))
+                       shared_repository = git_config_perm("arg", arg+9);
                else
                        die(init_db_usage);
        }
@@ -301,8 +303,15 @@ int cmd_init_db(int argc, const char **argv, char **envp)
        strcpy(path+len, "/info");
        safe_create_dir(path, 1);
 
-       if (shared_repository)
-               git_config_set("core.sharedrepository", "true");
+       if (shared_repository) {
+               char buf[10];
+               /* We do not spell "group" and such, so that
+                * the configuration can be read by older version
+                * of git.
+                */
+               sprintf(buf, "%d", shared_repository);
+               git_config_set("core.sharedrepository", buf);
+       }
 
        return 0;
 }
index f4d974a7b8bfa0472a110273edf62b34b90902fe..5a8a50b81dabea4ccd9b0ba0fcb5d925a00560d0 100644 (file)
@@ -40,6 +40,8 @@ static int cmd_log_wc(int argc, const char **argv, char **envp,
                log_tree_commit(rev, commit);
                free(commit->buffer);
                commit->buffer = NULL;
+               free_commit_list(commit->parents);
+               commit->parents = NULL;
        }
        return 0;
 }
@@ -218,8 +220,11 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
                }
                else if (!strcmp(argv[i], "--signoff") ||
                         !strcmp(argv[i], "-s")) {
-                       const char *committer = git_committer_info(1);
-                       const char *endpos = strchr(committer, '>');
+                       const char *committer;
+                       const char *endpos;
+                       setup_ident();
+                       committer = git_committer_info(1);
+                       endpos = strchr(committer, '>');
                        if (!endpos)
                                die("bogos committer info %s\n", committer);
                        add_signoff = xmalloc(endpos - committer + 2);
@@ -252,8 +257,8 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
                            output_directory);
        }
 
-       if (rev.pending_objects && rev.pending_objects->next == NULL) {
-               rev.pending_objects->item->flags |= UNINTERESTING;
+       if (rev.pending.nr == 1) {
+               rev.pending.objects[0].item->flags |= UNINTERESTING;
                add_head(&rev);
        }
 
index bb50fbd274e2d7e73fc3c6f86a73bd22f636400e..9a2099d7307903d62c85f3483a22969ab5094c84 100644 (file)
@@ -24,14 +24,14 @@ static int trivial_merges_only = 0;
 static int aggressive = 0;
 static int verbose_update = 0;
 static volatile int progress_update = 0;
+static const char *prefix = NULL;
 
 static int head_idx = -1;
 static int merge_size = 0;
 
 static struct object_list *trees = NULL;
 
-static struct cache_entry df_conflict_entry = {
-};
+static struct cache_entry df_conflict_entry;
 
 struct tree_entry_list {
        struct tree_entry_list *next;
@@ -412,7 +412,8 @@ static int unpack_trees(merge_fn_t fn)
                        posns[i] = create_tree_entry_list((struct tree *) posn->item);
                        posn = posn->next;
                }
-               if (unpack_trees_rec(posns, len, "", fn, &indpos))
+               if (unpack_trees_rec(posns, len, prefix ? prefix : "",
+                                    fn, &indpos))
                        return -1;
        }
 
@@ -761,6 +762,28 @@ static int twoway_merge(struct cache_entry **src)
                return deleted_entry(oldtree, current);
 }
 
+/*
+ * Bind merge.
+ *
+ * Keep the index entries at stage0, collapse stage1 but make sure
+ * stage0 does not have anything there.
+ */
+static int bind_merge(struct cache_entry **src)
+{
+       struct cache_entry *old = src[0];
+       struct cache_entry *a = src[1];
+
+       if (merge_size != 1)
+               return error("Cannot do a bind merge of %d trees\n",
+                            merge_size);
+       if (a && old)
+               die("Entry '%s' overlaps.  Cannot bind.", a->name);
+       if (!a)
+               return keep_entry(old);
+       else
+               return merged_entry(a, NULL);
+}
+
 /*
  * One-way merge.
  *
@@ -851,7 +874,7 @@ static void prime_cache_tree(void)
 
 }
 
-static const char read_tree_usage[] = "git-read-tree (<sha> | -m [--aggressive] [-u | -i] <sha1> [<sha2> [<sha3>]])";
+static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] <sha1> [<sha2> [<sha3>]])";
 
 static struct lock_file lock_file;
 
@@ -896,12 +919,27 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
                        continue;
                }
 
+               /* "--prefix=<subdirectory>/" means keep the current index
+                *  entries and put the entries from the tree under the
+                * given subdirectory.
+                */
+               if (!strncmp(arg, "--prefix=", 9)) {
+                       if (stage || merge || prefix)
+                               usage(read_tree_usage);
+                       prefix = arg + 9;
+                       merge = 1;
+                       stage = 1;
+                       if (read_cache_unmerged())
+                               die("you need to resolve your current index first");
+                       continue;
+               }
+
                /* This differs from "-m" in that we'll silently ignore
                 * unmerged entries and overwrite working tree files that
                 * correspond to them.
                 */
                if (!strcmp(arg, "--reset")) {
-                       if (stage || merge)
+                       if (stage || merge || prefix)
                                usage(read_tree_usage);
                        reset = 1;
                        merge = 1;
@@ -922,7 +960,7 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
 
                /* "-m" stands for "merge", meaning we start in stage 1 */
                if (!strcmp(arg, "-m")) {
-                       if (stage || merge)
+                       if (stage || merge || prefix)
                                usage(read_tree_usage);
                        if (read_cache_unmerged())
                                die("you need to resolve your current index first");
@@ -944,12 +982,31 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
        if ((update||index_only) && !merge)
                usage(read_tree_usage);
 
+       if (prefix) {
+               int pfxlen = strlen(prefix);
+               int pos;
+               if (prefix[pfxlen-1] != '/')
+                       die("prefix must end with /");
+               if (stage != 2)
+                       die("binding merge takes only one tree");
+               pos = cache_name_pos(prefix, pfxlen);
+               if (0 <= pos)
+                       die("corrupt index file");
+               pos = -pos-1;
+               if (pos < active_nr &&
+                   !strncmp(active_cache[pos]->name, prefix, pfxlen))
+                       die("subdirectory '%s' already exists.", prefix);
+               pos = cache_name_pos(prefix, pfxlen-1);
+               if (0 <= pos)
+                       die("file '%.*s' already exists.", pfxlen-1, prefix);
+       }
+
        if (merge) {
                if (stage < 2)
                        die("just how do you expect me to merge %d trees?", stage-1);
                switch (stage - 1) {
                case 1:
-                       fn = oneway_merge;
+                       fn = prefix ? bind_merge : oneway_merge;
                        break;
                case 2:
                        fn = twoway_merge;
@@ -975,7 +1032,7 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
         * valid cache-tree because the index must match exactly
         * what came from the tree.
         */
-       if (trees && trees->item && (!merge || (stage == 2))) {
+       if (trees && trees->item && !prefix && (!merge || (stage == 2))) {
                cache_tree_free(&active_cache_tree);
                prime_cache_tree();
        }
index e885624255ac8e1007df797d339e3e81020f95a2..63bad0e96ade657bef21d9ca0e0de2e0ba8af61c 100644 (file)
@@ -89,28 +89,36 @@ static void show_commit(struct commit *commit)
                printf("%s%c", pretty_header, hdr_termination);
        }
        fflush(stdout);
+       if (commit->parents) {
+               free_commit_list(commit->parents);
+               commit->parents = NULL;
+       }
+       if (commit->buffer) {
+               free(commit->buffer);
+               commit->buffer = NULL;
+       }
 }
 
-static struct object_list **process_blob(struct blob *blob,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
+static void process_blob(struct blob *blob,
+                        struct object_array *p,
+                        struct name_path *path,
+                        const char *name)
 {
        struct object *obj = &blob->object;
 
        if (!revs.blob_objects)
-               return p;
+               return;
        if (obj->flags & (UNINTERESTING | SEEN))
-               return p;
+               return;
        obj->flags |= SEEN;
        name = strdup(name);
-       return add_object(obj, p, path, name);
+       add_object(obj, p, path, name);
 }
 
-static struct object_list **process_tree(struct tree *tree,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
+static void process_tree(struct tree *tree,
+                        struct object_array *p,
+                        struct name_path *path,
+                        const char *name)
 {
        struct object *obj = &tree->object;
        struct tree_desc desc;
@@ -118,14 +126,14 @@ static struct object_list **process_tree(struct tree *tree,
        struct name_path me;
 
        if (!revs.tree_objects)
-               return p;
+               return;
        if (obj->flags & (UNINTERESTING | SEEN))
-               return p;
+               return;
        if (parse_tree(tree) < 0)
                die("bad tree object %s", sha1_to_hex(obj->sha1));
        obj->flags |= SEEN;
        name = strdup(name);
-       p = add_object(obj, p, path, name);
+       add_object(obj, p, path, name);
        me.up = path;
        me.elem = name;
        me.elem_len = strlen(name);
@@ -135,57 +143,59 @@ static struct object_list **process_tree(struct tree *tree,
 
        while (tree_entry(&desc, &entry)) {
                if (S_ISDIR(entry.mode))
-                       p = process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
+                       process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
                else
-                       p = process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
+                       process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
        }
        free(tree->buffer);
        tree->buffer = NULL;
-       return p;
 }
 
 static void show_commit_list(struct rev_info *revs)
 {
+       int i;
        struct commit *commit;
-       struct object_list *objects = NULL, **p = &objects, *pending;
+       struct object_array objects = { 0, 0, NULL };
 
        while ((commit = get_revision(revs)) != NULL) {
-               p = process_tree(commit->tree, p, NULL, "");
+               process_tree(commit->tree, &objects, NULL, "");
                show_commit(commit);
        }
-       for (pending = revs->pending_objects; pending; pending = pending->next) {
+       for (i = 0; i < revs->pending.nr; i++) {
+               struct object_array_entry *pending = revs->pending.objects + i;
                struct object *obj = pending->item;
                const char *name = pending->name;
                if (obj->flags & (UNINTERESTING | SEEN))
                        continue;
-               if (obj->type == tag_type) {
+               if (obj->type == TYPE_TAG) {
                        obj->flags |= SEEN;
-                       p = add_object(obj, p, NULL, name);
+                       add_object_array(obj, name, &objects);
                        continue;
                }
-               if (obj->type == tree_type) {
-                       p = process_tree((struct tree *)obj, p, NULL, name);
+               if (obj->type == TYPE_TREE) {
+                       process_tree((struct tree *)obj, &objects, NULL, name);
                        continue;
                }
-               if (obj->type == blob_type) {
-                       p = process_blob((struct blob *)obj, p, NULL, name);
+               if (obj->type == TYPE_BLOB) {
+                       process_blob((struct blob *)obj, &objects, NULL, name);
                        continue;
                }
                die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
        }
-       while (objects) {
+       for (i = 0; i < objects.nr; i++) {
+               struct object_array_entry *p = objects.objects + i;
+
                /* An object with name "foo\n0000000..." can be used to
                 * confuse downstream git-pack-objects very badly.
                 */
-               const char *ep = strchr(objects->name, '\n');
+               const char *ep = strchr(p->name, '\n');
                if (ep) {
-                       printf("%s %.*s\n", sha1_to_hex(objects->item->sha1),
-                              (int) (ep - objects->name),
-                              objects->name);
+                       printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
+                              (int) (ep - p->name),
+                              p->name);
                }
                else
-                       printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name);
-               objects = objects->next;
+                       printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
        }
 }
 
@@ -340,7 +350,7 @@ int cmd_rev_list(int argc, const char **argv, char **envp)
 
        if ((!list &&
             (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
-             !revs.pending_objects)) ||
+             !revs.pending.nr)) ||
            revs.diff)
                usage(rev_list_usage);
 
index 2895140915cb603e2c5f971d0356f2e48106bc0e..09d82278625584213f710a984652a7efc07339c5 100644 (file)
@@ -15,7 +15,7 @@ static const char **default_arg = NULL;
 #define UNINTERESTING  01
 
 #define REV_SHIFT       2
-#define MAX_REVS       29 /* should not exceed bits_per_int - REV_SHIFT */
+#define MAX_REVS       (FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
 
 static struct commit *interesting(struct commit_list *list)
 {
@@ -51,9 +51,9 @@ struct commit_name {
 static void name_commit(struct commit *commit, const char *head_name, int nth)
 {
        struct commit_name *name;
-       if (!commit->object.util)
-               commit->object.util = xmalloc(sizeof(struct commit_name));
-       name = commit->object.util;
+       if (!commit->util)
+               commit->util = xmalloc(sizeof(struct commit_name));
+       name = commit->util;
        name->head_name = head_name;
        name->generation = nth;
 }
@@ -65,8 +65,8 @@ static void name_commit(struct commit *commit, const char *head_name, int nth)
  */
 static void name_parent(struct commit *commit, struct commit *parent)
 {
-       struct commit_name *commit_name = commit->object.util;
-       struct commit_name *parent_name = parent->object.util;
+       struct commit_name *commit_name = commit->util;
+       struct commit_name *parent_name = parent->util;
        if (!commit_name)
                return;
        if (!parent_name ||
@@ -80,12 +80,12 @@ static int name_first_parent_chain(struct commit *c)
        int i = 0;
        while (c) {
                struct commit *p;
-               if (!c->object.util)
+               if (!c->util)
                        break;
                if (!c->parents)
                        break;
                p = c->parents->item;
-               if (!p->object.util) {
+               if (!p->util) {
                        name_parent(c, p);
                        i++;
                }
@@ -106,7 +106,7 @@ static void name_commits(struct commit_list *list,
        /* First give names to the given heads */
        for (cl = list; cl; cl = cl->next) {
                c = cl->item;
-               if (c->object.util)
+               if (c->util)
                        continue;
                for (i = 0; i < num_rev; i++) {
                        if (rev[i] == c) {
@@ -132,9 +132,9 @@ static void name_commits(struct commit_list *list,
                        struct commit_name *n;
                        int nth;
                        c = cl->item;
-                       if (!c->object.util)
+                       if (!c->util)
                                continue;
-                       n = c->object.util;
+                       n = c->util;
                        parents = c->parents;
                        nth = 0;
                        while (parents) {
@@ -142,7 +142,7 @@ static void name_commits(struct commit_list *list,
                                char newname[1000], *en;
                                parents = parents->next;
                                nth++;
-                               if (p->object.util)
+                               if (p->util)
                                        continue;
                                en = newname;
                                switch (n->generation) {
@@ -257,7 +257,7 @@ static void join_revs(struct commit_list **list_p,
 static void show_one_commit(struct commit *commit, int no_name)
 {
        char pretty[256], *cp;
-       struct commit_name *name = commit->object.util;
+       struct commit_name *name = commit->util;
        if (commit->object.parsed)
                pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
                                    pretty, sizeof(pretty), 0, NULL, NULL);
index f6310b9032374d6fd262b807d85987465887cdbf..39a61b629367df9dd274acf5fa310b45dd06f126 100644 (file)
@@ -22,8 +22,10 @@ static unsigned long offset;
 static time_t archive_time;
 
 /* tries hard to write, either succeeds or dies in the attempt */
-static void reliable_write(void *buf, unsigned long size)
+static void reliable_write(const void *data, unsigned long size)
 {
+       const char *buf = data;
+
        while (size > 0) {
                long ret = xwrite(1, buf, size);
                if (ret < 0) {
@@ -47,37 +49,13 @@ static void write_if_needed(void)
        }
 }
 
-/* acquire the next record from the buffer; user must call write_if_needed() */
-static char *get_record(void)
-{
-       char *p = block + offset;
-       memset(p, 0, RECORDSIZE);
-       offset += RECORDSIZE;
-       return p;
-}
-
-/*
- * The end of tar archives is marked by 1024 nul bytes and after that
- * follows the rest of the block (if any).
- */
-static void write_trailer(void)
-{
-       get_record();
-       write_if_needed();
-       get_record();
-       write_if_needed();
-       while (offset) {
-               get_record();
-               write_if_needed();
-       }
-}
-
 /*
  * queues up writes, so that all our write(2) calls write exactly one
  * full block; pads writes to RECORDSIZE
  */
-static void write_blocked(void *buf, unsigned long size)
+static void write_blocked(const void *data, unsigned long size)
 {
+       const char *buf = data;
        unsigned long tail;
 
        if (offset) {
@@ -107,6 +85,21 @@ static void write_blocked(void *buf, unsigned long size)
        write_if_needed();
 }
 
+/*
+ * The end of tar archives is marked by 2*512 nul bytes and after that
+ * follows the rest of the block (if any).
+ */
+static void write_trailer(void)
+{
+       int tail = BLOCKSIZE - offset;
+       memset(block + offset, 0, tail);
+       reliable_write(block, BLOCKSIZE);
+       if (tail < 2 * RECORDSIZE) {
+               memset(block, 0, offset);
+               reliable_write(block, BLOCKSIZE);
+       }
+}
+
 static void strbuf_append_string(struct strbuf *sb, const char *s)
 {
        int slen = strlen(s);
index a880c97b38e7d36f2a45a1743e9565cc1e58280d..d9f7e1e3dd598d34e08d6370544b562daf4640d2 100644 (file)
@@ -529,3 +529,29 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size)
                return NULL; /* not the whole tree */
        return read_one(&buffer, &size);
 }
+
+struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
+{
+       while (*path) {
+               const char *slash;
+               struct cache_tree_sub *sub;
+
+               slash = strchr(path, '/');
+               if (!slash)
+                       slash = path + strlen(path);
+               /* between path and slash is the name of the
+                * subtree to look for.
+                */
+               sub = find_subtree(it, path, slash - path, 0);
+               if (!sub)
+                       return NULL;
+               it = sub->cache_tree;
+               if (slash)
+                       while (*slash && *slash == '/')
+                               slash++;
+               if (!slash || !*slash)
+                       return it; /* prefix ended with slashes */
+               path = slash;
+       }
+       return it;
+}
index 72c64801f5e16d1e5d03dab505a388138dfcd8ab..119407e3a10562166fc61e009613842b213dfcfc 100644 (file)
@@ -28,4 +28,6 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
 int cache_tree_fully_valid(struct cache_tree *);
 int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int);
 
+struct cache_tree *cache_tree_find(struct cache_tree *, const char *);
+
 #endif
diff --git a/cache.h b/cache.h
index f630cf4bfa92e45600a83d2c3bac05a855deb847..efeafea70f61a8496cfd6fd6405793459d3df7a9 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -208,6 +208,12 @@ extern const unsigned char null_sha1[20];
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
+enum sharedrepo {
+       PERM_UMASK = 0,
+       PERM_GROUP,
+       PERM_EVERYBODY
+};
+int git_config_perm(const char *var, const char *value);
 int adjust_shared_perm(const char *path);
 int safe_create_leading_directories(char *path);
 size_t safe_strncpy(char *, const char *, size_t);
@@ -368,8 +374,8 @@ extern char git_commit_encoding[MAX_ENCODING_LENGTH];
 extern int copy_fd(int ifd, int ofd);
 
 /* Finish off pack transfer receiving end */
-extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
-extern int receive_keep_pack(int fd[2], const char *me, int quiet);
+extern int receive_unpack_pack(int fd[2], const char *me, int quiet, int);
+extern int receive_keep_pack(int fd[2], const char *me, int quiet, int);
 
 /* pager.c */
 extern void setup_pager(void);
@@ -378,4 +384,15 @@ extern void setup_pager(void);
 int decode_85(char *dst, char *line, int linelen);
 void encode_85(char *buf, unsigned char *data, int bytes);
 
+/* alloc.c */
+struct blob;
+struct tree;
+struct commit;
+struct tag;
+extern struct blob *alloc_blob_node(void);
+extern struct tree *alloc_tree_node(void);
+extern struct commit *alloc_commit_node(void);
+extern struct tag *alloc_tag_node(void);
+extern void alloc_report(void);
+
 #endif /* CACHE_H */
diff --git a/clone-pack.c b/clone-pack.c
deleted file mode 100644 (file)
index a4370f5..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-#include "cache.h"
-#include "refs.h"
-#include "pkt-line.h"
-
-static const char clone_pack_usage[] =
-"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
-static const char *exec = "git-upload-pack";
-
-static int quiet = 0;
-
-static void clone_handshake(int fd[2], struct ref *ref)
-{
-       unsigned char sha1[20];
-
-       while (ref) {
-               packet_write(fd[1], "want %s\n", sha1_to_hex(ref->old_sha1));
-               ref = ref->next;
-       }
-       packet_flush(fd[1]);
-
-       /* We don't have nuttin' */
-       packet_write(fd[1], "done\n");
-       if (get_ack(fd[0], sha1))
-               error("Huh! git-clone-pack got positive ack for %s", sha1_to_hex(sha1));
-}
-
-static int is_master(struct ref *ref)
-{
-       return !strcmp(ref->name, "refs/heads/master");
-}
-
-static void write_one_ref(struct ref *ref)
-{
-       char *path = git_path("%s", ref->name);
-       int fd;
-       char *hex;
-
-       if (!strncmp(ref->name, "refs/", 5) &&
-           check_ref_format(ref->name + 5)) {
-               error("refusing to create funny ref '%s' locally", ref->name);
-               return;
-       }
-
-       if (safe_create_leading_directories(path))
-               die("unable to create leading directory for %s", ref->name);
-       fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);
-       if (fd < 0)
-               die("unable to create ref %s", ref->name);
-       hex = sha1_to_hex(ref->old_sha1);
-       hex[40] = '\n';
-       if (write(fd, hex, 41) != 41)
-               die("unable to write ref %s", ref->name);
-       close(fd);
-}
-
-static void write_refs(struct ref *ref)
-{
-       struct ref *head = NULL, *head_ptr, *master_ref;
-       char *head_path;
-
-       /* Upload-pack must report HEAD first */
-       if (!strcmp(ref->name, "HEAD")) {
-               head = ref;
-               ref = ref->next;
-       }
-       head_ptr = NULL;
-       master_ref = NULL;
-       while (ref) {
-               if (is_master(ref))
-                       master_ref = ref;
-               if (head &&
-                   !memcmp(ref->old_sha1, head->old_sha1, 20) &&
-                   !strncmp(ref->name, "refs/heads/",11) &&
-                   (!head_ptr || ref == master_ref))
-                       head_ptr = ref;
-
-               write_one_ref(ref);
-               ref = ref->next;
-       }
-       if (!head) {
-               fprintf(stderr, "No HEAD in remote.\n");
-               return;
-       }
-
-       head_path = strdup(git_path("HEAD"));
-       if (!head_ptr) {
-               /*
-                * If we had a master ref, and it wasn't HEAD, we need to undo the
-                * symlink, and write a standalone HEAD. Give a warning, because that's
-                * really really wrong.
-                */
-               if (master_ref) {
-                       error("HEAD doesn't point to any refs! Making standalone HEAD");
-                       unlink(head_path);
-               }
-               write_one_ref(head);
-               free(head_path);
-               return;
-       }
-
-       /* We reset to the master branch if it's available */
-       if (master_ref)
-               return;
-
-       fprintf(stderr, "Setting HEAD to %s\n", head_ptr->name);
-
-       /*
-        * Uhhuh. Other end didn't have master. We start HEAD off with
-        * the first branch with the same value.
-        */
-       if (create_symref(head_path, head_ptr->name) < 0)
-               die("unable to link HEAD to %s", head_ptr->name);
-       free(head_path);
-}
-
-static int clone_pack(int fd[2], int nr_match, char **match)
-{
-       struct ref *refs;
-       int status;
-
-       get_remote_heads(fd[0], &refs, nr_match, match, 1);
-       if (!refs) {
-               packet_flush(fd[1]);
-               die("no matching remote head");
-       }
-       clone_handshake(fd, refs);
-
-       status = receive_keep_pack(fd, "git-clone-pack", quiet);
-       if (!quiet)
-               fprintf(stderr, "\n");
-
-       if (!status) {
-               if (nr_match == 0)
-                       write_refs(refs);
-               else
-                       while (refs) {
-                               printf("%s %s\n",
-                                      sha1_to_hex(refs->old_sha1),
-                                      refs->name);
-                               refs = refs->next;
-                       }
-       }
-       return status;
-}
-
-int main(int argc, char **argv)
-{
-       int i, ret, nr_heads;
-       char *dest = NULL, **heads;
-       int fd[2];
-       pid_t pid;
-
-       setup_git_directory();
-
-       nr_heads = 0;
-       heads = NULL;
-       for (i = 1; i < argc; i++) {
-               char *arg = argv[i];
-
-               if (*arg == '-') {
-                       if (!strcmp("-q", arg)) {
-                               quiet = 1;
-                               continue;
-                       }
-                       if (!strncmp("--exec=", arg, 7)) {
-                               exec = arg + 7;
-                               continue;
-                       }
-                       usage(clone_pack_usage);
-               }
-               dest = arg;
-               heads = argv + i + 1;
-               nr_heads = argc - i - 1;
-               break;
-       }
-       if (!dest)
-               usage(clone_pack_usage);
-       pid = git_connect(fd, dest, exec);
-       if (pid < 0)
-               return 1;
-       ret = clone_pack(fd, nr_heads, heads);
-       close(fd[0]);
-       close(fd[1]);
-       finish_connect(pid);
-       return ret;
-}
index 94f470b75cfc68bfd8e14d1e421e19c5ad6004d6..946615d2ad5c364fe63b201aa9a9574737804c38 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -56,10 +56,10 @@ static struct commit *check_commit(struct object *obj,
                                   const unsigned char *sha1,
                                   int quiet)
 {
-       if (obj->type != commit_type) {
+       if (obj->type != TYPE_COMMIT) {
                if (!quiet)
                        error("Object %s is a %s, not a commit",
-                             sha1_to_hex(sha1), obj->type);
+                             sha1_to_hex(sha1), typename(obj->type));
                return NULL;
        }
        return (struct commit *) obj;
@@ -84,13 +84,13 @@ struct commit *lookup_commit(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj) {
-               struct commit *ret = xcalloc(1, sizeof(struct commit));
+               struct commit *ret = alloc_commit_node();
                created_object(sha1, &ret->object);
-               ret->object.type = commit_type;
+               ret->object.type = TYPE_COMMIT;
                return ret;
        }
        if (!obj->type)
-               obj->type = commit_type;
+               obj->type = TYPE_COMMIT;
        return check_commit(obj, sha1, 0);
 }
 
@@ -447,7 +447,7 @@ static int add_rfc2047(char *buf, const char *line, int len)
        memcpy(bp, q_utf8, sizeof(q_utf8)-1);
        bp += sizeof(q_utf8)-1;
        for (i = 0; i < len; i++) {
-               unsigned ch = line[i];
+               unsigned ch = line[i] & 0xFF;
                if (is_rfc2047_special(ch)) {
                        sprintf(bp, "=%02X", ch);
                        bp += 3;
@@ -571,10 +571,23 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
         * to say this is not a 7-bit ASCII.
         */
        if (fmt == CMIT_FMT_EMAIL && !after_subject) {
-               int i;
-               for (i = 0; !plain_non_ascii && msg[i] && i < len; i++)
-                       if (msg[i] & 0x80)
+               int i, ch, in_body;
+
+               for (in_body = i = 0; (ch = msg[i]) && i < len; i++) {
+                       if (!in_body) {
+                               /* author could be non 7-bit ASCII but
+                                * the log may so; skip over the
+                                * header part first.
+                                */
+                               if (ch == '\n' &&
+                                   i + 1 < len && msg[i+1] == '\n')
+                                       in_body = 1;
+                       }
+                       else if (ch & 0x80) {
                                plain_non_ascii = 1;
+                               break;
+                       }
+               }
        }
 
        for (;;) {
@@ -711,12 +724,12 @@ int count_parents(struct commit * commit)
 
 void topo_sort_default_setter(struct commit *c, void *data)
 {
-       c->object.util = data;
+       c->util = data;
 }
 
 void *topo_sort_default_getter(struct commit *c)
 {
-       return c->object.util;
+       return c->util;
 }
 
 /*
index c9de1677e903ead414e5133424b722bea907b4d9..7c9ca3fbed728d946e48c787720b3ab5ad575a85 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -11,6 +11,7 @@ struct commit_list {
 
 struct commit {
        struct object object;
+       void *util;
        unsigned long date;
        struct commit_list *parents;
        struct tree *tree;
index 984c75f5dd06bd1d53eda206a2b57eea093dfd58..3e077d4c6ca4f7162e3a3254e1b3e90db33270ff 100644 (file)
--- a/config.c
+++ b/config.c
@@ -317,7 +317,33 @@ int git_config_from_file(config_fn_t fn, const char *filename)
 
 int git_config(config_fn_t fn)
 {
-       return git_config_from_file(fn, git_path("config"));
+       int ret = 0;
+       char *repo_config = NULL;
+       const char *home = NULL, *filename;
+
+       /* $GIT_CONFIG makes git read _only_ the given config file,
+        * $GIT_CONFIG_LOCAL will make it process it in addition to the
+        * global config file, the same way it would the per-repository
+        * config file otherwise. */
+       filename = getenv("GIT_CONFIG");
+       if (!filename) {
+               home = getenv("HOME");
+               filename = getenv("GIT_CONFIG_LOCAL");
+               if (!filename)
+                       filename = repo_config = strdup(git_path("config"));
+       }
+
+       if (home) {
+               char *user_config = strdup(mkpath("%s/.gitconfig", home));
+               if (!access(user_config, R_OK))
+                       ret = git_config_from_file(fn, user_config);
+               free(user_config);
+       }
+
+       ret += git_config_from_file(fn, filename);
+       if (repo_config)
+               free(repo_config);
+       return ret;
 }
 
 /*
@@ -490,10 +516,19 @@ int git_config_set_multivar(const char* key, const char* value,
        int i, dot;
        int fd = -1, in_fd;
        int ret;
-       char* config_filename = strdup(git_path("config"));
-       char* lock_file = strdup(git_path("config.lock"));
+       char* config_filename;
+       char* lock_file;
        const char* last_dot = strrchr(key, '.');
 
+       config_filename = getenv("GIT_CONFIG");
+       if (!config_filename) {
+               config_filename = getenv("GIT_CONFIG_LOCAL");
+               if (!config_filename)
+                       config_filename  = git_path("config");
+       }
+       config_filename = strdup(config_filename);
+       lock_file = strdup(mkpath("%s.lock", config_filename));
+
        /*
         * Since "key" actually contains the section name and the real
         * key name separated by a dot, we have to know where the dot is.
@@ -600,7 +635,7 @@ int git_config_set_multivar(const char* key, const char* value,
                 * As a side effect, we make sure to transform only a valid
                 * existing config file.
                 */
-               if (git_config(store_aux)) {
+               if (git_config_from_file(store_aux, config_filename)) {
                        fprintf(stderr, "invalid config file\n");
                        free(store.key);
                        if (store.value_regex != NULL) {
index 52d709e58d53f053ec00bfb9f31501684cbaf0e5..db7342e4d26baa50dd944ebf06fb8b66fea59aaa 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -581,6 +581,11 @@ int git_connect(int fd[2], char *url, const char *prog)
        enum protocol protocol = PROTO_LOCAL;
        int free_path = 0;
 
+       /* Without this we cannot rely on waitpid() to tell
+        * what happened to our children.
+        */
+       signal(SIGCHLD, SIG_DFL);
+
        host = strstr(url, "://");
        if(host) {
                *host = '\0';
index 6aedb10f1261bbcef6a48ef65e1f47d9edc1afda..7c209469438bcef2a5cee0988448a41a56ec30cc 100644 (file)
@@ -29,8 +29,7 @@ git-svn.html : git-svn.txt
        asciidoc -b xhtml11 -d manpage \
                -f ../../Documentation/asciidoc.conf $<
 test: git-svn
-       cd t && $(SHELL) ./t0000-contrib-git-svn.sh $(TEST_FLAGS)
-       cd t && $(SHELL) ./t0001-contrib-git-svn-props.sh $(TEST_FLAGS)
+       cd t && for i in t????-*.sh; do $(SHELL) ./$$i $(TEST_FLAGS); done
 
 # we can test NO_OPTIMIZE_COMMITS independently of LC_ALL
 full-test:
index da0ff9ad8a56f41c351946990ee17d1e80f533e8..08c30103f5c247559e15ebd4bb20d7177889ed88 100755 (executable)
@@ -479,17 +479,18 @@ sub commit_lib {
        my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
        my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$";
 
+       if (defined $LC_ALL) {
+               $ENV{LC_ALL} = $LC_ALL;
+       } else {
+               delete $ENV{LC_ALL};
+       }
        foreach my $c (@revs) {
+               my $log_msg = get_commit_message($c, $commit_msg);
+
                # fork for each commit because there's a memory leak I
                # can't track down... (it's probably in the SVN code)
                defined(my $pid = open my $fh, '-|') or croak $!;
                if (!$pid) {
-                       if (defined $LC_ALL) {
-                               $ENV{LC_ALL} = $LC_ALL;
-                       } else {
-                               delete $ENV{LC_ALL};
-                       }
-                       my $log_msg = get_commit_message($c, $commit_msg);
                        my $ed = SVN::Git::Editor->new(
                                        {       r => $r_last,
                                                ra => $SVN,
@@ -535,6 +536,7 @@ sub commit_lib {
                        ($r_last, $cmt_last) = ($r_new, $cmt_new);
                }
        }
+       $ENV{LC_ALL} = 'C';
        unlink $commit_msg;
 }
 
@@ -2841,13 +2843,20 @@ sub rmdirs {
                exec qw/git-ls-tree --name-only -r -z/, $self->{c} or croak $!;
        }
        local $/ = "\0";
+       my @svn_path = split m#/#, $self->{svn_path};
        while (<$fh>) {
                chomp;
-               $_ = $self->{svn_path} . '/' . $_;
-               my ($dn) = ($_ =~ m#^(.*?)/?(?:[^/]+)$#);
-               delete $rm->{$dn};
-               last unless %$rm;
+               my @dn = (@svn_path, (split m#/#, $_));
+               while (pop @dn) {
+                       delete $rm->{join '/', @dn};
+               }
+               unless (%$rm) {
+                       close $fh;
+                       return;
+               }
        }
+       close $fh;
+
        my ($r, $p, $bat) = ($self->{r}, $self->{pool}, $self->{bat});
        foreach my $d (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$rm) {
                $self->close_directory($bat->{$d}, $p);
diff --git a/contrib/git-svn/t/t0002-deep-rmdir.sh b/contrib/git-svn/t/t0002-deep-rmdir.sh
new file mode 100644 (file)
index 0000000..d693d18
--- /dev/null
@@ -0,0 +1,29 @@
+test_description='git-svn rmdir'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize repo' "
+       mkdir import &&
+       cd import &&
+       mkdir -p deeply/nested/directory/number/1 &&
+       mkdir -p deeply/nested/directory/number/2 &&
+       echo foo > deeply/nested/directory/number/1/file &&
+       echo foo > deeply/nested/directory/number/2/another &&
+       svn import -m 'import for git-svn' . $svnrepo &&
+       cd ..
+       "
+
+test_expect_success 'mirror via git-svn' "
+       git-svn init $svnrepo &&
+       git-svn fetch &&
+       git checkout -f -b test-rmdir remotes/git-svn
+       "
+
+test_expect_success 'Try a commit on rmdir' "
+       git rm -f deeply/nested/directory/number/2/another &&
+       git commit -a -m 'remove another' &&
+       git-svn commit --rmdir HEAD &&
+       svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+       "
+
+
+test_done
index a67d6b479ec57816de1b259f9efed2258e999703..0fabd8981c6047e5144cfb3776b4f4a5588f24e5 100644 (file)
@@ -103,12 +103,12 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base
                if (!slash) {
                        newlen += sprintf(new + newlen, "%o %s", mode, path);
                        new[newlen++] = '\0';
-                       memcpy(new + newlen, buffer + len - 20, 20);
+                       memcpy(new + newlen, (char *) buffer + len - 20, 20);
                        newlen += 20;
 
                        used += len;
                        size -= len;
-                       buffer += len;
+                       buffer = (char *) buffer + len;
                        continue;
                }
 
@@ -121,7 +121,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base
 
                used += len;
                size -= len;
-               buffer += len;
+               buffer = (char *) buffer + len;
        }
 
        write_sha1_file(new, newlen, tree_type, result_sha1);
@@ -137,13 +137,13 @@ static void convert_tree(void *buffer, unsigned long size, unsigned char *result
        while (size) {
                int len = 1+strlen(buffer);
 
-               convert_binary_sha1(buffer + len);
+               convert_binary_sha1((char *) buffer + len);
 
                len += 20;
                if (len > size)
                        die("corrupt tree object");
                size -= len;
-               buffer += len;
+               buffer = (char *) buffer + len;
        }
 
        write_subdirectory(orig_buffer, orig_size, "", 0, result_sha1);
@@ -244,14 +244,14 @@ static void convert_date(void *buffer, unsigned long size, unsigned char *result
        // "tree <sha1>\n"
        memcpy(new + newlen, buffer, 46);
        newlen += 46;
-       buffer += 46;
+       buffer = (char *) buffer + 46;
        size -= 46;
 
        // "parent <sha1>\n"
        while (!memcmp(buffer, "parent ", 7)) {
                memcpy(new + newlen, buffer, 48);
                newlen += 48;
-               buffer += 48;
+               buffer = (char *) buffer + 48;
                size -= 48;
        }
 
@@ -275,11 +275,11 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu
 
        if (memcmp(buffer, "tree ", 5))
                die("Bad commit '%s'", (char*) buffer);
-       convert_ascii_sha1(buffer+5);
-       buffer += 46;    /* "tree " + "hex sha1" + "\n" */
+       convert_ascii_sha1((char *) buffer + 5);
+       buffer = (char *) buffer + 46;    /* "tree " + "hex sha1" + "\n" */
        while (!memcmp(buffer, "parent ", 7)) {
-               convert_ascii_sha1(buffer+7);
-               buffer += 48;
+               convert_ascii_sha1((char *) buffer + 7);
+               buffer = (char *) buffer + 48;
        }
        convert_date(orig_buffer, orig_size, result_sha1);
 }
index 5f9249aeedfa7d4156cf412da6a7e7d77f33ff86..ebaad0397f0bce50db7542abb904ba42b6173344 100644 (file)
@@ -17,7 +17,7 @@ static int sha1flush(struct sha1file *f, unsigned int count)
        for (;;) {
                int ret = xwrite(f->fd, buf, count);
                if (ret > 0) {
-                       buf += ret;
+                       buf = (char *) buf + ret;
                        count -= ret;
                        if (count)
                                continue;
@@ -57,7 +57,7 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count)
                memcpy(f->buffer + offset, buf, nr);
                count -= nr;
                offset += nr;
-               buf += nr;
+               buf = (char *) buf + nr;
                left -= nr;
                if (!left) {
                        SHA1_Update(&f->ctx, f->buffer, offset);
index 2f03f99d2d9f2ed9a23932e5104456f69b721116..1ba4d669da346abb5dab86ea7842a7ad4d3e1cde 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -264,11 +264,34 @@ static int upload(char *dir)
        return -1;
 }
 
-static int execute(void)
+static int execute(struct sockaddr *addr)
 {
        static char line[1000];
        int pktlen, len;
 
+       if (addr) {
+               char addrbuf[256] = "";
+               int port = -1;
+
+               if (addr->sa_family == AF_INET) {
+                       struct sockaddr_in *sin_addr = (void *) addr;
+                       inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
+                       port = sin_addr->sin_port;
+#ifndef NO_IPV6
+               } else if (addr && addr->sa_family == AF_INET6) {
+                       struct sockaddr_in6 *sin6_addr = (void *) addr;
+
+                       char *buf = addrbuf;
+                       *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
+                       inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
+                       strcat(buf, "]");
+
+                       port = sin6_addr->sin6_port;
+#endif
+               }
+               loginfo("Connection from %s:%d", addrbuf, port);
+       }
+
        alarm(init_timeout ? init_timeout : timeout);
        pktlen = packet_read_line(0, line, sizeof(line));
        alarm(0);
@@ -414,8 +437,6 @@ static void check_max_connections(void)
 static void handle(int incoming, struct sockaddr *addr, int addrlen)
 {
        pid_t pid = fork();
-       char addrbuf[256] = "";
-       int port = -1;
 
        if (pid) {
                unsigned idx;
@@ -436,26 +457,7 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
        dup2(incoming, 1);
        close(incoming);
 
-       if (addr->sa_family == AF_INET) {
-               struct sockaddr_in *sin_addr = (void *) addr;
-               inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
-               port = sin_addr->sin_port;
-
-#ifndef NO_IPV6
-       } else if (addr->sa_family == AF_INET6) {
-               struct sockaddr_in6 *sin6_addr = (void *) addr;
-
-               char *buf = addrbuf;
-               *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
-               inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
-               strcat(buf, "]");
-
-               port = sin6_addr->sin6_port;
-#endif
-       }
-       loginfo("Connection from %s:%d", addrbuf, port);
-
-       exit(execute());
+       exit(execute(addr));
 }
 
 static void child_handler(int signo)
@@ -671,6 +673,11 @@ int main(int argc, char **argv)
        int inetd_mode = 0;
        int i;
 
+       /* Without this we cannot rely on waitpid() to tell
+        * what happened to our children.
+        */
+       signal(SIGCHLD, SIG_DFL);
+
        for (i = 1; i < argc; i++) {
                char *arg = argv[i];
 
@@ -751,8 +758,16 @@ int main(int argc, char **argv)
        }
 
        if (inetd_mode) {
-               fclose(stderr); //FIXME: workaround
-               return execute();
+               struct sockaddr_storage ss;
+               struct sockaddr *peer = (struct sockaddr *)&ss;
+               socklen_t slen = sizeof(ss);
+
+               freopen("/dev/null", "w", stderr);
+
+               if (getpeername(0, peer, &slen))
+                       peer = NULL;
+
+               return execute(peer);
        }
 
        return serve(port);
diff --git a/date.c b/date.c
index 365dc3b14e47826dd7becf19a76e29bfaa6b2eb5..66be23ab21ef855ecbadeceae1dea2972efd4c2f 100644 (file)
--- a/date.c
+++ b/date.c
@@ -369,7 +369,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
 
        /* Four-digit year or a timezone? */
        if (n == 4) {
-               if (num <= 1200 && *offset == -1) {
+               if (num <= 1400 && *offset == -1) {
                        unsigned int minutes = num % 100;
                        unsigned int hours = num / 100;
                        *offset = hours*60 + minutes;
index 8a9cd5d52c555330c512b977179ab030ccd28861..aa3434a4cbfe62563b7621ddd7e72be3adbea1cc 100644 (file)
@@ -67,7 +67,7 @@ static int get_name(const char *path, const unsigned char *sha1)
         * Otherwise only annotated tags are used.
         */
        if (!strncmp(path, "refs/tags/", 10)) {
-               if (object->type == tag_type)
+               if (object->type == TYPE_TAG)
                        prio = 2;
                else
                        prio = 1;
index 25a798d050c6319f3d524c9c605ab70ea35ae7a1..8b9172aa2ef7402b0a847815bb11a26d1c4444fe 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 #include "delta.h"
 
+#include "git-compat-util.h"
 
 /* maximum hash entry list for the same hash bucket */
 #define HASH_LIMIT 64
@@ -131,7 +132,7 @@ struct delta_index {
        const void *src_buf;
        unsigned long src_size;
        unsigned int hash_mask;
-       struct index_entry *hash[0];
+       struct index_entry *hash[FLEX_ARRAY];
 };
 
 struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
@@ -283,7 +284,7 @@ create_delta(const struct delta_index *index,
        ref_data = index->src_buf;
        ref_top = ref_data + index->src_size;
        data = trg_buf;
-       top = trg_buf + trg_size;
+       top = (const unsigned char *) trg_buf + trg_size;
 
        outpos++;
        val = 0;
index 2183b41b03d08092ba6d98a642757640b86710d6..116b5a9d6834c9517ccc2202510b37a1e1d863a5 100644 (file)
@@ -34,21 +34,23 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                        continue;
 
                if (ce_stage(ce)) {
-                       struct {
-                               struct combine_diff_path p;
-                               struct combine_diff_parent filler[5];
-                       } combine;
+                       struct combine_diff_path *dpath;
                        int num_compare_stages = 0;
+                       size_t path_len;
 
-                       combine.p.next = NULL;
-                       combine.p.len = ce_namelen(ce);
-                       combine.p.path = xmalloc(combine.p.len + 1);
-                       memcpy(combine.p.path, ce->name, combine.p.len);
-                       combine.p.path[combine.p.len] = 0;
-                       combine.p.mode = 0;
-                       memset(combine.p.sha1, 0, 20);
-                       memset(&combine.p.parent[0], 0,
-                              sizeof(combine.filler));
+                       path_len = ce_namelen(ce);
+
+                       dpath = xmalloc (combine_diff_path_size (5, path_len));
+                       dpath->path = (char *) &(dpath->parent[5]);
+
+                       dpath->next = NULL;
+                       dpath->len = path_len;
+                       memcpy(dpath->path, ce->name, path_len);
+                       dpath->path[path_len] = '\0';
+                       dpath->mode = 0;
+                       memset(dpath->sha1, 0, 20);
+                       memset(&(dpath->parent[0]), 0,
+                                       sizeof(struct combine_diff_parent)*5);
 
                        while (i < entries) {
                                struct cache_entry *nce = active_cache[i];
@@ -64,11 +66,11 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                                if (2 <= stage) {
                                        int mode = ntohl(nce->ce_mode);
                                        num_compare_stages++;
-                                       memcpy(combine.p.parent[stage-2].sha1,
+                                       memcpy(dpath->parent[stage-2].sha1,
                                               nce->sha1, 20);
-                                       combine.p.parent[stage-2].mode =
+                                       dpath->parent[stage-2].mode =
                                                canon_mode(mode);
-                                       combine.p.parent[stage-2].status =
+                                       dpath->parent[stage-2].status =
                                                DIFF_STATUS_MODIFIED;
                                }
 
@@ -83,13 +85,14 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                        i--;
 
                        if (revs->combine_merges && num_compare_stages == 2) {
-                               show_combined_diff(&combine.p, 2,
+                               show_combined_diff(dpath, 2,
                                                   revs->dense_combined_merges,
                                                   revs);
-                               free(combine.p.path);
+                               free(dpath);
                                continue;
                        }
-                       free(combine.p.path);
+                       free(dpath);
+                       dpath = NULL;
 
                        /*
                         * Show the diff for the 'ce' if we found the one
@@ -329,8 +332,8 @@ int run_diff_index(struct rev_info *revs, int cached)
        }
        mark_merge_entries();
 
-       ent = revs->pending_objects->item;
-       tree_name = revs->pending_objects->name;
+       ent = revs->pending.objects[0].item;
+       tree_name = revs->pending.objects[0].name;
        tree = parse_tree_indirect(ent->sha1);
        if (!tree)
                return error("bad tree object %s", tree_name);
diff --git a/diff.c b/diff.c
index bc32a4aa29171af6ca268a54cde881934079de83..22b643cc2520664416ceac9998d401a6585f07bf 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -560,7 +560,7 @@ static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
                else
                        line[0] = bytes - 26 + 'a' - 1;
                encode_85(line + 1, cp, bytes);
-               cp += bytes;
+               cp = (char *) cp + bytes;
                puts(line);
        }
        printf("\n");
index 0bc2b22f848457a8e6ffafc6a1d9a26be677209f..aef6da60447b98a05d91513b4aa74e505b0a0d84 100644 (file)
@@ -30,7 +30,7 @@ static void prepare_order(const char *orderfile)
        close(fd);
        if (map == MAP_FAILED)
                return;
-       endp = map + st.st_size;
+       endp = (char *) map + st.st_size;
        for (pass = 0; pass < 2; pass++) {
                cnt = 0;
                cp = map;
index 2e79eab18d322b61e783f45758fdbdc5210de13c..3de8eb3b2a2359a9f8a9f702076292f1e1429df3 100644 (file)
@@ -18,7 +18,7 @@ int log_all_ref_updates = 0;
 int warn_ambiguous_refs = 1;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
-int shared_repository = 0;
+int shared_repository = PERM_UMASK;
 const char *apply_default_whitespace = NULL;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
index da1b3ffbaa13ee4dfc8d080759b3f936850b7647..c16b0c481bb4b7dd3810e7dfbcb21243572f6844 100644 (file)
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "exec_cmd.h"
+#include "pkt-line.h"
 #include <sys/wait.h>
 #include <sys/time.h>
 
@@ -23,7 +24,7 @@ static int finish_pack(const char *pack_tmp_name, const char *me)
 
        pid = fork();
        if (pid < 0)
-               die("git-clone-pack: unable to fork off git-index-pack");
+               die("%s: unable to fork off git-index-pack", me);
        if (!pid) {
                close(0);
                dup2(pipe_fd[1], 1);
@@ -94,11 +95,69 @@ static int finish_pack(const char *pack_tmp_name, const char *me)
        exit(1);
 }
 
-int receive_unpack_pack(int fd[2], const char *me, int quiet)
+static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2])
+{
+       pid_t side_pid;
+
+       if (!sideband) {
+               fd[0] = xd[0];
+               fd[1] = xd[1];
+               return 0;
+       }
+       /* xd[] is talking with upload-pack; subprocess reads from
+        * xd[0], spits out band#2 to stderr, and feeds us band#1
+        * through our fd[0].
+        */
+       if (pipe(fd) < 0)
+               die("%s: unable to set up pipe", me);
+       side_pid = fork();
+       if (side_pid < 0)
+               die("%s: unable to fork off sideband demultiplexer", me);
+       if (!side_pid) {
+               /* subprocess */
+               close(fd[0]);
+               if (xd[0] != xd[1])
+                       close(xd[1]);
+               while (1) {
+                       char buf[1024];
+                       int len = packet_read_line(xd[0], buf, sizeof(buf));
+                       if (len == 0)
+                               break;
+                       if (len < 1)
+                               die("%s: protocol error: no band designator",
+                                   me);
+                       len--;
+                       switch (buf[0] & 0xFF) {
+                       case 3:
+                               safe_write(2, buf+1, len);
+                               fprintf(stderr, "\n");
+                               exit(1);
+                       case 2:
+                               safe_write(2, buf+1, len);
+                               continue;
+                       case 1:
+                               safe_write(fd[1], buf+1, len);
+                               continue;
+                       default:
+                               die("%s: protocol error: bad band #%d",
+                                   me, (buf[0] & 0xFF));
+                       }
+               }
+               exit(0);
+       }
+       close(xd[0]);
+       close(fd[1]);
+       fd[1] = xd[1];
+       return side_pid;
+}
+
+int receive_unpack_pack(int xd[2], const char *me, int quiet, int sideband)
 {
        int status;
-       pid_t pid;
+       pid_t pid, side_pid;
+       int fd[2];
 
+       side_pid = setup_sideband(sideband, me, fd, xd);
        pid = fork();
        if (pid < 0)
                die("%s: unable to fork off git-unpack-objects", me);
@@ -147,10 +206,10 @@ int receive_unpack_pack(int fd[2], const char *me, int quiet)
  */
 #define usec_to_binarymsec(x) ((int)(x) / (1000512 >> 10))
 
-int receive_keep_pack(int fd[2], const char *me, int quiet)
+int receive_keep_pack(int xd[2], const char *me, int quiet, int sideband)
 {
        char tmpfile[PATH_MAX];
-       int ofd, ifd;
+       int ofd, ifd, fd[2];
        unsigned long total;
        static struct timeval prev_tv;
        struct average {
@@ -160,6 +219,8 @@ int receive_keep_pack(int fd[2], const char *me, int quiet)
        unsigned long avg_bytes, avg_time;
        int idx = 0;
 
+       setup_sideband(sideband, me, fd, xd);
+
        ifd = fd[0];
        snprintf(tmpfile, sizeof(tmpfile),
                 "%s/pack/tmp-XXXXXX", get_object_directory());
index 8daa93d024158e6d8daff304db57ac80d1803c65..f2c51ebe4b2b524e5d5bce6af8aa3105df19f177 100644 (file)
@@ -18,8 +18,14 @@ static const char *exec = "git-upload-pack";
 #define SEEN           (1U << 3)
 #define POPPED         (1U << 4)
 
+/*
+ * After sending this many "have"s if we do not get any new ACK , we
+ * give up traversing our history.
+ */
+#define MAX_IN_VAIN 256
+
 static struct commit_list *rev_list = NULL;
-static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0;
+static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0, use_sideband;
 
 static void rev_list_push(struct commit *commit, int mark)
 {
@@ -40,7 +46,7 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
 {
        struct object *o = deref_tag(parse_object(sha1), path, 0);
 
-       if (o && o->type == commit_type)
+       if (o && o->type == TYPE_COMMIT)
                rev_list_push((struct commit *)o, SEEN);
 
        return 0;
@@ -134,6 +140,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
        int fetching;
        int count = 0, flushes = 0, retval;
        const unsigned char *sha1;
+       unsigned in_vain = 0;
+       int got_continue = 0;
 
        for_each_ref(rev_list_insert_ref);
 
@@ -157,9 +165,14 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                        continue;
                }
 
-               packet_write(fd[1], "want %s%s%s\n", sha1_to_hex(remote),
-                            (multi_ack ? " multi_ack" : ""),
-                            (use_thin_pack ? " thin-pack" : ""));
+               if (!fetching)
+                       packet_write(fd[1], "want %s%s%s%s\n",
+                                    sha1_to_hex(remote),
+                                    (multi_ack ? " multi_ack" : ""),
+                                    (use_sideband ? " side-band" : ""),
+                                    (use_thin_pack ? " thin-pack" : ""));
+               else
+                       packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
                fetching++;
        }
        packet_flush(fd[1]);
@@ -172,6 +185,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
                if (verbose)
                        fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
+               in_vain++;
                if (!(31 & ++count)) {
                        int ack;
 
@@ -200,9 +214,16 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                                                lookup_commit(result_sha1);
                                        mark_common(commit, 0, 1);
                                        retval = 0;
+                                       in_vain = 0;
+                                       got_continue = 1;
                                }
                        } while (ack);
                        flushes--;
+                       if (got_continue && MAX_IN_VAIN < in_vain) {
+                               if (verbose)
+                                       fprintf(stderr, "giving up\n");
+                               break; /* give up */
+                       }
                }
        }
 done:
@@ -235,14 +256,14 @@ static int mark_complete(const char *path, const unsigned char *sha1)
 {
        struct object *o = parse_object(sha1);
 
-       while (o && o->type == tag_type) {
+       while (o && o->type == TYPE_TAG) {
                struct tag *t = (struct tag *) o;
                if (!t->tagged)
                        break; /* broken repository */
                o->flags |= COMPLETE;
                o = parse_object(t->tagged->sha1);
        }
-       if (o && o->type == commit_type) {
+       if (o && o->type == TYPE_COMMIT) {
                struct commit *commit = (struct commit *)o;
                commit->object.flags |= COMPLETE;
                insert_by_date(commit, &complete);
@@ -336,7 +357,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
                 * in sync with the other side at some time after
                 * that (it is OK if we guess wrong here).
                 */
-               if (o->type == commit_type) {
+               if (o->type == TYPE_COMMIT) {
                        struct commit *commit = (struct commit *)o;
                        if (!cutoff || cutoff < commit->date)
                                cutoff = commit->date;
@@ -355,7 +376,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
                struct object *o = deref_tag(lookup_object(ref->old_sha1),
                                             NULL, 0);
 
-               if (!o || o->type != commit_type || !(o->flags & COMPLETE))
+               if (!o || o->type != TYPE_COMMIT || !(o->flags & COMPLETE))
                        continue;
 
                if (!(o->flags & SEEN)) {
@@ -405,6 +426,11 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
                        fprintf(stderr, "Server supports multi_ack\n");
                multi_ack = 1;
        }
+       if (server_supports("side-band")) {
+               if (verbose)
+                       fprintf(stderr, "Server supports side-band\n");
+               use_sideband = 1;
+       }
        if (!ref) {
                packet_flush(fd[1]);
                die("no matching remote head");
@@ -421,9 +447,9 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
                        fprintf(stderr, "warning: no common commits\n");
 
        if (keep_pack)
-               status = receive_keep_pack(fd, "git-fetch-pack", quiet);
+               status = receive_keep_pack(fd, "git-fetch-pack", quiet, use_sideband);
        else
-               status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
+               status = receive_unpack_pack(fd, "git-fetch-pack", quiet, use_sideband);
 
        if (status)
                die("git-fetch-pack: fetch failed.");
diff --git a/fetch.c b/fetch.c
index cf6c99490c234c5854146f8f6e72d8c615517eea..238032b798008cd1f96d5083b63dc582f8191a1d 100644 (file)
--- a/fetch.c
+++ b/fetch.c
@@ -118,27 +118,27 @@ static struct object_list **process_queue_end = &process_queue;
 
 static int process_object(struct object *obj)
 {
-       if (obj->type == commit_type) {
+       if (obj->type == TYPE_COMMIT) {
                if (process_commit((struct commit *)obj))
                        return -1;
                return 0;
        }
-       if (obj->type == tree_type) {
+       if (obj->type == TYPE_TREE) {
                if (process_tree((struct tree *)obj))
                        return -1;
                return 0;
        }
-       if (obj->type == blob_type) {
+       if (obj->type == TYPE_BLOB) {
                return 0;
        }
-       if (obj->type == tag_type) {
+       if (obj->type == TYPE_TAG) {
                if (process_tag((struct tag *)obj))
                        return -1;
                return 0;
        }
        return error("Unable to determine requirements "
                     "of type %s for %s",
-                    obj->type, sha1_to_hex(obj->sha1));
+                    typename(obj->type), sha1_to_hex(obj->sha1));
 }
 
 static int process(struct object *obj)
@@ -179,9 +179,7 @@ static int loop(void)
                 */
                if (! (obj->flags & TO_SCAN)) {
                        if (fetch(obj->sha1)) {
-                               report_missing(obj->type
-                                              ? obj->type
-                                              : "object", obj->sha1);
+                               report_missing(typename(obj->type), obj->sha1);
                                return -1;
                        }
                }
index 33ce366e99376619c96ad3b1a1d883a98d55193b..769bb2a6a75f34192cfd7d6f99ea8f6efbfdce7e 100644 (file)
@@ -34,7 +34,7 @@ static void objreport(struct object *obj, const char *severity,
                       const char *err, va_list params)
 {
        fprintf(stderr, "%s in %s %s: ",
-               severity, obj->type, sha1_to_hex(obj->sha1));
+               severity, typename(obj->type), sha1_to_hex(obj->sha1));
        vfprintf(stderr, err, params);
        fputs("\n", stderr);
 }
@@ -64,6 +64,7 @@ static void check_connectivity(void)
 
        /* Look up all the requirements, warn about missing objects.. */
        for (i = 0; i < obj_allocs; i++) {
+               const struct object_refs *refs;
                struct object *obj = objs[i];
 
                if (!obj)
@@ -74,12 +75,12 @@ static void check_connectivity(void)
                                ; /* it is in pack */
                        else
                                printf("missing %s %s\n",
-                                      obj->type, sha1_to_hex(obj->sha1));
+                                      typename(obj->type), sha1_to_hex(obj->sha1));
                        continue;
                }
 
-               if (obj->refs) {
-                       const struct object_refs *refs = obj->refs;
+               refs = lookup_object_refs(obj);
+               if (refs) {
                        unsigned j;
                        for (j = 0; j < refs->count; j++) {
                                struct object *ref = refs->ref[j];
@@ -87,20 +88,20 @@ static void check_connectivity(void)
                                    (has_sha1_file(ref->sha1)))
                                        continue;
                                printf("broken link from %7s %s\n",
-                                      obj->type, sha1_to_hex(obj->sha1));
+                                      typename(obj->type), sha1_to_hex(obj->sha1));
                                printf("              to %7s %s\n",
-                                      ref->type, sha1_to_hex(ref->sha1));
+                                      typename(ref->type), sha1_to_hex(ref->sha1));
                        }
                }
 
                if (show_unreachable && !(obj->flags & REACHABLE)) {
                        printf("unreachable %s %s\n",
-                              obj->type, sha1_to_hex(obj->sha1));
+                              typename(obj->type), sha1_to_hex(obj->sha1));
                        continue;
                }
 
                if (!obj->used) {
-                       printf("dangling %s %s\n", obj->type, 
+                       printf("dangling %s %s\n", typename(obj->type),
                               sha1_to_hex(obj->sha1));
                }
        }
@@ -282,7 +283,7 @@ static int fsck_tag(struct tag *tag)
        if (!show_tags)
                return 0;
 
-       printf("tagged %s %s", tagged->type, sha1_to_hex(tagged->sha1));
+       printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
        printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
        return 0;
 }
@@ -295,16 +296,16 @@ static int fsck_sha1(unsigned char *sha1)
        if (obj->flags & SEEN)
                return 0;
        obj->flags |= SEEN;
-       if (obj->type == blob_type)
+       if (obj->type == TYPE_BLOB)
                return 0;
-       if (obj->type == tree_type)
+       if (obj->type == TYPE_TREE)
                return fsck_tree((struct tree *) obj);
-       if (obj->type == commit_type)
+       if (obj->type == TYPE_COMMIT)
                return fsck_commit((struct commit *) obj);
-       if (obj->type == tag_type)
+       if (obj->type == TYPE_TAG)
                return fsck_tag((struct tag *) obj);
        /* By now, parse_object() would've returned NULL instead. */
-       return objerror(obj, "unknown type '%s' (internal fsck error)", obj->type);
+       return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type);
 }
 
 /*
@@ -470,7 +471,7 @@ static int fsck_cache_tree(struct cache_tree *it)
                }
                mark_reachable(obj, REACHABLE);
                obj->used = 1;
-               if (obj->type != tree_type)
+               if (obj->type != TYPE_TREE)
                        err |= objerror(obj, "non-tree in cache-tree");
        }
        for (i = 0; i < it->subtree_nr; i++)
index 564117f0064aba32e190a49106eaecfdb422b31e..77c25938091b75f51eb3cc5922d67db6333e1e74 100755 (executable)
@@ -137,8 +137,7 @@ fi
 
 if [ "$force" ]
 then
-    git-read-tree --reset $new &&
-       git-checkout-index -q -f -u -a
+    git-read-tree --reset -u $new
 else
     git-update-index --refresh >/dev/null
     merge_error=$(git-read-tree -m -u $old $new 2>&1) || (
index 7b1cca70abcfcbf12c171c91d3f71ad4e43b0474..c5d9e733512ddd4d266c85d4f5cdec4a7d74fa56 100755 (executable)
                    "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc,
         );
 
+# Verify the user input
+
+foreach my $entry (@to) {
+       die "Comma in --to entry: $entry'\n" unless $entry !~ m/,/;
+}
+
+foreach my $entry (@initial_cc) {
+       die "Comma in --cc entry: $entry'\n" unless $entry !~ m/,/;
+}
+
+foreach my $entry (@bcclist) {
+       die "Comma in --bcclist entry: $entry'\n" unless $entry !~ m/,/;
+}
+
 # Now, let's fill any that aren't set in with defaults:
 
 sub gitvar {
index da1a7f5416a4bf3a633d3577382984f528694a78..2b63d89501cc8838cca96506b3532d33fc452a15 100644 (file)
@@ -123,7 +123,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
        struct object_request *obj_req = (struct object_request *)data;
        do {
                ssize_t retval = write(obj_req->local,
-                                      ptr + posn, size - posn);
+                                      (char *) ptr + posn, size - posn);
                if (retval < 0)
                        return posn;
                posn += retval;
@@ -1136,13 +1136,14 @@ int fetch(unsigned char *sha1)
 
 static inline int needs_quote(int ch)
 {
-       switch (ch) {
-       case '/': case '-': case '.':
-       case 'A'...'Z': case 'a'...'z': case '0'...'9':
+       if (((ch >= 'A') && (ch <= 'Z'))
+                       || ((ch >= 'a') && (ch <= 'z'))
+                       || ((ch >= '0') && (ch <= '9'))
+                       || (ch == '/')
+                       || (ch == '-')
+                       || (ch == '.'))
                return 0;
-       default:
-               return 1;
-       }
+       return 1;
 }
 
 static inline int hex(int v)
index 2d9441ec60222be6806eddbd5e515b2233a4f06d..8d472f0202827db726ede451be3fd63940c38c96 100644 (file)
@@ -196,7 +196,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
        struct transfer_request *request = (struct transfer_request *)data;
        do {
                ssize_t retval = write(request->local_fileno,
-                                      ptr + posn, size - posn);
+                                      (char *) ptr + posn, size - posn);
                if (retval < 0)
                        return posn;
                posn += retval;
@@ -1077,13 +1077,14 @@ static int fetch_indices(void)
 
 static inline int needs_quote(int ch)
 {
-       switch (ch) {
-       case '/': case '-': case '.':
-       case 'A'...'Z': case 'a'...'z': case '0'...'9':
+       if (((ch >= 'A') && (ch <= 'Z'))
+                       || ((ch >= 'a') && (ch <= 'z'))
+                       || ((ch >= '0') && (ch <= '9'))
+                       || (ch == '/')
+                       || (ch == '-')
+                       || (ch == '.'))
                return 0;
-       default:
-               return 1;
-       }
+       return 1;
 }
 
 static inline int hex(int v)
@@ -1171,7 +1172,7 @@ static void one_remote_object(const char *hex)
 
        obj->flags |= REMOTE;
        if (!object_list_contains(objects, obj))
-               add_object(obj, &objects, NULL, "");
+               object_list_insert(obj, &objects);
 }
 
 static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
@@ -1699,6 +1700,15 @@ static int locking_available(void)
        return lock_flags;
 }
 
+struct object_list **add_one_object(struct object *obj, struct object_list **p)
+{
+       struct object_list *entry = xmalloc(sizeof(struct object_list));
+       entry->item = obj;
+       entry->next = *p;
+       *p = entry;
+       return &entry->next;
+}
+
 static struct object_list **process_blob(struct blob *blob,
                                         struct object_list **p,
                                         struct name_path *path,
@@ -1712,8 +1722,7 @@ static struct object_list **process_blob(struct blob *blob,
                return p;
 
        obj->flags |= SEEN;
-       name = strdup(name);
-       return add_object(obj, p, path, name);
+       return add_one_object(obj, p);
 }
 
 static struct object_list **process_tree(struct tree *tree,
@@ -1735,7 +1744,7 @@ static struct object_list **process_tree(struct tree *tree,
 
        obj->flags |= SEEN;
        name = strdup(name);
-       p = add_object(obj, p, NULL, name);
+       p = add_one_object(obj, p);
        me.up = path;
        me.elem = name;
        me.elem_len = strlen(name);
@@ -1756,8 +1765,9 @@ static struct object_list **process_tree(struct tree *tree,
 
 static int get_delta(struct rev_info *revs, struct remote_lock *lock)
 {
+       int i;
        struct commit *commit;
-       struct object_list **p = &objects, *pending;
+       struct object_list **p = &objects;
        int count = 0;
 
        while ((commit = get_revision(revs)) != NULL) {
@@ -1767,22 +1777,23 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
                        count += add_send_request(&commit->object, lock);
        }
 
-       for (pending = revs->pending_objects; pending; pending = pending->next) {
-               struct object *obj = pending->item;
-               const char *name = pending->name;
+       for (i = 0; i < revs->pending.nr; i++) {
+               struct object_array_entry *entry = revs->pending.objects + i;
+               struct object *obj = entry->item;
+               const char *name = entry->name;
 
                if (obj->flags & (UNINTERESTING | SEEN))
                        continue;
-               if (obj->type == tag_type) {
+               if (obj->type == TYPE_TAG) {
                        obj->flags |= SEEN;
-                       p = add_object(obj, p, NULL, name);
+                       p = add_one_object(obj, p);
                        continue;
                }
-               if (obj->type == tree_type) {
+               if (obj->type == TYPE_TREE) {
                        p = process_tree((struct tree *)obj, p, NULL, name);
                        continue;
                }
-               if (obj->type == blob_type) {
+               if (obj->type == TYPE_BLOB) {
                        p = process_blob((struct blob *)obj, p, NULL, name);
                        continue;
                }
@@ -1949,12 +1960,12 @@ static int ref_newer(const unsigned char *new_sha1,
         * old.  Otherwise we require --force.
         */
        o = deref_tag(parse_object(old_sha1), NULL, 0);
-       if (!o || o->type != commit_type)
+       if (!o || o->type != TYPE_COMMIT)
                return 0;
        old = (struct commit *) o;
 
        o = deref_tag(parse_object(new_sha1), NULL, 0);
-       if (!o || o->type != commit_type)
+       if (!o || o->type != TYPE_COMMIT)
                return 0;
        new = (struct commit *) o;
 
@@ -2033,7 +2044,7 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
        fwrite_buffer(ref_info, 1, len, buf);
        free(ref_info);
 
-       if (o->type == tag_type) {
+       if (o->type == TYPE_TAG) {
                o = deref_tag(o, ls->dentry_name, 0);
                if (o) {
                        len = strlen(ls->dentry_name) + 45;
diff --git a/http.c b/http.c
index 08769cc7cd4282a485fb9cd22c4ecfa97096a419..6c1937b676ecd584cededed1c82df30448046ebe 100644 (file)
--- a/http.c
+++ b/http.c
@@ -34,7 +34,7 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
        size_t size = eltsize * nmemb;
        if (size > buffer->size - buffer->posn)
                size = buffer->size - buffer->posn;
-       memcpy(ptr, buffer->buffer + buffer->posn, size);
+       memcpy(ptr, (char *) buffer->buffer + buffer->posn, size);
        buffer->posn += size;
        return size;
 }
@@ -49,7 +49,7 @@ size_t fwrite_buffer(const void *ptr, size_t eltsize,
                        buffer->size = buffer->posn + size;
                buffer->buffer = xrealloc(buffer->buffer, buffer->size);
        }
-       memcpy(buffer->buffer + buffer->posn, ptr, size);
+       memcpy((char *) buffer->buffer + buffer->posn, ptr, size);
        buffer->posn += size;
        data_received++;
        return size;
index 285ad29afb4c4126010ddc2f76963b4f8f1cce70..94e39cd94cb26b2147e214ce4032121df871834e 100644 (file)
@@ -93,7 +93,7 @@ typedef struct {
        char *data;
        int len;
        unsigned char flags;
-       unsigned char crlf:1;
+       unsigned int crlf:1;
 } msg_data_t;
 
 #define DRV_OK          0
index 024196e7ac53cb9ad09b38ea646bad81aff33306..190e12fb7ceeb012a063f8c97b574e9650d95cc1 100644 (file)
@@ -99,6 +99,11 @@ int main(int argc, char **argv)
 {
        int i, force_file = 0;
 
+       /* Without this we cannot rely on waitpid() to tell
+        * what happened to our children.
+        */
+       signal(SIGCHLD, SIG_DFL);
+
        if (argc < 3)
                usage("git-merge-index [-o] [-q] <merge-program> (-a | <filename>*)");
 
index bad8a5377771e678624d01895ca0603070d6bede..3a5ac35d163bae5431c9cad8c9e31918c2734241 100644 (file)
@@ -19,7 +19,7 @@ static void name_rev(struct commit *commit,
                const char *tip_name, int merge_traversals, int generation,
                int deref)
 {
-       struct rev_name *name = (struct rev_name *)commit->object.util;
+       struct rev_name *name = (struct rev_name *)commit->util;
        struct commit_list *parents;
        int parent_number = 1;
 
@@ -41,7 +41,7 @@ static void name_rev(struct commit *commit,
 
        if (name == NULL) {
                name = xmalloc(sizeof(rev_name));
-               commit->object.util = name;
+               commit->util = name;
                goto copy_data;
        } else if (name->merge_traversals > merge_traversals ||
                        (name->merge_traversals == merge_traversals &&
@@ -84,14 +84,14 @@ static int name_ref(const char *path, const unsigned char *sha1)
        if (tags_only && strncmp(path, "refs/tags/", 10))
                return 0;
 
-       while (o && o->type == tag_type) {
+       while (o && o->type == TYPE_TAG) {
                struct tag *t = (struct tag *) o;
                if (!t->tagged)
                        break; /* broken repository */
                o = parse_object(t->tagged->sha1);
                deref = 1;
        }
-       if (o && o->type == commit_type) {
+       if (o && o->type == TYPE_COMMIT) {
                struct commit *commit = (struct commit *)o;
 
                if (!strncmp(path, "refs/heads/", 11))
@@ -108,7 +108,13 @@ static int name_ref(const char *path, const unsigned char *sha1)
 static const char* get_rev_name(struct object *o)
 {
        static char buffer[1024];
-       struct rev_name *n = (struct rev_name *)o->util;
+       struct rev_name *n;
+       struct commit *c;
+
+       if (o->type != TYPE_COMMIT)
+               return "undefined";
+       c = (struct commit *) o;
+       n = c->util;
        if (!n)
                return "undefined";
 
@@ -119,11 +125,10 @@ static const char* get_rev_name(struct object *o)
 
        return buffer;
 }
-       
+
 int main(int argc, char **argv)
 {
-       struct object_list *revs = NULL;
-       struct object_list **walker = &revs;
+       struct object_array revs = { 0, 0, NULL };
        int as_is = 0, all = 0, transform_stdin = 0;
 
        setup_git_directory();
@@ -167,7 +172,7 @@ int main(int argc, char **argv)
                }
 
                o = deref_tag(parse_object(sha1), *argv, 0);
-               if (!o || o->type != commit_type) {
+               if (!o || o->type != TYPE_COMMIT) {
                        fprintf(stderr, "Could not get commit for %s. Skipping.\n",
                                        *argv);
                        continue;
@@ -178,9 +183,7 @@ int main(int argc, char **argv)
                if (cutoff > commit->date)
                        cutoff = commit->date;
 
-               object_list_append((struct object *)commit, walker);
-               (*walker)->name = *argv;
-               walker = &((*walker)->next);
+               add_object_array((struct object *)commit, *argv, &revs);
        }
 
        for_each_ref(name_ref);
@@ -237,9 +240,13 @@ int main(int argc, char **argv)
                        if (objs[i])
                                printf("%s %s\n", sha1_to_hex(objs[i]->sha1),
                                                get_rev_name(objs[i]));
-       } else
-               for ( ; revs; revs = revs->next)
-                       printf("%s %s\n", revs->name, get_rev_name(revs->item));
+       } else {
+               int i;
+               for (i = 0; i < revs.nr; i++)
+                       printf("%s %s\n",
+                               revs.objects[i].name,
+                               get_rev_name(revs.objects[i].item));
+       }
 
        return 0;
 }
diff --git a/object-refs.c b/object-refs.c
new file mode 100644 (file)
index 0000000..b1b8065
--- /dev/null
@@ -0,0 +1,143 @@
+#include "cache.h"
+#include "object.h"
+
+int track_object_refs = 0;
+
+static unsigned int refs_hash_size, nr_object_refs;
+static struct object_refs **refs_hash;
+
+static unsigned int hash_obj(struct object *obj, unsigned int n)
+{
+       unsigned int hash = *(unsigned int *)obj->sha1;
+       return hash % n;
+}
+
+static void insert_ref_hash(struct object_refs *ref, struct object_refs **hash, unsigned int size)
+{
+       int j = hash_obj(ref->base, size);
+
+       while (hash[j]) {
+               j++;
+               if (j >= size)
+                       j = 0;
+       }
+       hash[j] = ref;
+}
+
+static void grow_refs_hash(void)
+{
+       int i;
+       int new_hash_size = (refs_hash_size + 1000) * 3 / 2;
+       struct object_refs **new_hash;
+
+       new_hash = calloc(new_hash_size, sizeof(struct object_refs *));
+       for (i = 0; i < refs_hash_size; i++) {
+               struct object_refs *ref = refs_hash[i];
+               if (!ref)
+                       continue;
+               insert_ref_hash(ref, new_hash, new_hash_size);
+       }
+       free(refs_hash);
+       refs_hash = new_hash;
+       refs_hash_size = new_hash_size;
+}
+
+static void add_object_refs(struct object *obj, struct object_refs *ref)
+{
+       int nr = nr_object_refs + 1;
+
+       if (nr > refs_hash_size * 2 / 3)
+               grow_refs_hash();
+       ref->base = obj;
+       insert_ref_hash(ref, refs_hash, refs_hash_size);
+       nr_object_refs = nr;
+}
+
+struct object_refs *lookup_object_refs(struct object *obj)
+{
+       int j = hash_obj(obj, refs_hash_size);
+       struct object_refs *ref;
+
+       while ((ref = refs_hash[j]) != NULL) {
+               if (ref->base == obj)
+                       break;
+               j++;
+               if (j >= refs_hash_size)
+                       j = 0;
+       }
+       return ref;
+}
+
+struct object_refs *alloc_object_refs(unsigned count)
+{
+       struct object_refs *refs;
+       size_t size = sizeof(*refs) + count*sizeof(struct object *);
+
+       refs = xcalloc(1, 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;
+       if (*pa == *pb)
+               return 0;
+       else if (*pa < *pb)
+               return -1;
+       else
+               return 1;
+}
+
+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;
+       }
+
+       /* 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);
+       }
+
+       for (i = 0; i < refs->count; i++)
+               refs->ref[i]->used = 1;
+       add_object_refs(obj, refs);
+}
+
+void mark_reachable(struct object *obj, unsigned int mask)
+{
+       const struct object_refs *refs;
+
+       if (!track_object_refs)
+               die("cannot do reachability with object refs turned off");
+       /* nothing to lookup */
+       if (!refs_hash_size)
+               return;
+       /* If we've been here already, don't bother */
+       if (obj->flags & mask)
+               return;
+       obj->flags |= mask;
+       refs = lookup_object_refs(obj);
+       if (refs) {
+               unsigned i;
+               for (i = 0; i < refs->count; i++)
+                       mark_reachable(refs->ref[i], mask);
+       }
+}
+
+
index 9adc87479bde2a0b2a0a0335aed12a9f485facff..37784cee9a90a7e5b44dd660d6b7ea9191b59486 100644 (file)
--- a/object.c
+++ b/object.c
@@ -9,7 +9,9 @@ struct object **objs;
 static int nr_objs;
 int obj_allocs;
 
-int track_object_refs = 0;
+const char *type_names[] = {
+       "none", "blob", "tree", "commit", "bad"
+};
 
 static int hashtable_index(const unsigned char *sha1)
 {
@@ -50,8 +52,7 @@ void created_object(const unsigned char *sha1, struct object *obj)
 
        obj->parsed = 0;
        memcpy(obj->sha1, sha1, 20);
-       obj->type = NULL;
-       obj->refs = NULL;
+       obj->type = TYPE_NONE;
        obj->used = 0;
 
        if (obj_allocs - 1 <= nr_objs * 2) {
@@ -80,73 +81,6 @@ void created_object(const unsigned char *sha1, struct object *obj)
        nr_objs++;
 }
 
-struct object_refs *alloc_object_refs(unsigned count)
-{
-       struct object_refs *refs;
-       size_t size = sizeof(*refs) + count*sizeof(struct object *);
-
-       refs = xcalloc(1, 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;
-       if (*pa == *pb)
-               return 0;
-       else if (*pa < *pb)
-               return -1;
-       else
-               return 1;
-}
-
-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;
-       }
-
-       /* 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);
-       }
-
-       for (i = 0; i < refs->count; i++)
-               refs->ref[i]->used = 1;
-       obj->refs = refs;
-}
-
-void mark_reachable(struct object *obj, unsigned int 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;
-       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);
-       }
-}
-
 struct object *lookup_object_type(const unsigned char *sha1, const char *type)
 {
        if (!type) {
@@ -179,7 +113,7 @@ struct object *lookup_unknown_object(const unsigned char *sha1)
        if (!obj) {
                union any_object *ret = xcalloc(1, sizeof(*ret));
                created_object(sha1, &ret->object);
-               ret->object.type = NULL;
+               ret->object.type = TYPE_NONE;
                return &ret->object;
        }
        return obj;
@@ -266,3 +200,20 @@ int object_list_contains(struct object_list *list, struct object *obj)
        }
        return 0;
 }
+
+void add_object_array(struct object *obj, const char *name, struct object_array *array)
+{
+       unsigned nr = array->nr;
+       unsigned alloc = array->alloc;
+       struct object_array_entry *objects = array->objects;
+
+       if (nr >= alloc) {
+               alloc = (alloc + 32) * 2;
+               objects = xrealloc(objects, alloc * sizeof(*objects));
+               array->alloc = alloc;
+               array->objects = objects;
+       }
+       objects[nr].item = obj;
+       objects[nr].name = name;
+       array->nr = ++nr;
+}
index e08afbd29ff04cf463a4aacdc4fe141a2ab54ce6..6f23a9a18099cbc9fdc827f53843b1157dd10935 100644 (file)
--- a/object.h
+++ b/object.h
@@ -4,27 +4,52 @@
 struct object_list {
        struct object *item;
        struct object_list *next;
-       const char *name;
 };
 
 struct object_refs {
        unsigned count;
+       struct object *base;
        struct object *ref[FLEX_ARRAY]; /* more */
 };
 
+struct object_array {
+       unsigned int nr;
+       unsigned int alloc;
+       struct object_array_entry {
+               struct object *item;
+               const char *name;
+       } *objects;
+};
+
+#define TYPE_BITS   3
+#define FLAG_BITS  27
+
+#define TYPE_NONE   0
+#define TYPE_BLOB   1
+#define TYPE_TREE   2
+#define TYPE_COMMIT 3
+#define TYPE_TAG    4
+#define TYPE_BAD    5
+
 struct object {
        unsigned parsed : 1;
        unsigned used : 1;
-       unsigned int flags;
+       unsigned type : TYPE_BITS;
+       unsigned flags : FLAG_BITS;
        unsigned char sha1[20];
-       const char *type;
-       struct object_refs *refs;
-       void *util;
 };
 
 extern int track_object_refs;
 extern int obj_allocs;
 extern struct object **objs;
+extern const char *type_names[];
+
+static inline const char *typename(unsigned int type)
+{
+       return type_names[type > TYPE_TAG ? TYPE_BAD : type];
+}
+
+extern struct object_refs *lookup_object_refs(struct object *);
 
 /** Internal only **/
 struct object *lookup_object(const unsigned char *sha1);
@@ -55,4 +80,7 @@ unsigned object_list_length(struct object_list *list);
 
 int object_list_contains(struct object_list *list, struct object *obj);
 
+/* Object array handling .. */
+void add_object_array(struct object *obj, const char *name, struct object_array *array);
+
 #endif /* OBJECT_H */
index e57587909e54d9317a18e3bfd43559562a40f0d5..3a62e1b7e40927390e10ae63943596a367ecbf47 100644 (file)
@@ -29,10 +29,10 @@ static int verify_packfile(struct packed_git *p)
        pack_base = p->pack_base;
        SHA1_Update(&ctx, pack_base, pack_size - 20);
        SHA1_Final(sha1, &ctx);
-       if (memcmp(sha1, pack_base + pack_size - 20, 20))
+       if (memcmp(sha1, (char *) pack_base + pack_size - 20, 20))
                return error("Packfile %s SHA1 mismatch with itself",
                             p->pack_name);
-       if (memcmp(sha1, index_base + index_size - 40, 20))
+       if (memcmp(sha1, (char *) index_base + index_size - 40, 20))
                return error("Packfile %s SHA1 mismatch with idx",
                             p->pack_name);
 
@@ -135,7 +135,7 @@ int verify_pack(struct packed_git *p, int verbose)
        SHA1_Init(&ctx);
        SHA1_Update(&ctx, index_base, index_size - 20);
        SHA1_Final(sha1, &ctx);
-       if (memcmp(sha1, index_base + index_size - 20, 20))
+       if (memcmp(sha1, (char *) index_base + index_size - 20, 20))
                ret = error("Packfile index for %s SHA1 mismatch",
                            p->pack_name);
 
index 179560f2bd67e08d25bef0199c41ee0ee70793f9..bed2497b7974bed96a6ac9478807059cb8de17cb 100644 (file)
@@ -156,7 +156,7 @@ static void prepare_pack_revindex(struct pack_revindex *rix)
 
        rix->revindex = xmalloc(sizeof(unsigned long) * (num_ent + 1));
        for (i = 0; i < num_ent; i++) {
-               unsigned int hl = *((unsigned int *)(index + 24 * i));
+               unsigned int hl = *((unsigned int *)((char *) index + 24*i));
                rix->revindex[i] = ntohl(hl);
        }
        /* This knows the pack format -- the 20-byte trailer
@@ -300,7 +300,7 @@ static unsigned long write_object(struct sha1file *f,
                use_packed_git(p);
 
                datalen = find_packed_object_size(p, entry->in_pack_offset);
-               buf = p->pack_base + entry->in_pack_offset;
+               buf = (char *) p->pack_base + entry->in_pack_offset;
                sha1write(f, buf, datalen);
                unuse_packed_git(p);
                hdrlen = 0; /* not really */
@@ -1221,6 +1221,10 @@ int main(int argc, char **argv)
                                local = 1;
                                continue;
                        }
+                       if (!strcmp("--progress", arg)) {
+                               progress = 1;
+                               continue;
+                       }
                        if (!strcmp("--incremental", arg)) {
                                incremental = 1;
                                continue;
index cd81f5a66eae2a4c1fdab4086b896d6a06dcf687..41fb960569e1c7ed479fb123902752c552ff1341 100644 (file)
@@ -246,12 +246,12 @@ static struct pack_list * pack_list_difference(const struct pack_list *A,
 static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
 {
        int p1_off, p2_off;
-       void *p1_base, *p2_base;
+       unsigned char *p1_base, *p2_base;
        struct llist_item *p1_hint = NULL, *p2_hint = NULL;
-       
+
        p1_off = p2_off = 256 * 4 + 4;
-       p1_base = (void *)p1->pack->index_base;
-       p2_base = (void *)p2->pack->index_base;
+       p1_base = (unsigned char *) p1->pack->index_base;
+       p2_base = (unsigned char *) p2->pack->index_base;
 
        while (p1_off <= p1->pack->index_size - 3 * 20 &&
               p2_off <= p2->pack->index_size - 3 * 20)
@@ -351,11 +351,11 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
 {
        size_t ret = 0;
        int p1_off, p2_off;
-       void *p1_base, *p2_base;
+       char *p1_base, *p2_base;
 
        p1_off = p2_off = 256 * 4 + 4;
-       p1_base = (void *)p1->index_base;
-       p2_base = (void *)p2->index_base;
+       p1_base = (char *)p1->index_base;
+       p2_base = (char *)p2->index_base;
 
        while (p1_off <= p1->index_size - 3 * 20 &&
               p2_off <= p2->index_size - 3 * 20)
@@ -534,7 +534,7 @@ static struct pack_list * add_pack(struct packed_git *p)
 {
        struct pack_list l;
        size_t off;
-       void *base;
+       unsigned char *base;
 
        if (!p->pack_local && !(alt_odb || verbose))
                return NULL;
@@ -543,7 +543,7 @@ static struct pack_list * add_pack(struct packed_git *p)
        llist_init(&l.all_objects);
 
        off = 256 * 4 + 4;
-       base = (void *)p->index_base;
+       base = (unsigned char *)p->index_base;
        while (off <= p->index_size - 3 * 20) {
                llist_insert_back(l.all_objects, base + off);
                off += 24;
index 8f318ed8aaf180419f97887501317fc1d2b54c09..e3a1d425ee2e333bce0f87b1e50fc112a8ec51a3 100644 (file)
@@ -25,7 +25,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
                return NULL;
 
        data = delta_buf;
-       top = delta_buf + delta_size;
+       top = (const unsigned char *) delta_buf + delta_size;
 
        /* make sure the orig file size matches what we expect */
        size = get_delta_hdr_size(&data, top);
@@ -56,7 +56,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
                            cp_off + cp_size > src_size ||
                            cp_size > size)
                                goto bad;
-                       memcpy(out, src_buf + cp_off, cp_size);
+                       memcpy(out, (char *) src_buf + cp_off, cp_size);
                        out += cp_size;
                        size -= cp_size;
                } else if (cmd) {
diff --git a/path.c b/path.c
index 194e0b553f7a5c4fd99b348228112b308c5419b6..36972fd6df63b3c4eebdcf89238df8ade60d53c3 100644 (file)
--- a/path.c
+++ b/path.c
@@ -267,11 +267,21 @@ int adjust_shared_perm(const char *path)
                return -1;
        mode = st.st_mode;
        if (mode & S_IRUSR)
-               mode |= S_IRGRP;
+               mode |= (shared_repository == PERM_GROUP
+                        ? S_IRGRP
+                        : (shared_repository == PERM_EVERYBODY
+                           ? (S_IRGRP|S_IROTH)
+                           : 0));
+
        if (mode & S_IWUSR)
                mode |= S_IWGRP;
+
        if (mode & S_IXUSR)
-               mode |= S_IXGRP;
+               mode |= (shared_repository == PERM_GROUP
+                        ? S_IXGRP
+                        : (shared_repository == PERM_EVERYBODY
+                           ? (S_IXGRP|S_IXOTH)
+                           : 0));
        if (S_ISDIR(mode))
                mode |= S_ISGID;
        if (chmod(path, mode) < 0)
index bb3bab05cd203e114b24b778cb5f55218abdec95..c1e81f976f26726db2432f72f7356087a6e3a7d8 100644 (file)
  * The writing side could use stdio, but since the reading
  * side can't, we stay with pure read/write interfaces.
  */
-static void safe_write(int fd, const void *buf, unsigned n)
+ssize_t safe_write(int fd, const void *buf, ssize_t n)
 {
+       ssize_t nn = n;
        while (n) {
                int ret = xwrite(fd, buf, n);
                if (ret > 0) {
-                       buf += ret;
+                       buf = (char *) buf + ret;
                        n -= ret;
                        continue;
                }
@@ -29,6 +30,7 @@ static void safe_write(int fd, const void *buf, unsigned n)
                        die("write error (disk full?)");
                die("write error (%s)", strerror(errno));
        }
+       return nn;
 }
 
 /*
@@ -66,7 +68,7 @@ static void safe_read(int fd, void *buffer, unsigned size)
        int n = 0;
 
        while (n < size) {
-               int ret = xread(fd, buffer + n, size - n);
+               int ret = xread(fd, (char *) buffer + n, size - n);
                if (ret < 0)
                        die("read error (%s)", strerror(errno));
                if (!ret)
index 51d0cbe219f2f45bf3920441f09dfcc2744adb06..9abef24de36119a56a9bee48e49c2c8fccae32fc 100644 (file)
@@ -8,5 +8,6 @@ void packet_flush(int fd);
 void packet_write(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
 
 int packet_read_line(int fd, char *buffer, unsigned size);
+ssize_t safe_write(int, const void *, ssize_t);
 
 #endif
index 5ba4fc5259b063dab6417c142938d987ee894fc0..0820398b004dd8af93a25e7fa26be60cf4dda410 100644 (file)
@@ -30,7 +30,7 @@ int SHA1_Update(SHA_CTX *c, const void *ptr, unsigned long n)
        unsigned long nb;
        const unsigned char *p = ptr;
 
-       c->len += n << 3;
+       c->len += (uint64_t) n << 3;
        while (n != 0) {
                if (c->cnt || n < 64) {
                        nb = 64 - c->cnt;
diff --git a/quote.c b/quote.c
index 06792d47c3e324ee9893a4e52035f0642f38005f..dcc23266109ce30e3fd098f3c76799b67b75a332 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -206,7 +206,14 @@ char *unquote_c_style(const char *quoted, const char **endp)
                                case '\\': case '"':
                                        break; /* verbatim */
 
-                               case '0'...'7':
+                               case '0':
+                               case '1':
+                               case '2':
+                               case '3':
+                               case '4':
+                               case '5':
+                               case '6':
+                               case '7':
                                        /* octal */
                                        ac = ((ch - '0') << 6);
                                        if ((ch = *sp++) < '0' || '7' < ch)
index c499c5185678b6b4ac35d57d1ab0b36cc2ff056b..3c32aae7e8ae63bccad83a603f2b86c66965cd26 100644 (file)
@@ -706,7 +706,7 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
        SHA1_Init(&c);
        SHA1_Update(&c, hdr, size - 20);
        SHA1_Final(sha1, &c);
-       if (memcmp(sha1, (void *)hdr + size - 20, 20))
+       if (memcmp(sha1, (char *) hdr + size - 20, 20))
                return error("bad index file sha1 signature");
        return 0;
 }
@@ -770,7 +770,7 @@ int read_cache(void)
 
        offset = sizeof(*hdr);
        for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = map + offset;
+               struct cache_entry *ce = (struct cache_entry *) ((char *) map + offset);
                offset = offset + ce_size(ce);
                active_cache[i] = ce;
        }
@@ -783,10 +783,11 @@ int read_cache(void)
                 * in 4-byte network byte order.
                 */
                unsigned long extsize;
-               memcpy(&extsize, map + offset + 4, 4);
+               memcpy(&extsize, (char *) map + offset + 4, 4);
                extsize = ntohl(extsize);
-               if (read_index_extension(map + offset,
-                                        map + offset + 8, extsize) < 0)
+               if (read_index_extension(((const char *) map) + offset,
+                                        (char *) map + offset + 8,
+                                        extsize) < 0)
                        goto unmap;
                offset += 8;
                offset += extsize;
@@ -820,7 +821,7 @@ static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
                }
                write_buffer_len = buffered;
                len -= partial;
-               data += partial;
+               data = (char *) data + partial;
        }
        return 0;
 }
index 08fc4cc57d064248247c912014e4eba32490f0ff..ab8f1afeea0cbff7707e313af1c18ff56363ae09 100644 (file)
@@ -64,7 +64,20 @@ static int show_config(const char* key_, const char* value_)
 
 static int get_value(const char* key_, const char* regex_)
 {
+       int ret = -1;
        char *tl;
+       char *global = NULL, *repo_config = NULL;
+       const char *local;
+
+       local = getenv("GIT_CONFIG");
+       if (!local) {
+               const char *home = getenv("HOME");
+               local = getenv("GIT_CONFIG_LOCAL");
+               if (!local)
+                       local = repo_config = strdup(git_path("config"));
+               if (home)
+                       global = strdup(mkpath("%s/.gitconfig", home));
+       }
 
        key = strdup(key_);
        for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
@@ -76,7 +89,7 @@ static int get_value(const char* key_, const char* regex_)
                key_regexp = (regex_t*)malloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
-                       return -1;
+                       goto free_strings;
                }
        }
 
@@ -89,11 +102,16 @@ static int get_value(const char* key_, const char* regex_)
                regexp = (regex_t*)malloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
-                       return -1;
+                       goto free_strings;
                }
        }
 
-       git_config(show_config);
+       if (do_all && global)
+               git_config_from_file(show_config, global);
+       git_config_from_file(show_config, local);
+       if (!do_all && !seen && global)
+               git_config_from_file(show_config, global);
+
        free(key);
        if (regexp) {
                regfree(regexp);
@@ -101,9 +119,16 @@ static int get_value(const char* key_, const char* regex_)
        }
 
        if (do_all)
-               return !seen;
-
-       return (seen == 1) ? 0 : 1;
+               ret = !seen;
+       else
+               ret =  (seen == 1) ? 0 : 1;
+
+free_strings:
+       if (repo_config)
+               free(repo_config);
+       if (global)
+               free(global);
+       return ret;
 }
 
 int main(int argc, const char **argv)
index 75c648c13c6c50335ffc3e79f5d6303bea20104e..b963f2adfd92050310f7327e1ee10e21d5996a7c 100644 (file)
@@ -31,17 +31,12 @@ static char *path_name(struct name_path *path, const char *name)
        return n;
 }
 
-struct object_list **add_object(struct object *obj,
-                                      struct object_list **p,
-                                      struct name_path *path,
-                                      const char *name)
+void add_object(struct object *obj,
+               struct object_array *p,
+               struct name_path *path,
+               const char *name)
 {
-       struct object_list *entry = xmalloc(sizeof(*entry));
-       entry->item = obj;
-       entry->next = *p;
-       entry->name = path_name(path, name);
-       *p = entry;
-       return &entry->next;
+       add_object_array(obj, path_name(path, name), p);
 }
 
 static void mark_blob_uninteresting(struct blob *blob)
@@ -117,9 +112,9 @@ void mark_parents_uninteresting(struct commit *commit)
        }
 }
 
-static void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
+void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
 {
-       add_object(obj, &revs->pending_objects, NULL, name);
+       add_object_array(obj, name, &revs->pending);
 }
 
 static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
@@ -140,7 +135,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
        /*
         * Tag object? Look what it points to..
         */
-       while (object->type == tag_type) {
+       while (object->type == TYPE_TAG) {
                struct tag *tag = (struct tag *) object;
                if (revs->tag_objects && !(flags & UNINTERESTING))
                        add_pending_object(revs, object, tag->tag);
@@ -153,7 +148,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
         * Commit object? Just return it, we'll do all the complex
         * reachability crud.
         */
-       if (object->type == commit_type) {
+       if (object->type == TYPE_COMMIT) {
                struct commit *commit = (struct commit *)object;
                if (parse_commit(commit) < 0)
                        die("unable to parse commit %s", name);
@@ -169,7 +164,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
         * Tree object? Either mark it uniniteresting, or add it
         * to the list of objects to look at later..
         */
-       if (object->type == tree_type) {
+       if (object->type == TYPE_TREE) {
                struct tree *tree = (struct tree *)object;
                if (!revs->tree_objects)
                        return NULL;
@@ -184,7 +179,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
        /*
         * Blob object? You know the drill by now..
         */
-       if (object->type == blob_type) {
+       if (object->type == TYPE_BLOB) {
                struct blob *blob = (struct blob *)object;
                if (!revs->blob_objects)
                        return NULL;
@@ -498,11 +493,11 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
                return 0;
        while (1) {
                it = get_reference(revs, arg, sha1, 0);
-               if (strcmp(it->type, tag_type))
+               if (it->type != TYPE_TAG)
                        break;
                memcpy(sha1, ((struct tag*)it)->tagged->sha1, 20);
        }
-       if (strcmp(it->type, commit_type))
+       if (it->type != TYPE_COMMIT)
                return 0;
        commit = (struct commit *)it;
        for (parents = commit->parents; parents; parents = parents->next) {
@@ -836,7 +831,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                object = get_reference(revs, arg, sha1, flags ^ local_flags);
                add_pending_object(revs, object, arg);
        }
-       if (def && !revs->pending_objects) {
+       if (def && !revs->pending.nr) {
                unsigned char sha1[20];
                struct object *object;
                if (get_sha1(def, sha1))
@@ -868,11 +863,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 
 void prepare_revision_walk(struct rev_info *revs)
 {
-       struct object_list *list;
+       int nr = revs->pending.nr;
+       struct object_array_entry *list = revs->pending.objects;
 
-       list = revs->pending_objects;
-       revs->pending_objects = NULL;
-       while (list) {
+       revs->pending.nr = 0;
+       revs->pending.alloc = 0;
+       revs->pending.objects = NULL;
+       while (--nr >= 0) {
                struct commit *commit = handle_commit(revs, list->item, list->name);
                if (commit) {
                        if (!(commit->object.flags & SEEN)) {
@@ -880,7 +877,7 @@ void prepare_revision_walk(struct rev_info *revs)
                                insert_by_date(commit, &revs->commits);
                        }
                }
-               list = list->next;
+               list++;
        }
 
        if (revs->no_walk)
@@ -949,9 +946,11 @@ struct commit *get_revision(struct rev_info *revs)
        }
 
        do {
-               struct commit *commit = revs->commits->item;
+               struct commit_list *entry = revs->commits;
+               struct commit *commit = entry->item;
 
-               revs->commits = revs->commits->next;
+               revs->commits = entry->next;
+               free(entry);
 
                /*
                 * If we haven't done the list limiting, we need to look at
index 4020e25c336356868057ee88e84b395f55b87b38..c010a0811604e55f4e46d08d986ae62edfb192ee 100644 (file)
@@ -18,7 +18,7 @@ typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
 struct rev_info {
        /* Starting list */
        struct commit_list *commits;
-       struct object_list *pending_objects;
+       struct object_array pending;
 
        /* Basic information */
        const char *prefix;
@@ -99,9 +99,11 @@ struct name_path {
        const char *elem;
 };
 
-extern struct object_list **add_object(struct object *obj,
-                                      struct object_list **p,
-                                      struct name_path *path,
-                                      const char *name);
+extern void add_object(struct object *obj,
+                      struct object_array *p,
+                      struct name_path *path,
+                      const char *name);
+
+extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
 
 #endif
index 409f18850357567748f63f73ec84c066f9e3fe94..af93b11f238e4583f6e7fb9dab5a2224acf4ee1f 100644 (file)
@@ -151,12 +151,12 @@ static int ref_newer(const unsigned char *new_sha1,
         * old.  Otherwise we require --force.
         */
        o = deref_tag(parse_object(old_sha1), NULL, 0);
-       if (!o || o->type != commit_type)
+       if (!o || o->type != TYPE_COMMIT)
                return 0;
        old = (struct commit *) o;
 
        o = deref_tag(parse_object(new_sha1), NULL, 0);
-       if (!o || o->type != commit_type)
+       if (!o || o->type != TYPE_COMMIT)
                return 0;
        new = (struct commit *) o;
 
index 05bce7da3b4935675465f993c24bb1188439d6d9..0eb5132cc1cf09ea7dacdf659d3c03adae761acf 100644 (file)
@@ -12,7 +12,7 @@ static int add_info_ref(const char *path, const unsigned char *sha1)
        struct object *o = parse_object(sha1);
 
        fprintf(info_ref_fp, "%s        %s\n", sha1_to_hex(sha1), path);
-       if (o->type == tag_type) {
+       if (o->type == TYPE_TAG) {
                o = deref_tag(o, path, 0);
                if (o)
                        fprintf(info_ref_fp, "%s        %s^{}\n",
diff --git a/setup.c b/setup.c
index fe7f8846962d1c656d258384dbfa466031e28896..4612f110ee0beaeada3cb31ce7d47ad7175eec9c 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -219,12 +219,27 @@ const char *setup_git_directory_gently(int *nongit_ok)
        return cwd + offset;
 }
 
+int git_config_perm(const char *var, const char *value)
+{
+       if (value) {
+               if (!strcmp(value, "umask"))
+                       return PERM_UMASK;
+               if (!strcmp(value, "group"))
+                       return PERM_GROUP;
+               if (!strcmp(value, "all") ||
+                   !strcmp(value, "world") ||
+                   !strcmp(value, "everybody"))
+                       return PERM_EVERYBODY;
+       }
+       return git_config_bool(var, value);
+}
+
 int check_repository_format_version(const char *var, const char *value)
 {
        if (strcmp(var, "core.repositoryformatversion") == 0)
                repository_format_version = git_config_int(var, value);
        else if (strcmp(var, "core.sharedrepository") == 0)
-               shared_repository = git_config_bool(var, value);
+               shared_repository = git_config_perm(var, value);
        return 0;
 }
 
index b4ff233bad3c15692610f93549b25cd0cf042392..c80528b506e98c1e1dae463fa08159677a2a9473 100644 (file)
@@ -486,8 +486,9 @@ int use_packed_git(struct packed_git *p)
                 * this is cheap.
                 */
                if (memcmp((char*)(p->index_base) + p->index_size - 40,
-                          p->pack_base + p->pack_size - 20, 20)) {
-                             
+                          (char *) p->pack_base + p->pack_size - 20,
+                          20)) {
+
                        die("packfile %s does not match index.", p->pack_name);
                }
        }
@@ -701,7 +702,7 @@ static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size
        int bytes = strlen(buffer) + 1;
        unsigned char *buf = xmalloc(1+size);
 
-       memcpy(buf, buffer + bytes, stream->total_out - bytes);
+       memcpy(buf, (char *) buffer + bytes, stream->total_out - bytes);
        bytes = stream->total_out - bytes;
        if (bytes < size) {
                stream->next_out = buf + bytes;
@@ -853,7 +854,7 @@ static unsigned long unpack_object_header(struct packed_git *p, unsigned long of
        if (offset >= p->pack_size)
                die("object offset outside of pack file");
 
-       pack =  p->pack_base + offset;
+       pack =  (unsigned char *) p->pack_base + offset;
        c = *pack++;
        offset++;
        *type = (c >> 4) & 7;
@@ -883,7 +884,7 @@ int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
        ptr = unpack_object_header(p, ptr, kindp, sizep);
        if (*kindp != OBJ_DELTA)
                goto done;
-       memcpy(base, p->pack_base + ptr, 20);
+       memcpy(base, (char *) p->pack_base + ptr, 20);
        status = 0;
  done:
        unuse_packed_git(p);
@@ -903,7 +904,7 @@ void packed_object_info_detail(struct pack_entry *e,
        enum object_type kind;
 
        offset = unpack_object_header(p, e->offset, &kind, size);
-       pack = p->pack_base + offset;
+       pack = (unsigned char *) p->pack_base + offset;
        if (kind != OBJ_DELTA)
                *delta_chain_length = 0;
        else {
@@ -919,7 +920,7 @@ void packed_object_info_detail(struct pack_entry *e,
                        find_pack_entry_one(pack, &base_ent, p);
                        offset = unpack_object_header(p, base_ent.offset,
                                                      &kind, &junk);
-                       pack = p->pack_base + offset;
+                       pack = (unsigned char *) p->pack_base + offset;
                        chain_length++;
                } while (kind == OBJ_DELTA);
                *delta_chain_length = chain_length;
@@ -957,7 +958,7 @@ static int packed_object_info(struct pack_entry *entry,
                die("cannot map packed file");
 
        offset = unpack_object_header(p, entry->offset, &kind, &size);
-       pack = p->pack_base + offset;
+       pack = (unsigned char *) p->pack_base + offset;
        left = p->pack_size - offset;
 
        switch (kind) {
@@ -1096,7 +1097,7 @@ void *unpack_entry_gently(struct pack_entry *entry,
        void *retval;
 
        offset = unpack_object_header(p, entry->offset, &kind, &size);
-       pack = p->pack_base + offset;
+       pack = (unsigned char *) p->pack_base + offset;
        left = p->pack_size - offset;
        switch (kind) {
        case OBJ_DELTA:
@@ -1134,7 +1135,7 @@ int nth_packed_object_sha1(const struct packed_git *p, int n,
        void *index = p->index_base + 256;
        if (n < 0 || num_packed_objects(p) <= n)
                return -1;
-       memcpy(sha1, (index + 24 * n + 4), 20);
+       memcpy(sha1, (char *) index + (24 * n) + 4, 20);
        return 0;
 }
 
@@ -1148,9 +1149,9 @@ int find_pack_entry_one(const unsigned char *sha1,
 
        do {
                int mi = (lo + hi) / 2;
-               int cmp = memcmp(index + 24 * mi + 4, sha1, 20);
+               int cmp = memcmp((char *) index + (24 * mi) + 4, sha1, 20);
                if (!cmp) {
-                       e->offset = ntohl(*((unsigned int *)(index + 24 * mi)));
+                       e->offset = ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
                        memcpy(e->sha1, sha1, 20);
                        e->p = p;
                        return 1;
@@ -1290,7 +1291,7 @@ void *read_object_with_reference(const unsigned char *sha1,
                ref_length = strlen(ref_type);
 
                if (memcmp(buffer, ref_type, ref_length) ||
-                   get_sha1_hex(buffer + ref_length, actual_sha1)) {
+                   get_sha1_hex((char *) buffer + ref_length, actual_sha1)) {
                        free(buffer);
                        return NULL;
                }
@@ -1408,7 +1409,7 @@ static int write_buffer(int fd, const void *buf, size_t len)
                        return error("file write error (%s)", strerror(errno));
                }
                len -= size;
-               buf += size;
+               buf = (char *) buf + size;
        }
        return 0;
 }
index 8fe9b7a75f0f8c43744ce6c031d953f51481ecab..cd85d1fa0f9f2afb4e159cb635db435e75ef3e58 100644 (file)
@@ -357,7 +357,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
 {
        unsigned char outer[20];
        const char *sp;
-       const char *type_string = NULL;
+       unsigned int expected_type = 0;
        struct object *o;
 
        /*
@@ -381,13 +381,13 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
 
        sp++; /* beginning of type name, or closing brace for empty */
        if (!strncmp(commit_type, sp, 6) && sp[6] == '}')
-               type_string = commit_type;
+               expected_type = TYPE_COMMIT;
        else if (!strncmp(tree_type, sp, 4) && sp[4] == '}')
-               type_string = tree_type;
+               expected_type = TYPE_TREE;
        else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
-               type_string = blob_type;
+               expected_type = TYPE_BLOB;
        else if (sp[0] == '}')
-               type_string = NULL;
+               expected_type = TYPE_NONE;
        else
                return -1;
 
@@ -397,7 +397,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
        o = parse_object(outer);
        if (!o)
                return -1;
-       if (!type_string) {
+       if (!expected_type) {
                o = deref_tag(o, name, sp - name - 2);
                if (!o || (!o->parsed && !parse_object(o->sha1)))
                        return -1;
@@ -412,18 +412,18 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                while (1) {
                        if (!o || (!o->parsed && !parse_object(o->sha1)))
                                return -1;
-                       if (o->type == type_string) {
+                       if (o->type == expected_type) {
                                memcpy(sha1, o->sha1, 20);
                                return 0;
                        }
-                       if (o->type == tag_type)
+                       if (o->type == TYPE_TAG)
                                o = ((struct tag*) o)->tagged;
-                       else if (o->type == commit_type)
+                       else if (o->type == TYPE_COMMIT)
                                o = &(((struct commit *) o)->tree->object);
                        else
                                return error("%.*s: expected %s type, but the object dereferences to %s type",
-                                            len, name, type_string,
-                                            o->type);
+                                            len, name, typename(expected_type),
+                                            typename(o->type));
                        if (!o->parsed)
                                parse_object(o->sha1);
                }
index e3067b878e8721886c9fe61b136b46415165671d..1e59cd2008d8089efef74b940d1a1094add7e687 100644 (file)
@@ -24,7 +24,7 @@ static ssize_t force_write(int fd, void *buffer, size_t length)
 {
        ssize_t ret = 0;
        while (ret < length) {
-               ssize_t size = write(fd, buffer + ret, length - ret);
+               ssize_t size = write(fd, (char *) buffer + ret, length - ret);
                if (size < 0) {
                        return size;
                }
index 549598575b9fdcefe857ddef1b6d980a9773b033..632c55f6d5d66c8e39e213284e163a23b32c2260 100644 (file)
@@ -19,7 +19,7 @@ endif
 all: $(T) clean
 
 $(T):
-       @echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
+       @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
 
 clean:
        rm -fr trash
index 114938c3ff18fadb130e6809fc14e89cfe3f36f2..1148b0257dafd4e9b63e030052b47b527b5c0d3b 100644 (file)
@@ -111,9 +111,7 @@ test_expect_success \
 
 test_expect_success \
     'some edit' \
-    'mv file file1 &&
-     sed -e 1d -e "5s/3A/99/" file1 >file &&
-     rm -f file1 &&
+    'perl -p -i.orig -e "s/^1A.*\n$//; s/^3A/99/" file &&
     GIT_AUTHOR_NAME="D" git commit -a -m "edit"'
 
 test_expect_success \
index cf33989b5687e171bcef159f74af9a37973c1285..2c9bbb59b03d97ea668ab3010eaca95eb36f64e8 100755 (executable)
@@ -195,6 +195,20 @@ test_expect_success \
     'git-ls-tree -r output for a known tree.' \
     'diff current expected'
 
+test_expect_success \
+    'writing partial tree out with git-write-tree --prefix.' \
+    'ptree=$(git-write-tree --prefix=path3)'
+test_expect_success \
+    'validate object ID for a known tree.' \
+    'test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3'
+
+test_expect_success \
+    'writing partial tree out with git-write-tree --prefix.' \
+    'ptree=$(git-write-tree --prefix=path3/subp3)'
+test_expect_success \
+    'validate object ID for a known tree.' \
+    'test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2'
+
 ################################################################
 rm .git/index
 test_expect_success \
index 8260d57b63d7f988a4c236d99ce2c9931a67c5e3..0de2497746e31f3dce418dbd248ff5d3e7cb939a 100755 (executable)
@@ -309,5 +309,29 @@ EOF
 
 test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
 
+cat > other-config << EOF
+[ein]
+       bahn = strasse
+EOF
+
+cat > expect << EOF
+ein.bahn=strasse
+EOF
+
+GIT_CONFIG=other-config git-repo-config -l > output
+
+test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
+
+GIT_CONFIG=other-config git-repo-config anwohner.park ausweis
+
+cat > expect << EOF
+[ein]
+       bahn = strasse
+[anwohner]
+       park = ausweis
+EOF
+
+test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+
 test_done
 
diff --git a/tag.c b/tag.c
index f390ee703036bc74d6447d7e96c828310a948c2b..74d0dabe5d8c1f06a3f67475368c34e3b4046456 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -5,7 +5,7 @@ const char *tag_type = "tag";
 
 struct object *deref_tag(struct object *o, const char *warn, int warnlen)
 {
-       while (o && o->type == tag_type)
+       while (o && o->type == TYPE_TAG)
                o = parse_object(((struct tag *)o)->tagged->sha1);
        if (!o && warn) {
                if (!warnlen)
@@ -19,16 +19,16 @@ struct tag *lookup_tag(const unsigned char *sha1)
 {
         struct object *obj = lookup_object(sha1);
         if (!obj) {
-                struct tag *ret = xcalloc(1, sizeof(struct tag));
+                struct tag *ret = alloc_tag_node();
                 created_object(sha1, &ret->object);
-                ret->object.type = tag_type;
+                ret->object.type = TYPE_TAG;
                 return ret;
         }
        if (!obj->type)
-               obj->type = tag_type;
-        if (obj->type != tag_type) {
-                error("Object %s is a %s, not a tree", 
-                      sha1_to_hex(sha1), obj->type);
+               obj->type = TYPE_TAG;
+        if (obj->type != TYPE_TAG) {
+                error("Object %s is a %s, not a tree",
+                      sha1_to_hex(sha1), typename(obj->type));
                 return NULL;
         }
         return (struct tag *) obj;
@@ -47,10 +47,10 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
 
        if (size < 64)
                return -1;
-       if (memcmp("object ", data, 7) || get_sha1_hex(data + 7, object))
+       if (memcmp("object ", data, 7) || get_sha1_hex((char *) data + 7, object))
                return -1;
 
-       type_line = data + 48;
+       type_line = (char *) data + 48;
        if (memcmp("\ntype ", type_line-1, 6))
                return -1;
 
index 297c6972b9256578f9cd7a92404dda55c8e34a2e..3f83e98f3a443e4537f53abf32bcca1389c5d9d8 100644 (file)
@@ -43,7 +43,7 @@ void update_tree_entry(struct tree_desc *desc)
 
        if (size < len)
                die("corrupt tree file");
-       desc->buf = buf + len;
+       desc->buf = (char *) buf + len;
        desc->size = size - len;
 }
 
@@ -66,7 +66,7 @@ const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pat
        const void *tree = desc->buf;
        unsigned long size = desc->size;
        int len = strlen(tree)+1;
-       const unsigned char *sha1 = tree + len;
+       const unsigned char *sha1 = (unsigned char *) tree + len;
        const char *path;
        unsigned int mode;
 
@@ -80,7 +80,8 @@ const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pat
 
 int tree_entry(struct tree_desc *desc, struct name_entry *entry)
 {
-       const void *tree = desc->buf, *path;
+       const void *tree = desc->buf;
+       const char *path;
        unsigned long len, size = desc->size;
 
        if (!size)
@@ -95,10 +96,10 @@ int tree_entry(struct tree_desc *desc, struct name_entry *entry)
        entry->pathlen = len;
 
        path += len + 1;
-       entry->sha1 = path;
+       entry->sha1 = (const unsigned char *) path;
 
        path += 20;
-       len = path - tree;
+       len = path - (char *) tree;
        if (len > size)
                die("corrupt tree file");
 
diff --git a/tree.c b/tree.c
index 9bbe2da37b24007b6409d5e1e5c61a20d0903628..10236555cc5c127b9b5b2cac8f2514c1b7e87676 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -129,16 +129,16 @@ struct tree *lookup_tree(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj) {
-               struct tree *ret = xcalloc(1, sizeof(struct tree));
+               struct tree *ret = alloc_tree_node();
                created_object(sha1, &ret->object);
-               ret->object.type = tree_type;
+               ret->object.type = TYPE_TREE;
                return ret;
        }
        if (!obj->type)
-               obj->type = tree_type;
-       if (obj->type != tree_type) {
-               error("Object %s is a %s, not a tree", 
-                     sha1_to_hex(sha1), obj->type);
+               obj->type = TYPE_TREE;
+       if (obj->type != TYPE_TREE) {
+               error("Object %s is a %s, not a tree",
+                     sha1_to_hex(sha1), typename(obj->type));
                return NULL;
        }
        return (struct tree *) obj;
@@ -216,11 +216,11 @@ struct tree *parse_tree_indirect(const unsigned char *sha1)
        do {
                if (!obj)
                        return NULL;
-               if (obj->type == tree_type)
+               if (obj->type == TYPE_TREE)
                        return (struct tree *) obj;
-               else if (obj->type == commit_type)
+               else if (obj->type == TYPE_COMMIT)
                        obj = &(((struct commit *) obj)->tree->object);
-               else if (obj->type == tag_type)
+               else if (obj->type == TYPE_TAG)
                        obj = ((struct tag *) obj)->tagged;
                else
                        return NULL;
index 47560c9527b9c17db34f10e78d7c1f0d99b746e1..7b86f6965b5306f2162a9076f6ab3bbc1cc32a4b 100644 (file)
@@ -5,6 +5,9 @@
 #include "object.h"
 #include "commit.h"
 #include "exec_cmd.h"
+#include <signal.h>
+#include <sys/poll.h>
+#include <sys/wait.h>
 
 static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
 
@@ -18,6 +21,7 @@ static int use_thin_pack = 0;
 static unsigned char has_sha1[MAX_HAS][20];
 static unsigned char needs_sha1[MAX_NEEDS][20];
 static unsigned int timeout = 0;
+static int use_sideband = 0;
 
 static void reset_timeout(void)
 {
@@ -31,19 +35,63 @@ static int strip(char *line, int len)
        return len;
 }
 
+#define PACKET_MAX 1000
+static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
+{
+       ssize_t ssz;
+       const char *p;
+
+       if (!data) {
+               if (!use_sideband)
+                       return 0;
+               packet_flush(1);
+       }
+
+       if (!use_sideband) {
+               if (fd == 3)
+                       /* emergency quit */
+                       fd = 2;
+               return safe_write(fd, data, sz);
+       }
+       p = data;
+       ssz = sz;
+       while (sz) {
+               unsigned n;
+               char hdr[5];
+
+               n = sz;
+               if (PACKET_MAX - 5 < n)
+                       n = PACKET_MAX - 5;
+               sprintf(hdr, "%04x", n + 5);
+               hdr[4] = fd;
+               safe_write(1, hdr, 5);
+               safe_write(1, p, n);
+               p += n;
+               sz -= n;
+       }
+       return ssz;
+}
+
 static void create_pack_file(void)
 {
-       int fd[2];
-       pid_t pid;
+       /* Pipes between rev-list to pack-objects, pack-objects to us
+        * and pack-objects error stream for progress bar.
+        */
+       int lp_pipe[2], pu_pipe[2], pe_pipe[2];
+       pid_t pid_rev_list, pid_pack_objects;
        int create_full_pack = (nr_our_refs == nr_needs && !nr_has);
+       char data[8193], progress[128];
+       char abort_msg[] = "aborting due to possible repository "
+               "corruption on the remote side.";
+       int buffered = -1;
 
-       if (pipe(fd) < 0)
+       if (pipe(lp_pipe) < 0)
                die("git-upload-pack: unable to create pipe");
-       pid = fork();
-       if (pid < 0)
+       pid_rev_list = fork();
+       if (pid_rev_list < 0)
                die("git-upload-pack: unable to fork git-rev-list");
 
-       if (!pid) {
+       if (!pid_rev_list) {
                int i;
                int args;
                const char **argv;
@@ -60,10 +108,10 @@ static void create_pack_file(void)
                argv = (const char **) p;
                buf = xmalloc(args * 45);
 
-               dup2(fd[1], 1);
+               dup2(lp_pipe[1], 1);
                close(0);
-               close(fd[0]);
-               close(fd[1]);
+               close(lp_pipe[0]);
+               close(lp_pipe[1]);
                *p++ = "rev-list";
                *p++ = use_thin_pack ? "--objects-edge" : "--objects";
                if (create_full_pack || MAX_NEEDS <= nr_needs)
@@ -86,11 +134,184 @@ static void create_pack_file(void)
                execv_git_cmd(argv);
                die("git-upload-pack: unable to exec git-rev-list");
        }
-       dup2(fd[0], 0);
-       close(fd[0]);
-       close(fd[1]);
-       execl_git_cmd("pack-objects", "--stdout", NULL);
-       die("git-upload-pack: unable to exec git-pack-objects");
+
+       if (pipe(pu_pipe) < 0)
+               die("git-upload-pack: unable to create pipe");
+       if (pipe(pe_pipe) < 0)
+               die("git-upload-pack: unable to create pipe");
+       pid_pack_objects = fork();
+       if (pid_pack_objects < 0) {
+               /* daemon sets things up to ignore TERM */
+               kill(pid_rev_list, SIGKILL);
+               die("git-upload-pack: unable to fork git-pack-objects");
+       }
+       if (!pid_pack_objects) {
+               dup2(lp_pipe[0], 0);
+               dup2(pu_pipe[1], 1);
+               dup2(pe_pipe[1], 2);
+
+               close(lp_pipe[0]);
+               close(lp_pipe[1]);
+               close(pu_pipe[0]);
+               close(pu_pipe[1]);
+               close(pe_pipe[0]);
+               close(pe_pipe[1]);
+               execl_git_cmd("pack-objects", "--stdout", "--progress", NULL);
+               kill(pid_rev_list, SIGKILL);
+               die("git-upload-pack: unable to exec git-pack-objects");
+       }
+
+       close(lp_pipe[0]);
+       close(lp_pipe[1]);
+
+       /* We read from pe_pipe[0] to capture stderr output for
+        * progress bar, and pu_pipe[0] to capture the pack data.
+        */
+       close(pe_pipe[1]);
+       close(pu_pipe[1]);
+
+       while (1) {
+               const char *who;
+               struct pollfd pfd[2];
+               pid_t pid;
+               int status;
+               ssize_t sz;
+               int pe, pu, pollsize;
+
+               pollsize = 0;
+               pe = pu = -1;
+
+               if (0 <= pu_pipe[0]) {
+                       pfd[pollsize].fd = pu_pipe[0];
+                       pfd[pollsize].events = POLLIN;
+                       pu = pollsize;
+                       pollsize++;
+               }
+               if (0 <= pe_pipe[0]) {
+                       pfd[pollsize].fd = pe_pipe[0];
+                       pfd[pollsize].events = POLLIN;
+                       pe = pollsize;
+                       pollsize++;
+               }
+
+               if (pollsize) {
+                       if (poll(pfd, pollsize, -1) < 0) {
+                               if (errno != EINTR) {
+                                       error("poll failed, resuming: %s",
+                                             strerror(errno));
+                                       sleep(1);
+                               }
+                               continue;
+                       }
+                       if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
+                               /* Data ready; we keep the last byte
+                                * to ourselves in case we detect
+                                * broken rev-list, so that we can
+                                * leave the stream corrupted.  This
+                                * is unfortunate -- unpack-objects
+                                * would happily accept a valid pack
+                                * data with trailing garbage, so
+                                * appending garbage after we pass all
+                                * the pack data is not good enough to
+                                * signal breakage to downstream.
+                                */
+                               char *cp = data;
+                               ssize_t outsz = 0;
+                               if (0 <= buffered) {
+                                       *cp++ = buffered;
+                                       outsz++;
+                               }
+                               sz = read(pu_pipe[0], cp,
+                                         sizeof(data) - outsz);
+                               if (0 < sz)
+                                               ;
+                               else if (sz == 0) {
+                                       close(pu_pipe[0]);
+                                       pu_pipe[0] = -1;
+                               }
+                               else
+                                       goto fail;
+                               sz += outsz;
+                               if (1 < sz) {
+                                       buffered = data[sz-1] & 0xFF;
+                                       sz--;
+                               }
+                               else
+                                       buffered = -1;
+                               sz = send_client_data(1, data, sz);
+                               if (sz < 0)
+                                       goto fail;
+                       }
+                       if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {
+                               /* Status ready; we ship that in the side-band
+                                * or dump to the standard error.
+                                */
+                               sz = read(pe_pipe[0], progress,
+                                         sizeof(progress));
+                               if (0 < sz)
+                                       send_client_data(2, progress, sz);
+                               else if (sz == 0) {
+                                       close(pe_pipe[0]);
+                                       pe_pipe[0] = -1;
+                               }
+                               else
+                                       goto fail;
+                       }
+               }
+
+               /* See if the children are still there */
+               if (pid_rev_list || pid_pack_objects) {
+                       pid = waitpid(-1, &status, WNOHANG);
+                       if (!pid)
+                               continue;
+                       who = ((pid == pid_rev_list) ? "git-rev-list" :
+                              (pid == pid_pack_objects) ? "git-pack-objects" :
+                              NULL);
+                       if (!who) {
+                               if (pid < 0) {
+                                       error("git-upload-pack: %s",
+                                             strerror(errno));
+                                       goto fail;
+                               }
+                               error("git-upload-pack: we weren't "
+                                     "waiting for %d", pid);
+                               continue;
+                       }
+                       if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) {
+                               error("git-upload-pack: %s died with error.",
+                                     who);
+                               goto fail;
+                       }
+                       if (pid == pid_rev_list)
+                               pid_rev_list = 0;
+                       if (pid == pid_pack_objects)
+                               pid_pack_objects = 0;
+                       if (pid_rev_list || pid_pack_objects)
+                               continue;
+               }
+
+               /* both died happily */
+               if (pollsize)
+                       continue;
+
+               /* flush the data */
+               if (0 <= buffered) {
+                       data[0] = buffered;
+                       sz = send_client_data(1, data, 1);
+                       if (sz < 0)
+                               goto fail;
+                       fprintf(stderr, "flushed.\n");
+               }
+               send_client_data(1, NULL, 0);
+               return;
+       }
+ fail:
+       if (pid_pack_objects)
+               kill(pid_pack_objects, SIGKILL);
+       if (pid_rev_list)
+               kill(pid_rev_list, SIGKILL);
+       send_client_data(3, abort_msg, sizeof(abort_msg));
+       die("git-upload-pack: %s", abort_msg);
 }
 
 static int got_sha1(char *hex, unsigned char *sha1)
@@ -105,7 +326,7 @@ static int got_sha1(char *hex, unsigned char *sha1)
                        o = parse_object(sha1);
                if (!o)
                        die("oops (%s)", sha1_to_hex(sha1));
-               if (o->type == commit_type) {
+               if (o->type == TYPE_COMMIT) {
                        struct commit_list *parents;
                        if (o->flags & THEY_HAVE)
                                return 0;
@@ -197,6 +418,8 @@ static int receive_needs(void)
                        multi_ack = 1;
                if (strstr(line+45, "thin-pack"))
                        use_thin_pack = 1;
+               if (strstr(line+45, "side-band"))
+                       use_sideband = 1;
 
                /* We have sent all our refs already, and the other end
                 * should have chosen out of them; otherwise they are
@@ -218,7 +441,7 @@ static int receive_needs(void)
 
 static int send_ref(const char *refname, const unsigned char *sha1)
 {
-       static char *capabilities = "multi_ack thin-pack";
+       static char *capabilities = "multi_ack thin-pack side-band";
        struct object *o = parse_object(sha1);
 
        if (!o)
@@ -234,7 +457,7 @@ static int send_ref(const char *refname, const unsigned char *sha1)
                o->flags |= OUR_REF;
                nr_our_refs++;
        }
-       if (o->type == tag_type) {
+       if (o->type == TYPE_TAG) {
                o = deref_tag(o, refname, 0);
                packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
        }
index d6a605893dcbb4d8d65979309cf9ce1199aa8279..bd07da6183b25470b00b9a2eedef29b7275760ec 100644 (file)
@@ -8,8 +8,10 @@
 #include "cache-tree.h"
 
 static int missing_ok = 0;
+static char *prefix = NULL;
 
-static const char write_tree_usage[] = "git-write-tree [--missing-ok]";
+static const char write_tree_usage[] =
+"git-write-tree [--missing-ok] [--prefix=<prefix>/]";
 
 static struct lock_file lock_file;
 
@@ -21,13 +23,18 @@ int main(int argc, char **argv)
 
        newfd = hold_lock_file_for_update(&lock_file, get_index_file());
        entries = read_cache();
-       if (argc == 2) {
-               if (!strcmp(argv[1], "--missing-ok"))
+
+       while (1 < argc) {
+               char *arg = argv[1];
+               if (!strcmp(arg, "--missing-ok"))
                        missing_ok = 1;
+               else if (!strncmp(arg, "--prefix=", 9))
+                       prefix = arg + 9;
                else
                        die(write_tree_usage);
+               argc--; argv++;
        }
-       
+
        if (argc > 2)
                die("too many options");
 
@@ -54,6 +61,12 @@ int main(int argc, char **argv)
                 * performance penalty and not a big deal.
                 */
        }
-       printf("%s\n", sha1_to_hex(active_cache_tree->sha1));
+       if (prefix) {
+               struct cache_tree *subtree =
+                       cache_tree_find(active_cache_tree, prefix);
+               printf("%s\n", sha1_to_hex(subtree->sha1));
+       }
+       else
+               printf("%s\n", sha1_to_hex(active_cache_tree->sha1));
        return 0;
 }
index 21ab8e7e263983b54c07e44150cedc5c43963a35..f91b4034751df72996afbe6b4b04a9f05638d322 100644 (file)
@@ -44,21 +44,18 @@ long xdl_bogosqrt(long n) {
 
 int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
                     xdemitcb_t *ecb) {
+       int i = 2;
        mmbuffer_t mb[3];
-       int i;
 
        mb[0].ptr = (char *) pre;
        mb[0].size = psize;
        mb[1].ptr = (char *) rec;
        mb[1].size = size;
-       i = 2;
-
-       if (!size || rec[size-1] != '\n') {
-               mb[2].ptr = "\n\\ No newline at end of file\n";
+       if (size > 0 && rec[size - 1] != '\n') {
+               mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
                mb[2].size = strlen(mb[2].ptr);
-               i = 3;
+               i++;
        }
-
        if (ecb->outf(ecb->priv, mb, i) < 0) {
 
                return -1;
index ea38ee903fa142742797feb600b691b5a22b8165..08691a2447126a8a8f96bb8a0369f21524c58c39 100644 (file)
@@ -24,6 +24,7 @@
 #define XUTILS_H
 
 
+
 long xdl_bogosqrt(long n);
 int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
                     xdemitcb_t *ecb);