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