Re: [RFC PATCH] Re: Empty directories...

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Thu, 19 Jul 2007, Tomash Brechko wrote:

> A year or so ago I too would strongly advocate the need of tracking 
> empty directories, permissions et al., it seemed so "natural" and "plain 
> obvious" to me back then.  But since that time I learned to appreciate 
> the "contents tracking" approach, and now view directories (paths in 
> general) only as the means for Git to know where to put the contents on 
> checkout.  This, BTW, is consistent with how Git figures container 
> copies/renames.

Thank you.  It is my impression, too, that after a while it becomes 
obvious what is good and what is not.

FWIW I just whipped up a proof-of-concept patch (so at least _I_ cannot be 
accused of chickening out of writing code):

This adds the command line option "--add-empty-dirs" to "git add", which 
does the only sane thing: putting a placeholder into that directory, and 
adding that.  Since ".gitignore" is already a reserved file name in git, 
it is used as the name of this place holder.

---

	It is probably not fool-proof yet, needs documentation and a test 
	case.  But I am really sick and tired of this discussion.

 builtin-add.c |   25 +++++++++++++++++++++----
 dir.c         |   16 +++++++++++++++-
 dir.h         |    3 ++-
 3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/builtin-add.c b/builtin-add.c
index 7345479..1294840 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -47,7 +47,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
 }
 
 static void fill_directory(struct dir_struct *dir, const char **pathspec,
-		int ignored_too)
+		int ignored_too, int substitute_empty_dirs)
 {
 	const char *path, *base;
 	int baselen;
@@ -63,6 +63,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
 		if (!access(excludes_file, R_OK))
 			add_excludes_from_file(dir, excludes_file);
 	}
+	dir->substitute_empty_directories = substitute_empty_dirs;
 
 	/*
 	 * Calculate common prefix for the pathspec, and
@@ -143,7 +144,8 @@ static const char ignore_warning[] =
 int cmd_add(int argc, const char **argv, const char *prefix)
 {
 	int i, newfd;
-	int verbose = 0, show_only = 0, ignored_too = 0;
+	int verbose = 0, show_only = 0, ignored_too = 0,
+		substitute_empty_dirs = 0;
 	const char **pathspec;
 	struct dir_struct dir;
 	int add_interactive = 0;
@@ -191,6 +193,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 			take_worktree_changes = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--add-empty-dirs")) {
+			substitute_empty_dirs = 1;
+			continue;
+		}
 		usage(builtin_add_usage);
 	}
 
@@ -206,7 +212,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 	}
 	pathspec = get_pathspec(prefix, argv + i);
 
-	fill_directory(&dir, pathspec, ignored_too);
+	fill_directory(&dir, pathspec, ignored_too, substitute_empty_dirs);
 
 	if (show_only) {
 		const char *sep = "", *eof = "";
@@ -231,8 +237,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		exit(1);
 	}
 
-	for (i = 0; i < dir.nr; i++)
+	for (i = 0; i < dir.nr; i++) {
+		const char *name = dir.entries[i]->name;
+		const char *slash;
+		if (substitute_empty_dirs && (slash = strrchr(name, '/')) &&
+				!strcmp(slash, "/.gitignore") &&
+				access(name, R_OK)) {
+			int fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
+			if (fd < 0)
+				return error("Could not create %s", name);
+			close(fd);
+		}
 		add_file_to_cache(dir.entries[i]->name, verbose);
+	}
 
  finish:
 	if (active_cache_changed) {
diff --git a/dir.c b/dir.c
index 8d8faf5..b0b4628 100644
--- a/dir.c
+++ b/dir.c
@@ -456,11 +456,11 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
 {
 	DIR *fdir = opendir(path);
 	int contents = 0;
+	char fullname[PATH_MAX + 1];
 
 	if (fdir) {
 		int exclude_stk;
 		struct dirent *de;
-		char fullname[PATH_MAX + 1];
 		memcpy(fullname, base, baselen);
 
 		exclude_stk = push_exclude_per_directory(dir, base, baselen);
@@ -536,6 +536,20 @@ exit_early:
 		pop_exclude_per_directory(dir, exclude_stk);
 	}
 
+	if (!contents && dir->substitute_empty_directories) {
+		const char *name = ".gitignore";
+		int len = strlen(name);
+		/* Ignore overly long pathnames! */
+		if (len + baselen + 8 > sizeof(fullname))
+			return 0;
+		memcpy(fullname + baselen, name, len+1);
+		if (simplify_away(fullname, baselen + len, simplify)
+				|| excluded(dir, fullname))
+			return 0;
+		dir_add_name(dir, fullname, baselen + len);
+		return 1;
+	}
+
 	return contents;
 }
 
diff --git a/dir.h b/dir.h
index ec0e8ab..0099718 100644
--- a/dir.h
+++ b/dir.h
@@ -34,7 +34,8 @@ struct dir_struct {
 		     show_other_directories:1,
 		     hide_empty_directories:1,
 		     no_gitlinks:1,
-		     collect_ignored:1;
+		     collect_ignored:1,
+		     substitute_empty_directories:1;
 	struct dir_entry **entries;
 	struct dir_entry **ignored;
 
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux