{"thread":{"id":"12380","subject":"'.git file' alternative, native (cross-platform) workdir support.","startedAt":"2008-02-29T12:27:53Z","lastAt":"2008-02-29T21:32:30Z","messageCount":8,"participants":["Marius Storm-Olsen","Johannes Schindelin","Jakub Narebski","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"70384","messageId":"47C7FA49.9010001@trolltech.com","threadId":"12380","inReplyTo":null,"subject":"'.git file' alternative, native (cross-platform) workdir support.","fromName":"Marius Storm-Olsen","fromEmail":"marius@trolltech.com","sentAt":"2008-02-29T12:27:53Z","receivedAt":"2008-02-29T12:27:53Z","isPatch":false,"sender":{"key":"marius@trolltech.com","avatar":"https://gravatar.com/avatar/a40071d8f651862c6ab10bd7996f0ad84d94f06c0399de9e3fa4f06beb390a71?d=mp&s=160"},"body":"Hi guys,\n\nI just caught a glimpse of the '.git file' efforts, as a file for \nredirection to a real repository.\n\nAs far as I can tell, the reason for adding the support is to in the \nend provide a cross-platform way of supporting workdirs. (If this is \nnot the [main] point, please point me to the thread describing the \nreal reason, I couldn't find it.)\n\nHowever, wouldn't simply redirecting everything into a real repo then \ncreate problems with shared index file and more? A problem which could \nbe tacled by file suffixes or other methods, I'm sure, but which would \nrequire even more patches to achieve the goal.\n\n\nI was actually thinking about the whole workdir thing the other day, \nsince I mainly work on Windows, and constantly green of envy of the \n'mainly Linux' guys. I figured, why not just add support for file \nredirection in\n     char *git_path(const char *fmt, ...)\nwhich we use all over the place? That surely is easy and \ncross-platform :-)\n\n\nAttached you'll find a patch which will achieve 'native workdir' \nsupport on all platforms, independent of underlying file system. And \nif you ignore the code added to builtin-init-db.c & \nbuiltin-rev-parse.c for minimal usage support, it's a mere 104 lines \ntouched. The patch should apply cleanly on both git's next branch, and \nHannes' j6t master branch (the mingw port).\n\nPlease note that the patch is not meant for end-user consumption, nor \ndoes it follow Git coding standards. It's just meant as a proof of \nconcept, and as a means of discussion.\nAlso note that this way of supporting workdirs suffers from the same \n'flaws' the current git-new-workdir has (locking of repo etc).\n\nIf people want, I can work with it, and implement this properly (with \nits own builtin-workdir, test cases etc). As I see it, the '.git file' \nconcept still has some way to go. Maybe the '.git file' concept is the \nbest way in the end, but that this way is an 'ok' temporary way of \ndoing it?\n\n^shrug^ - Input please!\n\nTo try out the patch, apply it on git 'next' branch, then in some \nrandom directory:\n     git init --workdir-for=<abs-path to repo>\n     git reset --hard\n     .. hack away as normal ..\n(I know I know, it just a quick hack to let ppl play with it.)\n\nPS. Sorry for the patch being an attachment, I'm a Thunderbird slave. \n(Someone really needs to make a Thunderbird addon for sending Git \npatches ;-)\n\n--\n.marius\n\n\nFrom a38bf926edcba780445ae2a67eb8fe33b266a94f Mon Sep 17 00:00:00 2001\nFrom: Marius Storm-Olsen <marius@trolltech.com>\nDate: Thu, 28 Feb 2008 13:22:42 +0100\nSubject: [PATCH] Add cross-platform workdir support\n\n---\n builtin-init-db.c   |   53 ++++++++++++++++++++++++++++++++++++++-----\n builtin-rev-parse.c |   19 +++++++++++++++\n cache.h             |    2 +\n environment.c       |   63 +++++++++++++++++++++++++++++++++++++++++++++-----\n path.c              |   37 +++++++++++++++++++++++++++--\n setup.c             |    2 +-\n 6 files changed, 159 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin-init-db.c b/builtin-init-db.c\nindex 79eaf8d..94622f9 100644\n--- a/builtin-init-db.c\n+++ b/builtin-init-db.c\n@@ -310,7 +310,7 @@ static void guess_repository_type(const char *git_dir)\n }\n \n static const char init_db_usage[] =\n-\"git-init [-q | --quiet] [--template=<template-directory>] [--shared]\";\n+\"git-init [-q | --quiet] [--template=<template-directory>] [--shared] [--workdir-for=<repository>]\";\n \n /*\n  * If you want to, you can share the DB area with any number of branches.\n@@ -323,8 +323,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \tconst char *git_dir;\n \tconst char *sha1_dir;\n \tconst char *template_dir = NULL;\n+\tchar *repo_dir = NULL;\n \tchar *path;\n-\tint len, i, reinit;\n+\tint len, i, reinit, workdir_fd;\n \tint quiet = 0;\n \n \tfor (i = 1; i < argc; i++, argv++) {\n@@ -337,7 +338,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t\t\tshared_repository = git_config_perm(\"arg\", arg+9);\n \t\telse if (!strcmp(arg, \"-q\") || !strcmp(arg, \"--quiet\"))\n \t\t        quiet = 1;\n-\t\telse\n+\t\telse if (!prefixcmp(arg, \"--workdir-for=\")) {\n+\t\t\trepo_dir = xmalloc(PATH_MAX);\n+\t\t\tstrcpy(repo_dir, arg+14);\n+\t\t} else\n \t\t\tusage(init_db_usage);\n \t}\n \n@@ -406,11 +410,48 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t\tgit_config_set(\"receive.denyNonFastforwards\", \"true\");\n \t}\n \n-\tif (!quiet)\n-\t\tprintf(\"%s%s Git repository in %s/\\n\",\n+\tif (repo_dir) {\n+\t\tlen = strlen(git_dir);\n+\t\tmemcpy(path, git_dir, len);\n+\t\tstrcpy(path+len, \"/workdir_for\");\n+\t\tlen = strlen(repo_dir);\n+#ifdef __MINGW32__\n+\t\tfor(i = 0; i < len; ++i) {\n+\t\t\tif (repo_dir[i] == '\\\\')\n+\t\t\t\trepo_dir[i] = '/';\n+\t\t}\n+#endif\n+\t\tif (!is_git_directory(repo_dir)) {\n+\t\t\tstrcpy(repo_dir+len, \"/.git\");\n+\t\t\tif (!is_git_directory(repo_dir))\n+\t\t\t\tdie(\"specified --workdir-for path is not a git repository (%s)\", repo_dir);\n+\t\t}\n+\t\tworkdir_fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);\n+\t\tif (!workdir_fd)\n+\t\t\tdie(\"couldn't create workdir redirection file: %s\", strerror(errno));\n+\t\twrite_or_die(workdir_fd, repo_dir, strlen(repo_dir));\n+\t\tif (close(workdir_fd) < 0)\n+\t\t\tdie(\"closing file %s: %s\", path, strerror(errno));\n+\n+\t\t/* Copy current HEAD */\n+\t\tstrcpy(repo_dir+len, \"/HEAD\");\n+\t\tlen = strlen(git_dir);\n+\t\tstrcpy(path+len, \"/HEAD\");\n+\t\tcopy_file(path, repo_dir, 0);\n+\n+\t\t/* Should force a checkout of the current HEAD. Oh well.. */\n+\t}\n+\n+\tif (!quiet) {\n+\t\tprintf(\"%s%s %s repository in %s/\\n\",\n \t\t       reinit ? \"Reinitialized existing\" : \"Initialized empty\",\n \t\t       shared_repository ? \" shared\" : \"\",\n+\t\t       repo_dir ? \"workdir\" : \"Git\",\n \t\t       git_dir);\n-\n+\t\tif (repo_dir)\n+\t\t\tprintf(\"You now either need to do a 'git reset --hard', or force a switch to another branch.\\n\");\n+\t}\n+\tif (repo_dir)\n+\t\tfree(repo_dir);\n \treturn 0;\n }\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 90dbb9d..d83ba59 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -511,6 +511,25 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\tprintf(\"%s/.git\\n\", cwd);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--git-redirection-dir\")) {\n+\t\t\t\tconst char *redir = get_git_redirection_dir();\n+\t\t\t\tprintf(\"%s\\n\", redir ? redir\n+\t\t\t\t\t\t: \"\");\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--git-object-dir\")) {\n+\t\t\t\tprintf(\"%s\\n\", get_object_directory());\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--git-refs-dir\")) {\n+\t\t\t\tprintf(\"%s\\n\", get_refs_directory());\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--uses-git-redirection\")) {\n+\t\t\t\tprintf(\"%s\\n\", get_git_redirection_dir() ? \"true\"\n+\t\t\t\t\t\t: \"false\");\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--is-inside-git-dir\")) {\n \t\t\t\tprintf(\"%s\\n\", is_inside_git_dir() ? \"true\"\n \t\t\t\t\t\t: \"false\");\ndiff --git a/cache.h b/cache.h\nindex 660ea04..e8b6879 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -301,6 +301,7 @@ static inline enum object_type object_type(unsigned int mode)\n extern int is_bare_repository_cfg;\n extern int is_bare_repository(void);\n extern int is_inside_git_dir(void);\n+extern int is_git_directory(const char *suspect);\n extern char *git_work_tree_cfg;\n extern int is_inside_work_tree(void);\n extern const char *get_git_dir(void);\n@@ -310,6 +311,7 @@ extern char *get_index_file(void);\n extern char *get_graft_file(void);\n extern int set_git_dir(const char *path);\n extern const char *get_git_work_tree(void);\n+extern const char *get_git_redirection_dir(void);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \ndiff --git a/environment.c b/environment.c\nindex 6739a3f..74391de 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -44,7 +44,7 @@ char *git_work_tree_cfg;\n static const char *work_tree;\n \n static const char *git_dir;\n-static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;\n+static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file, *git_workdir_redirection;\n \n static void setup_git_env(void)\n {\n@@ -53,15 +53,12 @@ static void setup_git_env(void)\n \t\tgit_dir = DEFAULT_GIT_DIR_ENVIRONMENT;\n \tgit_object_dir = getenv(DB_ENVIRONMENT);\n \tif (!git_object_dir) {\n-\t\tgit_object_dir = xmalloc(strlen(git_dir) + 9);\n-\t\tsprintf(git_object_dir, \"%s/objects\", git_dir);\n+\t\tgit_object_dir = xstrdup(git_path(\"objects\"));\n \t}\n-\tgit_refs_dir = xmalloc(strlen(git_dir) + 6);\n-\tsprintf(git_refs_dir, \"%s/refs\", git_dir);\n+\tgit_refs_dir = xstrdup(git_path(\"refs\"));\n \tgit_index_file = getenv(INDEX_ENVIRONMENT);\n \tif (!git_index_file) {\n-\t\tgit_index_file = xmalloc(strlen(git_dir) + 7);\n-\t\tsprintf(git_index_file, \"%s/index\", git_dir);\n+\t\tgit_index_file = xstrdup(git_path(\"index\"));\n \t}\n \tgit_graft_file = getenv(GRAFT_ENVIRONMENT);\n \tif (!git_graft_file)\n@@ -101,6 +98,58 @@ const char *get_git_work_tree(void)\n \treturn work_tree;\n }\n \n+static char *workdir_for = \"/workdir_for\";\n+const char *get_git_redirection_dir(void)\n+{\n+\tstatic int checked_for_redirection = 0;\n+\tif (!checked_for_redirection && git_dir) {\n+\t\tchar *buf;\n+\t\tstruct stat st;\n+\t\tint fd;\n+\t\tsize_t len;\n+\t\tint gitdirlen = strlen(git_dir);\n+\t\tint workdirlen = strlen(workdir_for);\n+\n+\t\tchecked_for_redirection = 1;\n+\n+\t\t/* Check if we have a .git/workdir_for redirection file */\n+\t\tbuf = xmalloc(gitdirlen + workdirlen + 1);\n+\t\tmemcpy(buf, git_dir, gitdirlen);\n+\t\tmemcpy(buf + gitdirlen, workdir_for, strlen(workdir_for));\n+\t\tbuf[gitdirlen + workdirlen] = '\\0';\n+\n+\t\tif (stat(buf, &st) || !S_ISREG(st.st_mode)) {\n+\t\t\tfree(buf);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\t/* Read the 1st line of the file */\n+\t\tfd = open(buf, O_RDONLY);\n+\t\tif (fd < 0) {\n+\t\t\tfprintf(stderr, \"Error opening %s: %s\", buf, strerror(errno));\n+\t\t\tfree(buf);\n+\t\t\treturn 0;\n+\t\t}\n+\t\tbuf = xrealloc(buf, st.st_size + 1);\n+\t\tlen = read_in_full(fd, buf, st.st_size);\n+\t\tclose(fd);\n+\t\tbuf[len] = '\\0';\n+\n+\t\tif (len != st.st_size)\n+\t\t\tfprintf(stderr, \"Error reading .git%s\", workdir_for);\n+\n+\t\tif (len < 4 || !is_git_directory(buf)) {\n+\t\t\tfprintf(stderr, \".git%s pointing to a non-proper git repo path '%s'\\n\", workdir_for, buf);\n+\t\t\tfree(buf);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\tgit_workdir_redirection = buf;\n+\t\t/* buf not freed, since redirected_gitpath now points to it */\n+\t}\n+\treturn git_workdir_redirection;\n+}\n+\n char *get_object_directory(void)\n {\n \tif (!git_object_dir)\ndiff --git a/path.c b/path.c\nindex 4260952..f6332d6 100644\n--- a/path.c\n+++ b/path.c\n@@ -46,12 +46,28 @@ char *mkpath(const char *fmt, ...)\n \treturn cleanup_path(pathname);\n }\n \n+static char *redirection_paths[] = { \"config\", \"refs\" ,\"logs/refs\", \"objects\", \"info\", \"hooks\", \"packed-refs\", \"remotes\", \"rr-cache\", 0 };\n+static const char *get_redirected_dir(const char *req_path)\n+{\n+\tint i = 0;\n+\tconst char *redir = get_git_redirection_dir();\n+\tif (redir) {\n+\t\tdo {\n+\t\t\tif (!memcmp(req_path, redirection_paths[i], strlen(redirection_paths[i]))) {\n+\t\t\t\t/* fprintf(stderr, \"Looking for '%s', returning in '%s' instead of workdir/.git '%s'\\n\", req_path, redir, get_git_dir()); */\n+\t\t\t\treturn redir;\n+\t\t\t}\n+\t\t} while(redirection_paths[++i]);\n+\t}\n+\treturn 0;\n+}\n+\n char *git_path(const char *fmt, ...)\n {\n \tconst char *git_dir = get_git_dir();\n \tchar *pathname = get_pathname();\n \tva_list args;\n-\tunsigned len;\n+\tunsigned len, newlen, rdlen, minlen;\n \n \tlen = strlen(git_dir);\n \tif (len > PATH_MAX-100)\n@@ -60,10 +76,25 @@ char *git_path(const char *fmt, ...)\n \tif (len && git_dir[len-1] != '/')\n \t\tpathname[len++] = '/';\n \tva_start(args, fmt);\n-\tlen += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);\n+\tnewlen = len + vsnprintf(pathname + len, PATH_MAX - len, fmt, args);\n \tva_end(args);\n-\tif (len >= PATH_MAX)\n+\tif (newlen >= PATH_MAX)\n \t\treturn bad_path;\n+\n+\t{ /* Redirect certain files when in a workdir */\n+\t\tconst char *redir = get_redirected_dir(pathname + len);\n+\t\tif (redir) {\n+\t\t\tchar *pathname_redir = get_pathname();\n+\t\t\trdlen = strlen(redir);\n+\t\t\tmemcpy(pathname_redir, redir, rdlen);\n+\t\t\tif (rdlen && redir[rdlen-1] != '/')\n+\t\t\t\tpathname_redir[rdlen++] = '/';\n+\t\t\tminlen = MIN(PATH_MAX-rdlen, strlen(pathname+len));\n+\t\t\tmemcpy(pathname_redir+rdlen, pathname+len, minlen);\n+\t\t\tpathname_redir[rdlen + minlen] = '\\0';\n+\t\t\tpathname = pathname_redir;\n+\t\t}\n+\t}\n \treturn cleanup_path(pathname);\n }\n \ndiff --git a/setup.c b/setup.c\nindex 89c81e5..2c507d5 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -221,7 +221,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n  *    a proper \"ref:\", or a regular file HEAD that has a properly\n  *    formatted sha1 object name.\n  */\n-static int is_git_directory(const char *suspect)\n+int is_git_directory(const char *suspect)\n {\n \tchar path[PATH_MAX];\n \tsize_t len = strlen(suspect);\n-- \n1.5.4.3.394.ga38b\n\n"},{"id":"70386","messageId":"alpine.LSU.1.00.0802291248510.22527@racer.site","threadId":"12380","inReplyTo":"47C7FA49.9010001@trolltech.com","subject":"Re: '.git file' alternative, native (cross-platform) workdir support.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-29T12:54:11Z","receivedAt":"2008-02-29T12:54:11Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 29 Feb 2008, Marius Storm-Olsen wrote:\n\n> I just caught a glimpse of the '.git file' efforts, as a file for \n> redirection to a real repository.\n> \n> As far as I can tell, the reason for adding the support is to in the end \n> provide a cross-platform way of supporting workdirs. (If this is not the \n> [main] point, please point me to the thread describing the real reason, \n> I couldn't find it.)\n\nThis is the main reason, yes.\n\nHowever, you can also use the .git file to separate the working directory \nfrom the repository, say, on two different drives, when you do not have \nsymbolic links.\n\n> However, wouldn't simply redirecting everything into a real repo then \n> create problems with shared index file and more? A problem which could \n> be tacled by file suffixes or other methods, I'm sure, but which would \n> require even more patches to achieve the goal.\n\nNot only would it requre these patches, but it would actually make a \n_safe_ multiple-workdirs feature possible.\n\nATM the problem is that you can change a ref that is checked out \nelsewhere, and if you are not a Git expert, it will just make your life \nmiserable.\n\nHowever, if we do not pretend to have different repositories, but actually \nuse the _identical_ repository for multiple working directories, we can \nmake the mechanisms safe!\n\nThis is basically the reason why I do not like the current new-workdir \nscript (and the patch in my private tree where I taught git-branch about \nit).\n\nSo while your approach may seem easier in the short run, there is no way \nyou can make it safe.  No way, except going the full nine yards, and \nactually use the same repository, which means that you have to have the \n\"other patches\", too.\n\nCiao,\nDscho\n\n"},{"id":"70392","messageId":"47C80786.4070701@trolltech.com","threadId":"12380","inReplyTo":"alpine.LSU.1.00.0802291248510.22527@racer.site","subject":"Re: '.git file' alternative, native (cross-platform) workdir support.","fromName":"Marius Storm-Olsen","fromEmail":"marius@trolltech.com","sentAt":"2008-02-29T13:24:22Z","receivedAt":"2008-02-29T13:24:22Z","isPatch":false,"sender":{"key":"marius@trolltech.com","avatar":"https://gravatar.com/avatar/a40071d8f651862c6ab10bd7996f0ad84d94f06c0399de9e3fa4f06beb390a71?d=mp&s=160"},"body":"Johannes Schindelin said the following on 29.02.2008 13:54:\n> On Fri, 29 Feb 2008, Marius Storm-Olsen wrote:\n>> However, wouldn't simply redirecting everything into a real repo\n>> then create problems with shared index file and more? A problem\n>> which could be tacled by file suffixes or other methods, I'm\n>> sure, but which would require even more patches to achieve the\n>> goal.\n> \n> Not only would it requre these patches, but it would actually make\n> a _safe_ multiple-workdirs feature possible.\n> \n> ATM the problem is that you can change a ref that is checked out \n> elsewhere, and if you are not a Git expert, it will just make your\n> life miserable.\n> \n> However, if we do not pretend to have different repositories, but\n> actually use the _identical_ repository for multiple working\n> directories, we can make the mechanisms safe!\n> \n> This is basically the reason why I do not like the current\n> new-workdir script (and the patch in my private tree where I taught\n> git-branch about it).\n> \n> So while your approach may seem easier in the short run, there is\n> no way you can make it safe.  No way, except going the full nine\n> yards, and actually use the same repository, which means that you\n> have to have the \"other patches\", too.\n\nSure, I'm aware of that. The initial goal was to make something which \nworks as the current contrib/workdir/git-new-workdir, just \ncross-platform. Then we can take it from there, step by step, until we \nhave something which works safely; instead of taking a single big leap.\n\nI'm actually not sure that it's impossible to make it safe.\nMy implementation works by redirecting files into the real repo. \nHowever, we can also detect when redirection is in effect, and do \nextra 'maintainance' things then, to avoid the bad effects.\n\nFor example, when setting up a workdir, we could duplicate\n         <real repo>/.git/refs/*\ninto    <real repo>/.git/refs/workdir-<sha1>/*\n(<sha1> being the sha1 of the abs path to the workdir)\nand have the redirection mechanism redirect all git_path(\"refs/*\") to \nthe duplicated locations. That way, when pulling in the workdir, it \nwouldn't create havok with the real repo's refs. Then in the real \nrepo, you can easily refer to the refs in from the workdir too, when \nyou need to.\n\nThere are several possibilities here. Since file redirection works \nfrom the beginning, we have a place to start, which can slowly migrate \ninto whatever. When you think about it, my approach is kinda similar \nto the '.git file' approach, just that I don't redirect everything \nfrom the start, just parts to make it work as today on Linux. In the \nend my technique could also redirect everything into the real repo, \ngiving you the same effect as the '.git file'.\n\n-- \n.marius\n\n"},{"id":"70393","messageId":"m3lk53kfy6.fsf@localhost.localdomain","threadId":"12380","inReplyTo":"47C80786.4070701@trolltech.com","subject":"Re: '.git file' alternative, native (cross-platform) workdir support.","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-02-29T14:14:36Z","receivedAt":"2008-02-29T14:14:36Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Marius Storm-Olsen <marius@trolltech.com> writes:\n\n> Johannes Schindelin said the following on 29.02.2008 13:54:\n>> On Fri, 29 Feb 2008, Marius Storm-Olsen wrote:\n>>>\n>>> However, wouldn't simply redirecting everything into a real repo\n>>> then create problems with shared index file and more? A problem\n>>> which could be tacled by file suffixes or other methods, I'm\n>>> sure, but which would require even more patches to achieve the\n>>> goal.\n>>\n>> Not only would it requre these patches, but it would actually make\n>> a _safe_ multiple-workdirs feature possible.\n>> ATM the problem is that you can change a ref that is checked out\n>> elsewhere, and if you are not a Git expert, it will just make your\n>> life miserable.\n>> However, if we do not pretend to have different repositories, but\n>> actually use the _identical_ repository for multiple working\n>> directories, we can make the mechanisms safe!\n>> This is basically the reason why I do not like the current\n>> new-workdir script (and the patch in my private tree where I taught\n>> git-branch about it).\n> \n> Sure, I'm aware of that. The initial goal was to make something which\n> works as the current contrib/workdir/git-new-workdir, just\n> cross-platform. Then we can take it from there, step by step, until we\n> have something which works safely; instead of taking a single big leap.\n> \n> I'm actually not sure that it's impossible to make it safe.\n> My implementation works by redirecting files into the real\n> repo. However, we can also detect when redirection is in effect, and\n> do extra 'maintainance' things then, to avoid the bad effects.\n> \n> For example, when setting up a workdir, we could duplicate\n>          <real repo>/.git/refs/*\n> into    <real repo>/.git/refs/workdir-<sha1>/*\n> (<sha1> being the sha1 of the abs path to the workdir)\n> and have the redirection mechanism redirect all git_path(\"refs/*\") to\n> the duplicated locations. That way, when pulling in the workdir, it\n> wouldn't create havok with the real repo's refs. Then in the real\n> repo, you can easily refer to the refs in from the workdir too, when\n> you need to.\n\nI have had yet another idea, namely of shadow / unionfs-alike, which I\nhave abandoned due to perceived difficulties in implementing it. But\nperhaps this would be the best solution for multiple working\ndirectories problem.\n\nThe idea is to add core.gitdir variable to the config, which would\npoint to \"master\" (main) GIT_DIR. \n\nWhen requesting any file from repository, be it .git/refs/HEAD,\n.git/index, .git/refs/heads/master or any other file, git would first\ntry to find it in the current GIT_DIR, as existing heuristics find it,\nand if not found try with GIT_DIR set to core.gitdir. When trying to\ncreate any file, git would check if directories / path leading to file\nin GIT_DIR exists, and if not create it under GIT_DIR set to\ncore.gitdir.\n\nThe only exception would be config file, where current GIT_DIR config\nwould be fourth layer, on top of system-wide config, global (per-user)\nconfig and core.gitdir config.\n\nWhat do you think of this idea?\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"70394","messageId":"alpine.LSU.1.00.0802291333310.22527@racer.site","threadId":"12380","inReplyTo":"47C80786.4070701@trolltech.com","subject":"Re: '.git file' alternative, native (cross-platform) workdir support.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-29T14:25:16Z","receivedAt":"2008-02-29T14:25:16Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 29 Feb 2008, Marius Storm-Olsen wrote:\n\n> Johannes Schindelin said the following on 29.02.2008 13:54:\n> > On Fri, 29 Feb 2008, Marius Storm-Olsen wrote:\n> > > However, wouldn't simply redirecting everything into a real repo \n> > > then create problems with shared index file and more? A problem \n> > > which could be tacled by file suffixes or other methods, I'm sure, \n> > > but which would require even more patches to achieve the goal.\n> > \n> > Not only would it requre these patches, but it would actually make a \n> > _safe_ multiple-workdirs feature possible.\n> \n> Sure, I'm aware of that. The initial goal was to make something which \n> works as the current contrib/workdir/git-new-workdir, just \n> cross-platform. Then we can take it from there, step by step, until we \n> have something which works safely; instead of taking a single big leap.\n\nThat's what I am saying: there is no way to make it safe.\n\n> I'm actually not sure that it's impossible to make it safe. My \n> implementation works by redirecting files into the real repo. However, \n> we can also detect when redirection is in effect, and do extra \n> 'maintainance' things then, to avoid the bad effects.\n\n>From the perspective of Windows, I guess it is easy to overlook the fact \nthat permissions can break your idea.\n\nEven after creating a second working tree for an existing repository, the \npermissions of the original repository can change.\n\nThe only way to be on the safe side is to use _the repository_ twice.  IOW \nnot having a second .git/ directory.\n\nAlso, having a single .git is just a very simple, and thus preferable \nconcept, to having part of this, and part of that repository.\n\nCiao,\nDscho\n"},{"id":"70397","messageId":"47C81C08.2060608@trolltech.com","threadId":"12380","inReplyTo":"alpine.LSU.1.00.0802291333310.22527@racer.site","subject":"Re: '.git file' alternative, native (cross-platform) workdir support.","fromName":"Marius Storm-Olsen","fromEmail":"marius@trolltech.com","sentAt":"2008-02-29T14:51:52Z","receivedAt":"2008-02-29T14:51:52Z","isPatch":false,"sender":{"key":"marius@trolltech.com","avatar":"https://gravatar.com/avatar/a40071d8f651862c6ab10bd7996f0ad84d94f06c0399de9e3fa4f06beb390a71?d=mp&s=160"},"body":"Johannes Schindelin said the following on 29.02.2008 15:25:\n> On Fri, 29 Feb 2008, Marius Storm-Olsen wrote:\n>> I'm actually not sure that it's impossible to make it safe. My \n>> implementation works by redirecting files into the real repo.\n>> However, we can also detect when redirection is in effect, and do\n>> extra 'maintainance' things then, to avoid the bad effects.\n> \n> From the perspective of Windows, I guess it is easy to overlook the\n> fact that permissions can break your idea.\n> \n> Even after creating a second working tree for an existing\n> repository, the permissions of the original repository can change.\n\nSure, but that would break _any_ working tree implementation. Without \naccess to the original data, it whole thing is bust, no matter if you \nredirect all or part of .git/.\n\nChecking if we have access to the redirected .git is trivial in both \ncases. (partial or whole redirection)\n\n> The only way to be on the safe side is to use _the repository_\n> twice.  IOW not having a second .git/ directory.\n> \n> Also, having a single .git is just a very simple, and thus\n> preferable concept, to having part of this, and part of that\n> repository.\n\nI whole heartedly agree. I'm not proposing to keep it split in the \nlong run. I'm just proposing something that 'works' *now*, and can be \nimproved incrementally; as opposed to, doesn't work now, and needs to \nbe fully implemented before it works for the Windows crowd.\n\nPS. The redirection method I propose already alleviates an issue of \nthe current git-new-workdir has, which Shawn has experienced many \natime: The deletion of .git/config and .git/packed-refs, making \n'git-config' and 'git tag -d' unsafe in a workdir. (Though I'm unsure \nif that has been fixed already. In any case, since the files are \nreally redirected, there no chance that deleting a file will remove a \nsynlink, only to be recreated as a normal file instead)\n\n-- \n.marius\n\n"},{"id":"70412","messageId":"7vabljcyzh.fsf@gitster.siamese.dyndns.org","threadId":"12380","inReplyTo":"alpine.LSU.1.00.0802291248510.22527@racer.site","subject":"Re: '.git file' alternative, native (cross-platform) workdir support.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-29T20:02:42Z","receivedAt":"2008-02-29T20:02:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Fri, 29 Feb 2008, Marius Storm-Olsen wrote:\n>\n>> I just caught a glimpse of the '.git file' efforts, as a file for \n>> redirection to a real repository.\n>> \n>> As far as I can tell, the reason for adding the support is to in the end \n>> provide a cross-platform way of supporting workdirs. (If this is not the \n>> [main] point, please point me to the thread describing the real reason, \n>> I couldn't find it.)\n>\n> This is the main reason, yes.\n\nI do not think so.  For repository and work tree separation, we already\nhave core.worktree.  Multiple work trees attached to a single repository\nis what contrib/workdir/ does, and it could probably be extended, but that\none needs more than \"redirect .git elsewhere\".\n\nThe primary reason we may want to do the \".git file\" thing is to sanely\nsupport switching between branches (or checking out a different revision,\nwhich amounts to the same thing) when one has a submodule and the other\none either does not have that submodule anywhere or have it in a different\nlocation in its tree.\n\nSuppose the HEAD one binds a submodule \"gitk\" at gitk-git.  Then suppose\nwe want to switch to an old branch that did not have that submodule bound\nyet.  Or the branch we are switching to has the submodule at modules/gitk.\nWhat happens?\n\nCurrently, when we are on HEAD, we create a directory at gitk-git and make\ngitk-git/.git directory its controlling repository (i.e. GIT_DIR).\nSwitching to a branch that did not have the submodule bound will need to\nrmdir gitk-git (this needs to happen no matter what) but as a side effect\nwe will lose gitk-git/.git repository.  Switching back to where we were\nwould require reloading that repository from somewhere else, but if you\nare \"the upstream\", that somewhere else may not even exist.\n\nOne way to solve this would be to add .git/submodules/paulus.git\nrepository inside the controlling reopsitory of the toplevel project, and\npoint that with the \".git file\" installed at gitk-git/.git, when we are on\nHEAD.  We can lose gitk-git directory and everything below it when\nswitching away from the revision, but when we come back, we can recreate\ngitk-git directory, point gitk-git/.git back to .git/submodules/paulus.git\nkept in the toplevel repository, and check the appropriate commit out there.\n\nAfter switching to an old revision that did not have the submodule,\nfurther switching to a branch that has the submodule at modules/gitk would\nbe the same deal.  Instead of creating gitk-git directory and installing\nthe \".git file\" there (which is what we did when we came back to the\noriginal HEAD), create modules/gitk and install the \".git file\" there, to\npoint at the same .git/submodules/paulus.git/.\n\nWe should be able to do this today without \".git file\" using symlinks.\nIt's just a Porcelain hackery, so I'll leave it to interested parties as\nan exercise.\n"},{"id":"70423","messageId":"47C879EE.2000808@trolltech.com","threadId":"12380","inReplyTo":"7vabljcyzh.fsf@gitster.siamese.dyndns.org","subject":"Re: '.git file' alternative, native (cross-platform) workdir support.","fromName":"Marius Storm-Olsen","fromEmail":"marius@trolltech.com","sentAt":"2008-02-29T21:32:30Z","receivedAt":"2008-02-29T21:32:30Z","isPatch":false,"sender":{"key":"marius@trolltech.com","avatar":"https://gravatar.com/avatar/a40071d8f651862c6ab10bd7996f0ad84d94f06c0399de9e3fa4f06beb390a71?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> The primary reason we may want to do the \".git file\" thing is to\n> sanely support switching between branches (or checking out a\n> different revision, which amounts to the same thing) when one has a\n> submodule and the other one either does not have that submodule\n> anywhere or have it in a different location in its tree.\n...\n> One way to solve this would be to add .git/submodules/paulus.git \n> repository inside the controlling reopsitory of the toplevel project,\n> and point that with the \".git file\" installed at gitk-git/.git, when\n> we are on HEAD.  We can lose gitk-git directory and everything below\n> it when switching away from the revision, but when we come back, we\n> can recreate gitk-git directory, point gitk-git/.git back to\n> .git/submodules/paulus.git kept in the toplevel repository, and check\n> the appropriate commit out there.\n> \n> After switching to an old revision that did not have the submodule, \n> further switching to a branch that has the submodule at modules/gitk\n> would be the same deal.  Instead of creating gitk-git directory and\n> installing the \".git file\" there (which is what we did when we came\n> back to the original HEAD), create modules/gitk and install the \".git\n> file\" there, to point at the same .git/submodules/paulus.git/.\n\nAhh, ok, this makes sense. *Then* you need to point all of .git to a \nspecific location. But, in this case you're not interested in keeping \nn-different states, as we are in a multiple workdir situation. So, it's \na much easier case.\n\nThe question is, is this also the appropriate basis for solving the \nmultiple workdir case? If so, we need to come up with a scheme that lets \nus keep n number of states inside one single .git structure. Is this \nreasonable? It's not like it's too hard, just a bit messy.\n\nThe reason I ask is to evaluate if I should cleanup the patch I did for \nthe native workdir support that started out this thread, or just lay it \ndead for the '.git file' solution which still would need a lot of work \nbefore it's finished. (Though, as I said before, my redirection way \ncould certainly migrate into a '.git file' solution over time)\n\nI basically just need a certain amount of knowledgeable people to either \nsay 'drop it' or 'roll with it'.. I'm ambivalent, though I want workdirs \non Windows yesterday. :-)\nSo, I guess I have Dscho's -1, and my own +1 = 0 :-p\n\n> We should be able to do this today without \".git file\" using\n> symlinks. It's just a Porcelain hackery, so I'll leave it to\n> interested parties as an exercise.\n\nSymlinks wouldn't really work, unless you force people to always keep \ntheir full .git next to the workdir. So, multiple workdirs with \nsubmodules would then fail, as would FS without symlink support (duh).\nThis seems to be the issue with the current '.git file' implementation \nas well. If the repo is not located next to the workdir, it will fail. \nOr am I reading the code incorrectly? And what happens with recursive \nsubmodules?\n\n--\n.marius\n\n\n"}]}