2 * libgit2 "init" example - shows how to initialize a new repo
4 * Written by the libgit2 contributors
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.
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/>.
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.
22 * This demonstrates using the libgit2 APIs to initialize a new repository.
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.
29 /** Forward declarations of helpers */
40 static void create_initial_commit(git_repository
*repo
);
41 static void parse_opts(struct init_opts
*o
, int argc
, char *argv
[]);
43 int lg2_init(git_repository
*repo
, int argc
, char *argv
[])
45 struct init_opts o
= { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK
, 0, 0, 0 };
47 parse_opts(&o
, argc
, argv
);
49 /* Initialize repository. */
53 * No options were specified, so let's demonstrate the default
54 * simple case of git_repository_init() API usage...
56 check_lg2(git_repository_init(&repo
, o
.dir
, 0),
57 "Could not initialize repository", NULL
);
61 * Some command line options were specified, so we'll use the
62 * extended init API to handle them
64 git_repository_init_options initopts
= GIT_REPOSITORY_INIT_OPTIONS_INIT
;
65 initopts
.flags
= GIT_REPOSITORY_INIT_MKPATH
;
68 initopts
.flags
|= GIT_REPOSITORY_INIT_BARE
;
71 initopts
.flags
|= GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE
;
72 initopts
.template_path
= o
.template;
77 * If you specified a separate git directory, then initialize
78 * the repository at that path and use the second path as the
79 * working directory of the repository (with a git-link file)
81 initopts
.workdir_path
= o
.dir
;
86 initopts
.mode
= o
.shared
;
88 check_lg2(git_repository_init_ext(&repo
, o
.dir
, &initopts
),
89 "Could not initialize repository", NULL
);
92 /** Print a message to stdout like "git init" does. */
95 if (o
.bare
|| o
.gitdir
)
96 o
.dir
= git_repository_path(repo
);
98 o
.dir
= git_repository_workdir(repo
);
100 printf("Initialized empty Git repository in %s\n", o
.dir
);
104 * As an extension to the basic "git init" command, this example
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.
109 if (o
.initial_commit
) {
110 create_initial_commit(repo
);
111 printf("Created empty initial commit\n");
114 git_repository_free(repo
);
120 * Unlike regular "git init", this example shows how to create an initial
121 * empty commit in the repository. This is the helper function that does
124 static void create_initial_commit(git_repository
*repo
)
128 git_oid tree_id
, commit_id
;
131 /** First use the config to initialize a commit signature for the user. */
133 if (git_signature_default(&sig
, repo
) < 0)
134 fatal("Unable to create a commit signature.",
135 "Perhaps 'user.name' and 'user.email' are not set");
137 /* Now let's create an empty tree for this commit */
139 if (git_repository_index(&index
, repo
) < 0)
140 fatal("Could not open repository index", NULL
);
143 * Outside of this example, you could call git_index_add_bypath()
144 * here to put actual files into the index. For our purposes, we'll
145 * leave it empty for now.
148 if (git_index_write_tree(&tree_id
, index
) < 0)
149 fatal("Unable to write initial tree from index", NULL
);
151 git_index_free(index
);
153 if (git_tree_lookup(&tree
, repo
, &tree_id
) < 0)
154 fatal("Could not look up initial tree", NULL
);
157 * Ready to create the initial commit.
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.
164 if (git_commit_create_v(
165 &commit_id
, repo
, "HEAD", sig
, sig
,
166 NULL
, "Initial commit", tree
, 0) < 0)
167 fatal("Could not create the initial commit", NULL
);
169 /** Clean up so we don't leak memory. */
172 git_signature_free(sig
);
175 static void usage(const char *error
, const char *arg
)
177 fprintf(stderr
, "error: %s '%s'\n", error
, arg
);
179 "usage: init [-q | --quiet] [--bare] [--template=<dir>]\n"
180 " [--shared[=perms]] [--initial-commit]\n"
181 " [--separate-git-dir] <directory>\n");
185 /** Parse the tail of the --shared= argument. */
186 static uint32_t parse_shared(const char *shared
)
188 if (!strcmp(shared
, "false") || !strcmp(shared
, "umask"))
189 return GIT_REPOSITORY_INIT_SHARED_UMASK
;
191 else if (!strcmp(shared
, "true") || !strcmp(shared
, "group"))
192 return GIT_REPOSITORY_INIT_SHARED_GROUP
;
194 else if (!strcmp(shared
, "all") || !strcmp(shared
, "world") ||
195 !strcmp(shared
, "everybody"))
196 return GIT_REPOSITORY_INIT_SHARED_ALL
;
198 else if (shared
[0] == '0') {
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
;
208 usage("unknown value for --shared", shared
);
213 static void parse_opts(struct init_opts
*o
, int argc
, char *argv
[])
215 struct args_info args
= ARGS_INFO_INIT
;
216 const char *sharedarg
;
218 /** Process arguments. */
220 for (args
.pos
= 1; args
.pos
< argc
; ++args
.pos
) {
221 char *a
= argv
[args
.pos
];
228 usage("extra argument", a
);
231 else if (!strcmp(a
, "-q") || !strcmp(a
, "--quiet"))
233 else if (!strcmp(a
, "--bare"))
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
);
247 usage("must specify directory to init", "");