Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Custom merge drivers and proper gitattributes merge handling #3564

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

Merged
merged 14 commits into from
Mar 17, 2016

Conversation

ethomson
Copy link
Member

While #3497 added support for merge=union in .gitattributes, I felt that we should have a more complete story for handling the merge attribute. This PR:

  1. Adds a framework for adding custom merge drivers. This is heavily inspired by the custom filter framework, and a consumer can add one or more custom merge drivers by name (for example, you may add a new custom driver) or - probably more useful - can add a wildcard merge driver. This allows a consumer to be given the option to handle all configured merge drivers that are not built-in.

    For example, a consumer could register a custom merge driver for the wildcard (*). If there were a merge=custom line in a .gitattributes for a file, the configured merge driver would be given the information about the file changes and the .gitattributes configuration. The driver could (for example) look for the corresponding custom merge driver and - if found - elect to accept responsibility for this change. It would then invoke the custom merge driver and provide the results back.

    The merge driver may also defer the check, at which point libgit2 will invoke the default built-in merge driver. This is equivalent to when a user has configured merge=foobar in their .gitattributes but has not configured the foobar merge driver. The merge driver configuration is ignored, and git will simply behave as if it was not configured at all.

  2. Additional handling for the merge attribute. When set (eg, merge) this will indicate that the file is mergeable and the default built-in text driver should be used. When unset (eg, -merge) this will indicate that the file is binary and should not be merged (ie, is simply a conflict). When unspecified (eg, no merge line) this indicates that the file is text but if a merge.default configuration setting exists, that will specify the driver to be used (otherwise the built-in text driver will be used). Finally, if it is set to a string (eg, merge=foobar) then that indicates the driver to be used.

    Any of the built-in drivers (text, binary or union) may be specified.

  3. Proper handling of the merge.default configuration setting. Query the merge.default to get the default merge driver name and use it when the merge attribute is not specified for a file.

Fixes #3497
Fixes #2180

* - check - considering using merge driver for file
* - apply - apply merge driver to the file
* - cleanup - done with file
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block won't show up in the doc viewer, so the "as documented above" comment there will seem rather nonsensical. This should probably be part of the documentation for the struct.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'll fix that; I think we're similarly deficient in the filter code, I copied this pattern from that.

@carlosmn
Copy link
Member

The rest of the PR is fine. I'm mostly worried about documenting when we call certain things, and about having a global registration which can be called from multiple threads at the same time.

@Envek
Copy link

Envek commented Jan 6, 2016

Hello everyone! I have a question: it's a bit unclear for me, but will this PR give an ability to configure and call external merge drivers (external executables for example)? See discussion at GitLab's issue #5902 for context and possible use cases.

@arthurschreiber
Copy link
Member

@Envek If I'm not mistaken, this does not "magically" add support for external merge drivers.

But you could write a custom libgit2 merge driver that either calls out to your existing merge driver executable or reimplements similar functionality.

@carlosmn
Copy link
Member

This will give you the ability to intercept those external merge drivers and call them, but libgit2 does not execute programs. It does give you the information you need to execute them as your environment needs.

@stanhu
Copy link
Contributor

stanhu commented Feb 5, 2016

Would love to see this PR merged soon. Anything I can do to help?

@ethomson
Copy link
Member Author

ethomson commented Feb 9, 2016

Sorry for the delay, @stanhu - I think that once we get #3597 merged, I'll be able to get this one fixed up!

@stanhu
Copy link
Contributor

stanhu commented Feb 9, 2016

Thanks, @ethomson! Awesome work.

@MiroslavHoudek
Copy link

A dumb question (possibly in a inappropriate place): I can't use this custom merge driver as developer linking to libgit2 library, right? I want to do my own merging, so I was hoping I will just simply register my function as a default driver somehow, and then it would get called, it'd get reference to two conflicting files as parameter, it'd produce the merged version and return it (and it'd get written). But looking at the code, it looks buried deep in the library, for some internal purpose, not accessible to me at all ... right?

@ethomson
Copy link
Member Author

Hi @MiroslavHoudek - you can wire this up as a developer, however it doesn't sound like this is quite what you're looking for. The purpose of this is to be able to wire up a custom merge driver so that you can specify merge=foobar in .gitattributes and then be able to have your custom function get called for those files.

But it will only invoke your custom code for those files that have those attributes, not for every file. If that's an acceptable limitation for you, then this will work fine. If not, we might need to think a bit more deeply about how to get you what you need.

@MiroslavHoudek
Copy link

Hi, I think I know where my brain took a wrong turn - I thought that I can add the custom driver in my (e.g.) main.cpp, and there I will write my handler, and then register it in libgit2.dll by calling git_merge_driver_register() ... whereas in reality the intended use seems to be to develop the driver and compile/link it with libgit2.dll, and then specify its invocation in the .gitattributes. Thank you @ethomson for your response (as well as for all the great work on libgit2), both much appreciated!

@carlosmn
Copy link
Member

The point of the custom drivers is that they don't live in this codebase. If you have a custom one, it should definitely be in your own code. This is why we publish registration, otherwise we'd hard-code it.

@matt-oakes
Copy link

Will this be looked at now #3597 has been merged? Is there anything I can do to help with this?

@carlosmn
Copy link
Member

That PR existed because this was looked at. We'll get back to this PR when we have time.

@matt-oakes
Copy link

That makes sense. Thanks for the swift reply and for working on libgit2!

@MiroslavHoudek
Copy link

@carlosmn thank you for your response, it gave me the confidence to find the real problem and get things straight. I have a functional custom driver now, yay!

@ethomson ethomson force-pushed the merge_drivers branch 2 times, most recently from 3da3371 to 349ff1c Compare February 27, 2016 22:18
@ethomson
Copy link
Member Author

Thanks for the sage comments as always @carlosmn - I think that I've addressed your concerns.

stanhu and others added 14 commits March 17, 2016 11:02
Consumers can now register custom merged drivers with
`git_merge_driver_register`.  This allows consumers to support the
merge drivers, as configured in `.gitattributes`.  Consumers will be
asked to perform the file-level merge when a custom driver is
configured.
When a `check` or `apply` callback function returns `GIT_PASSTHROUGH`,
move on to the default merge driver.
When a `check` or `apply` callback function returns `GIT_EMERGECONFLICT`
stop and product a conflict.
Allow merge users to configure a custom default merge driver via
`git_merge_options`.  Similarly, honor the `merge.default` configuration
option.
Ensure that setting the merge attribute forces the built-in default
`text` driver and does *not* honor the `merge.default` configuration
option.  Further ensure that unsetting the merge attribute forces
a conflict (the `binary` driver).
Since the `apply` callback can defer, the `check` callback is not
necessary.  Removing the `check` callback further makes the `payload`
unnecessary along with the `cleanup` callback.
@ethomson
Copy link
Member Author

I rebased this on master because some conflicts had crept in. @carlosmn - anything keeping us from 🚢 this?

carlosmn added a commit that referenced this pull request Mar 17, 2016
Custom merge drivers and proper gitattributes `merge` handling
@carlosmn carlosmn merged commit e18df18 into libgit2:master Mar 17, 2016
@metcalf
Copy link

metcalf commented May 6, 2016

Will this eventually change the behavior of merge conflict detection on Github pull requests? For certain generated files, I'm thinking of defaulting to union for rebases and merges since we can rebuild broken files. On the other hand, we don't want people pressing the big green button unless the merge is truly clean.

@ethomson
Copy link
Member Author

ethomson commented May 6, 2016

This will not change the behavior of GitHub PR merges directly, no. If GitHub wants to change behavior, that's not something that libgit2 would impose upon them.

@metcalf
Copy link

metcalf commented May 6, 2016

Makes sense, thanks!
On May 6, 2016 3:46 PM, "Edward Thomson" [email protected] wrote:

This will not change the behavior of GitHub PR merges directly, no. If
GitHub wants to change behavior, that's not something that libgit2 would
impose upon them.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#3564 (comment)

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

Successfully merging this pull request may close these issues.

8 participants