[prev in list] [next in list] [prev in thread] [next in thread]
List: git
Subject: [PATCH 3/3] merge-recursive: avoid the pipe to update-index
From: Johannes Schindelin <Johannes.Schindelin () gmx ! de>
Date: 2006-06-30 14:44:47
Message-ID: Pine.LNX.4.63.0606301644210.29667 () wbgn013 ! biozentrum ! uni-wuerzburg ! de
[Download RAW message or body]
Instead of a fork, we can use the plumbing ;-)
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
graph.c | 26 -----
merge-recursive.c | 270 +++++++++++++++++++++++++++++++++++++----------------
2 files changed, 191 insertions(+), 105 deletions(-)
diff --git a/graph.c b/graph.c
index fa2bfee..b784ea2 100644
--- a/graph.c
+++ b/graph.c
@@ -5,32 +5,6 @@ #include "cache.h"
#include "commit.h"
#include "graph.h"
-// does not belong here
-struct tree *git_write_tree()
-{
-#if 0
- fprintf(stderr, "GIT_INDEX_FILE='%s' git-write-tree\n",
- getenv("GIT_INDEX_FILE"));
-#endif
- FILE *fp = popen("git-write-tree 2>/dev/null", "r");
- char buf[41];
- unsigned char sha1[20];
- int ch;
- unsigned i = 0;
- while ( (ch = fgetc(fp)) != EOF )
- if ( i < sizeof(buf)-1 && ch >= '0' && ch <= 'f' )
- buf[i++] = ch;
- else
- break;
- int rc = pclose(fp);
- if ( rc == -1 || WEXITSTATUS(rc) )
- return NULL;
- buf[i] = '\0';
- if ( get_sha1(buf, sha1) != 0 )
- return NULL;
- return lookup_tree(sha1);
-}
-
const char *node_title(struct node *node, int *len)
{
const char *s = "(null commit)";
diff --git a/merge-recursive.c b/merge-recursive.c
index 9bbb426..6d4e797 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -9,6 +9,7 @@ #include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "cache.h"
+#include "cache-tree.h"
#include "commit.h"
#include "blob.h"
#include "tree-walk.h"
@@ -19,6 +20,47 @@ #include "run-command.h"
#include "graph.h"
#include "path-list.h"
+#ifdef DEBUG
+#include "quote.h"
+static void show_ce_entry(const char *tag, struct cache_entry *ce)
+{
+ if (tag && *tag &&
+ (ce->ce_flags & htons(CE_VALID))) {
+ static char alttag[4];
+ memcpy(alttag, tag, 3);
+ if (isalpha(tag[0]))
+ alttag[0] = tolower(tag[0]);
+ else if (tag[0] == '?')
+ alttag[0] = '!';
+ else {
+ alttag[0] = 'v';
+ alttag[1] = tag[0];
+ alttag[2] = ' ';
+ alttag[3] = 0;
+ }
+ tag = alttag;
+ }
+
+ fprintf(stderr,"%s%06o %s %d\t",
+ tag,
+ ntohl(ce->ce_mode),
+ sha1_to_hex(ce->sha1),
+ ce_stage(ce));
+ write_name_quoted("", 0, ce->name,
+ '\n', stderr);
+ fputc('\n', stderr);
+}
+
+static void ls_files() {
+ int i;
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ show_ce_entry("", ce);
+ }
+ fprintf(stderr, "---\n");
+}
+#endif
+
#define for_each_commit(p,list) for ( p = (list); p; p = p->next )
struct merge_result
@@ -94,12 +136,68 @@ static void output(const char *fmt, ...)
static const char *original_index_file;
static const char *temporary_index_file;
+static int cache_dirty = 0;
+
+static int flush_cache()
+{
+ /* flush temporary index */
+ struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+ int fd = hold_lock_file_for_update(lock, getenv("GIT_INDEX_FILE"));
+ if (fd < 0)
+ die("could not lock %s", temporary_index_file);
+ if (write_cache(fd, active_cache, active_nr) ||
+ commit_lock_file(lock))
+ die ("unable to write %s", temporary_index_file);
+ discard_cache();
+ cache_dirty = 0;
+ return 0;
+}
static void setup_index(int temp)
{
const char *idx = temp ? temporary_index_file: original_index_file;
+ if (cache_dirty)
+ die("fatal: cache changed flush_cache();");
unlink(temporary_index_file);
setenv("GIT_INDEX_FILE", idx, 1);
+ discard_cache();
+}
+
+static struct cache_entry *make_cache_entry(unsigned int mode,
+ const unsigned char *sha1, const char *path, int stage, int refresh)
+{
+ int size, len;
+ struct cache_entry *ce;
+
+ if (!verify_path(path))
+ return NULL;
+
+ len = strlen(path);
+ size = cache_entry_size(len);
+ ce = xcalloc(1, size);
+
+ memcpy(ce->sha1, sha1, 20);
+ memcpy(ce->name, path, len);
+ ce->ce_flags = create_ce_flags(len, stage);
+ ce->ce_mode = create_ce_mode(mode);
+
+ if (refresh)
+ return refresh_cache_entry(ce, 0);
+
+ return ce;
+}
+
+static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
+ const char *path, int stage, int refresh, int options)
+{
+ struct cache_entry *ce;
+ if (!cache_dirty)
+ read_cache_from(getenv("GIT_INDEX_FILE"));
+ cache_dirty++;
+ ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
+ if (!ce)
+ return error("cache_addinfo failed: %s", strerror(cache_errno));
+ return add_cache_entry(ce, options);
}
// This is a global variable which is used in a number of places but
@@ -119,6 +217,8 @@ #if 0
sha1_to_hex(tree->object.sha1));
#endif
const char *argv[] = { "git-read-tree", NULL, NULL, };
+ if (cache_dirty)
+ die("read-tree with dirty cache");
argv[1] = sha1_to_hex(tree->object.sha1);
int rc = run_command_v(2, argv);
return rc < 0 ? -1: rc;
@@ -141,6 +241,8 @@ #endif
"git-read-tree", NULL, "-m", NULL, NULL, NULL,
NULL,
};
+ if (cache_dirty)
+ flush_cache();
argv[1] = update_arg;
argv[3] = sha1_to_hex(common->object.sha1);
argv[4] = sha1_to_hex(head->object.sha1);
@@ -149,6 +251,33 @@ #endif
return rc < 0 ? -1: rc;
}
+struct tree *git_write_tree()
+{
+#if 0
+ fprintf(stderr, "GIT_INDEX_FILE='%s' git-write-tree\n",
+ getenv("GIT_INDEX_FILE"));
+#endif
+ if (cache_dirty)
+ flush_cache();
+ FILE *fp = popen("git-write-tree 2>/dev/null", "r");
+ char buf[41];
+ unsigned char sha1[20];
+ int ch;
+ unsigned i = 0;
+ while ( (ch = fgetc(fp)) != EOF )
+ if ( i < sizeof(buf)-1 && ch >= '0' && ch <= 'f' )
+ buf[i++] = ch;
+ else
+ break;
+ int rc = pclose(fp);
+ if ( rc == -1 || WEXITSTATUS(rc) )
+ return NULL;
+ buf[i] = '\0';
+ if ( get_sha1(buf, sha1) != 0 )
+ return NULL;
+ return lookup_tree(sha1);
+}
+
struct merge_tree_result merge_trees(struct tree *head,
struct tree *merge,
struct tree *common,
@@ -640,36 +769,25 @@ struct rename_entry *getRenames(struct t
return renames;
}
-static FILE *git_update_index_pipe()
-{
- return popen("git-update-index -z --index-info", "w");
-}
-
-int setIndexStages(FILE *fp,
- const char *path,
+int setIndexStages(const char *path,
unsigned char *osha, unsigned omode,
unsigned char *asha, unsigned amode,
unsigned char *bsha, unsigned bmode,
int clear /* =True */)
{
- if ( !fp )
- return -1;
- if ( clear ) {
- fprintf(fp, "0 %s\t%s", sha1_to_hex(null_sha1), path);
- fputc('\0', fp);
- }
- if ( omode ) {
- fprintf(fp, "0%o %s 1\t%s", omode, sha1_to_hex(osha), path);
- fputc('\0', fp);
- }
- if ( amode ) {
- fprintf(fp, "0%o %s 2\t%s", amode, sha1_to_hex(asha), path);
- fputc('\0', fp);
- }
- if ( bmode ) {
- fprintf(fp, "0%o %s 3\t%s", bmode, sha1_to_hex(bsha), path);
- fputc('\0', fp);
- }
+ int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
+ if ( clear )
+ if (add_cacheinfo(0, null_sha1, path, 0, 0, options))
+ return -1;
+ if ( omode )
+ if (add_cacheinfo(omode, osha, path, 1, 0, options))
+ return -1;
+ if ( amode )
+ if (add_cacheinfo(omode, osha, path, 2, 0, options))
+ return -1;
+ if ( bmode )
+ if (add_cacheinfo(omode, osha, path, 3, 0, options))
+ return -1;
return 0;
}
@@ -695,17 +813,17 @@ static int remove_path(const char *name)
return ret;
}
-int removeFile(FILE *fp, int clean, const char *path)
+int removeFile(int clean, const char *path)
{
int updateCache = index_only || clean;
int updateWd = !index_only;
if ( updateCache ) {
- if ( !fp )
+ if (!cache_dirty)
+ read_cache_from(getenv("GIT_INDEX_FILE"));
+ cache_dirty++;
+ if (remove_file_from_cache(path))
return -1;
- fprintf(fp, "0 %s\t%s", sha1_to_hex(null_sha1), path);
- fputc('\0', fp);
- return 0;
}
if ( updateWd )
{
@@ -785,8 +903,7 @@ static void flush_buffer(int fd, const c
}
}
-void updateFileExt(FILE *fp,
- const unsigned char *sha,
+void updateFileExt(const unsigned char *sha,
unsigned mode,
const char *path,
int updateCache,
@@ -830,20 +947,15 @@ void updateFileExt(FILE *fp,
mode, sha1_to_hex(sha), path);
}
if ( updateCache )
- {
- // XXX just always use "git update-index --index-info"?
- fprintf(fp, "%06o %s\t%s", mode, sha1_to_hex(sha), path);
- fputc('\0', fp);
- }
+ add_cacheinfo(mode, sha, path, 0, updateWd, ADD_CACHE_OK_TO_ADD);
}
-void updateFile(FILE *fp,
- int clean,
+void updateFile(int clean,
const unsigned char *sha,
unsigned mode,
const char *path)
{
- updateFileExt(fp, sha, mode, path, index_only || clean, !index_only);
+ updateFileExt(sha, mode, path, index_only || clean, !index_only);
}
// Low level file merging, update and removal
@@ -1004,7 +1116,6 @@ int processRenames(struct rename_entry *
for (sre = renamesB; sre; sre = sre->next)
path_list_insert(sre->src, &srcNames);
- FILE *fp = git_update_index_pipe();
for_each_path(src,&srcNames) {
struct rename_entry *renames1, *renames2, *ren1, *ren2;
const char *branchName1, *branchName2;
@@ -1050,26 +1161,26 @@ int processRenames(struct rename_entry *
dstName1 = uniquePath(ren1->dst, branchName1);
output("%s is a directory in %s adding as %s instead",
ren1->dst, branchName2, dstName1);
- removeFile(fp, 0, ren1->dst);
+ removeFile(0, ren1->dst);
}
if ( path_list_has_path(¤tDirectorySet, ren2->dst) ) {
dstName2 = uniquePath(ren2->dst, branchName2);
output("%s is a directory in %s adding as %s instead",
ren2->dst, branchName1, dstName2);
- removeFile(fp, 0, ren2->dst);
+ removeFile(0, ren2->dst);
}
- setIndexStages(fp, dstName1,
+ setIndexStages(dstName1,
NULL, 0,
ren1->dst_sha, ren1->dst_mode,
NULL, 0,
1 /* clear */);
- setIndexStages(fp, dstName2,
+ setIndexStages(dstName2,
NULL, 0,
NULL, 0,
ren2->dst_sha, ren2->dst_mode,
1 /* clear */);
} else {
- removeFile(fp, 1, ren1->src);
+ removeFile(1, ren1->src);
struct merge_file_info mfi;
mfi = mergeFile(ren1->src, ren1->src_sha, ren1->src_mode,
ren1->dst, ren1->dst_sha, ren1->dst_mode,
@@ -1087,18 +1198,17 @@ int processRenames(struct rename_entry *
cleanMerge = 0;
if ( !index_only )
- setIndexStages(fp,
- ren1->dst,
+ setIndexStages(ren1->dst,
ren1->src_sha, ren1->src_mode,
ren1->dst_sha, ren1->dst_mode,
ren2->dst_sha, ren2->dst_mode,
1 /* clear */);
}
- updateFile(fp, mfi.clean, mfi.sha, mfi.mode, ren1->dst);
+ updateFile(mfi.clean, mfi.sha, mfi.mode, ren1->dst);
}
} else {
// Renamed in 1, maybe changed in 2
- removeFile(fp, 1, ren1->src);
+ removeFile(1, ren1->src);
unsigned char srcShaOtherBranch[20], dstShaOtherBranch[20];
unsigned srcModeOtherBranch, dstModeOtherBranch;
@@ -1123,15 +1233,15 @@ int processRenames(struct rename_entry *
ren1->dst, branchName2);
output("Renaming %s to %s instead", ren1->src, newPath);
cleanMerge = 0;
- removeFile(fp, 0, ren1->dst);
- updateFile(fp, 0, ren1->dst_sha, ren1->dst_mode, newPath);
+ removeFile(0, ren1->dst);
+ updateFile(0, ren1->dst_sha, ren1->dst_mode, newPath);
} else if ( memcmp(srcShaOtherBranch, null_sha1, 20) == 0 ) {
output("CONFLICT (rename/delete): Rename %s->%s in %s "
"and deleted in %s",
ren1->src, ren1->dst, branchName1,
branchName2);
cleanMerge = 0;
- updateFile(fp, 0, ren1->dst_sha, ren1->dst_mode, ren1->dst);
+ updateFile(0, ren1->dst_sha, ren1->dst_mode, ren1->dst);
} else if ( memcmp(dstShaOtherBranch, null_sha1, 20) != 0 ) {
newPath = uniquePath(ren1->dst, branchName2);
output("CONFLICT (rename/add): Rename %s->%s in %s. "
@@ -1139,7 +1249,7 @@ int processRenames(struct rename_entry *
ren1->src, ren1->dst, branchName1,
ren1->dst, branchName2);
output("Adding as %s instead", newPath);
- updateFile(fp, 0, dstShaOtherBranch, dstModeOtherBranch, newPath);
+ updateFile(0, dstShaOtherBranch, dstModeOtherBranch, newPath);
cleanMerge = 0;
tryMerge = 1;
} else if ( (dst2 = find_rename_bydst(renames2, ren1->dst)) ) {
@@ -1151,9 +1261,9 @@ int processRenames(struct rename_entry *
dst2->src, dst2->dst, branchName2);
output("Renaming %s to %s and %s to %s instead",
ren1->src, newPath1, dst2->src, newPath2);
- removeFile(fp, 0, ren1->dst);
- updateFile(fp, 0, ren1->dst_sha, ren1->dst_mode, newPath1);
- updateFile(fp, 0, dst2->dst_sha, dst2->dst_mode, newPath2);
+ removeFile(0, ren1->dst);
+ updateFile(0, ren1->dst_sha, ren1->dst_mode, newPath1);
+ updateFile(0, dst2->dst_sha, dst2->dst_mode, newPath2);
dst2->processed = 1;
cleanMerge = 0;
} else
@@ -1194,21 +1304,19 @@ int processRenames(struct rename_entry *
cleanMerge = 0;
if ( !index_only )
- setIndexStages(fp,
- ren1->dst,
+ setIndexStages(ren1->dst,
osha, omode,
asha, amode,
bsha, bmode,
1 /* clear */);
}
- updateFile(fp, mfi.clean, mfi.sha, mfi.mode, ren1->dst);
+ updateFile(mfi.clean, mfi.sha, mfi.mode, ren1->dst);
}
}
}
path_list_clear(&srcNames, 0);
- if (pclose(fp)) {
- die("git update-index --index-info failed");
- }
+ if (cache_dirty)
+ flush_cache();
return cleanMerge;
}
@@ -1241,7 +1349,6 @@ int processEntry(struct index_entry *ent
unsigned oMode = entry->stages[1].mode;
unsigned aMode = entry->stages[2].mode;
unsigned bMode = entry->stages[3].mode;
- FILE *fp = git_update_index_pipe();
if ( oSha && (!aSha || !bSha) ) {
//
@@ -1253,7 +1360,7 @@ int processEntry(struct index_entry *ent
// Deleted in both or deleted in one and unchanged in the other
if ( aSha )
output("Removing %s", path);
- removeFile(fp, 1, path);
+ removeFile(1, path);
} else {
// Deleted in one and changed in the other
cleanMerge = 0;
@@ -1262,13 +1369,13 @@ int processEntry(struct index_entry *ent
"and modified in %s. Version %s of %s left in tree.",
path, branch1Name,
branch2Name, branch2Name, path);
- updateFile(fp, 0, bSha, bMode, path);
+ updateFile(0, bSha, bMode, path);
} else {
output("CONFLICT (delete/modify): %s deleted in %s "
"and modified in %s. Version %s of %s left in tree.",
path, branch2Name,
branch1Name, branch1Name, path);
- updateFile(fp, 0, aSha, aMode, path);
+ updateFile(0, aSha, aMode, path);
}
}
@@ -1302,11 +1409,11 @@ int processEntry(struct index_entry *ent
output("CONFLICT (%s): There is a directory with name %s in %s. "
"Adding %s as %s",
conf, path, otherBranch, path, newPath);
- removeFile(fp, 0, path);
- updateFile(fp, 0, sha, mode, newPath);
+ removeFile(0, path);
+ updateFile(0, sha, mode, newPath);
} else {
output("Adding %s", path);
- updateFile(fp, 1, sha, mode, path);
+ updateFile(1, sha, mode, path);
}
} else if ( !oSha && aSha && bSha ) {
//
@@ -1319,7 +1426,7 @@ int processEntry(struct index_entry *ent
"but permissions conflict %06o->%06o",
path, aMode, bMode);
output("CONFLICT: adding with permission: %06o", aMode);
- updateFile(fp, 0, aSha, aMode, path);
+ updateFile(0, aSha, aMode, path);
} else {
// This case is handled by git-read-tree
assert(0 && "This case must be handled by git-read-tree");
@@ -1331,9 +1438,9 @@ int processEntry(struct index_entry *ent
output("CONFLICT (add/add): File %s added non-identically "
"in both branches. Adding as %s and %s instead.",
path, newPath1, newPath2);
- removeFile(fp, 0, path);
- updateFile(fp, 0, aSha, aMode, newPath1);
- updateFile(fp, 0, bSha, bMode, newPath2);
+ removeFile(0, path);
+ updateFile(0, aSha, aMode, newPath1);
+ updateFile(0, bSha, bMode, newPath2);
}
} else if ( oSha && aSha && bSha ) {
@@ -1348,22 +1455,23 @@ int processEntry(struct index_entry *ent
branch1Name, branch2Name);
if ( mfi.clean )
- updateFile(fp, 1, mfi.sha, mfi.mode, path);
+ updateFile(1, mfi.sha, mfi.mode, path);
else {
cleanMerge = 0;
output("CONFLICT (content): Merge conflict in %s", path);
if ( index_only )
- updateFile(fp, 0, mfi.sha, mfi.mode, path);
+ updateFile(0, mfi.sha, mfi.mode, path);
else
- updateFileExt(fp, mfi.sha, mfi.mode, path,
+ updateFileExt(mfi.sha, mfi.mode, path,
0 /* updateCache */, 1 /* updateWd */);
}
} else
die("Fatal merge failure, shouldn't happen.");
- if (pclose(fp))
- die("updating entry failed in git update-index");
+ if (cache_dirty)
+ flush_cache();
+
return cleanMerge;
}
@@ -1570,6 +1678,10 @@ int main(int argc, char *argv[])
struct graph *graph = graph_build(commits);
result = merge(h1, h2, branch1, branch2, graph, 0, NULL);
}
+
+ if (cache_dirty)
+ flush_cache();
+
return result.clean ? 0: 1;
}
--
1.4.1.rc1.gb2d14
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic