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