Doing in-memory merge conflict resolution
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 2.1k
- Forks
- 450
- Avg merge
- 11m
- Merged PRs (30d)
- 1
Description
Hi all,
first of all, I would like to thank you for providing this awesome libgit2 wrapper, including the searchable docs.rs documentation. This already helped me a lot in my project!
I am currently struggling to get an in-memory merge conflict resolution done with the libgit2. But let's first explain why I am seeking for in-memory conflict resolution:
- I am currently building a rust-library for the pass password store. I would like to provide an easy-to-use API backed by git for decentralized synchronization (e.g. without a server) from device-to-device over e.g. the local network, ad-hoc wifi, etc. The original pass implementation (shell-script) just delegates the synchronization to git by mirroring the git cli. I therefore decided to base my synchronization approach on git as well, to make it (at least theoretically) compatible.
- As from a user perspective a synchronization is either successful or not (maybe requiring some manual conflict resolution via e.g. a GUI popup), I would like to do the messing with git stages, etc. in-memory to prevent interfering with other tools handling a
passpassword store (e.g. the original cli, the qt intercace, the Firefox extension, etc.). Therefore, I thought that checking out a conflicted index to the repository is not a good idea. Also, if my lib crashes, is quit by the user, etc. my library would have to somehow continue a conflict resolution of a previous run. Furthermore, if multiple instances of my library or another pass implementation are running on the same repository I might run into race condition problems, etc. Those problems are ofc fixable with e.g. locks but it makes the implementation way more complex. That's why I settled with in-memory conflict resolution of a conflicted index.
So, what exactly is my problem? I have (somewhat) the following code:
let mut index = self.repo.merge_trees(&ancestor, &local_tree, &remote_tree, None)?;
// go over index.conflicts() and resolve them
// in pass passwords are gpg encrypted, not really relevant for this issue
index.add_frombuffer(new_index_entry, &encrypted_resolved_password_content)?;
However, this errors with could not initialize index entry. Index is not backed up by an existing repository. Which is true, I could not (yet) do e.g. a index.write_tree_to(repo) as my index still contains conflicts. So I tried another variant:
let mut index = self.repo.merge_trees(&ancestor, &local_tree, &remote_tree, None)?;
// go over index.conflicts() and resolve them
let oid = repo.blob(&encrypted_resolved_password_content)?;
index_entry.file_size = encrypted_resolved_password_content.len() as u32;
index_entry.id = oid;
index.add(&index_entry)?;
let result_tree = repo.find_tree(index.write_tree_to(repo)?)?;
But this fails on write_tree_to as the conflict has not been marked as resolved. I checked the libgit2 C source code and found out that only index.add_bypath and index.add_frombuffer mark a conflict as resolved, but not index.add (although I might have missed sth in the C source).
There are the git_index_conflict_remove and git_index_conflict_cleanup functions present in libgit2 but those are not available in the git2-rs wrapper. They are indeed available in the libgit2-sys crate but not usable as I require access to the raw pointers of the index in order to use them which I do not have in git2-rs. Also, I am not sure whether these functions are actually necessary to solve my problem, I have not checked this as I would like to avoid reimplementing my rust code in C to check whether these two functions would make it work.
I could not find working examples on how to resolve merge conflicts in-memory with git (wondering now if it's even possible...). My question is: are git_index_conflict_remove and git_index_conflict_cleanup necessary for this and if so, why are these functions missing from git2-rs?
Thank you in advance for any help!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the libgit2 C implementations of git_index_conflict_remove and git_index_conflict_cleanup and the corresponding libgit2-sys bindings; compare them with the git2-rs Index APIs used by merge_trees, add_frombuffer, add, and write_tree_to. Done means establishing whether those functions are required and, if so, exposing a safe wrapper with coverage for resolving an in-memory conflicted index.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, rust
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100