commit-tree.con commit Merge branch 'master' (52b6536)
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7
   8#define BLOCKING (1ul << 14)
   9
  10/*
  11 * FIXME! Share the code with "write-tree.c"
  12 */
  13static void init_buffer(char **bufp, unsigned int *sizep)
  14{
  15        char *buf = xmalloc(BLOCKING);
  16        *sizep = 0;
  17        *bufp = buf;
  18}
  19
  20static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
  21{
  22        char one_line[2048];
  23        va_list args;
  24        int len;
  25        unsigned long alloc, size, newsize;
  26        char *buf;
  27
  28        va_start(args, fmt);
  29        len = vsnprintf(one_line, sizeof(one_line), fmt, args);
  30        va_end(args);
  31        size = *sizep;
  32        newsize = size + len;
  33        alloc = (size + 32767) & ~32767;
  34        buf = *bufp;
  35        if (newsize > alloc) {
  36                alloc = (newsize + 32767) & ~32767;
  37                buf = xrealloc(buf, alloc);
  38                *bufp = buf;
  39        }
  40        *sizep = newsize;
  41        memcpy(buf + size, one_line, len);
  42}
  43
  44static void check_valid(unsigned char *sha1, const char *expect)
  45{
  46        void *buf;
  47        char type[20];
  48        unsigned long size;
  49
  50        buf = read_sha1_file(sha1, type, &size);
  51        if (!buf || strcmp(type, expect))
  52                die("%s is not a valid '%s' object", sha1_to_hex(sha1), expect);
  53        free(buf);
  54}
  55
  56/*
  57 * Having more than two parents is not strange at all, and this is
  58 * how multi-way merges are represented.
  59 */
  60#define MAXPARENT (16)
  61static unsigned char parent_sha1[MAXPARENT][20];
  62
  63static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog";
  64
  65static int new_parent(int idx)
  66{
  67        int i;
  68        unsigned char *sha1 = parent_sha1[idx];
  69        for (i = 0; i < idx; i++) {
  70                if (!memcmp(parent_sha1[i], sha1, 20)) {
  71                        error("duplicate parent %s ignored", sha1_to_hex(sha1));
  72                        return 0;
  73                }
  74        }
  75        return 1;
  76}
  77
  78int main(int argc, char **argv)
  79{
  80        int i;
  81        int parents = 0;
  82        unsigned char tree_sha1[20];
  83        unsigned char commit_sha1[20];
  84        char comment[1000];
  85        char *buffer;
  86        unsigned int size;
  87
  88        setup_ident();
  89        git_config(git_default_config);
  90
  91        if (argc < 2 || get_sha1_hex(argv[1], tree_sha1) < 0)
  92                usage(commit_tree_usage);
  93
  94        check_valid(tree_sha1, "tree");
  95        for (i = 2; i < argc; i += 2) {
  96                char *a, *b;
  97                a = argv[i]; b = argv[i+1];
  98                if (!b || strcmp(a, "-p") || get_sha1(b, parent_sha1[parents]))
  99                        usage(commit_tree_usage);
 100                check_valid(parent_sha1[parents], "commit");
 101                if (new_parent(parents))
 102                        parents++;
 103        }
 104        if (!parents)
 105                fprintf(stderr, "Committing initial tree %s\n", argv[1]);
 106
 107        init_buffer(&buffer, &size);
 108        add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
 109
 110        /*
 111         * NOTE! This ordering means that the same exact tree merged with a
 112         * different order of parents will be a _different_ changeset even
 113         * if everything else stays the same.
 114         */
 115        for (i = 0; i < parents; i++)
 116                add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
 117
 118        /* Person/date information */
 119        add_buffer(&buffer, &size, "author %s\n", git_author_info());
 120        add_buffer(&buffer, &size, "committer %s\n\n", git_committer_info());
 121
 122        /* And add the comment */
 123        while (fgets(comment, sizeof(comment), stdin) != NULL)
 124                add_buffer(&buffer, &size, "%s", comment);
 125
 126        write_sha1_file(buffer, size, "commit", commit_sha1);
 127        printf("%s\n", sha1_to_hex(commit_sha1));
 128        return 0;
 129}