Git fork
1/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6#define USE_THE_REPOSITORY_VARIABLE
7#include "builtin.h"
8#include "config.h"
9#include "environment.h"
10#include "gettext.h"
11#include "hex.h"
12#include "object-name.h"
13#include "odb.h"
14
15#include "commit.h"
16#include "parse-options.h"
17
18static const char * const commit_tree_usage[] = {
19 N_("git commit-tree <tree> [(-p <parent>)...]"),
20 N_("git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
21 " [(-F <file>)...] <tree>"),
22 NULL
23};
24
25static const char *sign_commit;
26
27static void new_parent(struct commit *parent, struct commit_list **parents_p)
28{
29 struct object_id *oid = &parent->object.oid;
30 struct commit_list *parents;
31 for (parents = *parents_p; parents; parents = parents->next) {
32 if (parents->item == parent) {
33 error(_("duplicate parent %s ignored"), oid_to_hex(oid));
34 return;
35 }
36 parents_p = &parents->next;
37 }
38 commit_list_insert(parent, parents_p);
39}
40
41static int parse_parent_arg_callback(const struct option *opt,
42 const char *arg, int unset)
43{
44 struct object_id oid;
45 struct commit_list **parents = opt->value;
46
47 BUG_ON_OPT_NEG_NOARG(unset, arg);
48
49 if (repo_get_oid_commit(the_repository, arg, &oid))
50 die(_("not a valid object name %s"), arg);
51
52 odb_assert_oid_type(the_repository->objects, &oid, OBJ_COMMIT);
53 new_parent(lookup_commit(the_repository, &oid), parents);
54 return 0;
55}
56
57static int parse_message_arg_callback(const struct option *opt,
58 const char *arg, int unset)
59{
60 struct strbuf *buf = opt->value;
61
62 BUG_ON_OPT_NEG_NOARG(unset, arg);
63
64 if (buf->len)
65 strbuf_addch(buf, '\n');
66 strbuf_addstr(buf, arg);
67 strbuf_complete_line(buf);
68
69 return 0;
70}
71
72static int parse_file_arg_callback(const struct option *opt,
73 const char *arg, int unset)
74{
75 int fd;
76 struct strbuf *buf = opt->value;
77
78 BUG_ON_OPT_NEG_NOARG(unset, arg);
79
80 if (buf->len)
81 strbuf_addch(buf, '\n');
82 if (!strcmp(arg, "-"))
83 fd = 0;
84 else {
85 fd = xopen(arg, O_RDONLY);
86 }
87 if (strbuf_read(buf, fd, 0) < 0)
88 die_errno(_("git commit-tree: failed to read '%s'"), arg);
89 if (fd && close(fd))
90 die_errno(_("git commit-tree: failed to close '%s'"), arg);
91
92 return 0;
93}
94
95int cmd_commit_tree(int argc,
96 const char **argv,
97 const char *prefix,
98 struct repository *repo UNUSED)
99{
100 static struct strbuf buffer = STRBUF_INIT;
101 struct commit_list *parents = NULL;
102 struct object_id tree_oid;
103 struct object_id commit_oid;
104
105 struct option options[] = {
106 OPT_CALLBACK_F('p', NULL, &parents, N_("parent"),
107 N_("id of a parent commit object"), PARSE_OPT_NONEG,
108 parse_parent_arg_callback),
109 OPT_CALLBACK_F('m', NULL, &buffer, N_("message"),
110 N_("commit message"), PARSE_OPT_NONEG,
111 parse_message_arg_callback),
112 OPT_CALLBACK_F('F', NULL, &buffer, N_("file"),
113 N_("read commit log message from file"), PARSE_OPT_NONEG,
114 parse_file_arg_callback),
115 {
116 .type = OPTION_STRING,
117 .short_name = 'S',
118 .long_name = "gpg-sign",
119 .value = &sign_commit,
120 .argh = N_("key-id"),
121 .help = N_("GPG sign commit"),
122 .flags = PARSE_OPT_OPTARG,
123 .defval = (intptr_t) "",
124 },
125 OPT_END()
126 };
127 int ret;
128
129 repo_config(the_repository, git_default_config, NULL);
130
131 show_usage_with_options_if_asked(argc, argv,
132 commit_tree_usage, options);
133
134 argc = parse_options(argc, argv, prefix, options, commit_tree_usage, 0);
135
136 if (argc != 1)
137 die(_("must give exactly one tree"));
138
139 if (repo_get_oid_tree(the_repository, argv[0], &tree_oid))
140 die(_("not a valid object name %s"), argv[0]);
141
142 if (!buffer.len) {
143 if (strbuf_read(&buffer, 0, 0) < 0)
144 die_errno(_("git commit-tree: failed to read"));
145 }
146
147 if (commit_tree(buffer.buf, buffer.len, &tree_oid, parents, &commit_oid,
148 NULL, sign_commit)) {
149 ret = 1;
150 goto out;
151 }
152
153 printf("%s\n", oid_to_hex(&commit_oid));
154 ret = 0;
155
156out:
157 free_commit_list(parents);
158 strbuf_release(&buffer);
159 return ret;
160}