Code

Remove outdated references to cogito in documentation
[git.git] / builtin-init-db.c
index 01f366ad0bf5860aaf9123ef5d5653c612871a9f..763fa55e76ef5b7e2f244f11199b5925382dac92 100644 (file)
@@ -7,7 +7,13 @@
 #include "builtin.h"
 
 #ifndef DEFAULT_GIT_TEMPLATE_DIR
-#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
+#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
+#endif
+
+#ifdef NO_TRUSTABLE_FILEMODE
+#define TEST_FILEMODE 0
+#else
+#define TEST_FILEMODE 1
 #endif
 
 static void safe_create_dir(const char *dir, int share)
@@ -34,7 +40,8 @@ static int copy_file(const char *dst, const char *src, int mode)
                return fdo;
        }
        status = copy_fd(fdi, fdo);
-       close(fdo);
+       if (close(fdo) != 0)
+               return error("%s: write error: %s", dst, strerror(errno));
 
        if (!status && adjust_shared_perm(dst))
                return -1;
@@ -50,7 +57,7 @@ static void copy_templates_1(char *path, int baselen,
 
        /* Note: if ".git/hooks" file exists in the repository being
         * re-initialized, /etc/core-git/templates/hooks/update would
-        * cause git-init-db to fail here.  I think this is sane but
+        * cause git-init to fail here.  I think this is sane but
         * it means that the set of templates we ship by default, along
         * with the way the namespace under .git/ is organized, should
         * be really carefully chosen.
@@ -175,6 +182,7 @@ static int create_default_files(const char *git_dir, const char *template_path)
        struct stat st1;
        char repo_version_string[10];
        int reinit;
+       int filemode;
 
        if (len > sizeof(path)-50)
                die("insane git directory %s", git_dir);
@@ -224,7 +232,7 @@ static int create_default_files(const char *git_dir, const char *template_path)
        strcpy(path + len, "HEAD");
        reinit = !read_ref("HEAD", sha1);
        if (!reinit) {
-               if (create_symref("HEAD", "refs/heads/master") < 0)
+               if (create_symref("HEAD", "refs/heads/master", NULL) < 0)
                        exit(1);
        }
 
@@ -236,23 +244,84 @@ static int create_default_files(const char *git_dir, const char *template_path)
        strcpy(path + len, "config");
 
        /* Check filemode trustability */
-       if (!lstat(path, &st1)) {
+       filemode = TEST_FILEMODE;
+       if (TEST_FILEMODE && !lstat(path, &st1)) {
                struct stat st2;
-               int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
+               filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
                                !lstat(path, &st2) &&
                                st1.st_mode != st2.st_mode);
-               git_config_set("core.filemode",
-                              filemode ? "true" : "false");
+       }
+       git_config_set("core.filemode", filemode ? "true" : "false");
+
+       if (is_bare_repository())
+               git_config_set("core.bare", "true");
+       else {
+               const char *work_tree = get_git_work_tree();
+               git_config_set("core.bare", "false");
+               /* allow template config file to override the default */
+               if (log_all_ref_updates == -1)
+                   git_config_set("core.logallrefupdates", "true");
+               if (work_tree != git_work_tree_cfg)
+                       git_config_set("core.worktree", work_tree);
+       }
+
+       /* Check if symlink is supported in the work tree */
+       if (!reinit) {
+               path[len] = 0;
+               strcpy(path + len, "tXXXXXX");
+               if (!close(xmkstemp(path)) &&
+                   !unlink(path) &&
+                   !symlink("testing", path) &&
+                   !lstat(path, &st1) &&
+                   S_ISLNK(st1.st_mode))
+                       unlink(path); /* good */
+               else
+                       git_config_set("core.symlinks", "false");
        }
 
-       /* Enable logAllRefUpdates if a working tree is attached */
-       if (!is_bare_git_dir(git_dir))
-               git_config_set("core.logallrefupdates", "true");
        return reinit;
 }
 
+static void guess_repository_type(const char *git_dir)
+{
+       char cwd[PATH_MAX];
+       const char *slash;
+
+       if (0 <= is_bare_repository_cfg)
+               return;
+       if (!git_dir)
+               return;
+
+       /*
+        * "GIT_DIR=. git init" is always bare.
+        * "GIT_DIR=`pwd` git init" too.
+        */
+       if (!strcmp(".", git_dir))
+               goto force_bare;
+       if (!getcwd(cwd, sizeof(cwd)))
+               die("cannot tell cwd");
+       if (!strcmp(git_dir, cwd))
+               goto force_bare;
+       /*
+        * "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
+        */
+       if (!strcmp(git_dir, ".git"))
+               return;
+       slash = strrchr(git_dir, '/');
+       if (slash && !strcmp(slash, "/.git"))
+               return;
+
+       /*
+        * Otherwise it is often bare.  At this point
+        * we are just guessing.
+        */
+ force_bare:
+       is_bare_repository_cfg = 1;
+       return;
+}
+
 static const char init_db_usage[] =
-"git-init-db [--template=<template-directory>] [--shared]";
+"git-init [-q | --quiet] [--template=<template-directory>] [--shared]";
 
 /*
  * If you want to, you can share the DB area with any number of branches.
@@ -267,19 +336,45 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        const char *template_dir = NULL;
        char *path;
        int len, i, reinit;
+       int quiet = 0;
 
        for (i = 1; i < argc; i++, argv++) {
                const char *arg = argv[1];
-               if (!strncmp(arg, "--template=", 11))
+               if (!prefixcmp(arg, "--template="))
                        template_dir = arg+11;
                else if (!strcmp(arg, "--shared"))
                        shared_repository = PERM_GROUP;
-               else if (!strncmp(arg, "--shared=", 9))
+               else if (!prefixcmp(arg, "--shared="))
                        shared_repository = git_config_perm("arg", arg+9);
+               else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
+                       quiet = 1;
                else
                        usage(init_db_usage);
        }
 
+       /*
+        * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
+        * without --bare.  Catch the error early.
+        */
+       git_dir = getenv(GIT_DIR_ENVIRONMENT);
+       if ((!git_dir || is_bare_repository_cfg == 1)
+           && getenv(GIT_WORK_TREE_ENVIRONMENT))
+               die("%s (or --work-tree=<directory>) not allowed without "
+                   "specifying %s (or --git-dir=<directory>)",
+                   GIT_WORK_TREE_ENVIRONMENT,
+                   GIT_DIR_ENVIRONMENT);
+
+       guess_repository_type(git_dir);
+
+       if (is_bare_repository_cfg <= 0) {
+               git_work_tree_cfg = xcalloc(PATH_MAX, 1);
+               if (!getcwd(git_work_tree_cfg, PATH_MAX))
+                       die ("Cannot access current working directory.");
+               if (access(get_git_work_tree(), X_OK))
+                       die ("Cannot access work tree '%s'",
+                            get_git_work_tree());
+       }
+
        /*
         * Set up the default .git directory contents
         */
@@ -322,10 +417,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                git_config_set("receive.denyNonFastforwards", "true");
        }
 
-       printf("%s%s Git repository in %s/\n",
-               reinit ? "Reinitialized existing" : "Initialized empty",
-               shared_repository ? " shared" : "",
-               git_dir);
+       if (!quiet)
+               printf("%s%s Git repository in %s/\n",
+                      reinit ? "Reinitialized existing" : "Initialized empty",
+                      shared_repository ? " shared" : "",
+                      git_dir);
 
        return 0;
 }