{"thread":{"id":"4716","subject":"[PATCH 4/4] save another call to git-update-index","startedAt":"2006-06-30T00:27:56Z","lastAt":"2006-07-04T17:41:58Z","messageCount":16,"participants":["Alex Riesen","Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"22865","messageId":"20060630002756.GD22618@steel.home","threadId":"4716","inReplyTo":null,"subject":"[PATCH 4/4] save another call to git-update-index","fromName":"Alex Riesen","fromEmail":"fork0@t-online.de","sentAt":"2006-06-30T00:27:56Z","receivedAt":"2006-06-30T00:27:56Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"and a small cleanup\n---\n merge-recursive.c |   41 ++++++++++++++++++-----------------------\n 1 files changed, 18 insertions(+), 23 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 9a18e06..f3f8e7d 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -21,7 +21,7 @@ #include \"graph.h\"\n #include \"path-list.h\"\n \n #define HAVE_ALLOCA\n-#define DEBUG\n+/*#define DEBUG*/\n \n #ifdef DEBUG\n #define debug(args, ...) fprintf(stderr, args, ## __VA_ARGS__)\n@@ -629,8 +629,10 @@ static struct rename_entry *get_renames(\n \t\t\t\t\tstruct tree *bTree,\n \t\t\t\t\tstruct index_entry **entries)\n {\n+#ifdef DEBUG\n \ttime_t t = time(0);\n \tdebug(\"getRenames ...\\n\");\n+#endif\n \tstruct rename_entry *renames = NULL;\n \tstruct rename_entry **rptr = &renames;\n \tstruct diff_options opts;\n@@ -691,22 +693,16 @@ static int update_stages(FILE *up_index,\n {\n \tif ( !up_index )\n \t\treturn -1;\n-\tif ( clear ) {\n+\tif ( clear )\n \t\tfprintf(up_index, \"0 %s\\t%s\", sha1_to_hex(null_sha1), path);\n-\t\tfputc('\\0', up_index);\n-\t}\n-\tif ( omode ) {\n+\tif ( omode )\n \t\tfprintf(up_index, \"0%o %s 1\\t%s\", omode, sha1_to_hex(osha), path);\n-\t\tfputc('\\0', up_index);\n-\t}\n-\tif ( amode ) {\n+\tif ( amode )\n \t\tfprintf(up_index, \"0%o %s 2\\t%s\", amode, sha1_to_hex(asha), path);\n-\t\tfputc('\\0', up_index);\n-\t}\n-\tif ( bmode ) {\n+\tif ( bmode )\n \t\tfprintf(up_index, \"0%o %s 3\\t%s\", bmode, sha1_to_hex(bsha), path);\n+\tif ( clear || omode || amode || bmode )\n \t\tfputc('\\0', up_index);\n-\t}\n \treturn 0;\n }\n \n@@ -1080,7 +1076,8 @@ static void conflict_rename_rename_2(FIL\n \tfree(newPath1);\n }\n \n-static int process_renames(struct rename_entry *renamesA,\n+static int process_renames(FILE* fp,\n+\t\t\t   struct rename_entry *renamesA,\n \t\t\t   struct rename_entry *renamesB,\n \t\t\t   const char *branchNameA,\n \t\t\t   const char *branchNameB)\n@@ -1097,7 +1094,6 @@ static int process_renames(struct rename\n \tfor (sre = renamesB; sre; sre = sre->next)\n \t\tpath_list_insert(sre->pair->one->path, &srcNames);\n \n-\tFILE *fp = git_update_index_pipe();\n \tfor_each_path(src,&srcNames) {\n \t\tstruct rename_entry *renames1, *renames2, *ren1, *ren2;\n \t\tconst char *branchName1, *branchName2;\n@@ -1282,9 +1278,6 @@ static int process_renames(struct rename\n \t\t}\n \t}\n \tpath_list_clear(&srcNames, 0);\n-\tif (pclose(fp)) {\n-\t\tdie(\"git update-index --index-info failed\");\n-\t}\n \tdebug(\"  processRenames done\\n\");\n \treturn cleanMerge;\n }\n@@ -1467,24 +1460,26 @@ static struct merge_tree_result merge_tr\n \t\tstruct rename_entry *re_head, *re_merge;\n \t\tre_head  = get_renames(head, common, head, merge, &entries);\n \t\tre_merge = get_renames(merge, common, head, merge, &entries);\n-\t\tresult.clean = process_renames(re_head, re_merge,\n+\t\tFILE *up_index = git_update_index_pipe();\n+\t\tresult.clean = process_renames(up_index,\n+\t\t\t\t\t       re_head, re_merge,\n \t\t\t\t\t       branch1Name, branch2Name);\n \t\tdebug(\"\\tprocessing entries...\\n\");\n-\t\tFILE *fp = git_update_index_pipe();\n \t\tstruct index_entry *e;\n \t\tfor (e = entries; e; e = e->next) {\n \t\t\tif (e->processed)\n \t\t\t\tcontinue;\n-\t\t\tif (!process_entry(fp, e, branch1Name, branch2Name))\n+\t\t\tif (!process_entry(up_index, e,\n+\t\t\t\t\t   branch1Name, branch2Name))\n \t\t\t\tresult.clean = 0;\n \t\t}\n+\t\tif (pclose(up_index))\n+\t\t\tdie(\"updating entry failed in git update-index\");\n+\n \t\tfree_rename_entries(&re_merge);\n \t\tfree_rename_entries(&re_head);\n \t\tfree_index_entries(&entries);\n \n-\t\tif (pclose(fp))\n-\t\t\tdie(\"updating entry failed in git update-index\");\n-\n \t\tif (result.clean || index_only)\n \t\t\tresult.tree = git_write_tree();\n \t\telse\n-- \n1.4.1.rc1.g17dc\n"},{"id":"22869","messageId":"Pine.LNX.4.63.0606300235300.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"20060630002756.GD22618@steel.home","subject":"Re: [PATCH 4/4] save another call to git-update-index","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-30T00:37:49Z","receivedAt":"2006-06-30T00:37:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nFYI I've been just battling this pipe for a couple of hours. The first \nsteps were easy, but since I wanted to do it incrementally, the index has \nto be written every so often, and I seem not to be able to get that right.\n\nBut now it's time to go to bed, so this will wait for tomorrow.\n\nCiao,\nDscho\n"},{"id":"22893","messageId":"81b0412b0606300022k68d13dg8e292d9b768df51c@mail.gmail.com","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0606300235300.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 4/4] save another call to git-update-index","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2006-06-30T07:22:17Z","receivedAt":"2006-06-30T07:22:17Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On 6/30/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n>\n> FYI I've been just battling this pipe for a couple of hours. The first\n> steps were easy, but since I wanted to do it incrementally, the index has\n> to be written every so often, and I seem not to be able to get that right.\n>\nAre you sure? Does something use the index between starting update-index\npipe and pclose?\n"},{"id":"22905","messageId":"Pine.LNX.4.63.0606301155050.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"81b0412b0606300022k68d13dg8e292d9b768df51c@mail.gmail.com","subject":"Re: [PATCH 4/4] save another call to git-update-index","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-30T09:56:50Z","receivedAt":"2006-06-30T09:56:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 30 Jun 2006, Alex Riesen wrote:\n\n> On 6/30/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > \n> > FYI I've been just battling this pipe for a couple of hours. The first\n> > steps were easy, but since I wanted to do it incrementally, the index has\n> > to be written every so often, and I seem not to be able to get that right.\n> > \n> Are you sure? Does something use the index between starting update-index\n> pipe and pclose?\n\nYes, I am sure you have to write the cache before git-read-tree and \ngit-write-tree ;-) I must have done something severely wrong, though, \nsince there are not too many places where they are called. The problem is \nmore likely that the cache has to be _read_, and _before_ the first \nsubstituted call to git-update-index.\n\nCiao,\nDscho\n"},{"id":"22912","messageId":"81b0412b0606300433u54b5caa0i47d1ea83079b5898@mail.gmail.com","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0606301155050.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 4/4] save another call to git-update-index","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2006-06-30T11:33:31Z","receivedAt":"2006-06-30T11:33:31Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On 6/30/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > >\n> > > FYI I've been just battling this pipe for a couple of hours. The first\n> > > steps were easy, but since I wanted to do it incrementally, the index has\n> > > to be written every so often, and I seem not to be able to get that right.\n> > >\n> > Are you sure? Does something use the index between starting update-index\n> > pipe and pclose?\n>\n> Yes, I am sure you have to write the cache before git-read-tree and\n> git-write-tree ;-)\n\nIndeed :) That's what pclose before git-write-tree is for (which was not the\ncase as I published this optimization. Noticed it later. The last patch series\nhas pclose before git-write-tree)\n\n> I must have done something severely wrong, though,\n> since there are not too many places where they are called. The problem is\n> more likely that the cache has to be _read_, and _before_ the first\n> substituted call to git-update-index.\n\ngit-write-tree change index?\n"},{"id":"22918","messageId":"Pine.LNX.4.63.0606301641540.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0606300235300.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 4/4] save another call to git-update-index","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-30T14:43:06Z","receivedAt":"2006-06-30T14:43:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 30 Jun 2006, Johannes Schindelin wrote:\n\n> FYI I've been just battling this pipe for a couple of hours. The first \n> steps were easy, but since I wanted to do it incrementally, the index has \n> to be written every so often, and I seem not to be able to get that right.\n\nI just finished it. See my upcoming series of three patches. These apply \non top of your last cumulative patch (sometimes yesterday), although I am \ncertain we can merge our efforts.\n\nCiao,\nDscho\n"},{"id":"22920","messageId":"Pine.LNX.4.63.0606301643150.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0606300235300.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"[PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-30T14:43:29Z","receivedAt":"2006-06-30T14:43:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThese functions will be useful for the inbuilt merge-recursive.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n cache.h      |    2 ++\n read-cache.c |   57 +++++++++++++++++++++++++++++++++++++++------------------\n 2 files changed, 41 insertions(+), 18 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 8719939..a5343db 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -142,7 +142,9 @@ #define alloc_nr(x) (((x)+16)*3/2)\n \n /* Initialize and use the cache information */\n extern int read_cache(void);\n+extern int read_cache_from(const char *path);\n extern int write_cache(int newfd, struct cache_entry **cache, int entries);\n+extern int discard_cache(void);\n extern int verify_path(const char *path);\n extern int cache_name_pos(const char *name, int namelen);\n #define ADD_CACHE_OK_TO_ADD 1\t\t/* Ok to add */\ndiff --git a/read-cache.c b/read-cache.c\nindex 3c32aae..04d2ec7 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -24,6 +24,9 @@ unsigned int active_nr = 0, active_alloc\n \n struct cache_tree *active_cache_tree = NULL;\n \n+static void *cache_mmap = NULL;\n+static size_t cache_mmap_size = 0;\n+\n /*\n  * This only updates the \"non-critical\" parts of the directory\n  * cache, ie the parts that aren't tracked by GIT, and only used\n@@ -729,39 +732,43 @@ static int read_index_extension(const ch\n \n int read_cache(void)\n {\n+\treturn read_cache_from(get_index_file());\n+}\n+\n+/* remember to discard_cache() before reading a different cache! */\n+int read_cache_from(const char *path)\n+{\n \tint fd, i;\n \tstruct stat st;\n-\tunsigned long size, offset;\n-\tvoid *map;\n+\tunsigned long offset;\n \tstruct cache_header *hdr;\n \n \terrno = EBUSY;\n-\tif (active_cache)\n+\tif (cache_mmap)\n \t\treturn active_nr;\n \n \terrno = ENOENT;\n \tindex_file_timestamp = 0;\n-\tfd = open(get_index_file(), O_RDONLY);\n+\tfd = open(path, O_RDONLY);\n \tif (fd < 0) {\n \t\tif (errno == ENOENT)\n \t\t\treturn 0;\n \t\tdie(\"index file open failed (%s)\", strerror(errno));\n \t}\n \n-\tsize = 0; // avoid gcc warning\n-\tmap = MAP_FAILED;\n+\tcache_mmap = MAP_FAILED;\n \tif (!fstat(fd, &st)) {\n-\t\tsize = st.st_size;\n+\t\tcache_mmap_size = st.st_size;\n \t\terrno = EINVAL;\n-\t\tif (size >= sizeof(struct cache_header) + 20)\n-\t\t\tmap = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);\n+\t\tif (cache_mmap_size >= sizeof(struct cache_header) + 20)\n+\t\t\tcache_mmap = mmap(NULL, cache_mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);\n \t}\n \tclose(fd);\n-\tif (map == MAP_FAILED)\n+\tif (cache_mmap == MAP_FAILED)\n \t\tdie(\"index file mmap failed (%s)\", strerror(errno));\n \n-\thdr = map;\n-\tif (verify_hdr(hdr, size) < 0)\n+\thdr = cache_mmap;\n+\tif (verify_hdr(hdr, cache_mmap_size) < 0)\n \t\tgoto unmap;\n \n \tactive_nr = ntohl(hdr->hdr_entries);\n@@ -770,12 +777,12 @@ int read_cache(void)\n \n \toffset = sizeof(*hdr);\n \tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = (struct cache_entry *) ((char *) map + offset);\n+\t\tstruct cache_entry *ce = (struct cache_entry *) ((char *) cache_mmap + offset);\n \t\toffset = offset + ce_size(ce);\n \t\tactive_cache[i] = ce;\n \t}\n \tindex_file_timestamp = st.st_mtime;\n-\twhile (offset <= size - 20 - 8) {\n+\twhile (offset <= cache_mmap_size - 20 - 8) {\n \t\t/* After an array of active_nr index entries,\n \t\t * there can be arbitrary number of extended\n \t\t * sections, each of which is prefixed with\n@@ -783,10 +790,10 @@ int read_cache(void)\n \t\t * in 4-byte network byte order.\n \t\t */\n \t\tunsigned long extsize;\n-\t\tmemcpy(&extsize, (char *) map + offset + 4, 4);\n+\t\tmemcpy(&extsize, (char *) cache_mmap + offset + 4, 4);\n \t\textsize = ntohl(extsize);\n-\t\tif (read_index_extension(((const char *) map) + offset,\n-\t\t\t\t\t (char *) map + offset + 8,\n+\t\tif (read_index_extension(((const char *) cache_mmap) + offset,\n+\t\t\t\t\t (char *) cache_mmap + offset + 8,\n \t\t\t\t\t extsize) < 0)\n \t\t\tgoto unmap;\n \t\toffset += 8;\n@@ -795,11 +802,25 @@ int read_cache(void)\n \treturn active_nr;\n \n unmap:\n-\tmunmap(map, size);\n+\tmunmap(cache_mmap, cache_mmap_size);\n \terrno = EINVAL;\n \tdie(\"index file corrupt\");\n }\n \n+int discard_cache()\n+{\n+\tint ret;\n+\t\n+\tif (cache_mmap == NULL)\n+\t\treturn 0;\n+\tret = munmap(cache_mmap, cache_mmap_size);\n+\tcache_mmap = NULL;\n+\tcache_mmap_size = 0;\n+\tactive_nr = active_cache_changed = 0;\n+\t/* no need to throw away allocated active_cache */\n+\treturn ret;\n+}\n+\n #define WRITE_BUFFER_SIZE 8192\n static unsigned char write_buffer[WRITE_BUFFER_SIZE];\n static unsigned long write_buffer_len;\n-- \n1.4.1.rc1.gb2d14\n"},{"id":"22919","messageId":"Pine.LNX.4.63.0606301643400.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0606300235300.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"[PATCH 2/3] Make refresh_cache_entry() public","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-30T14:43:58Z","receivedAt":"2006-06-30T14:43:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis renames refresh_entry() to refresh_cache_entry(), to make clashes\nmore unlikely, and makes it public. It also rethinks the rather awkward\nway to pass an error: this is done by returning a NULL pointer and setting\ncache_errno now.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n cache.h      |    2 ++\n read-cache.c |   44 +++++++++++++++++---------------------------\n 2 files changed, 19 insertions(+), 27 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex a5343db..a59b319 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -115,6 +115,7 @@ #define cache_entry_size(len) ((offsetof\n extern struct cache_entry **active_cache;\n extern unsigned int active_nr, active_alloc, active_cache_changed;\n extern struct cache_tree *active_cache_tree;\n+extern int cache_errno;\n \n #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n@@ -151,6 +152,7 @@ #define ADD_CACHE_OK_TO_ADD 1\t\t/* Ok to \n #define ADD_CACHE_OK_TO_REPLACE 2\t/* Ok to replace file/directory */\n #define ADD_CACHE_SKIP_DFCHECK 4\t/* Ok to skip DF conflict checks */\n extern int add_cache_entry(struct cache_entry *ce, int option);\n+extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);\n extern int remove_cache_entry_at(int pos);\n extern int remove_file_from_cache(const char *path);\n extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);\ndiff --git a/read-cache.c b/read-cache.c\nindex 04d2ec7..1c0fc8b 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -24,6 +24,8 @@ unsigned int active_nr = 0, active_alloc\n \n struct cache_tree *active_cache_tree = NULL;\n \n+int cache_errno = 0;\n+\n static void *cache_mmap = NULL;\n static size_t cache_mmap_size = 0;\n \n@@ -580,22 +582,6 @@ 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@@ -607,14 +593,16 @@ static inline long IS_ERR(const void *pt\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+struct cache_entry *refresh_cache_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+\tif (lstat(ce->name, &st) < 0) {\n+\t\tcache_errno = errno;\n+\t\treturn NULL;\n+\t}\n \n \tchanged = ce_match_stat(ce, &st, really);\n \tif (!changed) {\n@@ -622,11 +610,13 @@ static struct cache_entry *refresh_entry\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\t\treturn ce;\n \t}\n \n-\tif (ce_modified(ce, &st, really))\n-\t\treturn ERR_PTR(-EINVAL);\n+\tif (ce_modified(ce, &st, really)) {\n+\t\tcache_errno = EINVAL;\n+\t\treturn NULL;\n+\t}\n \n \tsize = ce_size(ce);\n \tupdated = xmalloc(size);\n@@ -669,13 +659,13 @@ int refresh_cache(unsigned int flags)\n \t\t\tcontinue;\n \t\t}\n \n-\t\tnew = refresh_entry(ce, really);\n-\t\tif (!new)\n+\t\tnew = refresh_cache_entry(ce, really);\n+\t\tif (new == ce)\n \t\t\tcontinue;\n-\t\tif (IS_ERR(new)) {\n-\t\t\tif (not_new && PTR_ERR(new) == -ENOENT)\n+\t\tif (!new) {\n+\t\t\tif (not_new && cache_errno == ENOENT)\n \t\t\t\tcontinue;\n-\t\t\tif (really && PTR_ERR(new) == -EINVAL) {\n+\t\t\tif (really && cache_errno == 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-- \n1.4.1.rc1.gb2d14\n"},{"id":"22921","messageId":"Pine.LNX.4.63.0606301644210.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0606300235300.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"[PATCH 3/3] merge-recursive: avoid the pipe to update-index","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-30T14:44:47Z","receivedAt":"2006-06-30T14:44:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nInstead of a fork, we can use the plumbing ;-)\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n graph.c           |   26 -----\n merge-recursive.c |  270 +++++++++++++++++++++++++++++++++++++----------------\n 2 files changed, 191 insertions(+), 105 deletions(-)\n\ndiff --git a/graph.c b/graph.c\nindex fa2bfee..b784ea2 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -5,32 +5,6 @@ #include \"cache.h\"\n #include \"commit.h\"\n #include \"graph.h\"\n \n-// does not belong here\n-struct tree *git_write_tree()\n-{\n-#if 0\n-\tfprintf(stderr, \"GIT_INDEX_FILE='%s' git-write-tree\\n\",\n-\t\tgetenv(\"GIT_INDEX_FILE\"));\n-#endif\n-\tFILE *fp = popen(\"git-write-tree 2>/dev/null\", \"r\");\n-\tchar buf[41];\n-\tunsigned char sha1[20];\n-\tint ch;\n-\tunsigned i = 0;\n-\twhile ( (ch = fgetc(fp)) != EOF )\n-\t\tif ( i < sizeof(buf)-1 && ch >= '0' && ch <= 'f' )\n-\t\t\tbuf[i++] = ch;\n-\t\telse\n-\t\t\tbreak;\n-\tint rc = pclose(fp);\n-\tif ( rc == -1 || WEXITSTATUS(rc) )\n-\t\treturn NULL;\n-\tbuf[i] = '\\0';\n-\tif ( get_sha1(buf, sha1) != 0 )\n-\t\treturn NULL;\n-\treturn lookup_tree(sha1);\n-}\n-\n const char *node_title(struct node *node, int *len)\n {\n \tconst char *s = \"(null commit)\";\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 9bbb426..6d4e797 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -9,6 +9,7 @@ #include <sys/wait.h>\n #include <sys/types.h>\n #include <sys/stat.h>\n #include \"cache.h\"\n+#include \"cache-tree.h\"\n #include \"commit.h\"\n #include \"blob.h\"\n #include \"tree-walk.h\"\n@@ -19,6 +20,47 @@ #include \"run-command.h\"\n #include \"graph.h\"\n #include \"path-list.h\"\n \n+#ifdef DEBUG\n+#include \"quote.h\"\n+static void show_ce_entry(const char *tag, struct cache_entry *ce)\n+{\n+\tif (tag && *tag &&\n+\t    (ce->ce_flags & htons(CE_VALID))) {\n+\t\tstatic char alttag[4];\n+\t\tmemcpy(alttag, tag, 3);\n+\t\tif (isalpha(tag[0]))\n+\t\t\talttag[0] = tolower(tag[0]);\n+\t\telse if (tag[0] == '?')\n+\t\t\talttag[0] = '!';\n+\t\telse {\n+\t\t\talttag[0] = 'v';\n+\t\t\talttag[1] = tag[0];\n+\t\t\talttag[2] = ' ';\n+\t\t\talttag[3] = 0;\n+\t\t}\n+\t\ttag = alttag;\n+\t}\n+\n+\tfprintf(stderr,\"%s%06o %s %d\\t\",\n+\t\t\ttag,\n+\t\t\tntohl(ce->ce_mode),\n+\t\t\tsha1_to_hex(ce->sha1),\n+\t\t\tce_stage(ce));\n+\twrite_name_quoted(\"\", 0, ce->name,\n+\t\t\t'\\n', stderr);\n+\tfputc('\\n', stderr);\n+}\n+\n+static void ls_files() {\n+\tint i;\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tshow_ce_entry(\"\", ce);\n+\t}\n+\tfprintf(stderr, \"---\\n\");\n+}\n+#endif\n+\n #define for_each_commit(p,list) for ( p = (list); p; p = p->next )\n \n struct merge_result\n@@ -94,12 +136,68 @@ static void output(const char *fmt, ...)\n \n static const char *original_index_file;\n static const char *temporary_index_file;\n+static int cache_dirty = 0;\n+\n+static int flush_cache()\n+{\n+\t/* flush temporary index */\n+\tstruct lock_file *lock = xcalloc(1, sizeof(struct lock_file));\n+\tint fd = hold_lock_file_for_update(lock, getenv(\"GIT_INDEX_FILE\"));\n+\tif (fd < 0)\n+\t\tdie(\"could not lock %s\", temporary_index_file);\n+\tif (write_cache(fd, active_cache, active_nr) ||\n+\t\t\tcommit_lock_file(lock))\n+\t\tdie (\"unable to write %s\", temporary_index_file);\n+\tdiscard_cache();\n+\tcache_dirty = 0;\n+\treturn 0;\n+}\n \n static void setup_index(int temp)\n {\n \tconst char *idx = temp ? temporary_index_file: original_index_file;\n+\tif (cache_dirty)\n+\t\tdie(\"fatal: cache changed flush_cache();\");\n \tunlink(temporary_index_file);\n \tsetenv(\"GIT_INDEX_FILE\", idx, 1);\n+\tdiscard_cache();\n+}\n+\n+static struct cache_entry *make_cache_entry(unsigned int mode,\n+\t\tconst unsigned char *sha1, const char *path, int stage, int refresh)\n+{\n+\tint size, len;\n+\tstruct cache_entry *ce;\n+\n+\tif (!verify_path(path))\n+\t\treturn NULL;\n+\n+\tlen = strlen(path);\n+\tsize = cache_entry_size(len);\n+\tce = xcalloc(1, size);\n+\n+\tmemcpy(ce->sha1, sha1, 20);\n+\tmemcpy(ce->name, path, len);\n+\tce->ce_flags = create_ce_flags(len, stage);\n+\tce->ce_mode = create_ce_mode(mode);\n+\n+\tif (refresh)\n+\t\treturn refresh_cache_entry(ce, 0);\n+\n+\treturn ce;\n+}\n+\n+static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n+\t\tconst char *path, int stage, int refresh, int options)\n+{\n+\tstruct cache_entry *ce;\n+\tif (!cache_dirty)\n+\t\tread_cache_from(getenv(\"GIT_INDEX_FILE\"));\n+\tcache_dirty++;\n+\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);\n+\tif (!ce)\n+\t\treturn error(\"cache_addinfo failed: %s\", strerror(cache_errno));\n+\treturn add_cache_entry(ce, options);\n }\n \n // This is a global variable which is used in a number of places but\n@@ -119,6 +217,8 @@ #if 0\n \t\tsha1_to_hex(tree->object.sha1));\n #endif\n \tconst char *argv[] = { \"git-read-tree\", NULL, NULL, };\n+\tif (cache_dirty)\n+\t\tdie(\"read-tree with dirty cache\");\n \targv[1] = sha1_to_hex(tree->object.sha1);\n \tint rc = run_command_v(2, argv);\n \treturn rc < 0 ? -1: rc;\n@@ -141,6 +241,8 @@ #endif\n \t\t\"git-read-tree\", NULL, \"-m\", NULL, NULL, NULL,\n \t\tNULL,\n \t};\n+\tif (cache_dirty)\n+\t\tflush_cache();\n \targv[1] = update_arg;\n \targv[3] = sha1_to_hex(common->object.sha1);\n \targv[4] = sha1_to_hex(head->object.sha1);\n@@ -149,6 +251,33 @@ #endif\n \treturn rc < 0 ? -1: rc;\n }\n \n+struct tree *git_write_tree()\n+{\n+#if 0\n+\tfprintf(stderr, \"GIT_INDEX_FILE='%s' git-write-tree\\n\",\n+\t\tgetenv(\"GIT_INDEX_FILE\"));\n+#endif\n+\tif (cache_dirty)\n+\t\tflush_cache();\n+\tFILE *fp = popen(\"git-write-tree 2>/dev/null\", \"r\");\n+\tchar buf[41];\n+\tunsigned char sha1[20];\n+\tint ch;\n+\tunsigned i = 0;\n+\twhile ( (ch = fgetc(fp)) != EOF )\n+\t\tif ( i < sizeof(buf)-1 && ch >= '0' && ch <= 'f' )\n+\t\t\tbuf[i++] = ch;\n+\t\telse\n+\t\t\tbreak;\n+\tint rc = pclose(fp);\n+\tif ( rc == -1 || WEXITSTATUS(rc) )\n+\t\treturn NULL;\n+\tbuf[i] = '\\0';\n+\tif ( get_sha1(buf, sha1) != 0 )\n+\t\treturn NULL;\n+\treturn lookup_tree(sha1);\n+}\n+\n struct merge_tree_result merge_trees(struct tree *head,\n \t\t\t\t     struct tree *merge,\n \t\t\t\t     struct tree *common,\n@@ -640,36 +769,25 @@ struct rename_entry *getRenames(struct t\n \treturn renames;\n }\n \n-static FILE *git_update_index_pipe()\n-{\n-\treturn popen(\"git-update-index -z --index-info\", \"w\");\n-}\n-\n-int setIndexStages(FILE *fp,\n-\t\t   const char *path,\n+int setIndexStages(const char *path,\n \t\t   unsigned char *osha, unsigned omode,\n \t\t   unsigned char *asha, unsigned amode,\n \t\t   unsigned char *bsha, unsigned bmode,\n \t\t   int clear /* =True */)\n {\n-\tif ( !fp )\n-\t\treturn -1;\n-\tif ( clear ) {\n-\t\tfprintf(fp, \"0 %s\\t%s\", sha1_to_hex(null_sha1), path);\n-\t\tfputc('\\0', fp);\n-\t}\n-\tif ( omode ) {\n-\t\tfprintf(fp, \"0%o %s 1\\t%s\", omode, sha1_to_hex(osha), path);\n-\t\tfputc('\\0', fp);\n-\t}\n-\tif ( amode ) {\n-\t\tfprintf(fp, \"0%o %s 2\\t%s\", amode, sha1_to_hex(asha), path);\n-\t\tfputc('\\0', fp);\n-\t}\n-\tif ( bmode ) {\n-\t\tfprintf(fp, \"0%o %s 3\\t%s\", bmode, sha1_to_hex(bsha), path);\n-\t\tfputc('\\0', fp);\n-\t}\n+\tint options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;\n+\tif ( clear ) \n+\t\tif (add_cacheinfo(0, null_sha1, path, 0, 0, options))\n+\t\t\treturn -1;\n+\tif ( omode )\n+\t\tif (add_cacheinfo(omode, osha, path, 1, 0, options))\n+\t\t\treturn -1;\n+\tif ( amode )\n+\t\tif (add_cacheinfo(omode, osha, path, 2, 0, options))\n+\t\t\treturn -1;\n+\tif ( bmode )\n+\t\tif (add_cacheinfo(omode, osha, path, 3, 0, options))\n+\t\t\treturn -1;\n \treturn 0;\n }\n \n@@ -695,17 +813,17 @@ static int remove_path(const char *name)\n \treturn ret;\n }\n \n-int removeFile(FILE *fp, int clean, const char *path)\n+int removeFile(int clean, const char *path)\n {\n \tint updateCache = index_only || clean;\n \tint updateWd = !index_only;\n \n \tif ( updateCache ) {\n-\t\tif ( !fp )\n+\t\tif (!cache_dirty)\n+\t\t\tread_cache_from(getenv(\"GIT_INDEX_FILE\"));\n+\t\tcache_dirty++;\n+\t\tif (remove_file_from_cache(path))\n \t\t\treturn -1;\n-\t\tfprintf(fp, \"0 %s\\t%s\", sha1_to_hex(null_sha1), path);\n-\t\tfputc('\\0', fp);\n-\t\treturn 0;\n \t}\n \tif ( updateWd )\n \t{\n@@ -785,8 +903,7 @@ static void flush_buffer(int fd, const c\n \t}\n }\n \n-void updateFileExt(FILE *fp,\n-\t\t   const unsigned char *sha,\n+void updateFileExt(const unsigned char *sha,\n \t\t   unsigned mode,\n \t\t   const char *path,\n \t\t   int updateCache,\n@@ -830,20 +947,15 @@ void updateFileExt(FILE *fp,\n \t\t\t    mode, sha1_to_hex(sha), path);\n \t}\n \tif ( updateCache )\n-\t{\n-\t\t// XXX just always use \"git update-index --index-info\"?\n-\t\tfprintf(fp, \"%06o %s\\t%s\", mode, sha1_to_hex(sha), path);\n-\t\tfputc('\\0', fp);\n-\t}\n+\t\tadd_cacheinfo(mode, sha, path, 0, updateWd, ADD_CACHE_OK_TO_ADD);\n }\n \n-void updateFile(FILE *fp,\n-\t\tint clean,\n+void updateFile(int clean,\n \t\tconst unsigned char *sha,\n \t\tunsigned mode,\n \t\tconst char *path)\n {\n-\tupdateFileExt(fp, sha, mode, path, index_only || clean, !index_only);\n+\tupdateFileExt(sha, mode, path, index_only || clean, !index_only);\n }\n \n // Low level file merging, update and removal\n@@ -1004,7 +1116,6 @@ int processRenames(struct rename_entry *\n \tfor (sre = renamesB; sre; sre = sre->next)\n \t\tpath_list_insert(sre->src, &srcNames);\n \n-\tFILE *fp = git_update_index_pipe();\n \tfor_each_path(src,&srcNames) {\n \t\tstruct rename_entry *renames1, *renames2, *ren1, *ren2;\n \t\tconst char *branchName1, *branchName2;\n@@ -1050,26 +1161,26 @@ int processRenames(struct rename_entry *\n \t\t\t\t\tdstName1 = uniquePath(ren1->dst, branchName1);\n \t\t\t\t\toutput(\"%s is a directory in %s adding as %s instead\",\n \t\t\t\t\t       ren1->dst, branchName2, dstName1);\n-\t\t\t\t\tremoveFile(fp, 0, ren1->dst);\n+\t\t\t\t\tremoveFile(0, ren1->dst);\n \t\t\t\t}\n \t\t\t\tif ( path_list_has_path(&currentDirectorySet, ren2->dst) ) {\n \t\t\t\t\tdstName2 = uniquePath(ren2->dst, branchName2);\n \t\t\t\t\toutput(\"%s is a directory in %s adding as %s instead\",\n \t\t\t\t\t       ren2->dst, branchName1, dstName2);\n-\t\t\t\t\tremoveFile(fp, 0, ren2->dst);\n+\t\t\t\t\tremoveFile(0, ren2->dst);\n \t\t\t\t}\n-\t\t\t\tsetIndexStages(fp, dstName1,\n+\t\t\t\tsetIndexStages(dstName1,\n \t\t\t\t\t       NULL, 0,\n \t\t\t\t\t       ren1->dst_sha, ren1->dst_mode,\n \t\t\t\t\t       NULL, 0,\n \t\t\t\t\t       1 /* clear */);\n-\t\t\t\tsetIndexStages(fp, dstName2,\n+\t\t\t\tsetIndexStages(dstName2,\n \t\t\t\t\t       NULL, 0,\n \t\t\t\t\t       NULL, 0,\n \t\t\t\t\t       ren2->dst_sha, ren2->dst_mode,\n \t\t\t\t\t       1 /* clear */);\n \t\t\t} else {\n-\t\t\t\tremoveFile(fp, 1, ren1->src);\n+\t\t\t\tremoveFile(1, ren1->src);\n \t\t\t\tstruct merge_file_info mfi;\n \t\t\t\tmfi = mergeFile(ren1->src, ren1->src_sha, ren1->src_mode,\n \t\t\t\t\t\tren1->dst, ren1->dst_sha, ren1->dst_mode,\n@@ -1087,18 +1198,17 @@ int processRenames(struct rename_entry *\n \t\t\t\t\tcleanMerge = 0;\n \n \t\t\t\t\tif ( !index_only )\n-\t\t\t\t\t\tsetIndexStages(fp,\n-\t\t\t\t\t\t\t       ren1->dst,\n+\t\t\t\t\t\tsetIndexStages(ren1->dst,\n \t\t\t\t\t\t\t       ren1->src_sha, ren1->src_mode,\n \t\t\t\t\t\t\t       ren1->dst_sha, ren1->dst_mode,\n \t\t\t\t\t\t\t       ren2->dst_sha, ren2->dst_mode,\n \t\t\t\t\t\t\t       1 /* clear */);\n \t\t\t\t}\n-\t\t\t\tupdateFile(fp, mfi.clean, mfi.sha, mfi.mode, ren1->dst);\n+\t\t\t\tupdateFile(mfi.clean, mfi.sha, mfi.mode, ren1->dst);\n \t\t\t}\n \t\t} else {\n \t\t\t// Renamed in 1, maybe changed in 2\n-\t\t\tremoveFile(fp, 1, ren1->src);\n+\t\t\tremoveFile(1, ren1->src);\n \n \t\t\tunsigned char srcShaOtherBranch[20], dstShaOtherBranch[20];\n \t\t\tunsigned srcModeOtherBranch, dstModeOtherBranch;\n@@ -1123,15 +1233,15 @@ int processRenames(struct rename_entry *\n \t\t\t\t       ren1->dst, branchName2);\n \t\t\t\toutput(\"Renaming %s to %s instead\", ren1->src, newPath);\n \t\t\t\tcleanMerge = 0;\n-\t\t\t\tremoveFile(fp, 0, ren1->dst);\n-\t\t\t\tupdateFile(fp, 0, ren1->dst_sha, ren1->dst_mode, newPath);\n+\t\t\t\tremoveFile(0, ren1->dst);\n+\t\t\t\tupdateFile(0, ren1->dst_sha, ren1->dst_mode, newPath);\n \t\t\t} else if ( memcmp(srcShaOtherBranch, null_sha1, 20) == 0 ) {\n \t\t\t\toutput(\"CONFLICT (rename/delete): Rename %s->%s in %s \"\n \t\t\t\t       \"and deleted in %s\",\n \t\t\t\t       ren1->src, ren1->dst, branchName1,\n \t\t\t\t       branchName2);\n \t\t\t\tcleanMerge = 0;\n-\t\t\t\tupdateFile(fp, 0, ren1->dst_sha, ren1->dst_mode, ren1->dst);\n+\t\t\t\tupdateFile(0, ren1->dst_sha, ren1->dst_mode, ren1->dst);\n \t\t\t} else if ( memcmp(dstShaOtherBranch, null_sha1, 20) != 0 ) {\n \t\t\t\tnewPath = uniquePath(ren1->dst, branchName2);\n \t\t\t\toutput(\"CONFLICT (rename/add): Rename %s->%s in %s. \"\n@@ -1139,7 +1249,7 @@ int processRenames(struct rename_entry *\n \t\t\t\t       ren1->src, ren1->dst, branchName1,\n \t\t\t\t       ren1->dst, branchName2);\n \t\t\t\toutput(\"Adding as %s instead\", newPath);\n-\t\t\t\tupdateFile(fp, 0, dstShaOtherBranch, dstModeOtherBranch, newPath);\n+\t\t\t\tupdateFile(0, dstShaOtherBranch, dstModeOtherBranch, newPath);\n \t\t\t\tcleanMerge = 0;\n \t\t\t\ttryMerge = 1;\n \t\t\t} else if ( (dst2 = find_rename_bydst(renames2, ren1->dst)) ) {\n@@ -1151,9 +1261,9 @@ int processRenames(struct rename_entry *\n \t\t\t\t       dst2->src, dst2->dst, branchName2);\n \t\t\t\toutput(\"Renaming %s to %s and %s to %s instead\",\n \t\t\t\t       ren1->src, newPath1, dst2->src, newPath2);\n-\t\t\t\tremoveFile(fp, 0, ren1->dst);\n-\t\t\t\tupdateFile(fp, 0, ren1->dst_sha, ren1->dst_mode, newPath1);\n-\t\t\t\tupdateFile(fp, 0, dst2->dst_sha, dst2->dst_mode, newPath2);\n+\t\t\t\tremoveFile(0, ren1->dst);\n+\t\t\t\tupdateFile(0, ren1->dst_sha, ren1->dst_mode, newPath1);\n+\t\t\t\tupdateFile(0, dst2->dst_sha, dst2->dst_mode, newPath2);\n \t\t\t\tdst2->processed = 1;\n \t\t\t\tcleanMerge = 0;\n \t\t\t} else\n@@ -1194,21 +1304,19 @@ int processRenames(struct rename_entry *\n \t\t\t\t\tcleanMerge = 0;\n \n \t\t\t\t\tif ( !index_only )\n-\t\t\t\t\t\tsetIndexStages(fp,\n-\t\t\t\t\t\t\t       ren1->dst,\n+\t\t\t\t\t\tsetIndexStages(ren1->dst,\n \t\t\t\t\t\t\t       osha, omode,\n \t\t\t\t\t\t\t       asha, amode,\n \t\t\t\t\t\t\t       bsha, bmode,\n \t\t\t\t\t\t\t       1 /* clear */);\n \t\t\t\t}\n-\t\t\t\tupdateFile(fp, mfi.clean, mfi.sha, mfi.mode, ren1->dst);\n+\t\t\t\tupdateFile(mfi.clean, mfi.sha, mfi.mode, ren1->dst);\n \t\t\t}\n \t\t}\n \t}\n \tpath_list_clear(&srcNames, 0);\n-\tif (pclose(fp)) {\n-\t\tdie(\"git update-index --index-info failed\");\n-\t}\n+\tif (cache_dirty)\n+\t\tflush_cache();\n \treturn cleanMerge;\n }\n \n@@ -1241,7 +1349,6 @@ int processEntry(struct index_entry *ent\n \tunsigned oMode = entry->stages[1].mode;\n \tunsigned aMode = entry->stages[2].mode;\n \tunsigned bMode = entry->stages[3].mode;\n-\tFILE *fp = git_update_index_pipe();\n \n \tif ( oSha && (!aSha || !bSha) ) {\n \t\t//\n@@ -1253,7 +1360,7 @@ int processEntry(struct index_entry *ent\n \t\t\t// Deleted in both or deleted in one and unchanged in the other\n \t\t\tif ( aSha )\n \t\t\t\toutput(\"Removing %s\", path);\n-\t\t\tremoveFile(fp, 1, path);\n+\t\t\tremoveFile(1, path);\n \t\t} else {\n \t\t\t// Deleted in one and changed in the other\n \t\t\tcleanMerge = 0;\n@@ -1262,13 +1369,13 @@ int processEntry(struct index_entry *ent\n \t\t\t\t       \"and modified in %s. Version %s of %s left in tree.\",\n \t\t\t\t       path, branch1Name,\n \t\t\t\t       branch2Name, branch2Name, path);\n-\t\t\t\tupdateFile(fp, 0, bSha, bMode, path);\n+\t\t\t\tupdateFile(0, bSha, bMode, path);\n \t\t\t} else {\n \t\t\t\toutput(\"CONFLICT (delete/modify): %s deleted in %s \"\n \t\t\t\t       \"and modified in %s. Version %s of %s left in tree.\",\n \t\t\t\t       path, branch2Name,\n \t\t\t\t       branch1Name, branch1Name, path);\n-\t\t\t\tupdateFile(fp, 0, aSha, aMode, path);\n+\t\t\t\tupdateFile(0, aSha, aMode, path);\n \t\t\t}\n \t\t}\n \n@@ -1302,11 +1409,11 @@ int processEntry(struct index_entry *ent\n \t\t\toutput(\"CONFLICT (%s): There is a directory with name %s in %s. \"\n \t\t\t       \"Adding %s as %s\",\n \t\t\t       conf, path, otherBranch, path, newPath);\n-\t\t\tremoveFile(fp, 0, path);\n-\t\t\tupdateFile(fp, 0, sha, mode, newPath);\n+\t\t\tremoveFile(0, path);\n+\t\t\tupdateFile(0, sha, mode, newPath);\n \t\t} else {\n \t\t\toutput(\"Adding %s\", path);\n-\t\t\tupdateFile(fp, 1, sha, mode, path);\n+\t\t\tupdateFile(1, sha, mode, path);\n \t\t}\n \t} else if ( !oSha && aSha && bSha ) {\n \t\t//\n@@ -1319,7 +1426,7 @@ int processEntry(struct index_entry *ent\n \t\t\t\t       \"but permissions conflict %06o->%06o\",\n \t\t\t\t       path, aMode, bMode);\n \t\t\t\toutput(\"CONFLICT: adding with permission: %06o\", aMode);\n-\t\t\t\tupdateFile(fp, 0, aSha, aMode, path);\n+\t\t\t\tupdateFile(0, aSha, aMode, path);\n \t\t\t} else {\n \t\t\t\t// This case is handled by git-read-tree\n \t\t\t\tassert(0 && \"This case must be handled by git-read-tree\");\n@@ -1331,9 +1438,9 @@ int processEntry(struct index_entry *ent\n \t\t\toutput(\"CONFLICT (add/add): File %s added non-identically \"\n \t\t\t       \"in both branches. Adding as %s and %s instead.\",\n \t\t\t       path, newPath1, newPath2);\n-\t\t\tremoveFile(fp, 0, path);\n-\t\t\tupdateFile(fp, 0, aSha, aMode, newPath1);\n-\t\t\tupdateFile(fp, 0, bSha, bMode, newPath2);\n+\t\t\tremoveFile(0, path);\n+\t\t\tupdateFile(0, aSha, aMode, newPath1);\n+\t\t\tupdateFile(0, bSha, bMode, newPath2);\n \t\t}\n \n \t} else if ( oSha && aSha && bSha ) {\n@@ -1348,22 +1455,23 @@ int processEntry(struct index_entry *ent\n \t\t\t\tbranch1Name, branch2Name);\n \n \t\tif ( mfi.clean )\n-\t\t\tupdateFile(fp, 1, mfi.sha, mfi.mode, path);\n+\t\t\tupdateFile(1, mfi.sha, mfi.mode, path);\n \t\telse {\n \t\t\tcleanMerge = 0;\n \t\t\toutput(\"CONFLICT (content): Merge conflict in %s\", path);\n \n \t\t\tif ( index_only )\n-\t\t\t\tupdateFile(fp, 0, mfi.sha, mfi.mode, path);\n+\t\t\t\tupdateFile(0, mfi.sha, mfi.mode, path);\n \t\t\telse\n-\t\t\t\tupdateFileExt(fp, mfi.sha, mfi.mode, path,\n+\t\t\t\tupdateFileExt(mfi.sha, mfi.mode, path,\n \t\t\t\t\t      0 /* updateCache */, 1 /* updateWd */);\n \t\t}\n \t} else\n \t\tdie(\"Fatal merge failure, shouldn't happen.\");\n \n-\tif (pclose(fp))\n-\t\tdie(\"updating entry failed in git update-index\");\n+\tif (cache_dirty)\n+\t\tflush_cache();\n+\n \treturn cleanMerge;\n }\n \n@@ -1570,6 +1678,10 @@ int main(int argc, char *argv[])\n \t\tstruct graph *graph = graph_build(commits);\n \t\tresult = merge(h1, h2, branch1, branch2, graph, 0, NULL);\n \t}\n+\n+\tif (cache_dirty)\n+\t\tflush_cache();\n+\n \treturn result.clean ? 0: 1;\n }\n \n-- \n1.4.1.rc1.gb2d14\n"},{"id":"22927","messageId":"7v3bdmk2zj.fsf@assigned-by-dhcp.cox.net","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0606301643150.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-30T16:44:16Z","receivedAt":"2006-06-30T16:44:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> +int discard_cache()\n> +{\n> +\tint ret;\n> +\t\n> +\tif (cache_mmap == NULL)\n> +\t\treturn 0;\n> +\tret = munmap(cache_mmap, cache_mmap_size);\n> +\tcache_mmap = NULL;\n> +\tcache_mmap_size = 0;\n> +\tactive_nr = active_cache_changed = 0;\n> +\t/* no need to throw away allocated active_cache */\n> +\treturn ret;\n> +}\n> +\n\nI haven't been following the details of the patches in this\nthread while they are being cooked actively, but two things to\nlook out for are:\n\n - I am guessing you run discard_cache() because you want to\n   read in a new cache (or start from a clean slate).  I am not\n   sure what you are doing with the old cache tree data\n   structure.  If you are starting from a clean slate\n   (i.e. there is no read_cache_from() after you call\n   discard_cache), you would probably need to discard the old\n   cache tree; otherwise your next write-tree may produce an\n   incorrect index file.  If you keep the old one and later\n   swap it in, the problem might be even more severe.\n\n - index_timestamp is left as the old value in this patch when\n   you switch cache using read_cache_from() directly.  I have a\n   suspicion you may be bitten by \"Racy Git\" problem, especially\n   because the operations are supposed to happen quickly thanks\n   to the effort of you two ;-) increasing the risks that the\n   file timestamp of the working tree file and the cached entry\n   match.\n"},{"id":"22976","messageId":"Pine.LNX.4.63.0607011657460.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"7v3bdmk2zj.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-07-01T15:06:14Z","receivedAt":"2006-07-01T15:06:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 30 Jun 2006, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > +int discard_cache()\n> > +{\n> > +\tint ret;\n> > +\t\n> > +\tif (cache_mmap == NULL)\n> > +\t\treturn 0;\n> > +\tret = munmap(cache_mmap, cache_mmap_size);\n> > +\tcache_mmap = NULL;\n> > +\tcache_mmap_size = 0;\n> > +\tactive_nr = active_cache_changed = 0;\n> > +\t/* no need to throw away allocated active_cache */\n> > +\treturn ret;\n> > +}\n> > +\n> \n> I haven't been following the details of the patches in this\n> thread while they are being cooked actively, but two things to\n> look out for are:\n> \n>  - I am guessing you run discard_cache() because you want to\n>    read in a new cache (or start from a clean slate).  I am not\n>    sure what you are doing with the old cache tree data\n>    structure.  If you are starting from a clean slate\n>    (i.e. there is no read_cache_from() after you call\n>    discard_cache), you would probably need to discard the old\n>    cache tree; otherwise your next write-tree may produce an\n>    incorrect index file.  If you keep the old one and later\n>    swap it in, the problem might be even more severe.\n\nTrue, I missed that one. But it is just a call to \ncache_tree_free(active_cache_tree); in discard_cache(), right?\n\n>  - index_timestamp is left as the old value in this patch when\n>    you switch cache using read_cache_from() directly.  I have a\n>    suspicion you may be bitten by \"Racy Git\" problem, especially\n>    because the operations are supposed to happen quickly thanks\n>    to the effort of you two ;-) increasing the risks that the\n>    file timestamp of the working tree file and the cached entry\n>    match.\n\nYes. Again, just one line to discard_cache(), right?\n\n\tindex_file_timestamp = 0;\n\nIf there is more to it, please don't let me die dumb.\n\nCiao,\nDscho\n"},{"id":"22986","messageId":"7v64ihdupr.fsf@assigned-by-dhcp.cox.net","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0607011657460.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-07-01T18:51:44Z","receivedAt":"2006-07-01T18:51:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> True, I missed that one. But it is just a call to \n> cache_tree_free(active_cache_tree); in discard_cache(), right?\n\nOn the codepath to write out the new index file, calling\ncache_free_tree(&active_cache_tree) before write_cache() is all\nthat should be needed.  When \"active_cache_tree == NULL\",\nwrite_cache() would write out an index file without the cached\ntree information.\n\nCurrently not many things take advantage of cached tree\ninformation to optimize its operation.  But I'd like to change\nthat.  For example, tree merges by read-tree should be able to\ntake advantage of the fact that a cached tree read from the\nindex and three trees being read all match for a subdirectory\nand do the merge of the directory without descending into it.\n\n>>  - index_timestamp is left as the old value in this patch when\n>>    you switch cache using read_cache_from() directly.  I have a\n>>    suspicion you may be bitten by \"Racy Git\" problem, especially\n>>    because the operations are supposed to happen quickly thanks\n>>    to the effort of you two ;-) increasing the risks that the\n>>    file timestamp of the working tree file and the cached entry\n>>    match.\n>\n> Yes. Again, just one line to discard_cache(), right?\n>\n> \tindex_file_timestamp = 0;\n\nThis one I am not sure.  Read the comment in ce_match_stat() and\nsee the problematic sequence of events that this variable tries\nto help resolve applies to your use.\n"},{"id":"23025","messageId":"Pine.LNX.4.63.0607021043550.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"7v64ihdupr.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-07-02T08:51:37Z","receivedAt":"2006-07-02T08:51:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 1 Jul 2006, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > True, I missed that one. But it is just a call to \n> > cache_tree_free(active_cache_tree); in discard_cache(), right?\n> \n> On the codepath to write out the new index file, calling \n> cache_free_tree(&active_cache_tree) before write_cache() is all that \n> should be needed.  When \"active_cache_tree == NULL\", write_cache() would \n> write out an index file without the cached tree information.\n> \n> Currently not many things take advantage of cached tree information to \n> optimize its operation.  But I'd like to change that.  For example, tree \n> merges by read-tree should be able to take advantage of the fact that a \n> cached tree read from the index and three trees being read all match for \n> a subdirectory and do the merge of the directory without descending into \n> it.\n\nTogether with my argument, that a library function should make life easier \nfor you, not harder, you are making a fine point that the _clean() version \nof get_merge_bases() should clean the active_cache_tree, too.\n\nBesides, is it not better to clean up now-bogus memory anyway?\n\n> >>  - index_timestamp is left as the old value in this patch when\n> >>    you switch cache using read_cache_from() directly.  I have a\n> >>    suspicion you may be bitten by \"Racy Git\" problem, especially\n> >>    because the operations are supposed to happen quickly thanks\n> >>    to the effort of you two ;-) increasing the risks that the\n> >>    file timestamp of the working tree file and the cached entry\n> >>    match.\n> >\n> > Yes. Again, just one line to discard_cache(), right?\n> >\n> > \tindex_file_timestamp = 0;\n> \n> This one I am not sure.  Read the comment in ce_match_stat() and\n> see the problematic sequence of events that this variable tries\n> to help resolve applies to your use.\n\nOkay. After reading the comment, I am quite certain we can just set the \nindex_file_timestamp to 0.\n\nEither we start with an empty cache; In that case it is obviously correct \nto set the timestamp to 0.\n\nOr, after we discard the cache, we have to read a new cache before working \non it. Now, reading the cache means calling read_cache() (or \nread_cache_from()), and -- alas -- line number 12 in the body of that \nfunction sets the timestamp to 0 _anyway_, to be reset to the correct \nvalue later.\n\nSo, I still think that these two lines should be in the cleanup part of \nget_merge_bases().\n\nBTW personally, I prefer the one-function approach, i.e. a flag which says \nif it is okay not to clean up.\n\nCiao,\nDscho\n"},{"id":"23138","messageId":"7virmepfhx.fsf@assigned-by-dhcp.cox.net","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0607021043550.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-07-03T21:04:10Z","receivedAt":"2006-07-03T21:04:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Okay. After reading the comment, I am quite certain we can just set the \n> index_file_timestamp to 0.\n\nThanks.\n\n> So, I still think that these two lines should be in the cleanup part of \n> get_merge_bases().\n\nI think that is sane -- please make it so.\n\n> BTW personally, I prefer the one-function approach, i.e. a flag which says \n> if it is okay not to clean up.\n\nYup. Agreed.\n"},{"id":"23228","messageId":"Pine.LNX.4.63.0607041617290.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4716","inReplyTo":"7virmepfhx.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-07-04T14:18:49Z","receivedAt":"2006-07-04T14:18:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 3 Jul 2006, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > Okay. After reading the comment, I am quite certain we can just set the \n> > index_file_timestamp to 0.\n> \n> Thanks.\n> \n> > So, I still think that these two lines should be in the cleanup part of \n> > get_merge_bases().\n> \n> I think that is sane -- please make it so.\n\nUmmm. After reading my original mail again: bad tobacco that was. Of \ncourse, I meant discard_cache(), not get_merge_bases(). Setting \nindex_file_timestamp in get_merge_bases() would be wrong.\n\nSorry for the noise,\nDscho\n"},{"id":"23232","messageId":"7vodw5gtcp.fsf@assigned-by-dhcp.cox.net","threadId":"4716","inReplyTo":"Pine.LNX.4.63.0607041617290.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] Add read_cache_from() and discard_cache()","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-07-04T17:41:58Z","receivedAt":"2006-07-04T17:41:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Ummm. After reading my original mail again: bad tobacco that was. Of \n> course, I meant discard_cache(), not get_merge_bases(). Setting \n> index_file_timestamp in get_merge_bases() would be wrong.\n\nI was well aware you were talking about discard_cache().  I\nthink these two clean-ups are good to have there.\n"}]}