]> git.ipfire.org Git - thirdparty/git.git/blob - builtin/init-db.c
Merge branch 'ps/reftable-fixes-and-optims'
[thirdparty/git.git] / builtin / init-db.c
1 /*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6 #include "builtin.h"
7 #include "abspath.h"
8 #include "environment.h"
9 #include "gettext.h"
10 #include "object-file.h"
11 #include "parse-options.h"
12 #include "path.h"
13 #include "setup.h"
14 #include "strbuf.h"
15
16 static int guess_repository_type(const char *git_dir)
17 {
18 const char *slash;
19 char *cwd;
20 int cwd_is_git_dir;
21
22 /*
23 * "GIT_DIR=. git init" is always bare.
24 * "GIT_DIR=`pwd` git init" too.
25 */
26 if (!strcmp(".", git_dir))
27 return 1;
28 cwd = xgetcwd();
29 cwd_is_git_dir = !strcmp(git_dir, cwd);
30 free(cwd);
31 if (cwd_is_git_dir)
32 return 1;
33 /*
34 * "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
35 */
36 if (!strcmp(git_dir, ".git"))
37 return 0;
38 slash = strrchr(git_dir, '/');
39 if (slash && !strcmp(slash, "/.git"))
40 return 0;
41
42 /*
43 * Otherwise it is often bare. At this point
44 * we are just guessing.
45 */
46 return 1;
47 }
48
49 static int shared_callback(const struct option *opt, const char *arg, int unset)
50 {
51 BUG_ON_OPT_NEG(unset);
52 *((int *) opt->value) = (arg) ? git_config_perm("arg", arg) : PERM_GROUP;
53 return 0;
54 }
55
56 static const char *const init_db_usage[] = {
57 N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
58 " [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
59 " [-b <branch-name> | --initial-branch=<branch-name>]\n"
60 " [--shared[=<permissions>]] [<directory>]"),
61 NULL
62 };
63
64 /*
65 * If you want to, you can share the DB area with any number of branches.
66 * That has advantages: you can save space by sharing all the SHA1 objects.
67 * On the other hand, it might just make lookup slower and messier. You
68 * be the judge. The default case is to have one DB per managed directory.
69 */
70 int cmd_init_db(int argc, const char **argv, const char *prefix)
71 {
72 const char *git_dir;
73 const char *real_git_dir = NULL;
74 const char *work_tree;
75 const char *template_dir = NULL;
76 unsigned int flags = 0;
77 const char *object_format = NULL;
78 const char *initial_branch = NULL;
79 int hash_algo = GIT_HASH_UNKNOWN;
80 int init_shared_repository = -1;
81 const struct option init_db_options[] = {
82 OPT_STRING(0, "template", &template_dir, N_("template-directory"),
83 N_("directory from which templates will be used")),
84 OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
85 N_("create a bare repository"), 1),
86 { OPTION_CALLBACK, 0, "shared", &init_shared_repository,
87 N_("permissions"),
88 N_("specify that the git repository is to be shared amongst several users"),
89 PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
90 OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
91 OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
92 N_("separate git dir from working tree")),
93 OPT_STRING('b', "initial-branch", &initial_branch, N_("name"),
94 N_("override the name of the initial branch")),
95 OPT_STRING(0, "object-format", &object_format, N_("hash"),
96 N_("specify the hash algorithm to use")),
97 OPT_END()
98 };
99
100 argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
101
102 if (real_git_dir && is_bare_repository_cfg == 1)
103 die(_("options '%s' and '%s' cannot be used together"), "--separate-git-dir", "--bare");
104
105 if (real_git_dir && !is_absolute_path(real_git_dir))
106 real_git_dir = real_pathdup(real_git_dir, 1);
107
108 if (template_dir && *template_dir && !is_absolute_path(template_dir)) {
109 template_dir = absolute_pathdup(template_dir);
110 UNLEAK(template_dir);
111 }
112
113 if (argc == 1) {
114 int mkdir_tried = 0;
115 retry:
116 if (chdir(argv[0]) < 0) {
117 if (!mkdir_tried) {
118 int saved;
119 /*
120 * At this point we haven't read any configuration,
121 * and we know shared_repository should always be 0;
122 * but just in case we play safe.
123 */
124 saved = get_shared_repository();
125 set_shared_repository(0);
126 switch (safe_create_leading_directories_const(argv[0])) {
127 case SCLD_OK:
128 case SCLD_PERMS:
129 break;
130 case SCLD_EXISTS:
131 errno = EEXIST;
132 /* fallthru */
133 default:
134 die_errno(_("cannot mkdir %s"), argv[0]);
135 break;
136 }
137 set_shared_repository(saved);
138 if (mkdir(argv[0], 0777) < 0)
139 die_errno(_("cannot mkdir %s"), argv[0]);
140 mkdir_tried = 1;
141 goto retry;
142 }
143 die_errno(_("cannot chdir to %s"), argv[0]);
144 }
145 } else if (0 < argc) {
146 usage(init_db_usage[0]);
147 }
148 if (is_bare_repository_cfg == 1) {
149 char *cwd = xgetcwd();
150 setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
151 free(cwd);
152 }
153
154 if (object_format) {
155 hash_algo = hash_algo_by_name(object_format);
156 if (hash_algo == GIT_HASH_UNKNOWN)
157 die(_("unknown hash algorithm '%s'"), object_format);
158 }
159
160 if (init_shared_repository != -1)
161 set_shared_repository(init_shared_repository);
162
163 /*
164 * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
165 * without --bare. Catch the error early.
166 */
167 git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT));
168 work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT));
169 if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
170 die(_("%s (or --work-tree=<directory>) not allowed without "
171 "specifying %s (or --git-dir=<directory>)"),
172 GIT_WORK_TREE_ENVIRONMENT,
173 GIT_DIR_ENVIRONMENT);
174
175 /*
176 * Set up the default .git directory contents
177 */
178 if (!git_dir)
179 git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
180
181 /*
182 * When --separate-git-dir is used inside a linked worktree, take
183 * care to ensure that the common .git/ directory is relocated, not
184 * the worktree-specific .git/worktrees/<id>/ directory.
185 */
186 if (real_git_dir) {
187 int err;
188 const char *p;
189 struct strbuf sb = STRBUF_INIT;
190
191 p = read_gitfile_gently(git_dir, &err);
192 if (p && get_common_dir(&sb, p)) {
193 struct strbuf mainwt = STRBUF_INIT;
194
195 strbuf_addbuf(&mainwt, &sb);
196 strbuf_strip_suffix(&mainwt, "/.git");
197 if (chdir(mainwt.buf) < 0)
198 die_errno(_("cannot chdir to %s"), mainwt.buf);
199 strbuf_release(&mainwt);
200 git_dir = strbuf_detach(&sb, NULL);
201 }
202 strbuf_release(&sb);
203 }
204
205 if (is_bare_repository_cfg < 0)
206 is_bare_repository_cfg = guess_repository_type(git_dir);
207
208 if (!is_bare_repository_cfg) {
209 const char *git_dir_parent = strrchr(git_dir, '/');
210 if (git_dir_parent) {
211 char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
212 git_work_tree_cfg = real_pathdup(rel, 1);
213 free(rel);
214 }
215 if (!git_work_tree_cfg)
216 git_work_tree_cfg = xgetcwd();
217 if (work_tree)
218 set_git_work_tree(work_tree);
219 else
220 set_git_work_tree(git_work_tree_cfg);
221 if (access(get_git_work_tree(), X_OK))
222 die_errno (_("Cannot access work tree '%s'"),
223 get_git_work_tree());
224 }
225 else {
226 if (real_git_dir)
227 die(_("--separate-git-dir incompatible with bare repository"));
228 if (work_tree)
229 set_git_work_tree(work_tree);
230 }
231
232 UNLEAK(real_git_dir);
233 UNLEAK(git_dir);
234 UNLEAK(work_tree);
235
236 flags |= INIT_DB_EXIST_OK;
237 return init_db(git_dir, real_git_dir, template_dir, hash_algo,
238 initial_branch, init_shared_repository, flags);
239 }