merge: reload index before git_merge - #4407
Conversation
pks-t
left a comment
There was a problem hiding this comment.
Some stylistic nits. I won't comment about that regarding whats the right thing to do here before having a look at it with fresh eyes tomorrow.
|
|
||
| assert(repo && their_heads); | ||
|
|
||
| if((error = git_repository_index(&index, repo) < 0) || |
There was a problem hiding this comment.
Please put a whitespace between if and (.
There was a problem hiding this comment.
Furthermore, it would be nice to actually have a giterr_set() here describing why we failed. Furthermore, you'd have to call git_index_free on index.
There was a problem hiding this comment.
Actually, I think that the error message set by git_repository_index itself would be superior to changing the error message. It will have the OS error details, like permission denied, which we would not want to overwrite with a less descriptive error.
| git_repository_index(&index, repo); | ||
| git_index_read(index, 0); | ||
| if((error = git_repository_index(&index, repo) < 0) || | ||
| (error = git_index_read(index, 0) < 0)) |
There was a problem hiding this comment.
I think we usually indent continuation lines with four spaces from the originial start of the conditional, such that we can easily distinguish it from the first statement inside of that condition.
| git_annotated_commit *their_heads[1]; | ||
| git_oid their_oid; | ||
|
|
||
| git_index_entry entry = {{0}}; |
There was a problem hiding this comment.
We usually don't have newlines in the list of variable declarations.
|
One note: @pks-t and I have been discussing correct behavior here and whether we should always reload the index from disk. (Like checkout does.) It's worth noting that merge's behavior is to create a new index (that represents the merge results) and check that out, setting it as the new index. During discussion, we were concerned that somebody may want to After further thoughts, it does not. AFAICT, there is no case where somebody could |
|
|
||
| assert(repo && their_heads); | ||
|
|
||
| if((error = git_repository_index(&index, repo) < 0) || |
There was a problem hiding this comment.
This actually needs to move down in the code a bit, write after git_indexwriter_init_for_operation.
git_indexwriter will take set up the lockfile on the index. We should re-read the index under that lock - if we do not, there's still a race condition where we read the index, and somebody makes changes before we take the lock.
|
@ethomson Unfortunately, I don't think that's actually true. First, there's the So re-reading the index from disk does change behaviour in some cases. Whether those cases are cases are sane or not is an entirely different topic, though. |
If the index in memory is different from the index on the disk, previously merge would abort with GIT_ECONFLICT. Reload the index before merging to fix this. Fixes libgit2#4203
Adds a test case for the issue libgit2#4203, when diverging indexes on memory and disk cause git merge to abort with GIT_ECONFLICT
Cleans up should git_repository_index or git_index_read fail
Correct. I was totally mistaken about that. I'm going to introduce a test during index refresh paths that ensures that we do not have unwritten index entries (ie someone has called |
|
Summary of future improvements, then, based on IRL discussion:
|
|
I've been working on adding a guard to the index so that you can't run a command that reloads the index when the index is "dirty" - which is to say that you've made changes via Regrettably, we have a bunch of tests that believe that they can work in the old way and not flush the index to disk. Sensibly, because why should they? That would just slow our test runs down. I've mostly got everything fixed here, but there are still a few tests failing. I'm chipping away at these, and once that's done, I think we'll be good to merge this. |
|
@ethomson wonderful! Do you need help in that? |
|
Now that #4536 has landed, I think we can move forward with this. I have one code review point. And we should add some data to the changelog, something like:
|
| goto done; | ||
|
|
||
| if ((error = git_repository_index(&index, repo) < 0) || | ||
| (error = git_index_read(index, 0) < 0)) |
There was a problem hiding this comment.
We're leaking this index now. I would encourage us to use a separate variable here, eg:
if ((error = git_repository_index(&repo_index, repo) < 0) ||
(error = git_index_read(repo_index, 0) < 0))
And be sure to git_index_free this repo_index.
|
@Etiene do you have interest in finishing this up? Or would you like me to fix those two last little bits? |
|
I added a commit to fix the memory leak and merged this manually. Thanks again for doing this, @Etiene! |
When the index in memory diverges from the index in disk
git_mergeaborts with
GIT_ECONFLICT. More details about this are found in theissue #4203, which this PR attempts to fix.
A further discussion is needed wether this behaviour is actually desired.
(Suppose someone actually is writing something to the index in memory
and a concurrent task is merging. A possible argument is that the index
should be written to disk then.)
Closes #4203