Skip to content

Add support for gitattributes#874

Open
WGH- wants to merge 1 commit intoWilfred:masterfrom
WGH-:support-gitattributes
Open

Add support for gitattributes#874
WGH- wants to merge 1 commit intoWilfred:masterfrom
WGH-:support-gitattributes

Conversation

@WGH-
Copy link
Copy Markdown

@WGH- WGH- commented Aug 29, 2025

Runs git check-attr to get the files git attributes, and treats the file as binary if the attribute value is "unset", matching the built-in git diff.

Fixes #466

Idea-by: @anuramat (#466 (comment))

@WGH-
Copy link
Copy Markdown
Author

WGH- commented Aug 29, 2025

This is somewhat quick-and-dirty solution. Perhaps, we we shouldn't run git check-attr so eagerly. In any case, I want to hear some opinions.

@WGH- WGH- force-pushed the support-gitattributes branch from cd10de9 to 86ef851 Compare March 30, 2026 15:29
Copy link
Copy Markdown
Owner

@Wilfred Wilfred left a comment

Choose a reason for hiding this comment

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

Overall the approach here looks totally sensible, thanks for taking the time to write a PR!

I do think it needs a test: perhaps the easiest thing would be to write a unit test that e.g. "package.json\0diff\0unspecified\0" parses to the value you expect, and use that function after getting the raw string from git check-attr.

Otherwise, I think we should support at least the binary attribute too, and this is good to go. Thanks again, and let me know if you need any help :)

src/git.rs Outdated

/// Corresponds to the diff attribute. See man gitattribute.
pub(crate) enum DiffAttribute {
Set,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Would you mind adding doc comments to these? Even a brief phrase copied from the man page would be a big help. I think Other is something you've added, and isn't defined in git?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

src/git.rs Outdated
"set" => Self::Set,
"unset" => Self::Unset,
"unspecified" => Self::Unspecified,
_ => Self::Other,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I guess the other option would be to use TryFrom so you don't need this catch-all Other value.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I suppose this is no longer relevant since I changed this variant to Other(String)

src/git.rs Outdated
}
}
Err(err) => {
warn!("failed to execute git: {err}");
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

These should be debug logging I think, especially this one. You can run difft in a directory that isn't a git repository, or even on a machine that doesn't have git installed.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Running git outside of git repository is already handled by output.status.success() check, which gets logged with debug level.

I erroneously claimed that git being unavailable also goes there, but yeah, it actually ends up as a warning here.

Changed it to debug.

src/git.rs Outdated
/// Runs `git check-attr diff` to get the diff attribute of the path. Returns
/// [`Option::None`] when either `git` is not available, file is not inside git
/// directory, or something else went wrong.
pub(crate) fn check_attr(path: &Path) -> Option<DiffAttribute> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I think should either be check_diff_attr, or take an attribute name as an argument.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I changed this to check_diff_attr. It also checks binary attribute under the hood, but I decided against complicating thing to the caller too much

src/main.rs Outdated
let (mut lhs_src, mut rhs_src) = match (
guess_content(&lhs_bytes, lhs_path, binary_overrides),
guess_content(&rhs_bytes, rhs_path, binary_overrides),
check_attr(Path::new(display_path)),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This covers the case when someone writes *.ext -diff, but not *.ext binary, which is also mentioned in #466.

Apparently binary means -text -diff -merge according to https://git-scm.com/docs/gitattributes#_using_macro_attributes

I think we should support -text and binary too, and also treat them as forcing binary.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah, that's probably a good idea, since specifying both binary and an external diff driver with diff= is valid.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

To avoid calling git check-attr twice, and to hide this complexity in main, I decided to make binary essentially force -diff. Please tell if you're against this implicit behaviour

Copy link
Copy Markdown
Author

@WGH- WGH- Apr 2, 2026

Choose a reason for hiding this comment

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

Alternatively, we could return something like Option<(DiffAttribute, BinaryAttribute)>. That would be more explicit, but the patterm matching expression in main is already complicated as it is, and it will become even more ridiculous.

I don't really have a strong preference here. I can implement it either way, please tell me, how :)

@WGH- WGH- force-pushed the support-gitattributes branch from 86ef851 to 1fcd21d Compare April 1, 2026 20:02
@WGH- WGH- requested a review from Wilfred April 1, 2026 20:07
@WGH- WGH- force-pushed the support-gitattributes branch 3 times, most recently from 246876e to a120746 Compare April 2, 2026 18:42
Runs git check-attr to get the files git attributes, and treats the file
as binary if the attribute value is "unset", matching the built-in git diff.

Fixes Wilfred#466

Idea-by: @anuramat (Wilfred#466 (comment))
@WGH- WGH- force-pushed the support-gitattributes branch from a120746 to 982edb0 Compare April 2, 2026 18:59
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.

Support .gitattributes when doing file detection

2 participants