Merge branch 'jc/utf8'
authorJunio C Hamano <junkio@cox.net>
Fri, 29 Dec 2006 03:03:02 +0000 (19:03 -0800)
committerJunio C Hamano <junkio@cox.net>
Fri, 29 Dec 2006 03:03:02 +0000 (19:03 -0800)
* jc/utf8:
t3900: test conversion to non UTF-8 as well
Rename t3900 test vector file
UTF-8: introduce i18n.logoutputencoding.
Teach log family --encoding
i18n.logToUTF8: convert commit log message to UTF-8
Move encoding conversion routine out of mailinfo to utf8.c

Conflicts:

commit.c

1  2 
Documentation/config.txt
commit.c
diff --combined Documentation/config.txt
index 6452a8be144f92f9140fb133acda4d9fd32f2b15,ffef3abfb6c9381e84a9d3ee11789c6ea78d9283..178e0e1e209e066ad220d6ba95be0728c2db5e99
@@@ -192,25 -192,6 +192,25 @@@ format.headers:
        Additional email headers to include in a patch to be submitted
        by mail.  See gitlink:git-format-patch[1].
  
 +gc.reflogexpire::
 +      `git reflog expire` removes reflog entries older than
 +      this time; defaults to 90 days.
 +
 +gc.reflogexpireunreachable::
 +      `git reflog expire` removes reflog entries older than
 +      this time and are not reachable from the current tip;
 +      defaults to 30 days.
 +
 +gc.rerereresolved::
 +      Records of conflicted merge you resolved earlier are
 +      kept for this many days when `git rerere gc` is run.
 +      The default is 60 days.  See gitlink:git-rerere[1].
 +
 +gc.rerereunresolved::
 +      Records of conflicted merge you have not resolved are
 +      kept for this many days when `git rerere gc` is run.
 +      The default is 15 days.  See gitlink:git-rerere[1].
 +
  gitcvs.enabled::
        Whether the cvs pserver interface is enabled for this repository.
        See gitlink:git-cvsserver[1].
@@@ -267,6 -248,10 +267,10 @@@ i18n.commitEncoding:
        browser (and possibly at other places in the future or in other
        porcelains). See e.g. gitlink:git-mailinfo[1]. Defaults to 'utf-8'.
  
+ i18n.logOutputEncoding::
+       Character encoding the commit messages are converted to when
+       running `git-log` and friends.
  log.showroot::
        If true, the initial commit will be shown as a big creation event.
        This is equivalent to a diff against an empty tree.
diff --combined commit.c
index 59ea77c577886a3ba5b4ef385099d7a564af173c,6f2839a5cd3708fca9ef845375d3b16373fd3266..eb06afbbe0f00ac4f553e37c50eca290418a7907
+++ b/commit.c
@@@ -1,7 -1,7 +1,8 @@@
  #include "cache.h"
  #include "tag.h"
  #include "commit.h"
 +#include "pkt-line.h"
+ #include "utf8.h"
  
  int save_commit_buffer = 1;
  
@@@ -222,8 -222,6 +223,8 @@@ static void prepare_commit_graft(void
                return;
        graft_file = get_graft_file();
        read_graft_file(graft_file);
 +      /* make sure shallows are read */
 +      is_repository_shallow();
        commit_graft_prepared = 1;
  }
  
@@@ -237,37 -235,6 +238,37 @@@ static struct commit_graft *lookup_comm
        return commit_graft[pos];
  }
  
 +int write_shallow_commits(int fd, int use_pack_protocol)
 +{
 +      int i, count = 0;
 +      for (i = 0; i < commit_graft_nr; i++)
 +              if (commit_graft[i]->nr_parent < 0) {
 +                      const char *hex =
 +                              sha1_to_hex(commit_graft[i]->sha1);
 +                      count++;
 +                      if (use_pack_protocol)
 +                              packet_write(fd, "shallow %s", hex);
 +                      else {
 +                              write(fd, hex,  40);
 +                              write(fd, "\n", 1);
 +                      }
 +              }
 +      return count;
 +}
 +
 +int unregister_shallow(const unsigned char *sha1)
 +{
 +      int pos = commit_graft_pos(sha1);
 +      if (pos < 0)
 +              return -1;
 +      if (pos + 1 < commit_graft_nr)
 +              memcpy(commit_graft + pos, commit_graft + pos + 1,
 +                              sizeof(struct commit_graft *)
 +                              * (commit_graft_nr - pos - 1));
 +      commit_graft_nr--;
 +      return 0;
 +}
 +
  int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
  {
        char *tail = buffer;
@@@ -597,10 -564,61 +598,61 @@@ static int add_merge_info(enum cmit_fm
        return offset;
  }
  
- unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
-                                 unsigned long len, char *buf, unsigned long space,
+ static char *get_header(const struct commit *commit, const char *key)
+ {
+       int key_len = strlen(key);
+       const char *line = commit->buffer;
+       for (;;) {
+               const char *eol = strchr(line, '\n'), *next;
+               if (line == eol)
+                       return NULL;
+               if (!eol) {
+                       eol = line + strlen(line);
+                       next = NULL;
+               } else
+                       next = eol + 1;
+               if (!strncmp(line, key, key_len) && line[key_len] == ' ') {
+                       int len = eol - line - key_len;
+                       char *ret = xmalloc(len);
+                       memcpy(ret, line + key_len + 1, len - 1);
+                       ret[len - 1] = '\0';
+                       return ret;
+               }
+               line = next;
+       }
+ }
+ static char *logmsg_reencode(const struct commit *commit)
+ {
+       char *encoding;
+       char *out;
+       char *output_encoding = (git_log_output_encoding
+                                ? git_log_output_encoding
+                                : git_commit_encoding);
+       if (!output_encoding)
+               return NULL;
+       encoding = get_header(commit, "encoding");
+       if (!encoding || !strcmp(encoding, output_encoding)) {
+               free(encoding);
+               return NULL;
+       }
+       out = reencode_string(commit->buffer, output_encoding, encoding);
+       free(encoding);
+       if (!out)
+               return NULL;
+       return out;
+ }
+ unsigned long pretty_print_commit(enum cmit_fmt fmt,
+                                 const struct commit *commit,
+                                 unsigned long len,
+                                 char *buf, unsigned long space,
                                  int abbrev, const char *subject,
-                                 const char *after_subject, int relative_date)
+                                 const char *after_subject,
+                                 int relative_date)
  {
        int hdr = 1, body = 0;
        unsigned long offset = 0;
        int parents_shown = 0;
        const char *msg = commit->buffer;
        int plain_non_ascii = 0;
+       char *reencoded = logmsg_reencode(commit);
+       if (reencoded)
+               msg = reencoded;
  
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
                indent = 0;
                for (in_body = i = 0; (ch = msg[i]) && i < len; i++) {
                        if (!in_body) {
                                /* author could be non 7-bit ASCII but
-                                * the log may so; skip over the
+                                * the log may be so; skip over the
                                 * header part first.
                                 */
                                if (ch == '\n' &&
        if (fmt == CMIT_FMT_EMAIL && !body)
                buf[offset++] = '\n';
        buf[offset] = '\0';
+       free(reencoded);
        return offset;
  }
  
@@@ -1043,20 -1067,3 +1101,20 @@@ struct commit_list *get_merge_bases(str
        free(rslt);
        return result;
  }
 +
 +int in_merge_bases(struct commit *rev1, struct commit *rev2)
 +{
 +      struct commit_list *bases, *b;
 +      int ret = 0;
 +
 +      bases = get_merge_bases(rev1, rev2, 1);
 +      for (b = bases; b; b = b->next) {
 +              if (!hashcmp(rev1->object.sha1, b->item->object.sha1)) {
 +                      ret = 1;
 +                      break;
 +              }
 +      }
 +
 +      free_commit_list(bases);
 +      return ret;
 +}