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