Skip to content

Commit 81575f7

Browse files
committed
Merge 'hide-dotgit' into HEAD
2 parents 1d50c05 + 0e0c891 commit 81575f7

File tree

8 files changed

+111
-0
lines changed

8 files changed

+111
-0
lines changed

Documentation/config.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ See linkgit:git-update-index[1].
269269
+
270270
The default is true (when core.filemode is not specified in the config file).
271271

272+
core.hideDotFiles::
273+
(Windows-only) If true (which is the default), mark newly-created
274+
directories and files whose name starts with a dot as hidden.
275+
If 'dotGitOnly', only the .git/ directory is hidden, but no other
276+
files starting with a dot.
277+
272278
core.ignoreCase::
273279
If true, this option enables various workarounds to enable
274280
Git to work better on filesystems that are not case sensitive,

builtin/init-db.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ int init_db(const char *template_dir, unsigned int flags)
366366
check_repository_format();
367367

368368
reinit = create_default_files(template_dir);
369+
mark_as_git_dir(get_git_dir());
369370

370371
create_object_directory();
371372

cache.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,13 @@ extern int ref_paranoia;
697697
extern char comment_line_char;
698698
extern int auto_comment_line_char;
699699

700+
enum hide_dotfiles_type {
701+
HIDE_DOTFILES_FALSE = 0,
702+
HIDE_DOTFILES_TRUE,
703+
HIDE_DOTFILES_DOTGITONLY,
704+
};
705+
extern enum hide_dotfiles_type hide_dotfiles;
706+
700707
enum branch_track {
701708
BRANCH_TRACK_UNSPECIFIED = -1,
702709
BRANCH_TRACK_NEVER = 0,

compat/mingw.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define HCAST(type, handle) ((type)(intptr_t)handle)
1010

1111
static const int delay[] = { 0, 1, 10, 20, 40 };
12+
unsigned int _CRT_fmode = _O_BINARY;
1213

1314
int err_win_to_posix(DWORD winerr)
1415
{
@@ -286,13 +287,44 @@ int mingw_rmdir(const char *pathname)
286287
return ret;
287288
}
288289

290+
static int make_hidden(const wchar_t *path)
291+
{
292+
DWORD attribs = GetFileAttributesW(path);
293+
if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
294+
return 0;
295+
errno = err_win_to_posix(GetLastError());
296+
return -1;
297+
}
298+
299+
void mingw_mark_as_git_dir(const char *dir)
300+
{
301+
wchar_t wdir[MAX_PATH];
302+
if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
303+
if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
304+
warning("Failed to make '%s' hidden", dir);
305+
git_config_set("core.hideDotFiles",
306+
hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
307+
(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
308+
"dotGitOnly" : "true"));
309+
}
310+
289311
int mingw_mkdir(const char *path, int mode)
290312
{
291313
int ret;
292314
wchar_t wpath[MAX_PATH];
293315
if (xutftowcs_path(wpath, path) < 0)
294316
return -1;
295317
ret = _wmkdir(wpath);
318+
if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
319+
/*
320+
* In Windows a file or dir starting with a dot is not
321+
* automatically hidden. So lets mark it as hidden when
322+
* such a directory is created.
323+
*/
324+
const char *start = basename((char*)path);
325+
if (*start == '.')
326+
return make_hidden(wpath);
327+
}
296328
return ret;
297329
}
298330

@@ -319,6 +351,17 @@ int mingw_open (const char *filename, int oflags, ...)
319351
if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
320352
errno = EISDIR;
321353
}
354+
if ((oflags & O_CREAT) && fd >= 0 &&
355+
hide_dotfiles == HIDE_DOTFILES_TRUE) {
356+
/*
357+
* In Windows a file or dir starting with a dot is not
358+
* automatically hidden. So lets mark it as hidden when
359+
* such a file is created.
360+
*/
361+
const char *start = basename((char*)filename);
362+
if (*start == '.' && make_hidden(wfilename))
363+
warning("Could not mark '%s' as hidden.", filename);
364+
}
322365
return fd;
323366
}
324367

@@ -350,27 +393,39 @@ int mingw_fgetc(FILE *stream)
350393
#undef fopen
351394
FILE *mingw_fopen (const char *filename, const char *otype)
352395
{
396+
int hide = 0;
353397
FILE *file;
354398
wchar_t wfilename[MAX_PATH], wotype[4];
399+
if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
400+
basename((char*)filename)[0] == '.')
401+
hide = access(filename, F_OK);
355402
if (filename && !strcmp(filename, "/dev/null"))
356403
filename = "nul";
357404
if (xutftowcs_path(wfilename, filename) < 0 ||
358405
xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
359406
return NULL;
360407
file = _wfopen(wfilename, wotype);
408+
if (file && hide && make_hidden(wfilename))
409+
warning("Could not mark '%s' as hidden.", filename);
361410
return file;
362411
}
363412

364413
FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
365414
{
415+
int hide = 0;
366416
FILE *file;
367417
wchar_t wfilename[MAX_PATH], wotype[4];
418+
if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
419+
basename((char*)filename)[0] == '.')
420+
hide = access(filename, F_OK);
368421
if (filename && !strcmp(filename, "/dev/null"))
369422
filename = "nul";
370423
if (xutftowcs_path(wfilename, filename) < 0 ||
371424
xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
372425
return NULL;
373426
file = _wfreopen(wfilename, wotype, stream);
427+
if (file && hide && make_hidden(wfilename))
428+
warning("Could not mark '%s' as hidden.", filename);
374429
return file;
375430
}
376431

config.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,15 @@ static int git_default_core_config(const char *var, const char *value)
911911
return 0;
912912
}
913913

914+
if (!strcmp(var, "core.hidedotfiles")) {
915+
if (value && !strcasecmp(value, "dotgitonly")) {
916+
hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
917+
return 0;
918+
}
919+
hide_dotfiles = git_config_bool(var, value);
920+
return 0;
921+
}
922+
914923
/* Add other config variables here and to Documentation/config.txt. */
915924
return 0;
916925
}

environment.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ int merge_log_config = -1;
6666
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
6767
struct startup_info *startup_info;
6868
unsigned long pack_size_limit_cfg;
69+
enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
6970

7071
#ifndef PROTECT_HFS_DEFAULT
7172
#define PROTECT_HFS_DEFAULT 0

git-compat-util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,4 +1045,8 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);
10451045
#define getc_unlocked(fh) getc(fh)
10461046
#endif
10471047

1048+
#ifndef mark_as_git_dir
1049+
#define mark_as_git_dir(x) /* noop */
1050+
#endif
1051+
10481052
#endif

t/t0001-init.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,4 +339,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
339339
test_path_is_dir realgitdir/refs
340340
'
341341

342+
# Tests for the hidden file attribute on windows
343+
is_hidden () {
344+
test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
345+
}
346+
347+
test_expect_success MINGW 'plain hidden' '
348+
rm -rf newdir &&
349+
(
350+
unset GIT_DIR GIT_WORK_TREE
351+
mkdir newdir &&
352+
cd newdir &&
353+
git init &&
354+
is_hidden .git
355+
) &&
356+
check_config newdir/.git false unset
357+
'
358+
359+
test_expect_success MINGW 'plain bare not hidden' '
360+
rm -rf newdir &&
361+
(
362+
unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
363+
mkdir newdir &&
364+
cd newdir &&
365+
git --bare init
366+
) &&
367+
! is_hidden newdir
368+
'
369+
342370
test_done

0 commit comments

Comments
 (0)