{"thread":{"id":"4214","subject":"Libify the index refresh logic","startedAt":"2006-05-19T16:56:35Z","lastAt":"2006-05-19T22:36:28Z","messageCount":3,"participants":["Linus Torvalds","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"20292","messageId":"Pine.LNX.4.64.0605190942060.10823@g5.osdl.org","threadId":"4214","inReplyTo":null,"subject":"Libify the index refresh logic","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-19T16:56:35Z","receivedAt":"2006-05-19T16:56:35Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis cleans up and libifies the \"git update-index --[really-]refresh\" \nfunctionality. This will be eventually required for eventually doing the \n\"commit\" and \"status\" commands as built-ins.\n\nIt really just moves \"refresh_index()\" from update-index.c to \nread-cache.c, but it also has to change the calling convention so that the \nfunction uses a \"unsigned int flags\" argument instead of various static \nflags variables for passing down the information about whether to be quiet \nor not, and allow unmerged entries etc.\n\nThat actually cleans up update-index.c too, since it turns out that all \nthose flags were really specific to that one function of the index update, \nso they shouldn't have had file-scope visibility even before. \n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n\n[ To keep the changes to the refresh_index() function itself minimal, it \n  currently just unpacks the passed-in \"flags\" argument into local \n  variables with the same names as the old static variables. That's \n  almost certainly worth cleaning up later, but for now it's that way\n  just to show that no functionality or logic actually changed.\n\n  Also, while I could have moved the IS_ERR/ERR_PTR/PTR_ERR macros to be \n  globally visible in a real header file, they were only used within the \n  moved function, so I just moved them to read-cache.c too with the only\n  user. ]\n\ndiff --git a/cache.h b/cache.h\nindex f9b7049..31755c8 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -160,6 +160,12 @@ extern int index_pipe(unsigned char *sha\n extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);\n extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\n \n+#define REFRESH_REALLY\t\t0x0001\t/* ignore_valid */\n+#define REFRESH_UNMERGED\t0x0002\t/* allow unmerged */\n+#define REFRESH_QUIET\t\t0x0004\t/* be quiet about it */\n+#define REFRESH_IGNORE_MISSING\t0x0008\t/* ignore non-existent */\n+extern int refresh_cache(unsigned int flags);\n+\n struct cache_file {\n \tstruct cache_file *next;\n \tchar lockfile[PATH_MAX];\ndiff --git a/read-cache.c b/read-cache.c\nindex 9a272f8..36bd4ea 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -577,6 +577,123 @@ int add_cache_entry(struct cache_entry *\n \treturn 0;\n }\n \n+/* Three functions to allow overloaded pointer return; see linux/err.h */\n+static inline void *ERR_PTR(long error)\n+{\n+\treturn (void *) error;\n+}\n+\n+static inline long PTR_ERR(const void *ptr)\n+{\n+\treturn (long) ptr;\n+}\n+\n+static inline long IS_ERR(const void *ptr)\n+{\n+\treturn (unsigned long)ptr > (unsigned long)-1000L;\n+}\n+\n+/*\n+ * \"refresh\" does not calculate a new sha1 file or bring the\n+ * cache up-to-date for mode/content changes. But what it\n+ * _does_ do is to \"re-match\" the stat information of a file\n+ * with the cache, so that you can refresh the cache for a\n+ * file that hasn't been changed but where the stat entry is\n+ * out of date.\n+ *\n+ * For example, you'd want to do this after doing a \"git-read-tree\",\n+ * to link up the stat cache details with the proper files.\n+ */\n+static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)\n+{\n+\tstruct stat st;\n+\tstruct cache_entry *updated;\n+\tint changed, size;\n+\n+\tif (lstat(ce->name, &st) < 0)\n+\t\treturn ERR_PTR(-errno);\n+\n+\tchanged = ce_match_stat(ce, &st, really);\n+\tif (!changed) {\n+\t\tif (really && assume_unchanged &&\n+\t\t    !(ce->ce_flags & htons(CE_VALID)))\n+\t\t\t; /* mark this one VALID again */\n+\t\telse\n+\t\t\treturn NULL;\n+\t}\n+\n+\tif (ce_modified(ce, &st, really))\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\tsize = ce_size(ce);\n+\tupdated = xmalloc(size);\n+\tmemcpy(updated, ce, size);\n+\tfill_stat_cache_info(updated, &st);\n+\n+\t/* In this case, if really is not set, we should leave\n+\t * CE_VALID bit alone.  Otherwise, paths marked with\n+\t * --no-assume-unchanged (i.e. things to be edited) will\n+\t * reacquire CE_VALID bit automatically, which is not\n+\t * really what we want.\n+\t */\n+\tif (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))\n+\t\tupdated->ce_flags &= ~htons(CE_VALID);\n+\n+\treturn updated;\n+}\n+\n+int refresh_cache(unsigned int flags)\n+{\n+\tint i;\n+\tint has_errors = 0;\n+\tint really = (flags & REFRESH_REALLY) != 0;\n+\tint allow_unmerged = (flags & REFRESH_UNMERGED) != 0;\n+\tint quiet = (flags & REFRESH_QUIET) != 0;\n+\tint not_new = (flags & REFRESH_IGNORE_MISSING) != 0;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce, *new;\n+\t\tce = active_cache[i];\n+\t\tif (ce_stage(ce)) {\n+\t\t\twhile ((i < active_nr) &&\n+\t\t\t       ! strcmp(active_cache[i]->name, ce->name))\n+\t\t\t\ti++;\n+\t\t\ti--;\n+\t\t\tif (allow_unmerged)\n+\t\t\t\tcontinue;\n+\t\t\tprintf(\"%s: needs merge\\n\", ce->name);\n+\t\t\thas_errors = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tnew = refresh_entry(ce, really);\n+\t\tif (!new)\n+\t\t\tcontinue;\n+\t\tif (IS_ERR(new)) {\n+\t\t\tif (not_new && PTR_ERR(new) == -ENOENT)\n+\t\t\t\tcontinue;\n+\t\t\tif (really && PTR_ERR(new) == -EINVAL) {\n+\t\t\t\t/* If we are doing --really-refresh that\n+\t\t\t\t * means the index is not valid anymore.\n+\t\t\t\t */\n+\t\t\t\tce->ce_flags &= ~htons(CE_VALID);\n+\t\t\t\tactive_cache_changed = 1;\n+\t\t\t}\n+\t\t\tif (quiet)\n+\t\t\t\tcontinue;\n+\t\t\tprintf(\"%s: needs update\\n\", ce->name);\n+\t\t\thas_errors = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tactive_cache_changed = 1;\n+\t\t/* You can NOT just free active_cache[i] here, since it\n+\t\t * might not be necessarily malloc()ed but can also come\n+\t\t * from mmap(). */\n+\t\tactive_cache[i] = new;\n+\t}\n+\treturn has_errors;\n+}\n+\n static int verify_hdr(struct cache_header *hdr, unsigned long size)\n {\n \tSHA_CTX c;\ndiff --git a/update-index.c b/update-index.c\nindex 21448cc..956b6b3 100644\n--- a/update-index.c\n+++ b/update-index.c\n@@ -19,9 +19,6 @@ #include \"tree-walk.h\"\n static int allow_add;\n static int allow_remove;\n static int allow_replace;\n-static int allow_unmerged; /* --refresh needing merge is not error */\n-static int not_new; /* --refresh not having working tree files is not error */\n-static int quiet; /* --refresh needing update is not error */\n static int info_only;\n static int force_remove;\n static int verbose;\n@@ -29,23 +26,6 @@ static int mark_valid_only = 0;\n #define MARK_VALID 1\n #define UNMARK_VALID 2\n \n-\n-/* Three functions to allow overloaded pointer return; see linux/err.h */\n-static inline void *ERR_PTR(long error)\n-{\n-\treturn (void *) error;\n-}\n-\n-static inline long PTR_ERR(const void *ptr)\n-{\n-\treturn (long) ptr;\n-}\n-\n-static inline long IS_ERR(const void *ptr)\n-{\n-\treturn (unsigned long)ptr > (unsigned long)-1000L;\n-}\n-\n static void report(const char *fmt, ...)\n {\n \tva_list vp;\n@@ -148,103 +128,6 @@ static int add_file_to_cache(const char \n \treturn 0;\n }\n \n-/*\n- * \"refresh\" does not calculate a new sha1 file or bring the\n- * cache up-to-date for mode/content changes. But what it\n- * _does_ do is to \"re-match\" the stat information of a file\n- * with the cache, so that you can refresh the cache for a\n- * file that hasn't been changed but where the stat entry is\n- * out of date.\n- *\n- * For example, you'd want to do this after doing a \"git-read-tree\",\n- * to link up the stat cache details with the proper files.\n- */\n-static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)\n-{\n-\tstruct stat st;\n-\tstruct cache_entry *updated;\n-\tint changed, size;\n-\n-\tif (lstat(ce->name, &st) < 0)\n-\t\treturn ERR_PTR(-errno);\n-\n-\tchanged = ce_match_stat(ce, &st, really);\n-\tif (!changed) {\n-\t\tif (really && assume_unchanged &&\n-\t\t    !(ce->ce_flags & htons(CE_VALID)))\n-\t\t\t; /* mark this one VALID again */\n-\t\telse\n-\t\t\treturn NULL;\n-\t}\n-\n-\tif (ce_modified(ce, &st, really))\n-\t\treturn ERR_PTR(-EINVAL);\n-\n-\tsize = ce_size(ce);\n-\tupdated = xmalloc(size);\n-\tmemcpy(updated, ce, size);\n-\tfill_stat_cache_info(updated, &st);\n-\n-\t/* In this case, if really is not set, we should leave\n-\t * CE_VALID bit alone.  Otherwise, paths marked with\n-\t * --no-assume-unchanged (i.e. things to be edited) will\n-\t * reacquire CE_VALID bit automatically, which is not\n-\t * really what we want.\n-\t */\n-\tif (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))\n-\t\tupdated->ce_flags &= ~htons(CE_VALID);\n-\n-\treturn updated;\n-}\n-\n-static int refresh_cache(int really)\n-{\n-\tint i;\n-\tint has_errors = 0;\n-\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce, *new;\n-\t\tce = active_cache[i];\n-\t\tif (ce_stage(ce)) {\n-\t\t\twhile ((i < active_nr) &&\n-\t\t\t       ! strcmp(active_cache[i]->name, ce->name))\n-\t\t\t\ti++;\n-\t\t\ti--;\n-\t\t\tif (allow_unmerged)\n-\t\t\t\tcontinue;\n-\t\t\tprintf(\"%s: needs merge\\n\", ce->name);\n-\t\t\thas_errors = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tnew = refresh_entry(ce, really);\n-\t\tif (!new)\n-\t\t\tcontinue;\n-\t\tif (IS_ERR(new)) {\n-\t\t\tif (not_new && PTR_ERR(new) == -ENOENT)\n-\t\t\t\tcontinue;\n-\t\t\tif (really && PTR_ERR(new) == -EINVAL) {\n-\t\t\t\t/* If we are doing --really-refresh that\n-\t\t\t\t * means the index is not valid anymore.\n-\t\t\t\t */\n-\t\t\t\tce->ce_flags &= ~htons(CE_VALID);\n-\t\t\t\tactive_cache_changed = 1;\n-\t\t\t}\n-\t\t\tif (quiet)\n-\t\t\t\tcontinue;\n-\t\t\tprintf(\"%s: needs update\\n\", ce->name);\n-\t\t\thas_errors = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tactive_cache_changed = 1;\n-\t\t/* You can NOT just free active_cache[i] here, since it\n-\t\t * might not be necessarily malloc()ed but can also come\n-\t\t * from mmap(). */\n-\t\tactive_cache[i] = new;\n-\t}\n-\treturn has_errors;\n-}\n-\n static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n \t\t\t const char *path, int stage)\n {\n@@ -602,6 +485,7 @@ int main(int argc, const char **argv)\n \tconst char *prefix = setup_git_directory();\n \tint prefix_length = prefix ? strlen(prefix) : 0;\n \tchar set_executable_bit = 0;\n+\tunsigned int refresh_flags = 0;\n \n \tgit_config(git_default_config);\n \n@@ -622,7 +506,7 @@ int main(int argc, const char **argv)\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"-q\")) {\n-\t\t\t\tquiet = 1;\n+\t\t\t\trefresh_flags |= REFRESH_QUIET;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--add\")) {\n@@ -638,15 +522,15 @@ int main(int argc, const char **argv)\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--unmerged\")) {\n-\t\t\t\tallow_unmerged = 1;\n+\t\t\t\trefresh_flags |= REFRESH_UNMERGED;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--refresh\")) {\n-\t\t\t\thas_errors |= refresh_cache(0);\n+\t\t\t\thas_errors |= refresh_cache(refresh_flags);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--really-refresh\")) {\n-\t\t\t\thas_errors |= refresh_cache(1);\n+\t\t\t\thas_errors |= refresh_cache(REFRESH_REALLY | refresh_flags);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--cacheinfo\")) {\n@@ -719,7 +603,7 @@ int main(int argc, const char **argv)\n \t\t\t\tgoto finish;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--ignore-missing\")) {\n-\t\t\t\tnot_new = 1;\n+\t\t\t\trefresh_flags |= REFRESH_IGNORE_MISSING;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--verbose\")) {\n"},{"id":"20293","messageId":"Pine.LNX.4.64.0605191041280.10823@g5.osdl.org","threadId":"4214","inReplyTo":"Pine.LNX.4.64.0605190942060.10823@g5.osdl.org","subject":"Re: Libify the index refresh logic","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-19T17:42:12Z","receivedAt":"2006-05-19T17:42:12Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 19 May 2006, Linus Torvalds wrote:\n> \n> This cleans up and libifies the \"git update-index --[really-]refresh\" \n> functionality. This will be eventually required for eventually doing the \n> \"commit\" and \"status\" commands as built-ins.\n\nOops, that's one \"eventually\" too many. That's what you get for editing \nand moving text around.\n\n\t\t\tLinus\n"},{"id":"20305","messageId":"7vodxthcb7.fsf@assigned-by-dhcp.cox.net","threadId":"4214","inReplyTo":"Pine.LNX.4.64.0605190942060.10823@g5.osdl.org","subject":"Re: Libify the index refresh logic","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-19T22:36:28Z","receivedAt":"2006-05-19T22:36:28Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> This cleans up and libifies the \"git update-index --[really-]refresh\" \n> functionality. This will be eventually required for eventually doing the \n> \"commit\" and \"status\" commands as built-ins.\n\nThanks.\n\nWith the recent torrent of moving functions around across files\nwithout necessarily making the old file empty (thus resulting in\nwhat some people call \"file rename\"), the Porcelainish people\nwould have enough testcases to think about how to handle merges\nthat involve with cases like these.\n"}]}