From 659cc2a9d32a17c0f8396368fcd5f8b0f0ba8fad Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1/3] 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 | 51 ++++++++++++++++++++++++++++++++++++++++ config.c | 9 +++++++ environment.c | 1 + git-compat-util.h | 4 ++++ 7 files changed, 79 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index 2cd6bdd7d2..3e00746aba 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -269,6 +269,12 @@ See linkgit:git-update-index[1]. + The default is true (when core.filemode is not specified in the config file). +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 da531f6b76..1d66b58e9c 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -367,6 +367,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 9f09540bbc..a5a3f27c00 100644 --- a/cache.h +++ b/cache.h @@ -698,6 +698,13 @@ extern int ref_paranoia; extern char comment_line_char; extern int auto_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 0413d5c3cd..01db95365f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -9,6 +9,7 @@ #define HCAST(type, handle) ((type)(intptr_t)handle) static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -286,6 +287,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; @@ -293,6 +311,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; } @@ -319,6 +347,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; } @@ -350,27 +389,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 9ba40bc1b0..bfc92dddf6 100644 --- a/config.c +++ b/config.c @@ -912,6 +912,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 6cc0a7780f..d5e7a9ceda 100644 --- a/environment.c +++ b/environment.c @@ -65,6 +65,7 @@ int core_apply_sparse_checkout; int merge_log_config = -1; int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ unsigned long pack_size_limit_cfg; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; #ifndef PROTECT_HFS_DEFAULT #define PROTECT_HFS_DEFAULT 0 diff --git a/git-compat-util.h b/git-compat-util.h index 474395471f..9e8e16f084 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -1045,4 +1045,8 @@ struct tm *git_gmtime_r(const time_t *, struct tm *); #define getc_unlocked(fh) getc(fh) #endif +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 4288b2706f7eee094492d9c414cad29b2b8abb1d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 2/3] 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 01db95365f..a154c5a5a0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -302,6 +302,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 27a592cd1defe99e7cb683f4d7ce0798ff8e38b4 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 3/3] 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 a5b9e7a4c7..16dd053d37 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -354,4 +354,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