* [bug] git `next' does not do trivial merges
@ 2008-08-22 6:36 Paolo Bonzini
2008-08-22 19:31 ` Jeff King
0 siblings, 1 reply; 22+ messages in thread
From: Paolo Bonzini @ 2008-08-22 6:36 UTC (permalink / raw)
To: git
I had already posted this bug report yesterday but it was hidden in a
cover letter at
http://permalink.gmane.org/gmane.comp.version-control.git/93143 -- so
I'll copy the relevant info here:
> The included testcases demonstrate that trivial merges are
> currently broken. The failing test is:
>
> git init
> echo a > a
> git add a
> git commit -ma
> git checkout -b branch
> echo b > b
> git add b
> git commit -mb
> git checkout master
> git merge --no-ff -s resolve branch
>
> Running this in 1.5.5 shows:
>
> Trying really trivial in-index merge...
> Wonderful.
> In-index merge
>
> while `next' gives
>
> Trying really trivial in-index merge...
> error: Untracked working tree file 'a' would be overwritten by merge.
> Nope.
> Trying simple merge.
> Merge made by resolve.
Paolo
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [bug] git `next' does not do trivial merges 2008-08-22 6:36 [bug] git `next' does not do trivial merges Paolo Bonzini @ 2008-08-22 19:31 ` Jeff King 2008-08-23 6:08 ` Miklos Vajna 0 siblings, 1 reply; 22+ messages in thread From: Jeff King @ 2008-08-22 19:31 UTC (permalink / raw) To: Paolo Bonzini; +Cc: Miklos Vajna, git On Fri, Aug 22, 2008 at 08:36:39AM +0200, Paolo Bonzini wrote: > I had already posted this bug report yesterday but it was hidden in a > cover letter at > http://permalink.gmane.org/gmane.comp.version-control.git/93143 -- so > I'll copy the relevant info here: Sadly, this bisects to 1c7b76b (Build in merge). -Peff ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [bug] git `next' does not do trivial merges 2008-08-22 19:31 ` Jeff King @ 2008-08-23 6:08 ` Miklos Vajna 2008-08-23 8:14 ` [PATCH] Fix in-index merge Miklos Vajna 0 siblings, 1 reply; 22+ messages in thread From: Miklos Vajna @ 2008-08-23 6:08 UTC (permalink / raw) To: Jeff King; +Cc: Paolo Bonzini, git [-- Attachment #1: Type: text/plain, Size: 631 bytes --] On Fri, Aug 22, 2008 at 03:31:17PM -0400, Jeff King <peff@peff.net> wrote: > On Fri, Aug 22, 2008 at 08:36:39AM +0200, Paolo Bonzini wrote: > > > I had already posted this bug report yesterday but it was hidden in a > > cover letter at > > http://permalink.gmane.org/gmane.comp.version-control.git/93143 -- so > > I'll copy the relevant info here: > > Sadly, this bisects to 1c7b76b (Build in merge). I guessed the bug is in builtin-merge.c::read_tree_trivial(), but I don't see how it is different to builtin-read-tree.c::cmd_read_tree(), at least the unpack_trees_options struct is the same. I'm on it.. [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] Fix in-index merge. 2008-08-23 6:08 ` Miklos Vajna @ 2008-08-23 8:14 ` Miklos Vajna 2008-08-23 8:17 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Miklos Vajna ` (2 more replies) 0 siblings, 3 replies; 22+ messages in thread From: Miklos Vajna @ 2008-08-23 8:14 UTC (permalink / raw) To: Junio C Hamano; +Cc: Paolo Bonzini, Jeff King, git There were 3 issues: 1) We need read_cache() before using unpack_trees(). 2) commit_tree() frees the parents, so we need to malloc them. 3) The current HEAD was missing from the parent list. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Fri, Aug 22, 2008 at 08:36:39AM +0200, Paolo Bonzini <bonzini@gnu.org> wrote: > I had already posted this bug report yesterday but it was hidden in a > cover > letter at > http://permalink.gmane.org/gmane.comp.version-control.git/93143 This should fix the issue. builtin-merge.c | 11 +++++++---- t/t7607-merge-inindex.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100755 t/t7607-merge-inindex.sh diff --git a/builtin-merge.c b/builtin-merge.c index a201c66..dffe4b8 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -469,6 +469,7 @@ static int read_tree_trivial(unsigned char *common, unsigned char *head, struct tree_desc t[MAX_UNPACK_TREES]; struct unpack_trees_options opts; + read_cache(); memset(&opts, 0, sizeof(opts)); opts.head_idx = 2; opts.src_index = &the_index; @@ -651,13 +652,15 @@ static void add_strategies(const char *string, unsigned attr) static int merge_trivial(void) { unsigned char result_tree[20], result_commit[20]; - struct commit_list parent; + struct commit_list *parent = xmalloc(sizeof(struct commit_list *)); write_tree_trivial(result_tree); printf("Wonderful.\n"); - parent.item = remoteheads->item; - parent.next = NULL; - commit_tree(merge_msg.buf, result_tree, &parent, result_commit); + parent->item = lookup_commit(head); + parent->next = xmalloc(sizeof(struct commit_list *)); + parent->next->item = remoteheads->item; + parent->next->next = NULL; + commit_tree(merge_msg.buf, result_tree, parent, result_commit); finish(result_commit, "In-index merge"); drop_save(); return 0; diff --git a/t/t7607-merge-inindex.sh b/t/t7607-merge-inindex.sh new file mode 100755 index 0000000..98b778f --- /dev/null +++ b/t/t7607-merge-inindex.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +test_description='git-merge + +Testing in-index merge.' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo a > a && + git add a && + git commit -m a && + git tag a && + git checkout -b branch + echo b > b && + git add b && + git commit -m b && + git tag b +' + +test_expect_success 'in-index merge' ' + git checkout master && + git merge --no-ff -s resolve branch > out && + grep Wonderful. out && + test "$(git rev-parse a)" = "$(git rev-parse HEAD^1)" && + test "$(git rev-parse b)" = "$(git rev-parse HEAD^2)" +' + +test_done -- 1.6.0.rc3.17.gc14c8.dirty ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge 2008-08-23 8:14 ` [PATCH] Fix in-index merge Miklos Vajna @ 2008-08-23 8:17 ` Miklos Vajna 2008-08-23 9:01 ` Junio C Hamano 2008-08-23 9:50 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Junio C Hamano 2008-08-23 8:50 ` [PATCH] Fix in-index merge Junio C Hamano 2008-08-23 9:19 ` Paolo Bonzini 2 siblings, 2 replies; 22+ messages in thread From: Miklos Vajna @ 2008-08-23 8:17 UTC (permalink / raw) To: Junio C Hamano; +Cc: Paolo Bonzini, Jeff King, git Using unmerged_cache() without reading the cache first never will return anything. However, if we read the cache early then we have to discard it when we want to read it again from the disk. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- The code part is pretty much from you, I wanted to add your signoff, but then realized that you'll do it anyway. ;-) builtin-merge.c | 6 +++--- t/t7608-merge-dirty.sh | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100755 t/t7608-merge-dirty.sh diff --git a/builtin-merge.c b/builtin-merge.c index dffe4b8..71bd13b 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -565,8 +565,6 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote) struct dir_struct dir; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - if (read_cache_unmerged()) - die("you need to resolve your current index first"); refresh_cache(REFRESH_QUIET); fd = hold_locked_index(lock_file, 1); @@ -746,6 +744,7 @@ static int evaluate_result(void) int cnt = 0; struct rev_info rev; + discard_cache(); if (read_cache() < 0) die("failed to read the cache"); @@ -779,7 +778,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) struct commit_list **remotes = &remoteheads; setup_work_tree(); - if (unmerged_cache()) + if (read_cache_unmerged()) die("You are in the middle of a conflicted merge."); /* @@ -1076,6 +1075,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } /* Automerge succeeded. */ + discard_cache(); write_tree_trivial(result_tree); automerge_was_ok = 1; break; diff --git a/t/t7608-merge-dirty.sh b/t/t7608-merge-dirty.sh new file mode 100755 index 0000000..fb567f6 --- /dev/null +++ b/t/t7608-merge-dirty.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +test_description='git-merge + +Merge should fail if the index has unresolved entries.' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo a > a && + git add a && + git commit -m a && + git tag a && + git checkout -b branch1 + echo b > a && + git add a && + git commit -m b && + git tag b + git checkout -b branch2 HEAD~1 + echo c > a && + git add a && + git commit -m c && + git tag c +' + +test_expect_success 'in-index merge' ' + git checkout branch1 && + test_must_fail git merge branch2 && + test_must_fail git merge branch2 2> out && + grep "You are in the middle of a conflicted merge" out +' + +test_done -- 1.6.0.rc3.17.gc14c8.dirty ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge 2008-08-23 8:17 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Miklos Vajna @ 2008-08-23 9:01 ` Junio C Hamano 2008-08-23 10:57 ` Miklos Vajna 2008-08-23 9:50 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Junio C Hamano 1 sibling, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 9:01 UTC (permalink / raw) To: Miklos Vajna; +Cc: Paolo Bonzini, Jeff King, git Miklos Vajna <vmiklos@frugalware.org> writes: > Using unmerged_cache() without reading the cache first never will return > anything. However, if we read the cache early then we have to discard it > when we want to read it again from the disk. With this, I do not think you would need to keep the read_cache() you added to the beginning of the read_tree_trivial(), for the same reason you are removing read_cache_unmerged() from the beginning of checkout_fast_forward() in this patch. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge 2008-08-23 9:01 ` Junio C Hamano @ 2008-08-23 10:57 ` Miklos Vajna 2008-08-23 19:55 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Miklos Vajna @ 2008-08-23 10:57 UTC (permalink / raw) To: Junio C Hamano; +Cc: Paolo Bonzini, Jeff King, git Using unmerged_cache() without reading the cache first never will return anything. However, if we read the cache early then we have to discard it when we want to read it again from the disk. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Sat, Aug 23, 2008 at 02:01:43AM -0700, Junio C Hamano <gitster@pobox.com> wrote: > With this, I do not think you would need to keep the read_cache() you > added to the beginning of the read_tree_trivial(), for the same reason > you > are removing read_cache_unmerged() from the beginning of > checkout_fast_forward() in this patch. Right, I removed it as well. Also fixed the testcase (no more new file). builtin-merge.c | 7 +++---- t/t3030-merge-recursive.sh | 11 +++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/builtin-merge.c b/builtin-merge.c index dffe4b8..b280444 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -469,7 +469,6 @@ static int read_tree_trivial(unsigned char *common, unsigned char *head, struct tree_desc t[MAX_UNPACK_TREES]; struct unpack_trees_options opts; - read_cache(); memset(&opts, 0, sizeof(opts)); opts.head_idx = 2; opts.src_index = &the_index; @@ -565,8 +564,6 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote) struct dir_struct dir; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - if (read_cache_unmerged()) - die("you need to resolve your current index first"); refresh_cache(REFRESH_QUIET); fd = hold_locked_index(lock_file, 1); @@ -746,6 +743,7 @@ static int evaluate_result(void) int cnt = 0; struct rev_info rev; + discard_cache(); if (read_cache() < 0) die("failed to read the cache"); @@ -779,7 +777,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) struct commit_list **remotes = &remoteheads; setup_work_tree(); - if (unmerged_cache()) + if (read_cache_unmerged()) die("You are in the middle of a conflicted merge."); /* @@ -1076,6 +1074,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } /* Automerge succeeded. */ + discard_cache(); write_tree_trivial(result_tree); automerge_was_ok = 1; break; diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index aff3603..f288015 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -269,6 +269,17 @@ test_expect_success 'merge-recursive result' ' ' +test_expect_success 'fail if the index has unresolved entries' ' + + rm -fr [abcd] && + git checkout -f "$c1" && + + test_must_fail git merge "$c5" && + test_must_fail git merge "$c5" 2> out && + grep "You are in the middle of a conflicted merge" out + +' + test_expect_success 'merge-recursive remove conflict' ' rm -fr [abcd] && -- 1.6.0.rc3.17.gc14c8.dirty ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge 2008-08-23 10:57 ` Miklos Vajna @ 2008-08-23 19:55 ` Junio C Hamano 2008-08-23 19:56 ` [PATCH 1/2] merge: fix numerus bugs around "trivial merge" area Junio C Hamano 2008-08-23 19:57 ` [PATCH 2/2] unpack_trees(): protect the handcrafted in-core index from read_cache() Junio C Hamano 0 siblings, 2 replies; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 19:55 UTC (permalink / raw) To: Miklos Vajna; +Cc: Paolo Bonzini, Jeff King, git We've exchanged quite a few "here is a better one", "oops, that is not enough", which is confusing to bystanders. Here is my proposed final series, meant to be applied to 'maint'. [1/2] merge: fix numerus bugs around "trivial merge" area [2/2] unpack_trees(): protect the handcrafted in-core index from read_cache() ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/2] merge: fix numerus bugs around "trivial merge" area 2008-08-23 19:55 ` Junio C Hamano @ 2008-08-23 19:56 ` Junio C Hamano 2008-08-24 1:58 ` Junio C Hamano 2008-08-23 19:57 ` [PATCH 2/2] unpack_trees(): protect the handcrafted in-core index from read_cache() Junio C Hamano 1 sibling, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 19:56 UTC (permalink / raw) To: Miklos Vajna; +Cc: Paolo Bonzini, Jeff King, git The "trivial merge" codepath wanted to optimize itself by making an internal call to the read-tree machinery, but it did not read the index before doing so, and the codepath was never exercised. Incidentally, this failure to read the index upfront meant that the safety to refuse doing anything when the index is unmerged did not kick in, either. These two problem are fixed by using read_cache_unmerged() that does read the index before checking if it is unmerged at the beginning of cmd_merge(). The primary logic of the merge, however, had an assumption that the process never read the index in-core, and write_cache_as_tree() call it makes from write_tree_trivial() will always read from the on-disk index the strategies created and write it out as a tree. This assumption is now broken by the above fix. It now calls discard_cache() before calling write_tree_trivial() when it wants to write the on-disk index as a tree to fix this issue. When multiple strategies are tried, their results are evaluated by reading the resulting index and inspecting it. The codepath needs to make a call to read_cache() for each successful strategy, and for that to work, they need to discard_cache() the one from the previous round. Also the "trivial merge" forgot that the current commit is one of the parents of the resulting commit. This still has breakage in the way it writes out the resulting tree out of the trivial merge codepath, which is a topic of the next patch. One test in t7605-merge-resolve.sh exposes this breakage. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-merge.c | 16 +++++++++------- t/t3030-merge-recursive.sh | 11 +++++++++++ t/t7600-merge.sh | 9 +++++++++ t/t7605-merge-resolve.sh | 6 ++++-- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/builtin-merge.c b/builtin-merge.c index a201c66..b280444 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -564,8 +564,6 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote) struct dir_struct dir; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - if (read_cache_unmerged()) - die("you need to resolve your current index first"); refresh_cache(REFRESH_QUIET); fd = hold_locked_index(lock_file, 1); @@ -651,13 +649,15 @@ static void add_strategies(const char *string, unsigned attr) static int merge_trivial(void) { unsigned char result_tree[20], result_commit[20]; - struct commit_list parent; + struct commit_list *parent = xmalloc(sizeof(struct commit_list *)); write_tree_trivial(result_tree); printf("Wonderful.\n"); - parent.item = remoteheads->item; - parent.next = NULL; - commit_tree(merge_msg.buf, result_tree, &parent, result_commit); + parent->item = lookup_commit(head); + parent->next = xmalloc(sizeof(struct commit_list *)); + parent->next->item = remoteheads->item; + parent->next->next = NULL; + commit_tree(merge_msg.buf, result_tree, parent, result_commit); finish(result_commit, "In-index merge"); drop_save(); return 0; @@ -743,6 +743,7 @@ static int evaluate_result(void) int cnt = 0; struct rev_info rev; + discard_cache(); if (read_cache() < 0) die("failed to read the cache"); @@ -776,7 +777,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) struct commit_list **remotes = &remoteheads; setup_work_tree(); - if (unmerged_cache()) + if (read_cache_unmerged()) die("You are in the middle of a conflicted merge."); /* @@ -1073,6 +1074,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } /* Automerge succeeded. */ + discard_cache(); write_tree_trivial(result_tree); automerge_was_ok = 1; break; diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index aff3603..f288015 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -269,6 +269,17 @@ test_expect_success 'merge-recursive result' ' ' +test_expect_success 'fail if the index has unresolved entries' ' + + rm -fr [abcd] && + git checkout -f "$c1" && + + test_must_fail git merge "$c5" && + test_must_fail git merge "$c5" 2> out && + grep "You are in the middle of a conflicted merge" out + +' + test_expect_success 'merge-recursive remove conflict' ' rm -fr [abcd] && diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index fee8fb7..dbc90bc 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -498,4 +498,13 @@ test_expect_success 'merge fast-forward in a dirty tree' ' test_debug 'gitk --all' +test_expect_success 'in-index merge' ' + git reset --hard c0 && + git merge --no-ff -s resolve c1 > out && + grep "Wonderful." out && + verify_parents $c0 $c1 +' + +test_debug 'gitk --all' + test_done diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh index ee21a10..5c53608 100755 --- a/t/t7605-merge-resolve.sh +++ b/t/t7605-merge-resolve.sh @@ -27,7 +27,7 @@ test_expect_success 'setup' ' git tag c3 ' -test_expect_success 'merge c1 to c2' ' +test_expect_failure 'merge c1 to c2' ' git reset --hard c1 && git merge -s resolve c2 && test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" && @@ -36,7 +36,9 @@ test_expect_success 'merge c1 to c2' ' git diff --exit-code && test -f c0.c && test -f c1.c && - test -f c2.c + test -f c2.c && + test 3 = $(git ls-tree -r HEAD | wc -l) && + test 3 = $(git ls-files | wc -l) ' test_expect_success 'merge c2 to c3 (fails)' ' -- 1.6.0.51.g078ae ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 1/2] merge: fix numerus bugs around "trivial merge" area 2008-08-23 19:56 ` [PATCH 1/2] merge: fix numerus bugs around "trivial merge" area Junio C Hamano @ 2008-08-24 1:58 ` Junio C Hamano 2008-08-28 13:43 ` [PATCH] builtin-merge: avoid run_command_v_opt() for recursive and subtree Miklos Vajna 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-24 1:58 UTC (permalink / raw) To: Miklos Vajna; +Cc: Paolo Bonzini, Jeff King, git Junio C Hamano <gitster@pobox.com> writes: > The primary logic of the merge, however, had an assumption that the > process never read the index in-core, and write_cache_as_tree() call it > makes from write_tree_trivial() will always read from the on-disk index > the strategies created and write it out as a tree. This assumption is now > broken by the above fix. It now calls discard_cache() before calling > write_tree_trivial() when it wants to write the on-disk index as a tree to > fix this issue. By the way, in the medium term, if we are serious about making an internal call to merge_recursive() from cmd_merge(), I think we may be better off making it the responsibility for try_merge_strategy() to leave an committable state in the in-core index (aka "the_index") when they return with 0 (success) status. After calling external ones via the run_command interface, it should do a read_cache() (after calling discard_cache() if needed); if it calls merge_recursive(), hopefully you already have the committable state in the in-core index. That way, when automerge succeeds, write_tree_trivial() can write that in-core index out and create the tree object to be committed. The callchain to use merge_recursive() can avoid having to write to the on-disk index, read it again and write out the tree from it. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] builtin-merge: avoid run_command_v_opt() for recursive and subtree 2008-08-24 1:58 ` Junio C Hamano @ 2008-08-28 13:43 ` Miklos Vajna 0 siblings, 0 replies; 22+ messages in thread From: Miklos Vajna @ 2008-08-28 13:43 UTC (permalink / raw) To: Junio C Hamano; +Cc: Paolo Bonzini, Jeff King, git, Johannes Schindelin The try_merge_strategy() function always ran the strategy in a separate process, though this is not always necessary. The recursive and subtree strategy can be called without a fork(). This patch adds a check, and calls recursive in the same process without wasting resources. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Sat, Aug 23, 2008 at 06:58:37PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > By the way, in the medium term, if we are serious about making an > internal call to merge_recursive() from cmd_merge(), I think we may be > better off making it the responsibility for try_merge_strategy() to > leave an committable state in the in-core index (aka "the_index") when > they return with 0 (success) status. After calling external ones via > the run_command interface, it should do a read_cache() (after calling > discard_cache() if needed); if it calls merge_recursive(), hopefully > you already have the committable state in the in-core index. > > That way, when automerge succeeds, write_tree_trivial() can write that > in-core index out and create the tree object to be committed. The > callchain to use merge_recursive() can avoid having to write to the > on-disk index, read it again and write out the tree from it. This is mostly the same patch I submitted earlier, but this is now on top of mv/merge-recursive, and now it does what you suggested above. builtin-merge.c | 92 +++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 63 insertions(+), 29 deletions(-) diff --git a/builtin-merge.c b/builtin-merge.c index 0bff26e..3a38089 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -22,6 +22,7 @@ #include "log-tree.h" #include "color.h" #include "rerere.h" +#include "merge-recursive.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -511,28 +512,64 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, struct commit_list *j; struct strbuf buf; - args = xmalloc((4 + commit_list_count(common) + - commit_list_count(remoteheads)) * sizeof(char *)); - strbuf_init(&buf, 0); - strbuf_addf(&buf, "merge-%s", strategy); - args[i++] = buf.buf; - for (j = common; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); - args[i++] = "--"; - args[i++] = head_arg; - for (j = remoteheads; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); - args[i] = NULL; - ret = run_command_v_opt(args, RUN_GIT_CMD); - strbuf_release(&buf); - i = 1; - for (j = common; j; j = j->next) - free((void *)args[i++]); - i += 2; - for (j = remoteheads; j; j = j->next) - free((void *)args[i++]); - free(args); - return -ret; + if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { + int clean; + struct commit *result; + struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + int index_fd; + struct commit_list *reversed = NULL; + struct merge_options o; + + if (remoteheads->next) { + error("Not handling anything other than two heads merge."); + return 2; + } + + init_merge_options(&o); + if (!strcmp(strategy, "subtree")) + o.subtree_merge = 1; + + o.branch1 = head_arg; + o.branch2 = remoteheads->item->util; + + for (j = common; j; j = j->next) + commit_list_insert(j->item, &reversed); + + index_fd = hold_locked_index(lock, 1); + clean = merge_recursive(&o, lookup_commit(head), + remoteheads->item, reversed, &result); + if (active_cache_changed && + (write_cache(index_fd, active_cache, active_nr) || + commit_locked_index(lock))) + die ("unable to write %s", get_index_file()); + return clean ? 0 : 1; + } else { + args = xmalloc((4 + commit_list_count(common) + + commit_list_count(remoteheads)) * sizeof(char *)); + strbuf_init(&buf, 0); + strbuf_addf(&buf, "merge-%s", strategy); + args[i++] = buf.buf; + for (j = common; j; j = j->next) + args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i++] = "--"; + args[i++] = head_arg; + for (j = remoteheads; j; j = j->next) + args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i] = NULL; + ret = run_command_v_opt(args, RUN_GIT_CMD); + strbuf_release(&buf); + i = 1; + for (j = common; j; j = j->next) + free((void *)args[i++]); + i += 2; + for (j = remoteheads; j; j = j->next) + free((void *)args[i++]); + free(args); + discard_cache(); + if (read_cache() < 0) + die("failed to read the cache"); + return -ret; + } } static void count_diff_files(struct diff_queue_struct *q, @@ -743,10 +780,6 @@ static int evaluate_result(void) int cnt = 0; struct rev_info rev; - discard_cache(); - if (read_cache() < 0) - die("failed to read the cache"); - /* Check how many files differ. */ init_revisions(&rev, ""); setup_revisions(0, NULL, &rev, NULL); @@ -880,12 +913,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix) for (i = 0; i < argc; i++) { struct object *o; + struct commit *commit; o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT); if (!o) die("%s - not something we can merge", argv[i]); - remotes = &commit_list_insert(lookup_commit(o->sha1), - remotes)->next; + commit = lookup_commit(o->sha1); + commit->util = (void *)argv[i]; + remotes = &commit_list_insert(commit, remotes)->next; strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1)); setenv(buf.buf, argv[i], 1); @@ -1079,7 +1114,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } /* Automerge succeeded. */ - discard_cache(); write_tree_trivial(result_tree); automerge_was_ok = 1; break; -- 1.6.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/2] unpack_trees(): protect the handcrafted in-core index from read_cache() 2008-08-23 19:55 ` Junio C Hamano 2008-08-23 19:56 ` [PATCH 1/2] merge: fix numerus bugs around "trivial merge" area Junio C Hamano @ 2008-08-23 19:57 ` Junio C Hamano 1 sibling, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 19:57 UTC (permalink / raw) To: Miklos Vajna; +Cc: Paolo Bonzini, Jeff King, git unpack_trees() rebuilds the in-core index from scratch by allocating a new structure and finishing it off by copying the built one to the final index. The resulting in-core index is Ok for most use, but read_cache() does not recognize it as such. The function is meant to be no-op if you already have loaded the index, until you call discard_cache(). This change the way read_cache() detects an already initialized in-core index, by introducing an extra bit, and marks the handcrafted in-core index as initialized, to avoid this problem. A better fix in the longer term would be to change the read_cache() API so that it will always discard and re-read from the on-disk index to avoid confusion. But there are higher level API that have relied on the current semantics, and they and their users all need to get converted, which is outside the scope of 'maint' track. An example of such a higher level API is write_cache_as_tree(), which is used by git-write-tree as well as later Porcelains like git-merge, revert and cherry-pick. In the longer term, we should remove read_cache() from there and add one to cmd_write_tree(); other callers expect that the in-core index they prepared is what gets written as a tree so no other change is necessary for this particular codepath. The original version of this patch marked the index by pointing an otherwise wasted malloc'ed memory with o->result.alloc, but this version uses Linus's idea to use a new "initialized" bit, which is conceptually much cleaner. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- cache.h | 3 ++- read-cache.c | 4 +++- t/t7605-merge-resolve.sh | 2 +- unpack-trees.c | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cache.h b/cache.h index 2475de9..884fae8 100644 --- a/cache.h +++ b/cache.h @@ -222,7 +222,8 @@ struct index_state { struct cache_tree *cache_tree; time_t timestamp; void *alloc; - unsigned name_hash_initialized : 1; + unsigned name_hash_initialized : 1, + initialized : 1; struct hash_table name_hash; }; diff --git a/read-cache.c b/read-cache.c index 2c03ec3..35fec46 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1155,7 +1155,7 @@ int read_index_from(struct index_state *istate, const char *path) size_t mmap_size; errno = EBUSY; - if (istate->alloc) + if (istate->initialized) return istate->cache_nr; errno = ENOENT; @@ -1195,6 +1195,7 @@ int read_index_from(struct index_state *istate, const char *path) * index size */ istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr)); + istate->initialized = 1; src_offset = sizeof(*hdr); dst_offset = 0; @@ -1247,6 +1248,7 @@ int discard_index(struct index_state *istate) cache_tree_free(&(istate->cache_tree)); free(istate->alloc); istate->alloc = NULL; + istate->initialized = 0; /* no need to throw away allocated active_cache */ return 0; diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh index 5c53608..f1f86dd 100755 --- a/t/t7605-merge-resolve.sh +++ b/t/t7605-merge-resolve.sh @@ -27,7 +27,7 @@ test_expect_success 'setup' ' git tag c3 ' -test_expect_failure 'merge c1 to c2' ' +test_expect_success 'merge c1 to c2' ' git reset --hard c1 && git merge -s resolve c2 && test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" && diff --git a/unpack-trees.c b/unpack-trees.c index cba0aca..ef21c62 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -376,6 +376,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options state.refresh_cache = 1; memset(&o->result, 0, sizeof(o->result)); + o->result.initialized = 1; if (o->src_index) o->result.timestamp = o->src_index->timestamp; o->merge_size = len; -- 1.6.0.51.g078ae ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge 2008-08-23 8:17 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Miklos Vajna 2008-08-23 9:01 ` Junio C Hamano @ 2008-08-23 9:50 ` Junio C Hamano 1 sibling, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 9:50 UTC (permalink / raw) To: Miklos Vajna; +Cc: Paolo Bonzini, Jeff King, git Miklos Vajna <vmiklos@frugalware.org> writes: > Using unmerged_cache() without reading the cache first never will return > anything. However, if we read the cache early then we have to discard it > when we want to read it again from the disk. I do not think the fix is correct with or without this one. You are writing a wrong index and recording a wrong tree object in the commit. I have a two-liner fix for the issue I am testing right now. diff --git c/t/t7605-merge-resolve.sh w/t/t7605-merge-resolve.sh index ee21a10..a251dac 100755 --- c/t/t7605-merge-resolve.sh +++ w/t/t7605-merge-resolve.sh @@ -36,7 +36,9 @@ test_expect_success 'merge c1 to c2' ' git diff --exit-code && test -f c0.c && test -f c1.c && - test -f c2.c + test -f c2.c && + test 3 = $(git ls-tree -r HEAD | wc -l) && + test 2 = $(git ls-files) ' test_expect_success 'merge c2 to c3 (fails)' ' ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Fix in-index merge. 2008-08-23 8:14 ` [PATCH] Fix in-index merge Miklos Vajna 2008-08-23 8:17 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Miklos Vajna @ 2008-08-23 8:50 ` Junio C Hamano 2008-08-23 10:41 ` Miklos Vajna 2008-08-23 9:19 ` Paolo Bonzini 2 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 8:50 UTC (permalink / raw) To: Miklos Vajna; +Cc: Paolo Bonzini, Jeff King, git Miklos Vajna <vmiklos@frugalware.org> writes: > There were 3 issues: > > 1) We need read_cache() before using unpack_trees(). > > 2) commit_tree() frees the parents, so we need to malloc them. > > 3) The current HEAD was missing from the parent list. > > Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> > --- > > On Fri, Aug 22, 2008 at 08:36:39AM +0200, Paolo Bonzini <bonzini@gnu.org> wrote: >> I had already posted this bug report yesterday but it was hidden in a >> cover >> letter at >> http://permalink.gmane.org/gmane.comp.version-control.git/93143 > > This should fix the issue. > > builtin-merge.c | 11 +++++++---- > t/t7607-merge-inindex.sh | 29 +++++++++++++++++++++++++++++ > 2 files changed, 36 insertions(+), 4 deletions(-) > create mode 100755 t/t7607-merge-inindex.sh Please do not add new testfiles unnecessarily. You already have test scripts that cover "git-merge". Add new ones to them. The same comment goes to the other patch. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] Fix in-index merge. 2008-08-23 8:50 ` [PATCH] Fix in-index merge Junio C Hamano @ 2008-08-23 10:41 ` Miklos Vajna 0 siblings, 0 replies; 22+ messages in thread From: Miklos Vajna @ 2008-08-23 10:41 UTC (permalink / raw) To: Junio C Hamano; +Cc: Paolo Bonzini, Jeff King, git There were 3 issues: 1) We need read_cache() before using unpack_trees(). 2) commit_tree() frees the parents, so we need to malloc them. 3) The current HEAD was missing from the parent list. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Sat, Aug 23, 2008 at 01:50:52AM -0700, Junio C Hamano <gitster@pobox.com> wrote: > Please do not add new testfiles unnecessarily. You already have test > scripts that cover "git-merge". Add new ones to them. The same > comment > goes to the other patch. Here it is. builtin-merge.c | 11 +++++++---- t/t7600-merge.sh | 9 +++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/builtin-merge.c b/builtin-merge.c index a201c66..dffe4b8 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -469,6 +469,7 @@ static int read_tree_trivial(unsigned char *common, unsigned char *head, struct tree_desc t[MAX_UNPACK_TREES]; struct unpack_trees_options opts; + read_cache(); memset(&opts, 0, sizeof(opts)); opts.head_idx = 2; opts.src_index = &the_index; @@ -651,13 +652,15 @@ static void add_strategies(const char *string, unsigned attr) static int merge_trivial(void) { unsigned char result_tree[20], result_commit[20]; - struct commit_list parent; + struct commit_list *parent = xmalloc(sizeof(struct commit_list *)); write_tree_trivial(result_tree); printf("Wonderful.\n"); - parent.item = remoteheads->item; - parent.next = NULL; - commit_tree(merge_msg.buf, result_tree, &parent, result_commit); + parent->item = lookup_commit(head); + parent->next = xmalloc(sizeof(struct commit_list *)); + parent->next->item = remoteheads->item; + parent->next->next = NULL; + commit_tree(merge_msg.buf, result_tree, parent, result_commit); finish(result_commit, "In-index merge"); drop_save(); return 0; diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index fee8fb7..dbc90bc 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -498,4 +498,13 @@ test_expect_success 'merge fast-forward in a dirty tree' ' test_debug 'gitk --all' +test_expect_success 'in-index merge' ' + git reset --hard c0 && + git merge --no-ff -s resolve c1 > out && + grep "Wonderful." out && + verify_parents $c0 $c1 +' + +test_debug 'gitk --all' + test_done -- 1.6.0.rc3.17.gc14c8.dirty ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Fix in-index merge. 2008-08-23 8:14 ` [PATCH] Fix in-index merge Miklos Vajna 2008-08-23 8:17 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Miklos Vajna 2008-08-23 8:50 ` [PATCH] Fix in-index merge Junio C Hamano @ 2008-08-23 9:19 ` Paolo Bonzini 2008-08-23 9:55 ` Junio C Hamano 2 siblings, 1 reply; 22+ messages in thread From: Paolo Bonzini @ 2008-08-23 9:19 UTC (permalink / raw) To: Miklos Vajna; +Cc: Junio C Hamano, Jeff King, git Miklos Vajna wrote: > There were 3 issues: > > 1) We need read_cache() before using unpack_trees(). > > 2) commit_tree() frees the parents, so we need to malloc them. > > 3) The current HEAD was missing from the parent list. Unfortunately it does not really work yet, since the files only present on the second branch are not added. I do get Trying really trivial in-index merge... Wonderful. In-index merge but then "git status" gives: # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # b (in my testcase for pre-merge, this results in a failure of the "octopus" testcase). Paolo ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Fix in-index merge. 2008-08-23 9:19 ` Paolo Bonzini @ 2008-08-23 9:55 ` Junio C Hamano 2008-08-23 10:00 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 9:55 UTC (permalink / raw) To: Paolo Bonzini; +Cc: Miklos Vajna, Jeff King, git Here is a tentative fix on top of Miklos's two patches, even though I won't take them as-is until the test scripts are cleaned up. t/t7605-merge-resolve.sh | 4 +++- unpack-trees.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletions(-) diff --git c/t/t7605-merge-resolve.sh w/t/t7605-merge-resolve.sh index ee21a10..be21ded 100755 --- c/t/t7605-merge-resolve.sh +++ w/t/t7605-merge-resolve.sh @@ -36,7 +36,9 @@ test_expect_success 'merge c1 to c2' ' git diff --exit-code && test -f c0.c && test -f c1.c && - test -f c2.c + test -f c2.c && + test 3 = $(git ls-tree -r HEAD | wc -l) && + test 2 = $(git ls-files | wc -l) ' test_expect_success 'merge c2 to c3 (fails)' ' diff --git c/unpack-trees.c w/unpack-trees.c index cba0aca..016fd46 100644 --- c/unpack-trees.c +++ w/unpack-trees.c @@ -378,6 +378,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options memset(&o->result, 0, sizeof(o->result)); if (o->src_index) o->result.timestamp = o->src_index->timestamp; + if (o->dst_index) + o->result.alloc = xmalloc(1); o->merge_size = len; if (!dfc) ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Fix in-index merge. 2008-08-23 9:55 ` Junio C Hamano @ 2008-08-23 10:00 ` Junio C Hamano 2008-08-23 10:41 ` [RFH] two and half potential fixlets to the in-core index handling Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 10:00 UTC (permalink / raw) To: Paolo Bonzini; +Cc: Miklos Vajna, Jeff King, git Junio C Hamano <gitster@pobox.com> writes: > Here is a tentative fix on top of Miklos's two patches, even though I > won't take them as-is until the test scripts are cleaned up. > > t/t7605-merge-resolve.sh | 4 +++- > unpack-trees.c | 2 ++ > 2 files changed, 5 insertions(+), 1 deletions(-) > > diff --git c/t/t7605-merge-resolve.sh w/t/t7605-merge-resolve.sh > index ee21a10..be21ded 100755 > --- c/t/t7605-merge-resolve.sh > +++ w/t/t7605-merge-resolve.sh > @@ -36,7 +36,9 @@ test_expect_success 'merge c1 to c2' ' > git diff --exit-code && > test -f c0.c && > test -f c1.c && > - test -f c2.c > + test -f c2.c && > + test 3 = $(git ls-tree -r HEAD | wc -l) && > + test 2 = $(git ls-files | wc -l) > ' Sorry, the last "2" should obviously be "3". We are making sure all three paths are included in the result. > > test_expect_success 'merge c2 to c3 (fails)' ' > diff --git c/unpack-trees.c w/unpack-trees.c > index cba0aca..016fd46 100644 > --- c/unpack-trees.c > +++ w/unpack-trees.c > @@ -378,6 +378,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options > memset(&o->result, 0, sizeof(o->result)); > if (o->src_index) > o->result.timestamp = o->src_index->timestamp; > + if (o->dst_index) > + o->result.alloc = xmalloc(1); > o->merge_size = len; > > if (!dfc) ^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFH] two and half potential fixlets to the in-core index handling 2008-08-23 10:00 ` Junio C Hamano @ 2008-08-23 10:41 ` Junio C Hamano 2008-08-23 18:13 ` Linus Torvalds 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 10:41 UTC (permalink / raw) To: Linus Torvalds; +Cc: Paolo Bonzini, Miklos Vajna, Jeff King, git While debugging merge-in-C with Miklos, I noticed that relatively recent codepaths that deal with the in-core index are subtly broken when a single process calls read_cache() more than once. A historical invariant in the API is "if you have read the index or populated it, then the next read_cache() is a no-op and you need to run discard_cache() beforehand if you want to read a new on-disk index." I think this was broken by relatively recent unpack-trees rewrite, namely 34110cd (Make 'unpack_trees()' have a separate source and destination index, 2008-03-06) and also 7a51ed6 (Make on-disk index representation separate from in-core one, 2008-01-14). With the current code, unpack_trees() builds its merge into a cleaned o->result (an index_state structure), and it is copied to o->dst_index, which often is the_index. But the logic in read_from_index() that implements the historical invariant checks if istate->alloc is NULL (in which case the istate is empty -- just after startup, or just after discard_index()). The "result" index_state does not have alloc because it is built from scratch and never allocated anything. This wouldn't work very well. A hacky solution I have in the attached patch is to waste an xmalloc(1) and store it there when o->result is created, and also make read_from_index() pay attention to the cache_nr and the cache_changed bit. I think it is the safest and minimum fix. Another independent issue is that istate has name_hash_initialized bit that records the validity of the name_hash. discard_index() frees the name_hash, but it never resets the bit to zero. I am not sure what the ramifications of not doing so, but it certainly feels wrong. Also, discard_index() did not free the array of pointers istate->cache[]; I think it should. read-cache.c | 11 ++++------- unpack-trees.c | 2 ++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git c/read-cache.c w/read-cache.c index 2c03ec3..b29f263 100644 --- c/read-cache.c +++ w/read-cache.c @@ -1144,7 +1144,7 @@ static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entrie return ondisk_size + entries*per_entry; } -/* remember to discard_cache() before reading a different cache! */ +/* remember to discard_index() before reading a different cache! */ int read_index_from(struct index_state *istate, const char *path) { int fd, i; @@ -1155,7 +1155,7 @@ int read_index_from(struct index_state *istate, const char *path) size_t mmap_size; errno = EBUSY; - if (istate->alloc) + if (istate->alloc || istate->cache_nr || istate->cache_changed) return istate->cache_nr; errno = ENOENT; @@ -1240,15 +1240,12 @@ unmap: int discard_index(struct index_state *istate) { - istate->cache_nr = 0; - istate->cache_changed = 0; - istate->timestamp = 0; free_hash(&istate->name_hash); cache_tree_free(&(istate->cache_tree)); free(istate->alloc); - istate->alloc = NULL; + free(istate->cache); - /* no need to throw away allocated active_cache */ + memset(istate, 0, sizeof(*istate)); return 0; } diff --git c/unpack-trees.c w/unpack-trees.c index cba0aca..016fd46 100644 --- c/unpack-trees.c +++ w/unpack-trees.c @@ -378,6 +378,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options memset(&o->result, 0, sizeof(o->result)); if (o->src_index) o->result.timestamp = o->src_index->timestamp; + if (o->dst_index) + o->result.alloc = xmalloc(1); o->merge_size = len; if (!dfc) ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFH] two and half potential fixlets to the in-core index handling 2008-08-23 10:41 ` [RFH] two and half potential fixlets to the in-core index handling Junio C Hamano @ 2008-08-23 18:13 ` Linus Torvalds 2008-08-23 19:14 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Linus Torvalds @ 2008-08-23 18:13 UTC (permalink / raw) To: Junio C Hamano; +Cc: Paolo Bonzini, Miklos Vajna, Jeff King, git On Sat, 23 Aug 2008, Junio C Hamano wrote: > > A hacky solution I have in the attached patch is to waste an xmalloc(1) > and store it there when o->result is created, and also make > read_from_index() pay attention to the cache_nr and the cache_changed > bit. I think it is the safest and minimum fix. Hmm. Wouldn't it be nicer to just add another bit to istate? We have the space already, since we already have a bitfield there, with just one bit used? Something like this.. Untested. Of course. Linus --- cache.h | 3 ++- read-cache.c | 4 +++- unpack-trees.c | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index 68ce6e6..6e41ec4 100644 --- a/cache.h +++ b/cache.h @@ -222,7 +222,8 @@ struct index_state { struct cache_tree *cache_tree; time_t timestamp; void *alloc; - unsigned name_hash_initialized : 1; + unsigned name_hash_initialized : 1, + initialized : 1; struct hash_table name_hash; }; diff --git a/read-cache.c b/read-cache.c index 2c03ec3..35fec46 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1155,7 +1155,7 @@ int read_index_from(struct index_state *istate, const char *path) size_t mmap_size; errno = EBUSY; - if (istate->alloc) + if (istate->initialized) return istate->cache_nr; errno = ENOENT; @@ -1195,6 +1195,7 @@ int read_index_from(struct index_state *istate, const char *path) * index size */ istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr)); + istate->initialized = 1; src_offset = sizeof(*hdr); dst_offset = 0; @@ -1247,6 +1248,7 @@ int discard_index(struct index_state *istate) cache_tree_free(&(istate->cache_tree)); free(istate->alloc); istate->alloc = NULL; + istate->initialized = 0; /* no need to throw away allocated active_cache */ return 0; diff --git a/unpack-trees.c b/unpack-trees.c index cba0aca..ef21c62 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -376,6 +376,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options state.refresh_cache = 1; memset(&o->result, 0, sizeof(o->result)); + o->result.initialized = 1; if (o->src_index) o->result.timestamp = o->src_index->timestamp; o->merge_size = len; ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFH] two and half potential fixlets to the in-core index handling 2008-08-23 18:13 ` Linus Torvalds @ 2008-08-23 19:14 ` Junio C Hamano 2008-08-23 19:21 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 19:14 UTC (permalink / raw) To: Linus Torvalds; +Cc: Paolo Bonzini, Miklos Vajna, Jeff King, git Linus Torvalds <torvalds@linux-foundation.org> writes: > On Sat, 23 Aug 2008, Junio C Hamano wrote: >> >> A hacky solution I have in the attached patch is to waste an xmalloc(1) >> and store it there when o->result is created, and also make >> read_from_index() pay attention to the cache_nr and the cache_changed >> bit. I think it is the safest and minimum fix. > > Hmm. Wouldn't it be nicer to just add another bit to istate? We have the > space already, since we already have a bitfield there, with just one bit > used? cache_changed can also become a single-bit field. The oldest "the_index" users work from it in the BSS initialized all zero. We'd also need to mark it as initialized, wouldn't we? ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFH] two and half potential fixlets to the in-core index handling 2008-08-23 19:14 ` Junio C Hamano @ 2008-08-23 19:21 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2008-08-23 19:21 UTC (permalink / raw) To: Linus Torvalds; +Cc: Paolo Bonzini, Miklos Vajna, Jeff King, git Junio C Hamano <gitster@pobox.com> writes: > Linus Torvalds <torvalds@linux-foundation.org> writes: > >> On Sat, 23 Aug 2008, Junio C Hamano wrote: >>> >>> A hacky solution I have in the attached patch is to waste an xmalloc(1) >>> and store it there when o->result is created, and also make >>> read_from_index() pay attention to the cache_nr and the cache_changed >>> bit. I think it is the safest and minimum fix. >> >> Hmm. Wouldn't it be nicer to just add another bit to istate? We have the >> space already, since we already have a bitfield there, with just one bit >> used? > > cache_changed can also become a single-bit field. > > The oldest "the_index" users work from it in the BSS initialized all > zero. We'd also need to mark it as initialized, wouldn't we? Ah, sorry, even they start with read_cache() to read .git/index (which may not exist yet, which is fine). Sorry for a stupid thinko. ^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2008-08-28 13:43 UTC | newest] Thread overview: 22+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-08-22 6:36 [bug] git `next' does not do trivial merges Paolo Bonzini 2008-08-22 19:31 ` Jeff King 2008-08-23 6:08 ` Miklos Vajna 2008-08-23 8:14 ` [PATCH] Fix in-index merge Miklos Vajna 2008-08-23 8:17 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Miklos Vajna 2008-08-23 9:01 ` Junio C Hamano 2008-08-23 10:57 ` Miklos Vajna 2008-08-23 19:55 ` Junio C Hamano 2008-08-23 19:56 ` [PATCH 1/2] merge: fix numerus bugs around "trivial merge" area Junio C Hamano 2008-08-24 1:58 ` Junio C Hamano 2008-08-28 13:43 ` [PATCH] builtin-merge: avoid run_command_v_opt() for recursive and subtree Miklos Vajna 2008-08-23 19:57 ` [PATCH 2/2] unpack_trees(): protect the handcrafted in-core index from read_cache() Junio C Hamano 2008-08-23 9:50 ` [PATCH] builtin-merge: fail properly when we are in the middle of a conflicted merge Junio C Hamano 2008-08-23 8:50 ` [PATCH] Fix in-index merge Junio C Hamano 2008-08-23 10:41 ` Miklos Vajna 2008-08-23 9:19 ` Paolo Bonzini 2008-08-23 9:55 ` Junio C Hamano 2008-08-23 10:00 ` Junio C Hamano 2008-08-23 10:41 ` [RFH] two and half potential fixlets to the in-core index handling Junio C Hamano 2008-08-23 18:13 ` Linus Torvalds 2008-08-23 19:14 ` Junio C Hamano 2008-08-23 19:21 ` Junio C Hamano
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).