[PATCH] Handle entry removals during merge correctly.
From: Junio C Hamano <hidden>
Date: 2016-06-15 22:41:59
Subsystem:
the rest · Maintainer:
Linus Torvalds
From: Linus Torvalds <torvalds@osdl.org> We could handle delete the same way - to set the ce_mode to zero and add them to the "dst" array, and teach write-cache not to write them out. Then the same loop that goes around doing the CE_UPDATE thing could check for the delete case. Signed-off-by: Junio C Hamano <redacted> --- *** Linus, did I get the patch submission format right? This is *** essentially what you wrote (with one correction) but not *** really "a forwarded e-mail". read-cache.c | 10 ++++++++-- read-tree.c | 30 ++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c@@ -440,11 +440,15 @@ int write_cache(int newfd, struct cache_ { SHA_CTX c; struct cache_header hdr; - int i; + int i, removed; + + for (i = removed = 0; i < entries; i++) + if (!cache[i]->ce_mode) + removed++; hdr.hdr_signature = htonl(CACHE_SIGNATURE); hdr.hdr_version = htonl(2); - hdr.hdr_entries = htonl(entries); + hdr.hdr_entries = htonl(entries - removed); SHA1_Init(&c); if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
@@ -452,6 +456,8 @@ int write_cache(int newfd, struct cache_ for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; + if (!ce->ce_mode) + continue; if (ce_write(&c, newfd, ce, ce_size(ce)) < 0) return -1; }
diff --git a/read-tree.c b/read-tree.c
--- a/read-tree.c
+++ b/read-tree.c@@ -124,6 +124,15 @@ static int merged_entry(struct cache_ent return 1; } +static int deleted_entry(struct cache_entry *ce, struct cache_entry *old, struct cache_entry **dst) +{ + if (old) + verify_uptodate(old); + ce->ce_mode = 0; + *dst++ = ce; + return 1; +} + static int threeway_merge(struct cache_entry *stages[4], struct cache_entry **dst) { struct cache_entry *i = stages[0];
@@ -181,25 +190,21 @@ static int twoway_merge(struct cache_ent *dst++ = current; return 1; } - else if (oldtree && !newtree && same(current, oldtree)) { + else if (oldtree && !newtree && same(current, oldtree)) /* 10 or 11 */ - verify_uptodate(current); - return 0; - } + return deleted_entry(oldtree, current, dst); else if (oldtree && newtree && - same(current, oldtree) && !same(current, newtree)) { + same(current, oldtree) && !same(current, newtree)) /* 20 or 21 */ - verify_uptodate(current); - return merged_entry(newtree, NULL, dst); - } + return merged_entry(newtree, current, dst); else /* all other failures */ return -1; } else if (newtree) - return merged_entry(newtree, NULL, dst); + return merged_entry(newtree, current, dst); else - return 0; + return deleted_entry(oldtree, current, dst); } /*
@@ -236,6 +241,11 @@ static void check_updates(struct cache_e unsigned short mask = htons(CE_UPDATE); while (nr--) { struct cache_entry *ce = *src++; + if (!ce->ce_mode) { + if (update) + unlink(ce->name); + continue; + } if (ce->ce_flags & mask) { ce->ce_flags &= ~mask; if (update) ------------