Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doing in-memory merge conflict resolution #778

Open
fin-ger opened this issue Nov 28, 2021 · 2 comments
Open

Doing in-memory merge conflict resolution #778

fin-ger opened this issue Nov 28, 2021 · 2 comments

Comments

@fin-ger
Copy link

fin-ger commented Nov 28, 2021

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 pass password 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!

@arxanas
Copy link
Contributor

arxanas commented Nov 29, 2021

I'm not a maintainer of this project, but my guess is that nobody has needed these functions, and so nobody has implemented bindings for them.

As a workaround, you could try copying all the entries except the conflicting ones into a new index, or, since you no longer have conflicts, construct a tree object directly.

@fin-ger
Copy link
Author

fin-ger commented Nov 30, 2021

@arxanas Thank you for your response. Copying the index sounds like something that could work. However, I now tried to add the missing functions myself, so that anyone else needing those does not end up with a workaround as well :D

Let's see if my trivial implementation approach is fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants