]> git.proxmox.com Git - libgit2.git/blame - examples/init.c
Enable reproducible builds by default
[libgit2.git] / examples / init.c
CommitLineData
0ea41445 1/*
6cb831bd 2 * libgit2 "init" example - shows how to initialize a new repo
85c6730c 3 *
6cb831bd
BS
4 * Written by the libgit2 contributors
5 *
6 * To the extent possible under law, the author(s) have dedicated all copyright
7 * and related and neighboring rights to this software to the public domain
8 * worldwide. This software is distributed without any warranty.
9 *
10 * You should have received a copy of the CC0 Public Domain Dedication along
11 * with this software. If not, see
12 * <http://creativecommons.org/publicdomain/zero/1.0/>.
85c6730c
BS
13 */
14
15#include "common.h"
16
17/**
0ea41445
RB
18 * This is a sample program that is similar to "git init". See the
19 * documentation for that (try "git help init") to understand what this
20 * program is emulating.
21 *
22 * This demonstrates using the libgit2 APIs to initialize a new repository.
23 *
24 * This also contains a special additional option that regular "git init"
25 * does not support which is "--initial-commit" to make a first empty commit.
26 * That is demonstrated in the "create_initial_commit" helper function.
0ea41445
RB
27 */
28
85c6730c 29/** Forward declarations of helpers */
0c9c969a 30struct init_opts {
a8422f92
BS
31 int no_options;
32 int quiet;
33 int bare;
34 int initial_commit;
35 uint32_t shared;
36 const char *template;
37 const char *gitdir;
38 const char *dir;
39};
944c1589 40static void create_initial_commit(git_repository *repo);
0c9c969a 41static void parse_opts(struct init_opts *o, int argc, char *argv[]);
944c1589 42
0c9c969a 43int lg2_init(git_repository *repo, int argc, char *argv[])
944c1589 44{
0c9c969a 45 struct init_opts o = { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK, 0, 0, 0 };
944c1589 46
a8422f92 47 parse_opts(&o, argc, argv);
944c1589 48
85c6730c 49 /* Initialize repository. */
944c1589 50
a8422f92 51 if (o.no_options) {
85c6730c
BS
52 /**
53 * No options were specified, so let's demonstrate the default
944c1589
RB
54 * simple case of git_repository_init() API usage...
55 */
7cc3c9bf
BS
56 check_lg2(git_repository_init(&repo, o.dir, 0),
57 "Could not initialize repository", NULL);
944c1589
RB
58 }
59 else {
85c6730c
BS
60 /**
61 * Some command line options were specified, so we'll use the
944c1589
RB
62 * extended init API to handle them
63 */
a8422f92
BS
64 git_repository_init_options initopts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
65 initopts.flags = GIT_REPOSITORY_INIT_MKPATH;
944c1589 66
a8422f92
BS
67 if (o.bare)
68 initopts.flags |= GIT_REPOSITORY_INIT_BARE;
944c1589 69
a8422f92
BS
70 if (o.template) {
71 initopts.flags |= GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
72 initopts.template_path = o.template;
944c1589
RB
73 }
74
a8422f92 75 if (o.gitdir) {
85c6730c
BS
76 /**
77 * If you specified a separate git directory, then initialize
944c1589
RB
78 * the repository at that path and use the second path as the
79 * working directory of the repository (with a git-link file)
80 */
a8422f92
BS
81 initopts.workdir_path = o.dir;
82 o.dir = o.gitdir;
944c1589
RB
83 }
84
a8422f92
BS
85 if (o.shared != 0)
86 initopts.mode = o.shared;
944c1589 87
7cc3c9bf
BS
88 check_lg2(git_repository_init_ext(&repo, o.dir, &initopts),
89 "Could not initialize repository", NULL);
944c1589
RB
90 }
91
85c6730c 92 /** Print a message to stdout like "git init" does. */
0ea41445 93
a8422f92
BS
94 if (!o.quiet) {
95 if (o.bare || o.gitdir)
96 o.dir = git_repository_path(repo);
944c1589 97 else
a8422f92 98 o.dir = git_repository_workdir(repo);
944c1589 99
a8422f92 100 printf("Initialized empty Git repository in %s\n", o.dir);
944c1589
RB
101 }
102
85c6730c
BS
103 /**
104 * As an extension to the basic "git init" command, this example
944c1589
RB
105 * gives the option to create an empty initial commit. This is
106 * mostly to demonstrate what it takes to do that, but also some
107 * people like to have that empty base commit in their repo.
108 */
a8422f92 109 if (o.initial_commit) {
944c1589
RB
110 create_initial_commit(repo);
111 printf("Created empty initial commit\n");
112 }
113
114 git_repository_free(repo);
944c1589
RB
115
116 return 0;
117}
118
85c6730c
BS
119/**
120 * Unlike regular "git init", this example shows how to create an initial
0ea41445
RB
121 * empty commit in the repository. This is the helper function that does
122 * that.
123 */
944c1589
RB
124static void create_initial_commit(git_repository *repo)
125{
126 git_signature *sig;
127 git_index *index;
128 git_oid tree_id, commit_id;
129 git_tree *tree;
130
85c6730c 131 /** First use the config to initialize a commit signature for the user. */
944c1589
RB
132
133 if (git_signature_default(&sig, repo) < 0)
a8422f92
BS
134 fatal("Unable to create a commit signature.",
135 "Perhaps 'user.name' and 'user.email' are not set");
944c1589
RB
136
137 /* Now let's create an empty tree for this commit */
138
139 if (git_repository_index(&index, repo) < 0)
a8422f92 140 fatal("Could not open repository index", NULL);
944c1589 141
85c6730c
BS
142 /**
143 * Outside of this example, you could call git_index_add_bypath()
944c1589
RB
144 * here to put actual files into the index. For our purposes, we'll
145 * leave it empty for now.
146 */
147
148 if (git_index_write_tree(&tree_id, index) < 0)
a8422f92 149 fatal("Unable to write initial tree from index", NULL);
944c1589
RB
150
151 git_index_free(index);
152
153 if (git_tree_lookup(&tree, repo, &tree_id) < 0)
a8422f92 154 fatal("Could not look up initial tree", NULL);
944c1589 155
85c6730c
BS
156 /**
157 * Ready to create the initial commit.
944c1589
RB
158 *
159 * Normally creating a commit would involve looking up the current
160 * HEAD commit and making that be the parent of the initial commit,
161 * but here this is the first commit so there will be no parent.
162 */
163
164 if (git_commit_create_v(
165 &commit_id, repo, "HEAD", sig, sig,
166 NULL, "Initial commit", tree, 0) < 0)
a8422f92 167 fatal("Could not create the initial commit", NULL);
944c1589 168
85c6730c 169 /** Clean up so we don't leak memory. */
944c1589
RB
170
171 git_tree_free(tree);
172 git_signature_free(sig);
173}
a8422f92
BS
174
175static void usage(const char *error, const char *arg)
176{
177 fprintf(stderr, "error: %s '%s'\n", error, arg);
178 fprintf(stderr,
179 "usage: init [-q | --quiet] [--bare] [--template=<dir>]\n"
180 " [--shared[=perms]] [--initial-commit]\n"
181 " [--separate-git-dir] <directory>\n");
182 exit(1);
183}
184
85c6730c 185/** Parse the tail of the --shared= argument. */
a8422f92
BS
186static uint32_t parse_shared(const char *shared)
187{
188 if (!strcmp(shared, "false") || !strcmp(shared, "umask"))
189 return GIT_REPOSITORY_INIT_SHARED_UMASK;
190
191 else if (!strcmp(shared, "true") || !strcmp(shared, "group"))
192 return GIT_REPOSITORY_INIT_SHARED_GROUP;
193
194 else if (!strcmp(shared, "all") || !strcmp(shared, "world") ||
195 !strcmp(shared, "everybody"))
196 return GIT_REPOSITORY_INIT_SHARED_ALL;
197
198 else if (shared[0] == '0') {
199 long val;
200 char *end = NULL;
201 val = strtol(shared + 1, &end, 8);
202 if (end == shared + 1 || *end != 0)
203 usage("invalid octal value for --shared", shared);
204 return (uint32_t)val;
205 }
206
207 else
208 usage("unknown value for --shared", shared);
209
210 return 0;
211}
212
0c9c969a 213static void parse_opts(struct init_opts *o, int argc, char *argv[])
a8422f92
BS
214{
215 struct args_info args = ARGS_INFO_INIT;
216 const char *sharedarg;
217
85c6730c 218 /** Process arguments. */
a8422f92
BS
219
220 for (args.pos = 1; args.pos < argc; ++args.pos) {
221 char *a = argv[args.pos];
222
223 if (a[0] == '-')
224 o->no_options = 0;
225
226 if (a[0] != '-') {
227 if (o->dir != NULL)
228 usage("extra argument", a);
229 o->dir = a;
230 }
231 else if (!strcmp(a, "-q") || !strcmp(a, "--quiet"))
232 o->quiet = 1;
233 else if (!strcmp(a, "--bare"))
234 o->bare = 1;
235 else if (!strcmp(a, "--shared"))
236 o->shared = GIT_REPOSITORY_INIT_SHARED_GROUP;
237 else if (!strcmp(a, "--initial-commit"))
238 o->initial_commit = 1;
239 else if (match_str_arg(&sharedarg, &args, "--shared"))
240 o->shared = parse_shared(sharedarg);
241 else if (!match_str_arg(&o->template, &args, "--template") ||
242 !match_str_arg(&o->gitdir, &args, "--separate-git-dir"))
243 usage("unknown option", a);
244 }
245
246 if (!o->dir)
0c9c969a 247 usage("must specify directory to init", "");
a8422f92 248}