From 0cdb44c8bac2dc2bce24de8b33c06a62c6d32873 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1/4] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 +++++ builtin/init-db.c | 1 + cache.h | 7 ++++++ compat/mingw.c | 52 ++++++++++++++++++++++++++++++++++++++++ config.c | 9 +++++++ environment.c | 1 + git-compat-util.h | 4 ++++ 7 files changed, 80 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index 1932e9b9a2..28d57e3381 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -212,6 +212,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignorecase:: If true, this option enables various workarounds to enable Git to work better on filesystems that are not case sensitive, diff --git a/builtin/init-db.c b/builtin/init-db.c index 56f85e239a..ca433df331 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -385,6 +385,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 107ac61b68..96d231aee4 100644 --- a/cache.h +++ b/cache.h @@ -603,6 +603,13 @@ extern int precomposed_unicode; */ extern char comment_line_char; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum branch_track { BRANCH_TRACK_UNSPECIFIED = -1, BRANCH_TRACK_NEVER = 0, diff --git a/compat/mingw.c b/compat/mingw.c index 79bac118ba..d2c17c7024 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -4,8 +4,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -283,6 +285,23 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const wchar_t *path) +{ + DWORD attribs = GetFileAttributesW(path); + if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + wchar_t wdir[MAX_PATH]; + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository()) + if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir)) + warning("Failed to make '%s' hidden", dir); +} + int mingw_mkdir(const char *path, int mode) { int ret; @@ -290,6 +309,16 @@ int mingw_mkdir(const char *path, int mode) if (xutftowcs_path(wpath, path) < 0) return -1; ret = _wmkdir(wpath); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(wpath); + } return ret; } @@ -316,6 +345,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(wfilename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -347,27 +387,39 @@ int mingw_fgetc(FILE *stream) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; FILE *file; wchar_t wfilename[MAX_PATH], wotype[4]; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; if (xutftowcs_path(wfilename, filename) < 0 || xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) return NULL; file = _wfopen(wfilename, wotype); + if (file && hide && make_hidden(wfilename)) + warning("Could not mark '%s' as hidden.", filename); return file; } FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; FILE *file; wchar_t wfilename[MAX_PATH], wotype[4]; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; if (xutftowcs_path(wfilename, filename) < 0 || xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) return NULL; file = _wfreopen(wfilename, wotype, stream); + if (file && hide && make_hidden(wfilename)) + warning("Could not mark '%s' as hidden.", filename); return file; } diff --git a/config.c b/config.c index a30cb5c07d..e28f17c6bb 100644 --- a/config.c +++ b/config.c @@ -874,6 +874,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 5c4815dbe1..6366c85241 100644 --- a/environment.c +++ b/environment.c @@ -63,6 +63,7 @@ int merge_log_config = -1; int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ struct startup_info *startup_info; unsigned long pack_size_limit_cfg; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* * The character that begins a commented line in user-editable file diff --git a/git-compat-util.h b/git-compat-util.h index f6d3a46622..087bf78db5 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -723,4 +723,8 @@ struct tm *git_gmtime_r(const time_t *, struct tm *); #define gmtime_r git_gmtime_r #endif +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 94519d45f3cd492ab8591db0f38062d615fb495c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 2/4] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d2c17c7024..6eabebc514 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -300,6 +300,10 @@ void mingw_mark_as_git_dir(const char *dir) if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository()) if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } int mingw_mkdir(const char *path, int mode) From 4620246f73f56cf5dff131aa50b2f81d80acec88 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 3/4] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index bbc9cb60dd..d356f2a327 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -332,4 +332,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' test_path_is_dir realgitdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 8dfd8dc63452971b4d82794d4496f6b6db666379 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 4/4] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 41 +++++++++++++++++++++++++++++++++++++++++ compat/mingw.h | 3 +++ git-compat-util.h | 4 ++++ path.c | 4 ++-- shell.c | 2 +- 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6eabebc514..13ec7eae29 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1969,6 +1969,23 @@ pid_t waitpid(pid_t pid, int *status, int options) return -1; } +const char *get_windows_home_directory(void) +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen) { int upos = 0, wpos = 0; @@ -2158,3 +2175,27 @@ void mingw_startup() /* initialize Unicode console */ winansi_init(); } + +int mingw_offset_1st_component(const char *path) +{ + int offset = 0; + if (has_dos_drive_prefix(path)) + offset = 2; + + /* unc paths */ + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; /* Error: malformed unc path */ + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + offset = pos - path; + } + + return offset + is_dir_sep(path[offset]); +} diff --git a/compat/mingw.h b/compat/mingw.h index e5006e92d9..2a4a03e487 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -487,3 +487,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/git-compat-util.h b/git-compat-util.h index 087bf78db5..b7e145de62 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -727,4 +727,8 @@ struct tm *git_gmtime_r(const time_t *, struct tm *); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index f9c5062427..a5bb08cc3b 100644 --- a/path.c +++ b/path.c @@ -133,7 +133,7 @@ char *git_path(const char *fmt, ...) void home_config_paths(char **global, char **xdg, char *file) { char *xdg_home = getenv("XDG_CONFIG_HOME"); - char *home = getenv("HOME"); + const char *home = get_home_directory(); char *to_free = NULL; if (!home) { @@ -274,7 +274,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); diff --git a/shell.c b/shell.c index 5c0d47a5cc..edd8c3a1c1 100644 --- a/shell.c +++ b/shell.c @@ -55,7 +55,7 @@ static char *make_cmd(const char *prog) static void cd_to_homedir(void) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) die("could not determine user's home directory; HOME is unset"); if (chdir(home) == -1)