git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 00/24] nd/untracked-cache update

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Jan 20, 2015, 13:03 UTC
Message-ID
<1421759013-8494-1-git-send-email-pclouds@gmail.com>

Sorry for this really late update. This fixes bugs in extension writing code (10/24), support using the same cache from different hosts (23/24), and adds a new bug to point the user to untracked cache from 'git status -uno' (new patch 24/24)

Diff from 'pu' -- 8< --

diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index def635f..7850f53 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -58,7 +58,10 @@ When `-u` option is not used, untracked files and directories are
 shown (i.e. the same as specifying `normal`), to help you avoid
 forgetting to add newly created files.  Because it takes extra work
 to find untracked files in the filesystem, this mode may take some
-time in a large working tree.  You can use `no` to have `git status`
+time in a large working tree.
+Consider to enable untracked cache and split index if supported (see
+`git update-index --untracked-cache` and `git update-index
+--split-index`), Otherwise you can use `no` to have `git status`
 return more quickly without showing untracked files.
 +
 The default can be changed using the status.showUntrackedFiles
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 5dc2bee..0045b89 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -242,8 +242,9 @@ Git index format
 
   The extension starts with
 
-  - A NUL-terminated string describing the environment when the cache
-    is created.
+  - A sequence of NUL-terminated strings, preceded by the size of the
+    sequence in variable width encoding. Each string describes the
+    environment where the cache can be used.
 
   - Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
     ctime field until "file size".
diff --git a/builtin/update-index.c b/builtin/update-index.c
index f23ec83..e76740d 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -1083,7 +1083,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 		the_index.split_index = NULL;
 		the_index.cache_changed |= SOMETHING_CHANGED;
 	}
-	if (untracked_cache > 0 && !the_index.untracked) {
+	if (untracked_cache > 0) {
 		struct untracked_cache *uc;
 
 		if (untracked_cache < 2) {
@@ -1091,11 +1091,15 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 			if (!test_if_untracked_cache_is_supported())
 				return 1;
 		}
-		uc = xcalloc(1, sizeof(*uc));
-		uc->exclude_per_dir = ".gitignore";
-		/* should be the same flags used by git-status */
-		uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
-		the_index.untracked = uc;
+		if (!the_index.untracked) {
+			uc = xcalloc(1, sizeof(*uc));
+			strbuf_init(&uc->ident, 100);
+			uc->exclude_per_dir = ".gitignore";
+			/* should be the same flags used by git-status */
+			uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+			the_index.untracked = uc;
+		}
+		add_untracked_ident(the_index.untracked);
 		the_index.cache_changed |= UNTRACKED_CHANGED;
 	} else if (!untracked_cache && the_index.untracked) {
 		the_index.untracked = NULL;
diff --git a/dir.c b/dir.c
index 95ff3f0..b8a4f9e 100644
--- a/dir.c
+++ b/dir.c
@@ -1793,6 +1793,40 @@ static int treat_leading_path(struct dir_struct *dir,
 	return rc;
 }
 
+static const char *get_ident_string(void)
+{
+	static struct strbuf sb = STRBUF_INIT;
+	struct utsname uts;
+
+	if (sb.len)
+		return sb.buf;
+	if (uname(&uts))
+		die_errno(_("failed to get kernel name and information"));
+	strbuf_addf(&sb, "Location %s, system %s %s %s", get_git_work_tree(),
+		    uts.sysname, uts.release, uts.version);
+	return sb.buf;
+}
+
+static int ident_in_untracked(const struct untracked_cache *uc)
+{
+	const char *end = uc->ident.buf + uc->ident.len;
+	const char *p   = uc->ident.buf;
+
+	for (p = uc->ident.buf; p < end; p += strlen(p) + 1)
+		if (!strcmp(p, get_ident_string()))
+			return 1;
+	return 0;
+}
+
+void add_untracked_ident(struct untracked_cache *uc)
+{
+	if (ident_in_untracked(uc))
+		return;
+	strbuf_addstr(&uc->ident, get_ident_string());
+	/* this strbuf contains a list of strings, save NUL too */
+	strbuf_addch(&uc->ident, 0);
+}
+
 static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir,
 						      int base_len,
 						      const struct pathspec *pathspec)
@@ -1859,6 +1893,11 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
 		if (ce_skip_worktree(active_cache[i]))
 			return NULL;
 
+	if (!ident_in_untracked(dir->untracked)) {
+		warning(_("Untracked cache is disabled on this system."));
+		return NULL;
+	}
+
 	if (!dir->untracked->root) {
 		const int len = sizeof(*dir->untracked->root);
 		dir->untracked->root = xmalloc(len);
@@ -2169,9 +2208,11 @@ struct ondisk_untracked_cache {
 	uint32_t dir_flags;
 	unsigned char info_exclude_sha1[20];
 	unsigned char excludes_file_sha1[20];
-	char exclude_per_dir[1];
+	char exclude_per_dir[FLEX_ARRAY];
 };
 
+#define ouc_size(len) (offsetof(struct ondisk_untracked_cache, exclude_per_dir) + len + 1)
+
 struct write_data {
 	int index;	   /* number of written untracked_cache_dir */
 	struct ewah_bitmap *check_only; /* from untracked_cache_dir */
@@ -2246,26 +2287,15 @@ static void write_one_dir(struct untracked_cache_dir *untracked,
 			write_one_dir(untracked->dirs[i], wd);
 }
 
-static void get_ident_string(struct strbuf *sb)
-{
-	struct utsname uts;
-
-	if (uname(&uts))
-		die_errno(_("failed to get kernel name and information"));
-	strbuf_addf(sb, "Location %s, system %s %s %s", get_git_work_tree(),
-		    uts.sysname, uts.release, uts.version);
-}
-
 void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked)
 {
 	struct ondisk_untracked_cache *ouc;
 	struct write_data wd;
-	struct strbuf sb = STRBUF_INIT;
 	unsigned char varbuf[16];
 	int len = 0, varint_len;
 	if (untracked->exclude_per_dir)
 		len = strlen(untracked->exclude_per_dir);
-	ouc = xmalloc(sizeof(*ouc) + len);
+	ouc = xmalloc(sizeof(*ouc) + len + 1);
 	stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
 	stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
 	hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
@@ -2273,11 +2303,11 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
 	ouc->dir_flags = htonl(untracked->dir_flags);
 	memcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);
 
-	get_ident_string(&sb);
-	strbuf_add(out, sb.buf, sb.len + 1);
-	strbuf_release(&sb);
+	varint_len = encode_varint(untracked->ident.len, varbuf);
+	strbuf_add(out, varbuf, varint_len);
+	strbuf_add(out, untracked->ident.buf, untracked->ident.len);
 
-	strbuf_add(out, ouc, sizeof(*ouc) + len);
+	strbuf_add(out, ouc, ouc_size(len));
 	if (!untracked->root) {
 		varint_len = encode_varint(0, varbuf);
 		strbuf_add(out, varbuf, varint_len);
@@ -2460,29 +2490,26 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
 	struct untracked_cache *uc;
 	struct read_data rd;
 	const unsigned char *next = data, *end = (const unsigned char *)data + sz;
-	struct strbuf sb = STRBUF_INIT;
-	int len;
+	const char *ident;
+	int ident_len, len;
 
 	if (sz <= 1 || end[-1] != '\0')
 		return NULL;
 	end--;
 
-	get_ident_string(&sb);
-	if (strcmp(sb.buf, (const char *)next)) {
-		warning(_("system identification does not match, untracked cache disabled.\n"
-			  "Stored: %s\nCurrent: %s\n"),
-			next, sb.buf);
-		strbuf_release(&sb);
+	ident_len = decode_varint(&next);
+	if (next + ident_len > end)
 		return NULL;
-	}
-	next += sb.len + 1;
-	strbuf_release(&sb);
+	ident = (const char *)next;
+	next += ident_len;
 
 	ouc = (const struct ondisk_untracked_cache *)next;
-	if (next + sizeof(*ouc) > end)
+	if (next + ouc_size(0) > end)
 		return NULL;
 
 	uc = xcalloc(1, sizeof(*uc));
+	strbuf_init(&uc->ident, ident_len);
+	strbuf_add(&uc->ident, ident, ident_len);
 	load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat,
 		       ouc->info_exclude_sha1);
 	load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat,
@@ -2490,7 +2517,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
 	uc->dir_flags = get_be32(&ouc->dir_flags);
 	uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir);
 	/* NUL after exclude_per_dir is covered by sizeof(*ouc) */
-	next += sizeof(*ouc) + strlen(ouc->exclude_per_dir);
+	next += ouc_size(strlen(ouc->exclude_per_dir));
 	if (next >= end)
 		goto done2;
 
diff --git a/dir.h b/dir.h
index 2ce7dd3..6ccbc45 100644
--- a/dir.h
+++ b/dir.h
@@ -127,6 +127,7 @@ struct untracked_cache {
 	struct sha1_stat ss_info_exclude;
 	struct sha1_stat ss_excludes_file;
 	const char *exclude_per_dir;
+	struct strbuf ident;
 	/*
 	 * dir_struct#flags must match dir_flags or the untracked
 	 * cache is ignored.
@@ -305,4 +306,5 @@ void untracked_cache_add_to_index(struct index_state *, const char *);
 void free_untracked_cache(struct untracked_cache *);
 struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz);
 void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);
+void add_untracked_ident(struct untracked_cache *);
 #endif
-- 8< --
-- 
2.2.0.84.ge9c7a8a
Next: Nguyễn Thái Ngọc Duy
Message 1 of 34 in “nd/untracked-cache update”
  1. 00/24 nd/untracked-cache updateNguyễn Thái Ngọc Duy, Jan 20, 2015
  2. 01/24 dir.c: optionally compute sha-1 of a .gitignore fileNguyễn Thái Ngọc Duy, Jan 20, 2015
  3. 02/24 untracked cache: record .gitignore information and dir hierarchyNguyễn Thái Ngọc Duy, Jan 20, 2015
  4. 03/24 untracked cache: initial untracked cache validationNguyễn Thái Ngọc Duy, Jan 20, 2015
  5. 04/24 untracked cache: invalidate dirs recursively if .gitignore changesNguyễn Thái Ngọc Duy, Jan 20, 2015
  6. 05/24 untracked cache: make a wrapper around {open,read,close}dir()Nguyễn Thái Ngọc Duy, Jan 20, 2015
  7. 06/24 untracked cache: record/validate dir mtime and reuse cached outputNguyễn Thái Ngọc Duy, Jan 20, 2015
  8. 07/24 untracked cache: mark what dirs should be recursed/savedNguyễn Thái Ngọc Duy, Jan 20, 2015
  9. 08/24 untracked cache: don't open non-existent .gitignoreNguyễn Thái Ngọc Duy, Jan 20, 2015
  10. 09/24 ewah: add convenient wrapper ewah_serialize_strbuf()Nguyễn Thái Ngọc Duy, Jan 20, 2015
  11. 10/24 untracked cache: save to an index extensionNguyễn Thái Ngọc Duy, Jan 20, 2015
  12. 11/24 untracked cache: load from UNTR index extensionNguyễn Thái Ngọc Duy, Jan 20, 2015
  13. 12/24 untracked cache: invalidate at index addition or removalNguyễn Thái Ngọc Duy, Jan 20, 2015
  14. 13/24 read-cache.c: split racy stat test to a separate functionNguyễn Thái Ngọc Duy, Jan 20, 2015
  15. 14/24 untracked cache: avoid racy timestampsNguyễn Thái Ngọc Duy, Jan 20, 2015
  16. 15/24 untracked cache: print stats with $GIT_TRACE_UNTRACKED_STATSNguyễn Thái Ngọc Duy, Jan 20, 2015
  17. 16/24 untracked cache: mark index dirty if untracked cache is updatedNguyễn Thái Ngọc Duy, Jan 20, 2015
  18. 17/24 untracked-cache: temporarily disable with $GIT_DISABLE_UNTRACKED_CACHENguyễn Thái Ngọc Duy, Jan 20, 2015
  19. 18/24 status: enable untracked cacheNguyễn Thái Ngọc Duy, Jan 20, 2015
  20. 19/24 update-index: manually enable or disable untracked cacheNguyễn Thái Ngọc Duy, Jan 20, 2015
  21. 20/24 update-index: test the system before enabling untracked cacheNguyễn Thái Ngọc Duy, Jan 20, 2015
  22. Junio C HamanoJan 21, 2015
  23. Duy NguyenJan 21, 2015
  24. Junio C HamanoJan 21, 2015
  25. Duy NguyenJan 22, 2015
  26. Junio C HamanoJan 22, 2015
  27. Duy NguyenJan 24, 2015
  28. 21/24 t7063: tests for untracked cacheNguyễn Thái Ngọc Duy, Jan 20, 2015
  29. 22/24 mingw32: add uname()Nguyễn Thái Ngọc Duy, Jan 20, 2015
  30. 23/24 untracked cache: guard and disable on system changesNguyễn Thái Ngọc Duy, Jan 20, 2015
  31. 24/24 git-status.txt: advertisement for untracked cacheNguyễn Thái Ngọc Duy, Jan 20, 2015
  32. brian m. carlsonJan 22, 2015
  33. Torsten BögershausenJan 20, 2015
  34. Duy NguyenJan 21, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.