Update packedGit config option documentation.
[gitweb.git] / commit.c
index a6d543eee7831cd6a479d4cf8b2ba81a1438b298..afdf27eeceb76f4f3842ba09b48d07bc218846d6 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1,6 +1,8 @@
 #include "cache.h"
 #include "tag.h"
 #include "commit.h"
+#include "pkt-line.h"
+#include "utf8.h"
 
 int save_commit_buffer = 1;
 
@@ -221,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;
 }
 
@@ -234,6 +238,37 @@ static struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
        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;
@@ -563,10 +598,108 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com
        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 *replace_encoding_header(char *buf, char *encoding)
+{
+       char *encoding_header = strstr(buf, "\nencoding ");
+       char *end_of_encoding_header;
+       int encoding_header_pos;
+       int encoding_header_len;
+       int new_len;
+       int need_len;
+       int buflen = strlen(buf) + 1;
+
+       if (!encoding_header)
+               return buf; /* should not happen but be defensive */
+       encoding_header++;
+       end_of_encoding_header = strchr(encoding_header, '\n');
+       if (!end_of_encoding_header)
+               return buf; /* should not happen but be defensive */
+       end_of_encoding_header++;
+
+       encoding_header_len = end_of_encoding_header - encoding_header;
+       encoding_header_pos = encoding_header - buf;
+
+       if (is_encoding_utf8(encoding)) {
+               /* we have re-coded to UTF-8; drop the header */
+               memmove(encoding_header, end_of_encoding_header,
+                       buflen - (encoding_header_pos + encoding_header_len));
+               return buf;
+       }
+       new_len = strlen(encoding);
+       need_len = new_len + strlen("encoding \n");
+       if (encoding_header_len < need_len) {
+               buf = xrealloc(buf, buflen + (need_len - encoding_header_len));
+               encoding_header = buf + encoding_header_pos;
+               end_of_encoding_header = encoding_header + encoding_header_len;
+       }
+       memmove(end_of_encoding_header + (need_len - encoding_header_len),
+               end_of_encoding_header,
+               buflen - (encoding_header_pos + encoding_header_len));
+       memcpy(encoding_header + 9, encoding, strlen(encoding));
+       encoding_header[9 + new_len] = '\n';
+       return buf;
+}
+
+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)
+               output_encoding = "utf-8";
+       else 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);
+       if (out)
+               out = replace_encoding_header(out, output_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;
@@ -574,6 +707,10 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
        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;
@@ -590,7 +727,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
                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' &&
@@ -721,6 +858,8 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
        if (fmt == CMIT_FMT_EMAIL && !body)
                buf[offset++] = '\n';
        buf[offset] = '\0';
+
+       free(reencoded);
        return offset;
 }
 
@@ -868,11 +1007,11 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
 
 /* merge-rebase stuff */
 
-/* bits #0..7 in revision.h */
-#define PARENT1                (1u<< 8)
-#define PARENT2                (1u<< 9)
-#define STALE          (1u<<10)
-#define RESULT         (1u<<11)
+/* bits #0..15 in revision.h */
+#define PARENT1                (1u<<16)
+#define PARENT2                (1u<<17)
+#define STALE          (1u<<18)
+#define RESULT         (1u<<19)
 
 static struct commit *interesting(struct commit_list *list)
 {
@@ -1009,3 +1148,20 @@ struct commit_list *get_merge_bases(struct commit *one,
        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;
+}