Merge branch 'fixes'
authorJunio C Hamano <junkio@cox.net>
Wed, 5 Oct 2005 23:57:23 +0000 (16:57 -0700)
committerJunio C Hamano <junkio@cox.net>
Wed, 5 Oct 2005 23:57:23 +0000 (16:57 -0700)
.gitignore
Documentation/git-apply.txt
Makefile
apply.c
checkout-index.c
connect.c
daemon.c
entry.c
git-applypatch.sh
git-format-patch.sh
git.sh

index e90e2c3..d190c0a 100644 (file)
@@ -101,3 +101,4 @@ git-core-*/?*
 *.dsc
 *.deb
 git-core.spec
+*.exe
index 8cbbb4b..e095f93 100644 (file)
@@ -9,7 +9,7 @@ git-apply - Apply patch on a GIT index file and a work tree
 
 SYNOPSIS
 --------
-'git-apply' [--no-merge] [--stat] [--summary] [--check] [--index] [--show-files] [--apply] [<patch>...]
+'git-apply' [--stat] [--summary] [--check] [--index] [--show-files] [--apply] [<patch>...]
 
 DESCRIPTION
 -----------
@@ -22,11 +22,6 @@ OPTIONS
        The files to read patch from.  '-' can be used to read
        from the standard input.
 
---no-merge::
-       The default mode of operation is the merge behaviour
-       which is not implemented yet.  This flag explicitly
-       tells the program not to use the merge behaviour.
-
 --stat::
        Instead of applying the patch, output diffstat for the
        input.  Turns off "apply".
index 92f0bda..fd4e163 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,8 @@
 #
 # Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3.
 #
+# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
+#
 # Define COLLISION_CHECK below if you believe that SHA1's
 # 1461501637330902918203684832716283019655932542976 hashes do not give you
 # sufficient guarantee that no collisions between objects will ever happen.
@@ -48,7 +50,7 @@
 
 # DEFINES += -DUSE_STDEV
 
-GIT_VERSION = 0.99.8
+GIT_VERSION = 0.99.8.GIT
 
 CFLAGS = -g -O2 -Wall
 ALL_CFLAGS = $(CFLAGS) $(PLATFORM_DEFINES) $(DEFINES)
@@ -96,31 +98,31 @@ SCRIPT_PYTHON = \
 
 # The ones that do not have to link with lcrypto nor lz.
 SIMPLE_PROGRAMS = \
-       git-get-tar-commit-id git-mailinfo git-mailsplit git-stripspace \
-       git-daemon git-var
+       git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
+       git-stripspace$X git-var$X git-daemon$X
 
 # ... and all the rest
 PROGRAMS = \
-       git-apply git-cat-file \
-       git-checkout-index git-clone-pack git-commit-tree \
-       git-convert-objects git-diff-files \
-       git-diff-index git-diff-stages \
-       git-diff-tree git-fetch-pack git-fsck-objects \
-       git-hash-object git-init-db \
-       git-local-fetch git-ls-files git-ls-tree git-merge-base \
-       git-merge-index git-mktag git-pack-objects git-patch-id \
-       git-peek-remote git-prune-packed git-read-tree \
-       git-receive-pack git-rev-list git-rev-parse \
-       git-send-pack git-show-branch \
-       git-show-index git-ssh-fetch \
-       git-ssh-upload git-tar-tree git-unpack-file \
-       git-unpack-objects git-update-index git-update-server-info \
-       git-upload-pack git-verify-pack git-write-tree \
-       git-update-ref git-symbolic-ref \
+       git-apply$X git-cat-file$X \
+       git-checkout-index$X git-clone-pack$X git-commit-tree$X \
+       git-convert-objects$X git-diff-files$X \
+       git-diff-index$X git-diff-stages$X \
+       git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
+       git-hash-object$X git-init-db$X \
+       git-local-fetch$X git-ls-files$X git-ls-tree$X git-merge-base$X \
+       git-merge-index$X git-mktag$X git-pack-objects$X git-patch-id$X \
+       git-peek-remote$X git-prune-packed$X git-read-tree$X \
+       git-receive-pack$X git-rev-list$X git-rev-parse$X \
+       git-send-pack$X git-show-branch$X \
+       git-show-index$X git-ssh-fetch$X \
+       git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
+       git-unpack-objects$X git-update-index$X git-update-server-info$X \
+       git-upload-pack$X git-verify-pack$X git-write-tree$X \
+       git-update-ref$X git-symbolic-ref$X \
        $(SIMPLE_PROGRAMS)
 
 # Backward compatibility -- to be removed after 1.0
-PROGRAMS += git-ssh-pull git-ssh-push
+PROGRAMS += git-ssh-pull$X git-ssh-push$X
 
 GIT_LIST_TWEAK =
 
@@ -176,6 +178,13 @@ ifeq ($(shell uname -s),SunOS)
        TAR = gtar
        PLATFORM_DEFINES += -D__EXTENSIONS__
 endif
+ifeq ($(shell uname -o),Cygwin)
+       NO_STRCASESTR = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       NO_IPV6 = YesPlease
+       X = .exe
+       PLATFORM_DEFINES += -DUSE_SYMLINK_HEAD=0
+endif
 ifneq (,$(findstring arm,$(shell uname -m)))
        ARM_SHA1 = YesPlease
 endif
@@ -192,7 +201,7 @@ ifndef NO_CURL
        else
                CURL_LIBCURL = -lcurl
        endif
-       PROGRAMS += git-http-fetch
+       PROGRAMS += git-http-fetch$X
 endif
 
 ifndef SHELL_PATH
@@ -249,6 +258,9 @@ ifdef NO_STRCASESTR
        DEFINES += -Dstrcasestr=gitstrcasestr
        LIB_OBJS += compat/strcasestr.o
 endif
+ifdef NO_IPV6
+       DEFINES += -DNO_IPV6 -Dsockaddr_storage=sockaddr_in
+endif
 
 ifdef PPC_SHA1
        SHA1_HEADER = "ppc/sha1.h"
@@ -287,25 +299,31 @@ git: git.sh Makefile
        rm -f $@+ $@
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH)|' \
            -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+           -e 's/@@X@@/$(X)/g' \
            $(GIT_LIST_TWEAK) <$@.sh >$@+
        chmod +x $@+
        mv $@+ $@
 
 $(filter-out git,$(patsubst %.sh,%,$(SCRIPT_SH))) : % : %.sh
        rm -f $@
-       sed -e '1s|#!.*/sh|#!$(SHELL_PATH)|' $@.sh >$@
+       sed -e '1s|#!.*/sh|#!$(SHELL_PATH)|' \
+           -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+           $@.sh >$@
        chmod +x $@
 
 $(patsubst %.perl,%,$(SCRIPT_PERL)) : % : %.perl
        rm -f $@
-       sed -e '1s|#!.*perl|#!$(PERL_PATH)|' $@.perl >$@
+       sed -e '1s|#!.*perl|#!$(PERL_PATH)|' \
+           -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+           $@.perl >$@
        chmod +x $@
 
 $(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py
        rm -f $@
        sed -e '1s|#!.*python|#!$(PYTHON_PATH)|' \
            -e 's|@@GIT_PYTHON_PATH@@|$(GIT_PYTHON_DIR)|g' \
-               $@.py >$@
+           -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+           $@.py >$@
        chmod +x $@
 
 %.o: %.c
@@ -313,30 +331,30 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py
 %.o: %.S
        $(CC) -o $*.o -c $(ALL_CFLAGS) $<
 
-git-%: %.o $(LIB_FILE)
+git-%$X: %.o $(LIB_FILE)
        $(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
 
-git-mailinfo : SIMPLE_LIB += $(LIB_4_ICONV)
+git-mailinfo$X : SIMPLE_LIB += $(LIB_4_ICONV)
 $(SIMPLE_PROGRAMS) : $(LIB_FILE)
-$(SIMPLE_PROGRAMS) : git-% : %.o
+$(SIMPLE_PROGRAMS) : git-%$X : %.o
        $(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIB_FILE) $(SIMPLE_LIB)
 
-git-http-fetch: fetch.o
-git-local-fetch: fetch.o
-git-ssh-fetch: rsh.o fetch.o
-git-ssh-upload: rsh.o
-git-ssh-pull: rsh.o fetch.o
-git-ssh-push: rsh.o
+git-http-fetch$X: fetch.o
+git-local-fetch$X: fetch.o
+git-ssh-fetch$X: rsh.o fetch.o
+git-ssh-upload$X: rsh.o
+git-ssh-pull$X: rsh.o fetch.o
+git-ssh-push$X: rsh.o
 
-git-http-fetch: LIBS += $(CURL_LIBCURL)
-git-rev-list: LIBS += $(OPENSSL_LIBSSL)
+git-http-fetch$X: LIBS += $(CURL_LIBCURL)
+git-rev-list$X: LIBS += $(OPENSSL_LIBSSL)
 
 init-db.o: init-db.c
        $(CC) -c $(ALL_CFLAGS) \
                -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir)"' $*.c
 
 $(LIB_OBJS): $(LIB_H)
-$(patsubst git-%,%.o,$(PROGRAMS)): $(LIB_H)
+$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H)
 $(DIFF_OBJS): diffcore.h
 
 $(LIB_FILE): $(LIB_OBJS)
@@ -351,10 +369,10 @@ doc:
 test: all
        $(MAKE) -C t/ all
 
-test-date: test-date.c date.o
+test-date$X: test-date.c date.o
        $(CC) $(ALL_CFLAGS) -o $@ test-date.c date.o
 
-test-delta: test-delta.c diff-delta.o patch-delta.o
+test-delta$X: test-delta.c diff-delta.o patch-delta.o
        $(CC) $(ALL_CFLAGS) -o $@ $^
 
 check:
diff --git a/apply.c b/apply.c
index f886272..7be5041 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -5,26 +5,16 @@
  *
  * This applies patches on top of some (arbitrary) version of the SCM.
  *
- * NOTE! It does all its work in the index file, and only cares about
- * the files in the working directory if you tell it to "merge" the
- * patch apply.
- *
- * Even when merging it always takes the source from the index, and
- * uses the working tree as a "branch" for a 3-way merge.
  */
 #include <ctype.h>
 #include <fnmatch.h>
 #include "cache.h"
 
-// We default to the merge behaviour, since that's what most people would
-// expect.
-//
 //  --check turns on checking that the working tree matches the
 //    files that are being modified, but doesn't apply the patch
 //  --stat does just a diffstat, and doesn't actually apply
 //  --show-files shows the directory changes
 //
-static int merge_patch = 1;
 static int check_index = 0;
 static int write_index = 0;
 static int diffstat = 0;
@@ -33,7 +23,7 @@ static int check = 0;
 static int apply = 1;
 static int show_files = 0;
 static const char apply_usage[] =
-"git-apply [--no-merge] [--stat] [--summary] [--check] [--index] [--apply] [--show-files] <patch>...";
+"git-apply [--stat] [--summary] [--check] [--index] [--apply] [--show-files] <patch>...";
 
 /*
  * For "diff-stat" like behaviour, we keep track of the biggest change
@@ -676,7 +666,10 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
                 /* We allow "\ No newline at end of file". Depending
                  * on locale settings when the patch was produced we
                  * don't know what this line looks like. The only
-                 * thing we do know is that it begins with "\ ". */
+                 * thing we do know is that it begins with "\ ".
+                * Checking for 12 is just for sanity check -- any
+                * l10n of "\ No newline..." is at least that long.
+                */
                case '\\':
                        if (len < 12 || memcmp(line, "\\ ", 2))
                                return -1;
@@ -1030,17 +1023,39 @@ static int check_patch(struct patch *patch)
 
        if (old_name) {
                int changed;
+               int stat_ret = lstat(old_name, &st);
 
-               if (lstat(old_name, &st) < 0)
-                       return error("%s: %s", old_name, strerror(errno));
                if (check_index) {
                        int pos = cache_name_pos(old_name, strlen(old_name));
                        if (pos < 0)
-                               return error("%s: does not exist in index", old_name);
+                               return error("%s: does not exist in index",
+                                            old_name);
+                       if (stat_ret < 0) {
+                               struct checkout costate;
+                               if (errno != ENOENT)
+                                       return error("%s: %s", old_name,
+                                                    strerror(errno));
+                               /* checkout */
+                               costate.base_dir = "";
+                               costate.base_dir_len = 0;
+                               costate.force = 0;
+                               costate.quiet = 0;
+                               costate.not_new = 0;
+                               costate.refresh_cache = 1;
+                               if (checkout_entry(active_cache[pos],
+                                                  &costate) ||
+                                   lstat(old_name, &st))
+                                       return -1;
+                       }
+
                        changed = ce_match_stat(active_cache[pos], &st);
                        if (changed)
-                               return error("%s: does not match index", old_name);
+                               return error("%s: does not match index",
+                                            old_name);
                }
+               else if (stat_ret < 0)
+                       return error("%s: %s", old_name, strerror(errno));
+
                if (patch->is_new < 0)
                        patch->is_new = 0;
                st.st_mode = ntohl(create_ce_mode(st.st_mode));
@@ -1492,11 +1507,6 @@ int main(int argc, char **argv)
                        excludes = x;
                        continue;
                }
-               /* NEEDSWORK: this does not do anything at this moment. */
-               if (!strcmp(arg, "--no-merge")) {
-                       merge_patch = 0;
-                       continue;
-               }
                if (!strcmp(arg, "--stat")) {
                        apply = 0;
                        diffstat = 1;
index f32513c..9784532 100644 (file)
@@ -63,15 +63,20 @@ static int checkout_file(const char *name)
 
 static int checkout_all(void)
 {
-       int i;
+       int i, errs = 0;
 
        for (i = 0; i < active_nr ; i++) {
                struct cache_entry *ce = active_cache[i];
                if (ce_stage(ce))
                        continue;
                if (checkout_entry(ce, &state) < 0)
-                       return -1;
+                       errs++;
        }
+       if (errs)
+               /* we have already done our error reporting.
+                * exit with the same code as die().
+                */
+               exit(128);
        return 0;
 }
 
index 825c439..b157cf1 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -290,6 +290,8 @@ static enum protocol get_protocol(const char *name)
 #define STR_(s)        # s
 #define STR(s) STR_(s)
 
+#ifndef NO_IPV6
+
 static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
 {
        int sockfd = -1;
@@ -346,6 +348,77 @@ static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
        return 0;
 }
 
+#else /* NO_IPV6 */
+
+static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
+{
+       int sockfd = -1;
+       char *colon, *end;
+       char *port = STR(DEFAULT_GIT_PORT), *ep;
+       struct hostent *he;
+       struct sockaddr_in sa;
+       char **ap;
+       unsigned int nport;
+
+       if (host[0] == '[') {
+               end = strchr(host + 1, ']');
+               if (end) {
+                       *end = 0;
+                       end++;
+                       host++;
+               } else
+                       end = host;
+       } else
+               end = host;
+       colon = strchr(end, ':');
+
+       if (colon) {
+               *colon = 0;
+               port = colon + 1;
+       }
+
+
+       he = gethostbyname(host);
+       if (!he)
+               die("Unable to look up %s (%s)", host, hstrerror(h_errno));
+       nport = strtoul(port, &ep, 10);
+       if ( ep == port || *ep ) {
+               /* Not numeric */
+               struct servent *se = getservbyname(port,"tcp");
+               if ( !se )
+                       die("Unknown port %s\n", port);
+               nport = se->s_port;
+       }
+
+       for (ap = he->h_addr_list; *ap; ap++) {
+               sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
+               if (sockfd < 0)
+                       continue;
+
+               memset(&sa, 0, sizeof sa);
+               sa.sin_family = he->h_addrtype;
+               sa.sin_port = htons(nport);
+               memcpy(&sa.sin_addr, ap, he->h_length);
+
+               if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
+                       close(sockfd);
+                       sockfd = -1;
+                       continue;
+               }
+               break;
+       }
+
+       if (sockfd < 0)
+               die("unable to connect a socket (%s)", strerror(errno));
+
+       fd[0] = sockfd;
+       fd[1] = sockfd;
+       packet_write(sockfd, "%s %s\n", prog, path);
+       return 0;
+}
+
+#endif /* NO_IPV6 */
+
 /*
  * Yeah, yeah, fixme. Need to pass in the heads etc.
  */
index 65e62d7..f285a8c 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -4,6 +4,7 @@
 #include <sys/wait.h>
 #include <sys/socket.h>
 #include <sys/time.h>
+#include <sys/poll.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -328,6 +329,7 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
                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;
 
@@ -337,6 +339,7 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
                strcat(buf, "]");
 
                port = sin6_addr->sin6_port;
+#endif
        }
        loginfo("Connection from %s:%d", addrbuf, port);
 
@@ -369,16 +372,16 @@ static void child_handler(int signo)
        }
 }
 
-static int serve(int port)
+#ifndef NO_IPV6
+
+static int socksetup(int port, int **socklist_p)
 {
-       struct addrinfo hints, *ai0, *ai;
-       int gai;
        int socknum = 0, *socklist = NULL;
        int maxfd = -1;
-       fd_set fds_init, fds;
        char pbuf[NI_MAXSERV];
 
-       signal(SIGCHLD, child_handler);
+       struct addrinfo hints, *ai0, *ai;
+       int gai;
 
        sprintf(pbuf, "%d", port);
        memset(&hints, 0, sizeof(hints));
@@ -391,8 +394,6 @@ static int serve(int port)
        if (gai)
                die("getaddrinfo() failed: %s\n", gai_strerror(gai));
 
-       FD_ZERO(&fds_init);
-
        for (ai = ai0; ai; ai = ai->ai_next) {
                int sockfd;
                int *newlist;
@@ -431,23 +432,63 @@ static int serve(int port)
                socklist = newlist;
                socklist[socknum++] = sockfd;
 
-               FD_SET(sockfd, &fds_init);
                if (maxfd < sockfd)
                        maxfd = sockfd;
        }
 
        freeaddrinfo(ai0);
 
-       if (socknum == 0)
-               die("unable to allocate any listen sockets on port %u", port);
+       *socklist_p = socklist;
+       return socknum;
+}
+
+#else /* NO_IPV6 */
+
+static int socksetup(int port, int **socklist_p)
+{
+       struct sockaddr_in sin;
+       int sockfd;
+
+       sockfd = socket(AF_INET, SOCK_STREAM, 0);
+       if (sockfd < 0)
+               return 0;
+
+       memset(&sin, 0, sizeof sin);
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(INADDR_ANY);
+       sin.sin_port = htons(port);
+
+       if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
+               close(sockfd);
+               return 0;
+       }
 
+       *socklist_p = xmalloc(sizeof(int));
+       **socklist_p = sockfd;
+}
+
+#endif
+
+static int service_loop(int socknum, int *socklist)
+{
+       struct pollfd *pfd;
+       int i;
+
+       pfd = xcalloc(socknum, sizeof(struct pollfd));
+
+       for (i = 0; i < socknum; i++) {
+               pfd[i].fd = socklist[i];
+               pfd[i].events = POLLIN;
+       }
+
+       signal(SIGCHLD, child_handler);
+       
        for (;;) {
                int i;
-               fds = fds_init;
-               
-               if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
+
+               if (poll(pfd, socknum, 0) < 0) {
                        if (errno != EINTR) {
-                               error("select failed, resuming: %s",
+                               error("poll failed, resuming: %s",
                                      strerror(errno));
                                sleep(1);
                        }
@@ -455,12 +496,10 @@ static int serve(int port)
                }
 
                for (i = 0; i < socknum; i++) {
-                       int sockfd = socklist[i];
-
-                       if (FD_ISSET(sockfd, &fds)) {
+                       if (pfd[i].revents & POLLIN) {
                                struct sockaddr_storage ss;
-                               int sslen = sizeof(ss);
-                               int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen);
+                               unsigned int sslen = sizeof(ss);
+                               int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
                                if (incoming < 0) {
                                        switch (errno) {
                                        case EAGAIN:
@@ -477,6 +516,17 @@ static int serve(int port)
        }
 }
 
+static int serve(int port)
+{
+       int socknum, *socklist;
+       
+       socknum = socksetup(port, &socklist);
+       if (socknum == 0)
+               die("unable to allocate any listen sockets on port %u", port);
+       
+       return service_loop(socknum, socklist);
+}      
+
 int main(int argc, char **argv)
 {
        int port = DEFAULT_GIT_PORT;
@@ -526,7 +576,7 @@ int main(int argc, char **argv)
        if (inetd_mode) {
                fclose(stderr); //FIXME: workaround
                return execute();
+       } else {
+               return serve(port);
        }
-
-       return serve(port);
 }
diff --git a/entry.c b/entry.c
index b8426db..15b34eb 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -132,7 +132,7 @@ int checkout_entry(struct cache_entry *ce, struct checkout *state)
                if (!state->force) {
                        if (!state->quiet)
                                fprintf(stderr, "git-checkout-index: %s already exists\n", path);
-                       return 0;
+                       return -1;
                }
 
                /*
index 9f5a45b..14635d9 100755 (executable)
@@ -29,10 +29,10 @@ INFO=$3
 SIGNOFF=$4
 EDIT=${VISUAL:-${EDITOR:-vi}}
 
-export GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' .dotest/info)"
-export GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' .dotest/info)"
-export GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' .dotest/info)"
-export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' .dotest/info)"
+export GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$INFO")"
+export GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$INFO")"
+export GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$INFO")"
+export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$INFO")"
 
 if test '' != "$SIGNOFF"
 then
@@ -54,8 +54,10 @@ then
                        sed -ne '/^Signed-off-by: /p' "$MSGFILE" |
                        tail -n 1
                `
-               test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" ||
-               echo "$SIGNOFF" >>"$MSGFILE"
+               test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
+                   test '' = "$LAST_SIGNED_OFF_BY" && echo
+                   echo "$SIGNOFF"
+               } >>"$MSGFILE"
        fi
 fi
 
@@ -99,7 +101,12 @@ echo
 echo Applying "'$SUBJECT'"
 echo
 
-git-apply --index "$PATCHFILE" || exit 1
+git-apply --index "$PATCHFILE" || {
+       # Here if we know which revision the patch applies to,
+       # we create a temporary working tree and index, apply the
+       # patch, and attempt 3-way merge with the resulting tree.
+       exit 1
+}
 
 if test -x "$GIT_DIR"/hooks/pre-applypatch
 then
index 2844799..9378219 100755 (executable)
@@ -212,7 +212,10 @@ Date: '"$ad"
        echo
        git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
        echo
+       git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
        git-diff-tree -p $diff_opts "$commit"
+       echo "---"
+       echo "@@GIT_VERSION@@"
 
        case "$mbox" in
        t)
diff --git a/git.sh b/git.sh
index dc383ed..7400c16 100755 (executable)
--- a/git.sh
+++ b/git.sh
@@ -11,7 +11,17 @@ case "$#" in
                echo "git version @@GIT_VERSION@@"
                exit 0 ;;
        esac
-       test -x $path/git-$cmd && exec $path/git-$cmd "$@" ;;
+       
+       test -x $path/git-$cmd && exec $path/git-$cmd "$@"
+       
+       case '@@X@@' in
+           '')
+               ;;
+           *)
+               test -x $path/git-$cmd@@X@@ && exec $path/git-$cmd@@X@@ "$@"
+               ;;
+       esac
+       ;;
 esac
 
 echo "Usage: git COMMAND [OPTIONS] [TARGET]"