Merge branch 'jc/clone'
authorJunio C Hamano <junkio@cox.net>
Wed, 5 Apr 2006 21:06:50 +0000 (14:06 -0700)
committerJunio C Hamano <junkio@cox.net>
Wed, 5 Apr 2006 21:06:50 +0000 (14:06 -0700)
* jc/clone:
  git-clone: fix handling of upsteram whose HEAD does not point at master.

51 files changed:
.gitignore
Documentation/diff-options.txt
Documentation/git-clean.txt [new file with mode: 0644]
GIT-VERSION-GEN
Makefile
apply.c
blame.c
blob.c
cat-file.c
combine-diff.c
commit-tree.c
commit.c
contrib/git-svn/Makefile
contrib/git-svn/git-svn.perl
convert-objects.c
date.c
diff-tree.c
diff.c
diff.h
diffcore-pickaxe.c
entry.c
git-clean.sh [new file with mode: 0755]
git-cvsimport.perl
git-ls-remote.sh
gitk
hash-object.c
http-push.c
http.c
imap-send.c
index-pack.c
ls-tree.c
mktag.c
mktree.c
object.c
pack-objects.c
read-tree.c
revision.c
sha1_file.c
tag.c
tar-tree.c
tree-diff.c
tree-walk.c
tree.c
unpack-file.c
unpack-objects.c
update-index.c
write-tree.c
xdiff/xdiffi.c
xdiff/xprepare.c
xdiff/xutils.c
xdiff/xutils.h

index 75891c3..b5959d6 100644 (file)
@@ -15,6 +15,7 @@ git-checkout
 git-checkout-index
 git-cherry
 git-cherry-pick
+git-clean
 git-clone
 git-clone-pack
 git-commit
index 2a0275e..ec6811c 100644 (file)
        changeset, not just the files that contain the change
        in <string>.
 
+--pickaxe-regex::
+       Make the <string> not a plain string but an extended POSIX
+       regex to match.
+
 -O<orderfile>::
        Output the patch in the order specified in the
        <orderfile>, which has one shell glob pattern per line.
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
new file mode 100644 (file)
index 0000000..36890c5
--- /dev/null
@@ -0,0 +1,50 @@
+git-clean(1)
+============
+
+NAME
+----
+git-clean - Remove untracked files from the working tree
+
+SYNOPSIS
+--------
+[verse]
+'git-clean' [-d] [-n] [-q] [-x | -X]
+
+DESCRIPTION
+-----------
+Removes files unknown to git.  This allows to clean the working tree
+from files that are not under version control.  If the '-x' option is
+specified, ignored files are also removed, allowing to remove all
+build products.
+
+OPTIONS
+-------
+-d::
+       Remove untracked directories in addition to untracked files.
+
+-n::
+       Don't actually remove anything, just show what would be done.
+
+-q::
+       Be quiet, only report errors, but not the files that are
+       successfully removed.
+
+-x::
+       Don't use the ignore rules.  This allows removing all untracked
+       files, including build products.  This can be used (possibly in
+       conjunction with gitlink:git-reset[1]) to create a pristine
+       working directory to test a clean build.
+
+-X::
+       Remove only files ignored by git.  This may be useful to rebuild
+       everything from scratch, but keep manually created files.
+
+
+Author
+------
+Written by Pavel Roskin <proski@gnu.org>
+
+
+GIT
+---
+Part of the gitlink:git[7] suite
index 4764fd2..d2200ac 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.3-rc1.GIT
+DEF_VER=v1.3-rc2.GIT
 
 # First try git-describe, then see if there is a version file
 # (included in release tarballs), then default
index c79d646..3367b8c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -114,7 +114,7 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 
 SCRIPT_SH = \
        git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \
-       git-cherry.sh git-clone.sh git-commit.sh \
+       git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
        git-count-objects.sh git-diff.sh git-fetch.sh \
        git-format-patch.sh git-log.sh git-ls-remote.sh \
        git-merge-one-file.sh git-parse-remote.sh \
@@ -510,6 +510,9 @@ git$X git.spec \
 exec_cmd.o: exec_cmd.c
        $(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $<
 
+http.o: http.c
+       $(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
+
 git-%$X: %.o $(GITLIBS)
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
diff --git a/apply.c b/apply.c
index c50b3a6..33b4271 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -9,6 +9,7 @@
 #include <fnmatch.h>
 #include "cache.h"
 #include "quote.h"
+#include "blob.h"
 
 //  --check turns on checking that the working tree matches the
 //    files that are being modified, but doesn't apply the patch
@@ -924,8 +925,7 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
                struct fragment *fragment;
                int len;
 
-               fragment = xmalloc(sizeof(*fragment));
-               memset(fragment, 0, sizeof(*fragment));
+               fragment = xcalloc(1, sizeof(*fragment));
                len = parse_fragment(line, size, patch, fragment);
                if (len <= 0)
                        die("corrupt patch at line %d", linenr);
@@ -1296,7 +1296,7 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
                         * applies to.
                         */
                        write_sha1_file_prepare(desc->buffer, desc->size,
-                                               "blob", sha1, hdr, &hdrlen);
+                                               blob_type, sha1, hdr, &hdrlen);
                        if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
                                return error("the patch applies to '%s' (%s), "
                                             "which does not match the "
@@ -1651,15 +1651,14 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
        if (!write_index)
                return;
 
-       ce = xmalloc(ce_size);
-       memset(ce, 0, ce_size);
+       ce = xcalloc(1, ce_size);
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = htons(namelen);
        if (lstat(path, &st) < 0)
                die("unable to stat newly created file %s", path);
        fill_stat_cache_info(ce, &st);
-       if (write_sha1_file(buf, size, "blob", ce->sha1) < 0)
+       if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
                die("unable to create backing store for newly created file %s", path);
        if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
                die("unable to add cache entry for %s", path);
@@ -1808,8 +1807,7 @@ static int apply_patch(int fd, const char *filename)
                struct patch *patch;
                int nr;
 
-               patch = xmalloc(sizeof(*patch));
-               memset(patch, 0, sizeof(*patch));
+               patch = xcalloc(1, sizeof(*patch));
                nr = parse_chunk(buffer + offset, size, patch);
                if (nr < 0)
                        break;
diff --git a/blame.c b/blame.c
index 396defc..98f9992 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -229,7 +229,7 @@ static void get_blob(struct commit *commit)
 
        info->buf = read_sha1_file(info->sha1, type, &info->size);
 
-       assert(!strcmp(type, "blob"));
+       assert(!strcmp(type, blob_type));
 }
 
 /* For debugging only */
diff --git a/blob.c b/blob.c
index 84ec121..c1fdd86 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -8,8 +8,7 @@ struct blob *lookup_blob(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj) {
-               struct blob *ret = xmalloc(sizeof(struct blob));
-               memset(ret, 0, sizeof(struct blob));
+               struct blob *ret = xcalloc(1, sizeof(struct blob));
                created_object(sha1, &ret->object);
                ret->object.type = blob_type;
                return ret;
index 761111e..628f6ca 100644 (file)
@@ -5,6 +5,8 @@
  */
 #include "cache.h"
 #include "exec_cmd.h"
+#include "tag.h"
+#include "tree.h"
 
 static void flush_buffer(const char *buf, unsigned long size)
 {
@@ -136,13 +138,13 @@ int main(int argc, char **argv)
                        die("Not a valid object name %s", argv[2]);
 
                /* custom pretty-print here */
-               if (!strcmp(type, "tree"))
+               if (!strcmp(type, tree_type))
                        return execl_git_cmd("ls-tree", argv[2], NULL);
 
                buf = read_sha1_file(sha1, type, &size);
                if (!buf)
                        die("Cannot read object %s", argv[2]);
-               if (!strcmp(type, "tag"))
+               if (!strcmp(type, tag_type))
                        return pprint_tag(sha1, buf, size);
 
                /* otherwise just spit out the data */
index f17aab3..7693884 100644 (file)
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "commit.h"
+#include "blob.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "quote.h"
@@ -104,7 +105,7 @@ static char *grab_blob(const unsigned char *sha1, unsigned long *size)
                return xcalloc(1, 1);
        }
        blob = read_sha1_file(sha1, type, size);
-       if (strcmp(type, "blob"))
+       if (strcmp(type, blob_type))
                die("object '%s' is not a blob!", sha1_to_hex(sha1));
        return blob;
 }
index 16c1787..2d86518 100644 (file)
@@ -4,6 +4,8 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "cache.h"
+#include "commit.h"
+#include "tree.h"
 
 #define BLOCKING (1ul << 14)
 
@@ -93,13 +95,13 @@ int main(int argc, char **argv)
        if (argc < 2 || get_sha1_hex(argv[1], tree_sha1) < 0)
                usage(commit_tree_usage);
 
-       check_valid(tree_sha1, "tree");
+       check_valid(tree_sha1, tree_type);
        for (i = 2; i < argc; i += 2) {
                char *a, *b;
                a = argv[i]; b = argv[i+1];
                if (!b || strcmp(a, "-p") || get_sha1(b, parent_sha1[parents]))
                        usage(commit_tree_usage);
-               check_valid(parent_sha1[parents], "commit");
+               check_valid(parent_sha1[parents], commit_type);
                if (new_parent(parents))
                        parents++;
        }
@@ -125,7 +127,7 @@ int main(int argc, char **argv)
        while (fgets(comment, sizeof(comment), stdin) != NULL)
                add_buffer(&buffer, &size, "%s", comment);
 
-       if (!write_sha1_file(buffer, size, "commit", commit_sha1)) {
+       if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {
                printf("%s\n", sha1_to_hex(commit_sha1));
                return 0;
        }
index eb42d51..d4976fb 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -73,8 +73,7 @@ struct commit *lookup_commit(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj) {
-               struct commit *ret = xmalloc(sizeof(struct commit));
-               memset(ret, 0, sizeof(struct commit));
+               struct commit *ret = xcalloc(1, sizeof(struct commit));
                created_object(sha1, &ret->object);
                ret->object.type = commit_type;
                return ret;
index d7f1643..acedf73 100644 (file)
@@ -28,7 +28,7 @@ git-svn.xml : git-svn.txt
 git-svn.html : git-svn.txt
        asciidoc -b xhtml11 -d manpage \
                -f ../../Documentation/asciidoc.conf $<
-test:
+test: git-svn
        cd t && $(SHELL) ./t0000-contrib-git-svn.sh
 
 clean:
index edfb19c..7c44450 100755 (executable)
@@ -75,12 +75,14 @@ foreach my $o (keys %opts) {
        my $arg = 'git-repo-config';
        $arg .= ' --int' if ($o =~ /=i$/);
        $arg .= ' --bool' if ($o !~ /=[sfi]$/);
-       $arg .= " svn.$key"; # $key only matches [a-z\-], always shell-safe
        if (ref $v eq 'ARRAY') {
-               chomp(@$v = `$arg`);
+               chomp(my @tmp = `$arg --get-all svn.$key`);
+               @$v = @tmp if @tmp;
        } else {
-               chomp($$v = `$arg`);
-               $$v = 0 if $$v eq 'false';
+               chomp(my $tmp = `$arg --get svn.$key`);
+               if ($tmp && !($arg =~ / --bool / && $tmp eq 'false')) {
+                       $$v = $tmp;
+               }
        }
 }
 
index b49bce2..12aacef 100644 (file)
@@ -2,6 +2,9 @@
 #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
 #include <time.h>
 #include "cache.h"
+#include "blob.h"
+#include "commit.h"
+#include "tree.h"
 
 struct entry {
        unsigned char old_sha1[20];
@@ -18,8 +21,7 @@ static struct entry * convert_entry(unsigned char *sha1);
 
 static struct entry *insert_new(unsigned char *sha1, int pos)
 {
-       struct entry *new = xmalloc(sizeof(struct entry));
-       memset(new, 0, sizeof(*new));
+       struct entry *new = xcalloc(1, sizeof(struct entry));
        memcpy(new->old_sha1, sha1, 20);
        memmove(convert + pos + 1, convert + pos, (nr_convert - pos) * sizeof(struct entry *));
        convert[pos] = new;
@@ -122,7 +124,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base
                buffer += len;
        }
 
-       write_sha1_file(new, newlen, "tree", result_sha1);
+       write_sha1_file(new, newlen, tree_type, result_sha1);
        free(new);
        return used;
 }
@@ -262,8 +264,8 @@ static void convert_date(void *buffer, unsigned long size, unsigned char *result
        memcpy(new + newlen, buffer, size);
        newlen += size;
 
-       write_sha1_file(new, newlen, "commit", result_sha1);
-       free(new);      
+       write_sha1_file(new, newlen, commit_type, result_sha1);
+       free(new);
 }
 
 static void convert_commit(void *buffer, unsigned long size, unsigned char *result_sha1)
@@ -297,12 +299,12 @@ static struct entry * convert_entry(unsigned char *sha1)
 
        buffer = xmalloc(size);
        memcpy(buffer, data, size);
-       
-       if (!strcmp(type, "blob")) {
-               write_sha1_file(buffer, size, "blob", entry->new_sha1);
-       } else if (!strcmp(type, "tree"))
+
+       if (!strcmp(type, blob_type)) {
+               write_sha1_file(buffer, size, blob_type, entry->new_sha1);
+       } else if (!strcmp(type, tree_type))
                convert_tree(buffer, size, entry->new_sha1);
-       else if (!strcmp(type, "commit"))
+       else if (!strcmp(type, commit_type))
                convert_commit(buffer, size, entry->new_sha1);
        else
                die("unknown object type '%s' in %s", type, sha1_to_hex(sha1));
diff --git a/date.c b/date.c
index 1c1917b..376d25d 100644 (file)
--- a/date.c
+++ b/date.c
@@ -255,10 +255,10 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
                                break;
                }
                /* mm/dd/yy ? */
-               if (is_date(num3, num2, num, tm))
+               if (is_date(num3, num, num2, tm))
                        break;
                /* dd/mm/yy ? */
-               if (is_date(num3, num, num2, tm))
+               if (is_date(num3, num2, num, tm))
                        break;
                return 0;
        }
index f55a35a..d1265d7 100644 (file)
@@ -52,7 +52,7 @@ static int diff_root_tree(const unsigned char *new, const char *base)
        void *tree;
        struct tree_desc empty, real;
 
-       tree = read_object_with_reference(new, "tree", &real.size, NULL);
+       tree = read_object_with_reference(new, tree_type, &real.size, NULL);
        if (!tree)
                die("unable to read root tree (%s)", sha1_to_hex(new));
        real.buf = tree;
diff --git a/diff.c b/diff.c
index e496905..ce98a90 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -883,6 +883,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->filter = arg + 14;
        else if (!strcmp(arg, "--pickaxe-all"))
                options->pickaxe_opts = DIFF_PICKAXE_ALL;
+       else if (!strcmp(arg, "--pickaxe-regex"))
+               options->pickaxe_opts = DIFF_PICKAXE_REGEX;
        else if (!strncmp(arg, "-B", 2)) {
                if ((options->break_opt =
                     diff_scoreopt_parse(arg)) == -1)
@@ -1280,28 +1282,34 @@ void diff_flush(struct diff_options *options)
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
-               if ((diff_output_format == DIFF_FORMAT_NO_OUTPUT) ||
-                   (p->status == DIFF_STATUS_UNKNOWN))
-                       continue;
-               if (p->status == 0)
-                       die("internal error in diff-resolve-rename-copy");
-               switch (diff_output_format) {
-               case DIFF_FORMAT_PATCH:
-                       diff_flush_patch(p, options);
-                       break;
-               case DIFF_FORMAT_RAW:
-               case DIFF_FORMAT_NAME_STATUS:
-                       diff_flush_raw(p, line_termination,
-                                      inter_name_termination,
-                                      options);
+
+               switch (p->status) {
+               case DIFF_STATUS_UNKNOWN:
                        break;
-               case DIFF_FORMAT_NAME:
-                       diff_flush_name(p,
-                                       inter_name_termination,
-                                       line_termination);
+               case 0:
+                       die("internal error in diff-resolve-rename-copy");
                        break;
+               default:
+                       switch (diff_output_format) {
+                       case DIFF_FORMAT_PATCH:
+                               diff_flush_patch(p, options);
+                               break;
+                       case DIFF_FORMAT_RAW:
+                       case DIFF_FORMAT_NAME_STATUS:
+                               diff_flush_raw(p, line_termination,
+                                              inter_name_termination,
+                                              options);
+                               break;
+                       case DIFF_FORMAT_NAME:
+                               diff_flush_name(p,
+                                               inter_name_termination,
+                                               line_termination);
+                               break;
+                       case DIFF_FORMAT_NO_OUTPUT:
+                               break;
+                       }
                }
-               diff_free_filepair(q->queue[i]);
+               diff_free_filepair(p);
        }
        free(q->queue);
        q->queue = NULL;
diff --git a/diff.h b/diff.h
index a268d16..0cebec1 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -102,6 +102,7 @@ extern int diff_setup_done(struct diff_options *);
 #define DIFF_DETECT_COPY       2
 
 #define DIFF_PICKAXE_ALL       1
+#define DIFF_PICKAXE_REGEX     2
 
 extern void diffcore_std(struct diff_options *);
 
index 50e46ab..cfcce31 100644 (file)
@@ -5,8 +5,11 @@
 #include "diff.h"
 #include "diffcore.h"
 
+#include <regex.h>
+
 static unsigned int contains(struct diff_filespec *one,
-                            const char *needle, unsigned long len)
+                            const char *needle, unsigned long len,
+                            regex_t *regexp)
 {
        unsigned int cnt;
        unsigned long offset, sz;
@@ -18,15 +21,28 @@ static unsigned int contains(struct diff_filespec *one,
        data = one->data;
        cnt = 0;
 
-       /* Yes, I've heard of strstr(), but the thing is *data may
-        * not be NUL terminated.  Sue me.
-        */
-       for (offset = 0; offset + len <= sz; offset++) {
-               /* we count non-overlapping occurrences of needle */
-               if (!memcmp(needle, data + offset, len)) {
-                       offset += len - 1;
+       if (regexp) {
+               regmatch_t regmatch;
+               int flags = 0;
+
+               while (*data && !regexec(regexp, data, 1, &regmatch, flags)) {
+                       flags |= REG_NOTBOL;
+                       data += regmatch.rm_so;
+                       if (*data) data++;
                        cnt++;
                }
+
+       } else { /* Classic exact string match */
+               /* Yes, I've heard of strstr(), but the thing is *data may
+                * not be NUL terminated.  Sue me.
+                */
+               for (offset = 0; offset + len <= sz; offset++) {
+                       /* we count non-overlapping occurrences of needle */
+                       if (!memcmp(needle, data + offset, len)) {
+                               offset += len - 1;
+                               cnt++;
+                       }
+               }
        }
        return cnt;
 }
@@ -36,10 +52,24 @@ void diffcore_pickaxe(const char *needle, int opts)
        struct diff_queue_struct *q = &diff_queued_diff;
        unsigned long len = strlen(needle);
        int i, has_changes;
+       regex_t regex, *regexp = NULL;
        struct diff_queue_struct outq;
        outq.queue = NULL;
        outq.nr = outq.alloc = 0;
 
+       if (opts & DIFF_PICKAXE_REGEX) {
+               int err;
+               err = regcomp(&regex, needle, REG_EXTENDED | REG_NEWLINE);
+               if (err) {
+                       /* The POSIX.2 people are surely sick */
+                       char errbuf[1024];
+                       regerror(err, &regex, errbuf, 1024);
+                       regfree(&regex);
+                       die("invalid pickaxe regex: %s", errbuf);
+               }
+               regexp = &regex;
+       }
+
        if (opts & DIFF_PICKAXE_ALL) {
                /* Showing the whole changeset if needle exists */
                for (i = has_changes = 0; !has_changes && i < q->nr; i++) {
@@ -48,16 +78,16 @@ void diffcore_pickaxe(const char *needle, int opts)
                                if (!DIFF_FILE_VALID(p->two))
                                        continue; /* ignore unmerged */
                                /* created */
-                               if (contains(p->two, needle, len))
+                               if (contains(p->two, needle, len, regexp))
                                        has_changes++;
                        }
                        else if (!DIFF_FILE_VALID(p->two)) {
-                               if (contains(p->one, needle, len))
+                               if (contains(p->one, needle, len, regexp))
                                        has_changes++;
                        }
                        else if (!diff_unmodified_pair(p) &&
-                                contains(p->one, needle, len) !=
-                                contains(p->two, needle, len))
+                                contains(p->one, needle, len, regexp) !=
+                                contains(p->two, needle, len, regexp))
                                has_changes++;
                }
                if (has_changes)
@@ -80,16 +110,16 @@ void diffcore_pickaxe(const char *needle, int opts)
                                if (!DIFF_FILE_VALID(p->two))
                                        ; /* ignore unmerged */
                                /* created */
-                               else if (contains(p->two, needle, len))
+                               else if (contains(p->two, needle, len, regexp))
                                        has_changes = 1;
                        }
                        else if (!DIFF_FILE_VALID(p->two)) {
-                               if (contains(p->one, needle, len))
+                               if (contains(p->one, needle, len, regexp))
                                        has_changes = 1;
                        }
                        else if (!diff_unmodified_pair(p) &&
-                                contains(p->one, needle, len) !=
-                                contains(p->two, needle, len))
+                                contains(p->one, needle, len, regexp) !=
+                                contains(p->two, needle, len, regexp))
                                has_changes = 1;
 
                        if (has_changes)
@@ -98,6 +128,10 @@ void diffcore_pickaxe(const char *needle, int opts)
                                diff_free_filepair(p);
                }
 
+       if (opts & DIFF_PICKAXE_REGEX) {
+               regfree(&regex);
+       }
+
        free(q->queue);
        *q = outq;
        return;
diff --git a/entry.c b/entry.c
index 5d9aefd..793724f 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -1,6 +1,7 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include "cache.h"
+#include "blob.h"
 
 static void create_directories(const char *path, struct checkout *state)
 {
@@ -72,7 +73,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
        char type[20];
 
        new = read_sha1_file(ce->sha1, type, &size);
-       if (!new || strcmp(type, "blob")) {
+       if (!new || strcmp(type, blob_type)) {
                if (new)
                        free(new);
                return error("git-checkout-index: unable to read sha1 file of %s (%s)",
diff --git a/git-clean.sh b/git-clean.sh
new file mode 100755 (executable)
index 0000000..b200868
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+# Copyright (c) 2005-2006 Pavel Roskin
+#
+
+USAGE="[-d] [-n] [-q] [-x | -X]"
+LONG_USAGE='Clean untracked files from the working directory
+       -d      remove directories as well
+       -n      don'\''t remove anything, just show what would be done
+       -q      be quiet, only report errors
+       -x      remove ignored files as well
+       -X      remove only ignored files as well'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+
+ignored=
+ignoredonly=
+cleandir=
+quiet=
+rmf="rm -f"
+rmrf="rm -rf"
+rm_refuse="echo Not removing"
+echo1="echo"
+
+while case "$#" in 0) break ;; esac
+do
+       case "$1" in
+       -d)
+               cleandir=1
+               ;;
+       -n)
+               quiet=1
+               rmf="echo Would remove"
+               rmrf="echo Would remove"
+               rm_refuse="echo Would not remove"
+               echo1=":"
+               ;;
+       -q)
+               quiet=1
+               ;;
+       -x)
+               ignored=1
+               ;;
+       -X)
+               ignoredonly=1
+               ;;
+       *)
+               usage
+       esac
+       shift
+done
+
+case "$ignored,$ignoredonly" in
+       1,1) usage;;
+esac
+
+if [ -z "$ignored" ]; then
+       excl="--exclude-per-directory=.gitignore"
+       if [ -f "$GIT_DIR/info/exclude" ]; then
+               excl_info="--exclude-from=$GIT_DIR/info/exclude"
+       fi
+       if [ "$ignoredonly" ]; then
+               excl="$excl --ignored"
+       fi
+fi
+
+git-ls-files --others --directory $excl ${excl_info:+"$excl_info"} |
+while read -r file; do
+       if [ -d "$file" -a ! -L "$file" ]; then
+               if [ -z "$cleandir" ]; then
+                       $rm_refuse "$file"
+                       continue
+               fi
+               $echo1 "Removing $file"
+               $rmrf "$file"
+       else
+               $echo1 "Removing $file"
+               $rmf "$file"
+       fi
+done
index 3728294..c0ae00b 100755 (executable)
@@ -677,11 +677,7 @@ my $commit = sub {
        waitpid($pid,0);
        die "Error running git-commit-tree: $?\n" if $?;
 
-       open(C,">$git_dir/refs/heads/$branch")
-               or die "Cannot open branch $branch for update: $!\n";
-       print C "$cid\n"
-               or die "Cannot write branch $branch for update: $!\n";
-       close(C)
+       system("git-update-ref refs/heads/$branch $cid") == 0
                or die "Cannot write branch $branch for update: $!\n";
 
        if($tag) {
index 2c9a588..b6882a9 100755 (executable)
@@ -53,7 +53,7 @@ http://* | https://* )
         if [ -n "$GIT_SSL_NO_VERIFY" ]; then
             curl_extra_args="-k"
         fi
-       curl -nsf $curl_extra_args "$peek_repo/info/refs" ||
+       curl -nsf $curl_extra_args --header "Pragma: no-cache" "$peek_repo/info/refs" ||
                echo "failed    slurping"
        ;;
 
diff --git a/gitk b/gitk
index fa1e83c..26fa79a 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -75,6 +75,7 @@ proc getcommitlines {commfd}  {
     global commitlisted nextupdate
     global leftover
     global displayorder commitidx commitrow commitdata
+    global parentlist childlist children
 
     set stuff [read $commfd]
     if {$stuff == {}} {
@@ -140,15 +141,26 @@ proc getcommitlines {commfd}  {
        set id [lindex $ids 0]
        if {$listed} {
            set olds [lrange $ids 1 end]
-           set commitlisted($id) 1
+           if {[llength $olds] > 1} {
+               set olds [lsort -unique $olds]
+           }
+           foreach p $olds {
+               lappend children($p) $id
+           }
        } else {
            set olds {}
        }
-       updatechildren $id $olds
+       lappend parentlist $olds
+       if {[info exists children($id)]} {
+           lappend childlist $children($id)
+       } else {
+           lappend childlist {}
+       }
        set commitdata($id) [string range $cmit [expr {$j + 1}] end]
        set commitrow($id) $commitidx
        incr commitidx
        lappend displayorder $id
+       lappend commitlisted $listed
        set gotsome 1
     }
     if {$gotsome} {
@@ -181,14 +193,12 @@ proc doupdate {reading} {
 
 proc readcommit {id} {
     if {[catch {set contents [exec git-cat-file commit $id]}]} return
-    updatechildren $id {}
     parsecommit $id $contents 0
 }
 
 proc updatecommits {rargs} {
     stopfindproc
-    foreach v {children nchildren parents nparents commitlisted
-       colormap selectedline matchinglines treediffs
+    foreach v {colormap selectedline matchinglines treediffs
        mergefilelist currentid rowtextx commitrow
        rowidlist rowoffsets idrowranges idrangedrawn iddrawn
        linesegends crossings cornercrossings} {
@@ -200,26 +210,6 @@ proc updatecommits {rargs} {
     getcommits $rargs
 }
 
-proc updatechildren {id olds} {
-    global children nchildren parents nparents
-
-    if {![info exists nchildren($id)]} {
-       set children($id) {}
-       set nchildren($id) 0
-    }
-    set parents($id) $olds
-    set nparents($id) [llength $olds]
-    foreach p $olds {
-       if {![info exists nchildren($p)]} {
-           set children($p) [list $id]
-           set nchildren($p) 1
-       } elseif {[lsearch -exact $children($p) $id] < 0} {
-           lappend children($p) $id
-           incr nchildren($p)
-       }
-    }
-}
-
 proc parsecommit {id contents listed} {
     global commitinfo cdate
 
@@ -274,7 +264,7 @@ proc parsecommit {id contents listed} {
 }
 
 proc getcommit {id} {
-    global commitdata commitinfo nparents
+    global commitdata commitinfo
 
     if {[info exists commitdata($id)]} {
        parsecommit $id $commitdata($id) 1
@@ -282,7 +272,6 @@ proc getcommit {id} {
        readcommit $id
        if {![info exists commitinfo($id)]} {
            set commitinfo($id) {"No commit information available"}
-           set nparents($id) 0
        }
     }
     return 1
@@ -295,7 +284,7 @@ proc readrefs {} {
     foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
        catch {unset $v}
     }
-    set refd [open [list | git-ls-remote [gitdir]] r]
+    set refd [open [list | git ls-remote [gitdir]] r]
     while {0 <= [set n [gets $refd line]]} {
        if {![regexp {^([0-9a-f]{40})   refs/([^^]*)$} $line \
            match id path]} {
@@ -346,7 +335,7 @@ proc error_popup msg {
 }
 
 proc makewindow {rargs} {
-    global canv canv2 canv3 linespc charspc ctext cflist textfont
+    global canv canv2 canv3 linespc charspc ctext cflist textfont mainfont uifont
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
@@ -354,16 +343,21 @@ proc makewindow {rargs} {
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
+    .bar configure -font $uifont
     menu .bar.file
     .bar.file add command -label "Update" -command [list updatecommits $rargs]
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
+    .bar.file configure -font $uifont
     menu .bar.edit
     .bar add cascade -label "Edit" -menu .bar.edit
     .bar.edit add command -label "Preferences" -command doprefs
+    .bar.edit configure -font $uifont
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
     .bar.help add command -label "About gitk" -command about
+    .bar.help add command -label "Key bindings" -command keys
+    .bar.help configure -font $uifont
     . configure -menu .bar
 
     if {![info exists geometry(canv1)]} {
@@ -410,7 +404,7 @@ proc makewindow {rargs} {
     set entries $sha1entry
     set sha1but .ctop.top.bar.sha1label
     button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
-       -command gotocommit -width 8
+       -command gotocommit -width 8 -font $uifont
     $sha1but conf -disabledforeground [$sha1but cget -foreground]
     pack .ctop.top.bar.sha1label -side left
     entry $sha1entry -width 40 -font $textfont -textvariable sha1string
@@ -440,19 +434,24 @@ proc makewindow {rargs} {
        -state disabled -width 26
     pack .ctop.top.bar.rightbut -side left -fill y
 
-    button .ctop.top.bar.findbut -text "Find" -command dofind
+    button .ctop.top.bar.findbut -text "Find" -command dofind -font $uifont
     pack .ctop.top.bar.findbut -side left
     set findstring {}
     set fstring .ctop.top.bar.findstring
     lappend entries $fstring
-    entry $fstring -width 30 -font $textfont -textvariable findstring
+    entry $fstring -width 30 -font $textfont -textvariable findstring -font $textfont
     pack $fstring -side left -expand 1 -fill x
     set findtype Exact
     set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
                          findtype Exact IgnCase Regexp]
+    .ctop.top.bar.findtype configure -font $uifont
+    .ctop.top.bar.findtype.menu configure -font $uifont
     set findloc "All fields"
     tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
        Comments Author Committer Files Pickaxe
+    .ctop.top.bar.findloc configure -font $uifont
+    .ctop.top.bar.findloc.menu configure -font $uifont
+
     pack .ctop.top.bar.findloc -side right
     pack .ctop.top.bar.findtype -side right
     # for making sure type==Exact whenever loc==Pickaxe
@@ -499,7 +498,7 @@ proc makewindow {rargs} {
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
     listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
-       -yscrollcommand ".ctop.cdet.right.sb set"
+       -yscrollcommand ".ctop.cdet.right.sb set" -font $mainfont
     scrollbar .ctop.cdet.right.sb -command "$cflist yview"
     pack .ctop.cdet.right.sb -side right -fill y
     pack $cflist -side left -fill both -expand 1
@@ -514,12 +513,20 @@ proc makewindow {rargs} {
     bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
     bindall <2> "canvscan mark %W %x %y"
     bindall <B2-Motion> "canvscan dragto %W %x %y"
+    bindkey <Home> selfirstline
+    bindkey <End> sellastline
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
-    bind . <Key-Right> "goforw"
-    bind . <Key-Left> "goback"
-    bind . <Key-Prior> "allcanvs yview scroll -1 pages"
-    bind . <Key-Next> "allcanvs yview scroll 1 pages"
+    bindkey <Key-Right> "goforw"
+    bindkey <Key-Left> "goback"
+    bind . <Key-Prior> "selnextpage -1"
+    bind . <Key-Next> "selnextpage 1"
+    bind . <Control-Home> "allcanvs yview moveto 0.0"
+    bind . <Control-End> "allcanvs yview moveto 1.0"
+    bind . <Control-Key-Up> "allcanvs yview scroll -1 units"
+    bind . <Control-Key-Down> "allcanvs yview scroll 1 units"
+    bind . <Control-Key-Prior> "allcanvs yview scroll -1 pages"
+    bind . <Control-Key-Next> "allcanvs yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
     bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
     bindkey <Key-space> "$ctext yview scroll 1 pages"
@@ -612,7 +619,7 @@ proc click {w} {
 }
 
 proc savestuff {w} {
-    global canv canv2 canv3 ctext cflist mainfont textfont
+    global canv canv2 canv3 ctext cflist mainfont textfont uifont
     global stuffsaved findmergefiles maxgraphpct
     global maxwidth
 
@@ -622,6 +629,7 @@ proc savestuff {w} {
        set f [open "~/.gitk-new" w]
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
+       puts $f [list set uifont $uifont]
        puts $f [list set findmergefiles $findmergefiles]
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
@@ -729,6 +737,55 @@ Use and redistribute under the terms of the GNU General Public License} \
     pack $w.ok -side bottom
 }
 
+proc keys {} {
+    set w .keys
+    if {[winfo exists $w]} {
+       raise $w
+       return
+    }
+    toplevel $w
+    wm title $w "Gitk key bindings"
+    message $w.m -text {
+Gitk key bindings:
+
+<Ctrl-Q>               Quit
+<Home>         Move to first commit
+<End>          Move to last commit
+<Up>, p, i     Move up one commit
+<Down>, n, k   Move down one commit
+<Left>, z, j   Go back in history list
+<Right>, x, l  Go forward in history list
+<PageUp>       Move up one page in commit list
+<PageDown>     Move down one page in commit list
+<Ctrl-Home>    Scroll to top of commit list
+<Ctrl-End>     Scroll to bottom of commit list
+<Ctrl-Up>      Scroll commit list up one line
+<Ctrl-Down>    Scroll commit list down one line
+<Ctrl-PageUp>  Scroll commit list up one page
+<Ctrl-PageDown>        Scroll commit list down one page
+<Delete>, b    Scroll diff view up one page
+<Backspace>    Scroll diff view up one page
+<Space>                Scroll diff view down one page
+u              Scroll diff view up 18 lines
+d              Scroll diff view down 18 lines
+<Ctrl-F>               Find
+<Ctrl-G>               Move to next find hit
+<Ctrl-R>               Move to previous find hit
+<Return>       Move to next find hit
+/              Move to next find hit, or redo find
+?              Move to previous find hit
+f              Scroll diff view to next file
+<Ctrl-KP+>     Increase font size
+<Ctrl-plus>    Increase font size
+<Ctrl-KP->     Decrease font size
+<Ctrl-minus>   Decrease font size
+} \
+           -justify left -bg white -border 2 -relief sunken
+    pack $w.m -side top -fill both
+    button $w.ok -text Close -command "destroy $w"
+    pack $w.ok -side bottom
+}
+
 proc shortids {ids} {
     set res {}
     foreach id $ids {
@@ -843,15 +900,20 @@ proc makeuparrow {oid x y z} {
 }
 
 proc initlayout {} {
-    global rowidlist rowoffsets displayorder
+    global rowidlist rowoffsets displayorder commitlisted
     global rowlaidout rowoptim
     global idinlist rowchk
     global commitidx numcommits canvxmax canv
     global nextcolor
+    global parentlist childlist children
 
     set commitidx 0
     set numcommits 0
     set displayorder {}
+    set commitlisted {}
+    set parentlist {}
+    set childlist {}
+    catch {unset children}
     set nextcolor 0
     set rowidlist {{}}
     set rowoffsets {{}}
@@ -950,7 +1012,7 @@ proc showstuff {canshow} {
 proc layoutrows {row endrow last} {
     global rowidlist rowoffsets displayorder
     global uparrowlen downarrowlen maxwidth mingaplen
-    global nchildren parents nparents
+    global childlist parentlist
     global idrowranges linesegends
     global commitidx
     global idinlist rowchk
@@ -961,7 +1023,7 @@ proc layoutrows {row endrow last} {
        set id [lindex $displayorder $row]
        set oldolds {}
        set newolds {}
-       foreach p $parents($id) {
+       foreach p [lindex $parentlist $row] {
            if {![info exists idinlist($p)]} {
                lappend newolds $p
            } elseif {!$idinlist($p)} {
@@ -1000,7 +1062,7 @@ proc layoutrows {row endrow last} {
            lappend idlist $id
            lset rowidlist $row $idlist
            set z {}
-           if {$nchildren($id) > 0} {
+           if {[lindex $childlist $row] ne {}} {
                set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}]
                unset idinlist($id)
            }
@@ -1053,16 +1115,22 @@ proc layoutrows {row endrow last} {
 }
 
 proc addextraid {id row} {
-    global displayorder commitrow commitinfo nparents
+    global displayorder commitrow commitinfo
     global commitidx
+    global parentlist childlist children
 
     incr commitidx
     lappend displayorder $id
+    lappend parentlist {}
     set commitrow($id) $row
     readcommit $id
     if {![info exists commitinfo($id)]} {
        set commitinfo($id) {"No commit information available"}
-       set nparents($id) 0
+    }
+    if {[info exists children($id)]} {
+       lappend childlist $children($id)
+    } else {
+       lappend childlist {}
     }
 }
 
@@ -1365,7 +1433,7 @@ proc drawparentlinks {id row col olds} {
 proc drawlines {id} {
     global colormap canv
     global idrowranges idrangedrawn
-    global children iddrawn commitrow rowidlist
+    global childlist iddrawn commitrow rowidlist
 
     $canv delete lines.$id
     set nr [expr {[llength $idrowranges($id)] / 2}]
@@ -1374,14 +1442,12 @@ proc drawlines {id} {
            drawlineseg $id $i
        }
     }
-    if {[info exists children($id)]} {
-       foreach child $children($id) {
-           if {[info exists iddrawn($child)]} {
-               set row $commitrow($child)
-               set col [lsearch -exact [lindex $rowidlist $row] $child]
-               if {$col >= 0} {
-                   drawparentlinks $child $row $col [list $id]
-               }
+    foreach child [lindex $childlist $commitrow($id)] {
+       if {[info exists iddrawn($child)]} {
+           set row $commitrow($child)
+           set col [lsearch -exact [lindex $rowidlist $row] $child]
+           if {$col >= 0} {
+               drawparentlinks $child $row $col [list $id]
            }
        }
     }
@@ -1394,7 +1460,7 @@ proc drawcmittext {id row col rmx} {
     global linehtag linentag linedtag
     global mainfont namefont canvxmax
 
-    set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
+    set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
     set x [xc $row $col]
     set y [yc $row]
     set orad [expr {$linespc / 3}]
@@ -1434,7 +1500,7 @@ proc drawcmittext {id row col rmx} {
 proc drawcmitrow {row} {
     global displayorder rowidlist
     global idrowranges idrangedrawn iddrawn
-    global commitinfo commitlisted parents numcommits
+    global commitinfo commitlisted parentlist numcommits
 
     if {$row >= $numcommits} return
     foreach id [lindex $rowidlist $row] {
@@ -1465,9 +1531,9 @@ proc drawcmitrow {row} {
        getcommit $id
     }
     assigncolor $id
-    if {[info exists commitlisted($id)] && [info exists parents($id)]
-       && $parents($id) ne {}} {
-       set rmx [drawparentlinks $id $row $col $parents($id)]
+    set olds [lindex $parentlist $row]
+    if {$olds ne {}} {
+       set rmx [drawparentlinks $id $row $col $olds]
     } else {
        set rmx 0
     }
@@ -1511,15 +1577,22 @@ proc clear_display {} {
 
 proc assigncolor {id} {
     global colormap colors nextcolor
-    global parents nparents children nchildren
+    global commitrow parentlist children childlist
     global cornercrossings crossings
 
     if {[info exists colormap($id)]} return
     set ncolors [llength $colors]
-    if {$nchildren($id) == 1} {
-       set child [lindex $children($id) 0]
+    if {[info exists commitrow($id)]} {
+       set kids [lindex $childlist $commitrow($id)]
+    } elseif {[info exists children($id)]} {
+       set kids $children($id)
+    } else {
+       set kids {}
+    }
+    if {[llength $kids] == 1} {
+       set child [lindex $kids 0]
        if {[info exists colormap($child)]
-           && $nparents($child) == 1} {
+           && [llength [lindex $parentlist $commitrow($child)]] == 1} {
            set colormap($id) $colormap($child)
            return
        }
@@ -1552,17 +1625,15 @@ proc assigncolor {id} {
        set origbad $badcolors
     }
     if {[llength $badcolors] < $ncolors - 1} {
-       foreach child $children($id) {
+       foreach child $kids {
            if {[info exists colormap($child)]
                && [lsearch -exact $badcolors $colormap($child)] < 0} {
                lappend badcolors $colormap($child)
            }
-           if {[info exists parents($child)]} {
-               foreach p $parents($child) {
-                   if {[info exists colormap($p)]
-                       && [lsearch -exact $badcolors $colormap($p)] < 0} {
-                       lappend badcolors $colormap($p)
-                   }
+           foreach p [lindex $parentlist $commitrow($child)] {
+               if {[info exists colormap($p)]
+                   && [lsearch -exact $badcolors $colormap($p)] < 0} {
+                   lappend badcolors $colormap($p)
                }
            }
        }
@@ -1657,14 +1728,14 @@ proc drawtags {id x xt y1} {
 }
 
 proc checkcrossings {row endrow} {
-    global displayorder parents rowidlist
+    global displayorder parentlist rowidlist
 
     for {} {$row < $endrow} {incr row} {
        set id [lindex $displayorder $row]
        set i [lsearch -exact [lindex $rowidlist $row] $id]
        if {$i < 0} continue
        set idlist [lindex $rowidlist [expr {$row+1}]]
-       foreach p $parents($id) {
+       foreach p [lindex $parentlist $row] {
            set j [lsearch -exact $idlist $p]
            if {$j > 0} {
                if {$j < $i - 1} {
@@ -2046,7 +2117,7 @@ proc insertmatch {l id} {
 
 proc findfiles {} {
     global selectedline numcommits displayorder ctext
-    global ffileline finddidsel parents nparents
+    global ffileline finddidsel parentlist
     global findinprogress findstartline findinsertpos
     global treediffs fdiffid fdiffsneeded fdiffpos
     global findmergefiles
@@ -2064,7 +2135,7 @@ proc findfiles {} {
     set fdiffsneeded {}
     while 1 {
        set id [lindex $displayorder $l]
-       if {$findmergefiles || $nparents($id) == 1} {
+       if {$findmergefiles || [llength [lindex $parentlist $l]] == 1} {
            if {![info exists treediffs($id)]} {
                append diffsneeded "$id\n"
                lappend fdiffsneeded $id
@@ -2096,7 +2167,7 @@ proc findfiles {} {
     . config -cursor watch
     settextcursor watch
     set findinprogress 1
-    findcont $id
+    findcont
     update
 }
 
@@ -2143,7 +2214,7 @@ proc donefilediff {} {
            set treediffs($nullid) {}
            if {[info exists findid] && $nullid eq $findid} {
                unset findid
-               findcont $nullid
+               findcont
            }
            incr fdiffpos
        }
@@ -2154,20 +2225,21 @@ proc donefilediff {} {
        }
        if {[info exists findid] && $fdiffid eq $findid} {
            unset findid
-           findcont $fdiffid
+           findcont
        }
     }
 }
 
 proc findcont {id} {
-    global findid treediffs parents nparents
+    global findid treediffs parentlist
     global ffileline findstartline finddidsel
     global displayorder numcommits matchinglines findinprogress
     global findmergefiles
 
     set l $ffileline
-    while 1 {
-       if {$findmergefiles || $nparents($id) == 1} {
+    while {1} {
+       set id [lindex $displayorder $l]
+       if {$findmergefiles || [llength [lindex $parentlist $l]] == 1} {
            if {![info exists treediffs($id)]} {
                set findid $id
                set ffileline $l
@@ -2189,7 +2261,6 @@ proc findcont {id} {
            set l 0
        }
        if {$l == $findstartline} break
-       set id [lindex $displayorder $l]
     }
     stopfindproc
     if {!$finddidsel} {
@@ -2286,10 +2357,26 @@ proc appendwithlinks {text} {
     $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
 }
 
+proc viewnextline {dir} {
+    global canv linespc
+
+    $canv delete hover
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    set wnow [$canv yview]
+    set wtop [expr {[lindex $wnow 0] * $ymax}]
+    set newtop [expr {$wtop + $dir * $linespc}]
+    if {$newtop < 0} {
+       set newtop 0
+    } elseif {$newtop > $ymax} {
+       set newtop $ymax
+    }
+    allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
+}
+
 proc selectline {l isnew} {
     global canv canv2 canv3 ctext commitinfo selectedline
     global displayorder linehtag linentag linedtag
-    global canvy0 linespc parents nparents children
+    global canvy0 linespc parentlist childlist
     global cflist currentid sha1entry
     global commentend idtags linknum
     global mergemax numcommits
@@ -2379,9 +2466,10 @@ proc selectline {l isnew} {
     }
  
     set comment {}
-    if {$nparents($id) > 1} {
+    set olds [lindex $parentlist $l]
+    if {[llength $olds] > 1} {
        set np 0
-       foreach p $parents($id) {
+       foreach p $olds {
            if {$np >= $mergemax} {
                set tag mmax
            } else {
@@ -2392,17 +2480,13 @@ proc selectline {l isnew} {
            incr np
        }
     } else {
-       if {[info exists parents($id)]} {
-           foreach p $parents($id) {
-               append comment "Parent: [commit_descriptor $p]\n"
-           }
+       foreach p $olds {
+           append comment "Parent: [commit_descriptor $p]\n"
        }
     }
 
-    if {[info exists children($id)]} {
-       foreach c $children($id) {
-           append comment "Child:  [commit_descriptor $c]\n"
-       }
+    foreach c [lindex $childlist $l] {
+       append comment "Child:  [commit_descriptor $c]\n"
     }
     append comment "\n"
     append comment [lindex $info 5]
@@ -2417,13 +2501,25 @@ proc selectline {l isnew} {
 
     $cflist delete 0 end
     $cflist insert end "Comments"
-    if {$nparents($id) <= 1} {
+    if {[llength $olds] <= 1} {
        startdiff $id
     } else {
-       mergediff $id
+       mergediff $id $l
     }
 }
 
+proc selfirstline {} {
+    unmarkmatches
+    selectline 0 1
+}
+
+proc sellastline {} {
+    global numcommits
+    unmarkmatches
+    set l [expr {$numcommits - 1}]
+    selectline $l 1
+}
+
 proc selnextline {dir} {
     global selectedline
     if {![info exists selectedline]} return
@@ -2432,6 +2528,25 @@ proc selnextline {dir} {
     selectline $l 1
 }
 
+proc selnextpage {dir} {
+    global canv linespc selectedline numcommits
+
+    set lpp [expr {([winfo height $canv] - 2) / $linespc}]
+    if {$lpp < 1} {
+       set lpp 1
+    }
+    allcanvs yview scroll [expr {$dir * $lpp}] units
+    if {![info exists selectedline]} return
+    set l [expr {$selectedline + $dir * $lpp}]
+    if {$l < 0} {
+       set l 0
+    } elseif {$l >= $numcommits} {
+        set l [expr $numcommits - 1]
+    }
+    unmarkmatches
+    selectline $l 1    
+}
+
 proc unselectline {} {
     global selectedline
 
@@ -2489,9 +2604,10 @@ proc goforw {} {
     }
 }
 
-proc mergediff {id} {
-    global parents diffmergeid diffopts mdifffd
+proc mergediff {id l} {
+    global diffmergeid diffopts mdifffd
     global difffilestart diffids
+    global parentlist
 
     set diffmergeid $id
     set diffids $id
@@ -2505,12 +2621,13 @@ proc mergediff {id} {
     }
     fconfigure $mdf -blocking 0
     set mdifffd($id) $mdf
-    fileevent $mdf readable [list getmergediffline $mdf $id]
+    set np [llength [lindex $parentlist $l]]
+    fileevent $mdf readable [list getmergediffline $mdf $id $np]
     set nextupdate [expr {[clock clicks -milliseconds] + 100}]
 }
 
-proc getmergediffline {mdf id} {
-    global diffmergeid ctext cflist nextupdate nparents mergemax
+proc getmergediffline {mdf id np} {
+    global diffmergeid ctext cflist nextupdate mergemax
     global difffilestart mdifffd
 
     set n [gets $mdf line]
@@ -2543,7 +2660,6 @@ proc getmergediffline {mdf id} {
        # do nothing
     } else {
        # parse the prefix - one ' ', '-' or '+' for each parent
-       set np $nparents($id)
        set spaces {}
        set minuses {}
        set pluses {}
@@ -2611,7 +2727,7 @@ proc addtocflist {ids} {
 }
 
 proc gettreediffs {ids} {
-    global treediff parents treepending
+    global treediff treepending
     set treepending $ids
     set treediff {}
     if {[catch \
@@ -2846,13 +2962,15 @@ proc sha1change {n1 n2 op} {
 }
 
 proc gotocommit {} {
-    global sha1string currentid commitrow tagids
+    global sha1string currentid commitrow tagids headids
     global displayorder numcommits
 
     if {$sha1string == {}
        || ([info exists currentid] && $sha1string == $currentid)} return
     if {[info exists tagids($sha1string)]} {
        set id $tagids($sha1string)
+    } elseif {[info exists headids($sha1string)]} {
+       set id $headids($sha1string)
     } else {
        set id [string tolower $sha1string]
        if {[regexp {^[0-9a-f]{4,39}$} $id]} {
@@ -2878,7 +2996,7 @@ proc gotocommit {} {
     if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
        set type "SHA1 id"
     } else {
-       set type "Tag"
+       set type "Tag/Head"
     }
     error_popup "$type $sha1string is not known"
 }
@@ -2979,7 +3097,7 @@ proc arrowjump {id n y} {
 }
 
 proc lineclick {x y id isnew} {
-    global ctext commitinfo children cflist canv thickerline
+    global ctext commitinfo childlist commitrow cflist canv thickerline
 
     if {![info exists commitinfo($id)] && ![getcommit $id]} return
     unmarkmatches
@@ -3018,10 +3136,11 @@ proc lineclick {x y id isnew} {
     $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
     set date [formatdate [lindex $info 2]]
     $ctext insert end "\tDate:\t$date\n"
-    if {[info exists children($id)]} {
+    set kids [lindex $childlist $commitrow($id)]
+    if {$kids ne {}} {
        $ctext insert end "\nChildren:"
        set i 0
-       foreach child $children($id) {
+       foreach child $kids {
            incr i
            if {![info exists commitinfo($child)] && ![getcommit $child]} continue
            set info $commitinfo($child)
@@ -3368,7 +3487,6 @@ proc listrefs {id} {
 
 proc rereadrefs {} {
     global idtags idheads idotherrefs
-    global tagids headids otherrefids
 
     set refids [concat [array names idtags] \
                    [array names idheads] [array names idotherrefs]]
@@ -3777,6 +3895,7 @@ if {$tclencoding == {}} {
 
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
+set uifont {Helvetica 9 bold}
 set findmergefiles 0
 set maxgraphpct 50
 set maxwidth 16
index 6502b5b..43bd93b 100644 (file)
@@ -2,9 +2,10 @@
  * GIT - The information manager from hell
  *
  * Copyright (C) Linus Torvalds, 2005
- * Copyright (C) Junio C Hamano, 2005 
+ * Copyright (C) Junio C Hamano, 2005
  */
 #include "cache.h"
+#include "blob.h"
 
 static void hash_object(const char *path, const char *type, int write_object)
 {
@@ -35,7 +36,7 @@ static const char hash_object_usage[] =
 int main(int argc, char **argv)
 {
        int i;
-       const char *type = "blob";
+       const char *type = blob_type;
        int write_object = 0;
        const char *prefix = NULL;
        int prefix_length = -1;
index ba7d9de..b60fa8d 100644 (file)
@@ -1008,8 +1008,7 @@ static int fetch_indices(void)
        struct active_request_slot *slot;
        struct slot_results results;
 
-       data = xmalloc(4096);
-       memset(data, 0, 4096);
+       data = xcalloc(1, 4096);
        buffer.size = 4096;
        buffer.posn = 0;
        buffer.buffer = data;
@@ -2042,8 +2041,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
        char *if_header;
        struct curl_slist *dav_headers = NULL;
 
-       buffer.buffer = xmalloc(4096);
-       memset(buffer.buffer, 0, 4096);
+       buffer.buffer = xcalloc(1, 4096);
        buffer.size = 4096;
        buffer.posn = 0;
        remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
diff --git a/http.c b/http.c
index 9604e33..0cb42a8 100644 (file)
--- a/http.c
+++ b/http.c
@@ -195,6 +195,8 @@ static CURL* get_curl_handle(void)
        if (getenv("GIT_CURL_VERBOSE"))
                curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
 
+       curl_easy_setopt(result, CURLOPT_USERAGENT, GIT_USER_AGENT);
+
        return result;
 }
 
index f3cb79b..52e2400 100644 (file)
@@ -1202,6 +1202,7 @@ read_message( FILE *f, msg_data_t *msg )
                        p = xrealloc(msg->data, len+1);
                        if (!p)
                                break;
+                       msg->data = p;
                }
                r = fread( &msg->data[msg->len], 1, len - msg->len, f );
                if (r <= 0)
@@ -1332,6 +1333,12 @@ main(int argc, char **argv)
                return 1;
        }
 
+       total = count_messages( &all_msgs );
+       if (!total) {
+               fprintf(stderr,"no messages to send\n");
+               return 1;
+       }
+
        /* write it to the imap server */
        ctx = imap_open_store( &server );
        if (!ctx) {
@@ -1339,7 +1346,6 @@ main(int argc, char **argv)
                return 1;
        }
 
-       total = count_messages( &all_msgs );
        fprintf( stderr, "sending %d message%s\n", total, (total!=1)?"s":"" );
        ctx->name = imap_folder;
        while (1) {
index babe34b..b39953d 100644 (file)
@@ -2,6 +2,10 @@
 #include "delta.h"
 #include "pack.h"
 #include "csum-file.h"
+#include "blob.h"
+#include "commit.h"
+#include "tag.h"
+#include "tree.h"
 
 static const char index_pack_usage[] =
 "git-index-pack [-o index-file] pack-file";
@@ -224,10 +228,10 @@ static void sha1_object(const void *data, unsigned long size,
        const char *type_str;
 
        switch (type) {
-       case OBJ_COMMIT: type_str = "commit"; break;
-       case OBJ_TREE:   type_str = "tree"; break;
-       case OBJ_BLOB:   type_str = "blob"; break;
-       case OBJ_TAG:    type_str = "tag"; break;
+       case OBJ_COMMIT: type_str = commit_type; break;
+       case OBJ_TREE:   type_str = tree_type; break;
+       case OBJ_BLOB:   type_str = blob_type; break;
+       case OBJ_TAG:    type_str = tag_type; break;
        default:
                die("bad type %d", type);
        }
index 26258c3..e4ef200 100644 (file)
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -56,7 +56,7 @@ static int show_tree(unsigned char *sha1, const char *base, int baselen,
                     const char *pathname, unsigned mode, int stage)
 {
        int retval = 0;
-       const char *type = "blob";
+       const char *type = blob_type;
 
        if (S_ISDIR(mode)) {
                if (show_recursive(base, baselen, pathname)) {
@@ -64,7 +64,7 @@ static int show_tree(unsigned char *sha1, const char *base, int baselen,
                        if (!(ls_options & LS_SHOW_TREES))
                                return retval;
                }
-               type = "tree";
+               type = tree_type;
        }
        else if (ls_options & LS_TREE_ONLY)
                return 0;
diff --git a/mktag.c b/mktag.c
index fc6a9bf..2328878 100644 (file)
--- a/mktag.c
+++ b/mktag.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "tag.h"
 
 /*
  * A signature file has a very simple fixed format: three lines
@@ -126,7 +127,7 @@ int main(int argc, char **argv)
        if (verify_tag(buffer, size) < 0)
                die("invalid tag signature file");
 
-       if (write_sha1_file(buffer, size, "tag", result_sha1) < 0)
+       if (write_sha1_file(buffer, size, tag_type, result_sha1) < 0)
                die("unable to write tag file");
        printf("%s\n", sha1_to_hex(result_sha1));
        return 0;
index f853585..ab63cd9 100644 (file)
--- a/mktree.c
+++ b/mktree.c
@@ -6,6 +6,7 @@
 #include "cache.h"
 #include "strbuf.h"
 #include "quote.h"
+#include "tree.h"
 
 static struct treeent {
        unsigned mode;
@@ -67,7 +68,7 @@ static void write_tree(unsigned char *sha1)
                memcpy(buffer + offset, ent->sha1, 20);
                offset += 20;
        }
-       write_sha1_file(buffer, offset, "tree", sha1);
+       write_sha1_file(buffer, offset, tree_type, sha1);
 }
 
 static const char mktree_usage[] = "mktree [-z]";
index c9ca481..4d46e0d 100644 (file)
--- a/object.c
+++ b/object.c
@@ -85,8 +85,7 @@ struct object_refs *alloc_object_refs(unsigned count)
        struct object_refs *refs;
        size_t size = sizeof(*refs) + count*sizeof(struct object *);
 
-       refs = xmalloc(size);
-       memset(refs, 0, size);
+       refs = xcalloc(1, size);
        refs->count = count;
        return refs;
 }
@@ -178,8 +177,7 @@ struct object *lookup_unknown_object(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj) {
-               union any_object *ret = xmalloc(sizeof(*ret));
-               memset(ret, 0, sizeof(*ret));
+               union any_object *ret = xcalloc(1, sizeof(*ret));
                created_object(sha1, &ret->object);
                ret->object.type = NULL;
                return &ret->object;
@@ -196,15 +194,15 @@ struct object *parse_object(const unsigned char *sha1)
                struct object *obj;
                if (check_sha1_signature(sha1, buffer, size, type) < 0)
                        printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
-               if (!strcmp(type, "blob")) {
+               if (!strcmp(type, blob_type)) {
                        struct blob *blob = lookup_blob(sha1);
                        parse_blob_buffer(blob, buffer, size);
                        obj = &blob->object;
-               } else if (!strcmp(type, "tree")) {
+               } else if (!strcmp(type, tree_type)) {
                        struct tree *tree = lookup_tree(sha1);
                        parse_tree_buffer(tree, buffer, size);
                        obj = &tree->object;
-               } else if (!strcmp(type, "commit")) {
+               } else if (!strcmp(type, commit_type)) {
                        struct commit *commit = lookup_commit(sha1);
                        parse_commit_buffer(commit, buffer, size);
                        if (!commit->buffer) {
@@ -212,7 +210,7 @@ struct object *parse_object(const unsigned char *sha1)
                                buffer = NULL;
                        }
                        obj = &commit->object;
-               } else if (!strcmp(type, "tag")) {
+               } else if (!strcmp(type, tag_type)) {
                        struct tag *tag = lookup_tag(sha1);
                        parse_tag_buffer(tag, buffer, size);
                        obj = &tag->object;
index ccfaa5f..9346392 100644 (file)
@@ -1,5 +1,9 @@
 #include "cache.h"
 #include "object.h"
+#include "blob.h"
+#include "commit.h"
+#include "tag.h"
+#include "tree.h"
 #include "delta.h"
 #include "pack.h"
 #include "csum-file.h"
@@ -58,7 +62,7 @@ static int nr_objects = 0, nr_alloc = 0, nr_result = 0;
 static const char *base_name;
 static unsigned char pack_file_sha1[20];
 static int progress = 1;
-static volatile int progress_update = 0;
+static volatile sig_atomic_t progress_update = 0;
 
 /*
  * The object names in objects array are hashed with this hashtable,
@@ -603,7 +607,7 @@ static void add_pbase_tree(struct tree_desc *tree, struct name_path *up)
                if (!add_object_entry(sha1, hash, 1))
                        continue;
 
-               if (!strcmp(type, "tree")) {
+               if (!strcmp(type, tree_type)) {
                        struct tree_desc sub;
                        void *elem;
                        struct name_path me;
@@ -626,7 +630,7 @@ static void add_preferred_base(unsigned char *sha1)
        struct tree_desc tree;
        void *elem;
 
-       elem = read_object_with_reference(sha1, "tree", &tree.size, NULL);
+       elem = read_object_with_reference(sha1, tree_type, &tree.size, NULL);
        tree.buf = elem;
        if (!tree.buf)
                return;
@@ -684,13 +688,13 @@ static void check_object(struct object_entry *entry)
                die("unable to get type of object %s",
                    sha1_to_hex(entry->sha1));
 
-       if (!strcmp(type, "commit")) {
+       if (!strcmp(type, commit_type)) {
                entry->type = OBJ_COMMIT;
-       } else if (!strcmp(type, "tree")) {
+       } else if (!strcmp(type, tree_type)) {
                entry->type = OBJ_TREE;
-       } else if (!strcmp(type, "blob")) {
+       } else if (!strcmp(type, blob_type)) {
                entry->type = OBJ_BLOB;
-       } else if (!strcmp(type, "tag")) {
+       } else if (!strcmp(type, tag_type)) {
                entry->type = OBJ_TAG;
        } else
                die("unable to pack object %s of type %s",
@@ -879,7 +883,6 @@ static int try_delta(struct unpacked *cur, struct unpacked *old, unsigned max_de
 
 static void progress_interval(int signum)
 {
-       signal(SIGALRM, progress_interval);
        progress_update = 1;
 }
 
@@ -1025,6 +1028,23 @@ static int reuse_cached_pack(unsigned char *sha1, int pack_to_stdout)
        return 1;
 }
 
+static void setup_progress_signal(void)
+{
+       struct sigaction sa;
+       struct itimerval v;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = progress_interval;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       sigaction(SIGALRM, &sa, NULL);
+
+       v.it_interval.tv_sec = 1;
+       v.it_interval.tv_usec = 0;
+       v.it_value = v.it_interval;
+       setitimer(ITIMER_REAL, &v, NULL);
+}
+
 int main(int argc, char **argv)
 {
        SHA_CTX ctx;
@@ -1090,18 +1110,24 @@ int main(int argc, char **argv)
        prepare_packed_git();
 
        if (progress) {
-               struct itimerval v;
-               v.it_interval.tv_sec = 1;
-               v.it_interval.tv_usec = 0;
-               v.it_value = v.it_interval;
-               signal(SIGALRM, progress_interval);
-               setitimer(ITIMER_REAL, &v, NULL);
                fprintf(stderr, "Generating pack...\n");
+               setup_progress_signal();
        }
 
-       while (fgets(line, sizeof(line), stdin) != NULL) {
+       for (;;) {
                unsigned char sha1[20];
 
+               if (!fgets(line, sizeof(line), stdin)) {
+                       if (feof(stdin))
+                               break;
+                       if (!ferror(stdin))
+                               die("fgets returned NULL, not EOF, not error!");
+                       if (errno != EINTR)
+                               die("fgets: %s", strerror(errno));
+                       clearerr(stdin);
+                       continue;
+               }
+
                if (line[0] == '-') {
                        if (get_sha1_hex(line+1, sha1))
                                die("expected edge sha1, got garbage:\n %s",
index eaff444..26f4f7e 100644 (file)
@@ -133,11 +133,9 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
                pathlen = strlen(first);
                ce_size = cache_entry_size(baselen + pathlen);
 
-               src = xmalloc(sizeof(struct cache_entry *) * src_size);
-               memset(src, 0, sizeof(struct cache_entry *) * src_size);
+               src = xcalloc(src_size, sizeof(struct cache_entry *));
 
-               subposns = xmalloc(sizeof(struct tree_list_entry *) * len);
-               memset(subposns, 0, sizeof(struct tree_list_entry *) * len);
+               subposns = xcalloc(len, sizeof(struct tree_list_entry *));
 
                if (cache_name && !strcmp(cache_name, first)) {
                        any_files = 1;
@@ -177,8 +175,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
                        else
                                ce_stage = 2;
 
-                       ce = xmalloc(ce_size);
-                       memset(ce, 0, ce_size);
+                       ce = xcalloc(1, ce_size);
                        ce->ce_mode = create_ce_mode(posns[i]->mode);
                        ce->ce_flags = create_ce_flags(baselen + pathlen,
                                                       ce_stage);
@@ -273,10 +270,26 @@ static void unlink_entry(char *name)
 
 static void progress_interval(int signum)
 {
-       signal(SIGALRM, progress_interval);
        progress_update = 1;
 }
 
+static void setup_progress_signal(void)
+{
+       struct sigaction sa;
+       struct itimerval v;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = progress_interval;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       sigaction(SIGALRM, &sa, NULL);
+
+       v.it_interval.tv_sec = 1;
+       v.it_interval.tv_usec = 0;
+       v.it_value = v.it_interval;
+       setitimer(ITIMER_REAL, &v, NULL);
+}
+
 static void check_updates(struct cache_entry **src, int nr)
 {
        static struct checkout state = {
@@ -289,8 +302,6 @@ static void check_updates(struct cache_entry **src, int nr)
        unsigned last_percent = 200, cnt = 0, total = 0;
 
        if (update && verbose_update) {
-               struct itimerval v;
-
                for (total = cnt = 0; cnt < nr; cnt++) {
                        struct cache_entry *ce = src[cnt];
                        if (!ce->ce_mode || ce->ce_flags & mask)
@@ -302,12 +313,8 @@ static void check_updates(struct cache_entry **src, int nr)
                        total = 0;
 
                if (total) {
-                       v.it_interval.tv_sec = 1;
-                       v.it_interval.tv_usec = 0;
-                       v.it_value = v.it_interval;
-                       signal(SIGALRM, progress_interval);
-                       setitimer(ITIMER_REAL, &v, NULL);
                        fprintf(stderr, "Checking files out...\n");
+                       setup_progress_signal();
                        progress_update = 1;
                }
                cnt = 0;
@@ -341,8 +348,8 @@ static void check_updates(struct cache_entry **src, int nr)
                }
        }
        if (total) {
-               fputc('\n', stderr);
                signal(SIGALRM, SIG_IGN);
+               fputc('\n', stderr);
        }
 }
 
index 728b6d1..ce35b5a 100644 (file)
@@ -260,7 +260,7 @@ int rev_same_tree_as_empty(struct tree *t1)
        if (!t1)
                return 0;
 
-       tree = read_object_with_reference(t1->object.sha1, "tree", &real.size, NULL);
+       tree = read_object_with_reference(t1->object.sha1, tree_type, &real.size, NULL);
        if (!tree)
                return 0;
        real.buf = tree;
index 58edec0..ba8c4f7 100644 (file)
@@ -9,6 +9,10 @@
 #include "cache.h"
 #include "delta.h"
 #include "pack.h"
+#include "blob.h"
+#include "commit.h"
+#include "tag.h"
+#include "tree.h"
 
 #ifndef O_NOATIME
 #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -894,16 +898,16 @@ void packed_object_info_detail(struct pack_entry *e,
        }
        switch (kind) {
        case OBJ_COMMIT:
-               strcpy(type, "commit");
+               strcpy(type, commit_type);
                break;
        case OBJ_TREE:
-               strcpy(type, "tree");
+               strcpy(type, tree_type);
                break;
        case OBJ_BLOB:
-               strcpy(type, "blob");
+               strcpy(type, blob_type);
                break;
        case OBJ_TAG:
-               strcpy(type, "tag");
+               strcpy(type, tag_type);
                break;
        default:
                die("corrupted pack file %s containing object of kind %d",
@@ -934,16 +938,16 @@ static int packed_object_info(struct pack_entry *entry,
                unuse_packed_git(p);
                return retval;
        case OBJ_COMMIT:
-               strcpy(type, "commit");
+               strcpy(type, commit_type);
                break;
        case OBJ_TREE:
-               strcpy(type, "tree");
+               strcpy(type, tree_type);
                break;
        case OBJ_BLOB:
-               strcpy(type, "blob");
+               strcpy(type, blob_type);
                break;
        case OBJ_TAG:
-               strcpy(type, "tag");
+               strcpy(type, tag_type);
                break;
        default:
                die("corrupted pack file %s containing object of kind %d",
@@ -1071,16 +1075,16 @@ void *unpack_entry_gently(struct pack_entry *entry,
                retval = unpack_delta_entry(pack, size, left, type, sizep, p);
                return retval;
        case OBJ_COMMIT:
-               strcpy(type, "commit");
+               strcpy(type, commit_type);
                break;
        case OBJ_TREE:
-               strcpy(type, "tree");
+               strcpy(type, tree_type);
                break;
        case OBJ_BLOB:
-               strcpy(type, "blob");
+               strcpy(type, blob_type);
                break;
        case OBJ_TAG:
-               strcpy(type, "tag");
+               strcpy(type, tag_type);
                break;
        default:
                return NULL;
@@ -1241,9 +1245,9 @@ void *read_object_with_reference(const unsigned char *sha1,
                        return buffer;
                }
                /* Handle references */
-               else if (!strcmp(type, "commit"))
+               else if (!strcmp(type, commit_type))
                        ref_type = "tree ";
-               else if (!strcmp(type, "tag"))
+               else if (!strcmp(type, tag_type))
                        ref_type = "object ";
                else {
                        free(buffer);
@@ -1625,7 +1629,7 @@ int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
                return -1;
        }
        if (!type)
-               type = "blob";
+               type = blob_type;
        if (write_object)
                ret = write_sha1_file(buf, off, type, sha1);
        else {
@@ -1652,7 +1656,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, con
                return -1;
 
        if (!type)
-               type = "blob";
+               type = blob_type;
        if (write_object)
                ret = write_sha1_file(buf, size, type, sha1);
        else {
@@ -1690,9 +1694,9 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
                if (!write_object) {
                        unsigned char hdr[50];
                        int hdrlen;
-                       write_sha1_file_prepare(target, st->st_size, "blob",
+                       write_sha1_file_prepare(target, st->st_size, blob_type,
                                                sha1, hdr, &hdrlen);
-               } else if (write_sha1_file(target, st->st_size, "blob", sha1))
+               } else if (write_sha1_file(target, st->st_size, blob_type, sha1))
                        return error("%s: failed to insert into database",
                                     path);
                free(target);
diff --git a/tag.c b/tag.c
index ac0e573..f390ee7 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -19,8 +19,7 @@ struct tag *lookup_tag(const unsigned char *sha1)
 {
         struct object *obj = lookup_object(sha1);
         if (!obj) {
-                struct tag *ret = xmalloc(sizeof(struct tag));
-                memset(ret, 0, sizeof(struct tag));
+                struct tag *ret = xcalloc(1, sizeof(struct tag));
                 created_object(sha1, &ret->object);
                 ret->object.type = tag_type;
                 return ret;
index bd289a9..fc60a90 100644 (file)
@@ -335,7 +335,7 @@ int main(int argc, char **argv)
        } else
                archive_time = time(NULL);
 
-       tree.buf = read_object_with_reference(sha1, "tree", &tree.size,
+       tree.buf = read_object_with_reference(sha1, tree_type, &tree.size,
                                              tree_sha1);
        if (!tree.buf)
                die("not a reference to a tag, commit or tree object: %s",
index 7bb6109..701fbba 100644 (file)
@@ -3,6 +3,7 @@
  */
 #include "cache.h"
 #include "diff.h"
+#include "tree.h"
 
 // What paths are we interested in?
 static int nr_paths = 0;
@@ -148,7 +149,7 @@ static int show_entry(struct diff_options *opt, const char *prefix, struct tree_
                void *tree;
 
                tree = read_sha1_file(sha1, type, &inner.size);
-               if (!tree || strcmp(type, "tree"))
+               if (!tree || strcmp(type, tree_type))
                        die("corrupt tree sha %s", sha1_to_hex(sha1));
 
                inner.buf = tree;
@@ -206,10 +207,10 @@ int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const cha
        struct tree_desc t1, t2;
        int retval;
 
-       tree1 = read_object_with_reference(old, "tree", &t1.size, NULL);
+       tree1 = read_object_with_reference(old, tree_type, &t1.size, NULL);
        if (!tree1)
                die("unable to read source tree (%s)", sha1_to_hex(old));
-       tree2 = read_object_with_reference(new, "tree", &t2.size, NULL);
+       tree2 = read_object_with_reference(new, tree_type, &t2.size, NULL);
        if (!tree2)
                die("unable to read destination tree (%s)", sha1_to_hex(new));
        t1.buf = tree1;
index 0735f40..bf8bfdf 100644 (file)
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "tree-walk.h"
+#include "tree.h"
 
 void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
 {
@@ -7,7 +8,7 @@ void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
        void *buf = NULL;
 
        if (sha1) {
-               buf = read_object_with_reference(sha1, "tree", &size, NULL);
+               buf = read_object_with_reference(sha1, tree_type, &size, NULL);
                if (!buf)
                        die("unable to read tree %s", sha1_to_hex(sha1));
        }
diff --git a/tree.c b/tree.c
index 87e0d74..d599fb5 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -18,9 +18,7 @@ static int read_one_entry(unsigned char *sha1, const char *base, int baselen, co
 
        len = strlen(pathname);
        size = cache_entry_size(baselen + len);
-       ce = xmalloc(size);
-
-       memset(ce, 0, size);
+       ce = xcalloc(1, size);
 
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = create_ce_flags(baselen + len, stage);
@@ -130,8 +128,7 @@ struct tree *lookup_tree(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj) {
-               struct tree *ret = xmalloc(sizeof(struct tree));
-               memset(ret, 0, sizeof(struct tree));
+               struct tree *ret = xcalloc(1, sizeof(struct tree));
                created_object(sha1, &ret->object);
                ret->object.type = tree_type;
                return ret;
index 3accb97..23a8562 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "blob.h"
 
 static char *create_temp_file(unsigned char *sha1)
 {
@@ -9,7 +10,7 @@ static char *create_temp_file(unsigned char *sha1)
        int fd;
 
        buf = read_sha1_file(sha1, type, &size);
-       if (!buf || strcmp(type, "blob"))
+       if (!buf || strcmp(type, blob_type))
                die("unable to read blob object %s", sha1_to_hex(sha1));
 
        strcpy(path, ".merge_file_XXXXXX");
index 815a1b3..3b824b0 100644 (file)
@@ -2,6 +2,10 @@
 #include "object.h"
 #include "delta.h"
 #include "pack.h"
+#include "blob.h"
+#include "commit.h"
+#include "tag.h"
+#include "tree.h"
 
 #include <sys/time.h>
 
@@ -148,10 +152,10 @@ static int unpack_non_delta_entry(enum object_type kind, unsigned long size)
        const char *type;
 
        switch (kind) {
-       case OBJ_COMMIT: type = "commit"; break;
-       case OBJ_TREE:   type = "tree"; break;
-       case OBJ_BLOB:   type = "blob"; break;
-       case OBJ_TAG:    type = "tag"; break;
+       case OBJ_COMMIT: type = commit_type; break;
+       case OBJ_TREE:   type = tree_type; break;
+       case OBJ_BLOB:   type = blob_type; break;
+       case OBJ_TAG:    type = tag_type; break;
        default: die("bad type %d", kind);
        }
        if (!dry_run)
index 797245a..1efac27 100644 (file)
@@ -114,8 +114,7 @@ static int add_file_to_cache(const char *path)
 
        namelen = strlen(path);
        size = cache_entry_size(namelen);
-       ce = xmalloc(size);
-       memset(ce, 0, size);
+       ce = xcalloc(1, size);
        memcpy(ce->name, path, namelen);
        ce->ce_flags = htons(namelen);
        fill_stat_cache_info(ce, &st);
@@ -312,8 +311,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
 
        len = strlen(path);
        size = cache_entry_size(len);
-       ce = xmalloc(size);
-       memset(ce, 0, size);
+       ce = xcalloc(1, size);
 
        memcpy(ce->sha1, sha1, 20);
        memcpy(ce->name, path, len);
index addb5de..dcad6e6 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "cache.h"
+#include "tree.h"
 
 static int missing_ok = 0;
 
@@ -78,7 +79,7 @@ static int write_tree(struct cache_entry **cachep, int maxentries, const char *b
                nr++;
        }
 
-       write_sha1_file(buffer, offset, "tree", returnsha1);
+       write_sha1_file(buffer, offset, tree_type, returnsha1);
        free(buffer);
        return nr;
 }
index 8ea0483..e81bca6 100644 (file)
@@ -349,12 +349,7 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
        kvdf += xe->xdf2.nreff + 1;
        kvdb += xe->xdf2.nreff + 1;
 
-       /*
-        * Classical integer square root approximation using shifts.
-        */
-       xenv.mxcost = 1;
-       for (; ndiags; ndiags >>= 2)
-               xenv.mxcost <<= 1;
+       xenv.mxcost = xdl_bogosqrt(ndiags);
        if (xenv.mxcost < XDL_MAX_COST_MIN)
                xenv.mxcost = XDL_MAX_COST_MIN;
        xenv.snake_cnt = XDL_SNAKE_CNT;
index 27a0879..add5a75 100644 (file)
@@ -25,6 +25,7 @@
 
 
 #define XDL_KPDIS_RUN 4
+#define XDL_MAX_EQLIMIT 1024
 
 
 
@@ -305,26 +306,48 @@ void xdl_free_env(xdfenv_t *xe) {
 
 
 static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
-       long r, rdis, rpdis;
-
-       for (r = 1, rdis = 0, rpdis = 1; (i - r) >= s; r++) {
+       long r, rdis0, rpdis0, rdis1, rpdis1;
+
+       /*
+        * Scans the lines before 'i' to find a run of lines that either
+        * have no match (dis[j] == 0) or have multiple matches (dis[j] > 1).
+        * Note that we always call this function with dis[i] > 1, so the
+        * current line (i) is already a multimatch line.
+        */
+       for (r = 1, rdis0 = 0, rpdis0 = 1; (i - r) >= s; r++) {
                if (!dis[i - r])
-                       rdis++;
+                       rdis0++;
                else if (dis[i - r] == 2)
-                       rpdis++;
+                       rpdis0++;
                else
                        break;
        }
-       for (r = 1; (i + r) <= e; r++) {
+       /*
+        * If the run before the line 'i' found only multimatch lines, we
+        * return 0 and hence we don't make the current line (i) discarded.
+        * We want to discard multimatch lines only when they appear in the
+        * middle of runs with nomatch lines (dis[j] == 0).
+        */
+       if (rdis0 == 0)
+               return 0;
+       for (r = 1, rdis1 = 0, rpdis1 = 1; (i + r) <= e; r++) {
                if (!dis[i + r])
-                       rdis++;
+                       rdis1++;
                else if (dis[i + r] == 2)
-                       rpdis++;
+                       rpdis1++;
                else
                        break;
        }
-
-       return rpdis * XDL_KPDIS_RUN < (rpdis + rdis);
+       /*
+        * If the run after the line 'i' found only multimatch lines, we
+        * return 0 and hence we don't make the current line (i) discarded.
+        */
+       if (rdis1 == 0)
+               return 0;
+       rdis1 += rdis0;
+       rpdis1 += rpdis0;
+
+       return rpdis1 * XDL_KPDIS_RUN < (rpdis1 + rdis1);
 }
 
 
@@ -334,34 +357,40 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
  * might be potentially discarded if they happear in a run of discardable.
  */
 static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) {
-       long i, rhi, nreff;
+       long i, nm, rhi, nreff, mlim;
        unsigned long hav;
        xrecord_t **recs;
        xrecord_t *rec;
        char *dis, *dis1, *dis2;
 
-       if (!(dis = (char *) xdl_malloc((xdf1->nrec + xdf2->nrec + 2) * sizeof(char)))) {
+       if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) {
 
                return -1;
        }
-       memset(dis, 0, (xdf1->nrec + xdf2->nrec + 2) * sizeof(char));
+       memset(dis, 0, xdf1->nrec + xdf2->nrec + 2);
        dis1 = dis;
        dis2 = dis1 + xdf1->nrec + 1;
 
+       if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT)
+               mlim = XDL_MAX_EQLIMIT;
        for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {
                hav = (*recs)->ha;
                rhi = (long) XDL_HASHLONG(hav, xdf2->hbits);
-               for (rec = xdf2->rhash[rhi]; rec; rec = rec->next)
-                       if (rec->ha == hav && ++dis1[i] == 2)
+               for (nm = 0, rec = xdf2->rhash[rhi]; rec; rec = rec->next)
+                       if (rec->ha == hav && ++nm == mlim)
                                break;
+               dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
        }
 
+       if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT)
+               mlim = XDL_MAX_EQLIMIT;
        for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {
                hav = (*recs)->ha;
                rhi = (long) XDL_HASHLONG(hav, xdf1->hbits);
-               for (rec = xdf1->rhash[rhi]; rec; rec = rec->next)
-                       if (rec->ha == hav && ++dis2[i] == 2)
+               for (nm = 0, rec = xdf1->rhash[rhi]; rec; rec = rec->next)
+                       if (rec->ha == hav && ++nm == mlim)
                                break;
+               dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
        }
 
        for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart];
index afaada1..21ab8e7 100644 (file)
 
 
 
+long xdl_bogosqrt(long n) {
+       long i;
+
+       /*
+        * Classical integer square root approximation using shifts.
+        */
+       for (i = 1; n > 0; n >>= 2)
+               i <<= 1;
+
+       return i;
+}
+
+
 int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
                     xdemitcb_t *ecb) {
        mmbuffer_t mb[3];
@@ -244,7 +257,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
        memcpy(buf, "@@ -", 4);
        nb += 4;
 
-       nb += xdl_num_out(buf + nb, c1 ? s1: 0);
+       nb += xdl_num_out(buf + nb, c1 ? s1: s1 - 1);
 
        if (c1 != 1) {
                memcpy(buf + nb, ",", 1);
@@ -256,7 +269,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
        memcpy(buf + nb, " +", 2);
        nb += 2;
 
-       nb += xdl_num_out(buf + nb, c2 ? s2: 0);
+       nb += xdl_num_out(buf + nb, c2 ? s2: s2 - 1);
 
        if (c2 != 1) {
                memcpy(buf + nb, ",", 1);
index 55b0d39..ea38ee9 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);
 int xdl_cha_init(chastore_t *cha, long isize, long icount);