Git fork
at reftables-rust 264 lines 7.9 kB view raw
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}