Skip to content

git-lfs: add ability to ignore files based on git attributes - #9635

Open
sbarfurth wants to merge 1 commit into
mainfrom
sbarfurth/push-uulvmqxnpmzk
Open

git-lfs: add ability to ignore files based on git attributes#9635
sbarfurth wants to merge 1 commit into
mainfrom
sbarfurth/push-uulvmqxnpmzk

Conversation

@sbarfurth

Copy link
Copy Markdown
Contributor

Adapted from #9068, which also contains a history of past attempts at this change. It combines the multiple commits on that PR into one.

This adaptation also addresses the most recent set of comments on the source PR, which mostly revolved around documentation. I'm mostly creating this as a backup to finally keep driving this to the end. My organization relies on patched jj today and we would very much like to see this through.

This code (aka. "the patch") has been running very well for many people, including myself and my peers at my organization.

From that PR:

Partially addresses #80 by ignoring files matched by configurable .gitattributes filter attributes during snapshot. This lets users work with Git LFS (and git-crypt, etc.) repos in jj by excluding filtered files from tracking, deferring actual file handling to the external tool (e.g. git lfs pull).

Approach

A new git.ignore-filters setting (defaulting to ["lfs"]) names .gitattributes filter attributes whose matching files should be excluded from snapshots. During snapshot, the working copy reads .gitattributes files from both disk and the tree store, matches paths against gix-attributes, and skips files whose filter attribute matches a configured ignore filter. Skipped files are also omitted from the deleted-files check so they don't appear as spuriously removed.

This only affects the snapshot path (disk → store). Checkout (store → disk) is unaffected, which is intentional: files are still checked out normally so that git lfs pull works afterward.

Known limitations

  • All .gitattributes files in the repo are parsed on every snapshot, regardless of which directories changed.
  • Symlinked .gitattributes files are followed (matching jj's current .gitignore behavior, but diverging from git).
  • No checkout-path filtering — this is snapshot-only.

These are acceptable tradeoffs for an initial implementation and can be refined alongside the broader gitattributes design (#7164, #8144).

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added/updated tests to cover my changes
  • I fully understand the code that I am submitting (what it does,
    how it works, how it's organized), including any code drafted by an LLM.
  • For any prose generated by an LLM, I have proof-read and copy-edited with
    an eye towards deleting anything that is irrelevant, clarifying anything
    that is confusing, and adding details that are relevant. This includes,
    for example, commit descriptions, PR descriptions, and code comments.

@PhilipMetzger

Copy link
Copy Markdown
Contributor

This commit is missing its motivation.

@sbarfurth
sbarfurth force-pushed the sbarfurth/push-uulvmqxnpmzk branch 2 times, most recently from a321cb4 to 11b9b5a Compare June 10, 2026 15:30
@sbarfurth

Copy link
Copy Markdown
Contributor Author

This commit is missing its motivation.

Added description into the commit itself as well.

@steadmon

Copy link
Copy Markdown
Member

On a first pass, it looks like this filtering behavior is enabled even when the repo backend is not Git. I'm not actually sure if we want that behavior or not, but I think I would find it a bit surprising. I'm also not sure yet if anything bad happens if this code runs in a build where the git feature is disabled. I'll try to take a deeper look at this tomorrow.

@PhilipMetzger

Copy link
Copy Markdown
Contributor

On a first pass, it looks like this filtering behavior is enabled even when the repo backend is not Git. I'm not actually sure if we want that behavior or not, but I think I would find it a bit surprising.

I don't think we want that, but you can find some conversations about that behavior in @06393993 design docs.

@sbarfurth
sbarfurth force-pushed the sbarfurth/push-uulvmqxnpmzk branch from 11b9b5a to 433687e Compare June 19, 2026 09:14
@sbarfurth

Copy link
Copy Markdown
Contributor Author

On a first pass, it looks like this filtering behavior is enabled even when the repo backend is not Git. I'm not actually sure if we want that behavior or not, but I think I would find it a bit surprising. I'm also not sure yet if anything bad happens if this code runs in a build where the git feature is disabled. I'll try to take a deeper look at this tomorrow.

Added a check to only perform any ignoring on the git backend.

@sbarfurth
sbarfurth force-pushed the sbarfurth/push-uulvmqxnpmzk branch from 433687e to 504f4e4 Compare June 19, 2026 09:50
@joshka

joshka commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

#9676 does a review / fix of the problems found and points at this PR to update it.
Mostly edge cases that hit other parts of jj that overlap with this with tests that show the problem.

@antisaling

Copy link
Copy Markdown
Contributor

I have a branch for basic LFS pointer hydration that depends on this, any plans to merge?

@sbarfurth
sbarfurth force-pushed the sbarfurth/push-uulvmqxnpmzk branch 2 times, most recently from c4b9512 to 263ba23 Compare July 29, 2026 14:05
@sbarfurth

Copy link
Copy Markdown
Contributor Author

I synced and resolved conflicts. I also squashed the intermediate commits down for better management of the change.

This is ready for another review.

@PhilipMetzger @steadmon @martinvonz

I have been testing this in a medium-large repo for multiple months and so have some of my colleagues. Judging from comments it appears that others have done the same.

Anyone subscribed to this thread: Feel free to also provide a supporting review to help maintainers and potentially make this more solid.

@jgilchrist

Copy link
Copy Markdown
Contributor

I've also been using this in a large repo for a while and it has been solid for me too.

@tuto193

tuto193 commented Aug 1, 2026

Copy link
Copy Markdown

I've also been using this in a large repo for a couple weeks, and seems to be great first stable steps

@tuto193 tuto193 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is working, since I tested it myself, and just wanted to review the code itself. Just some minor remarks overall, but it looks pretty good to me on this sided as well.

Comment thread docs/git-compatibility.md Outdated
Comment thread lib/src/gitattributes.rs Outdated
Comment thread lib/src/gitattributes.rs
Comment thread web/docs/src/content/docs/git-compatibility.md Outdated
@sbarfurth
sbarfurth force-pushed the sbarfurth/push-uulvmqxnpmzk branch 2 times, most recently from 584bdfe to fb9f6d9 Compare August 14, 2026 17:12
Partially addresses #80 by ignoring files matched by configurable
`.gitattributes` filter attributes during snapshot. This lets users work with
Git LFS (and git-crypt, etc.) repos in jj by excluding filtered files from
tracking, deferring actual file handling to the external tool (e.g. `git lfs
pull`).

Adds a new `git.ignore-filters` setting (defaulting to `["lfs"]`) names
`.gitattributes` filter attributes whose matching files should be excluded from
snapshots. During snapshot, the working copy reads `.gitattributes` files from
both disk and the tree store, matches paths against `gix-attributes`, and skips
files whose `filter` attribute matches a configured ignore filter. Skipped files
are also omitted from the deleted-files check so they don't appear as spuriously
removed.

This only affects the snapshot path (disk → store). Checkout (store → disk) is
unaffected, which is intentional: files are still checked out normally so that
`git lfs pull` works afterward.

Known limitations:

- All `.gitattributes` files in the repo are parsed on every snapshot,
  regardless of which directories changed.
- Symlinked `.gitattributes` files are followed (matching jj's current
  `.gitignore` behavior, but diverging from git).
- No checkout-path filtering — this is snapshot-only.

These are acceptable tradeoffs for an initial implementation and can be refined
alongside the broader gitattributes design (#7164, #8144).

Co-authored-by: Gustavo Inacio <incio.gusta@gmail.com>
Co-authored-by: Alpha Chen <alpha@kejadlen.dev>
Co-authored-by: Josh McKinney <joshka@users.noreply.github.com>
@sbarfurth
sbarfurth force-pushed the sbarfurth/push-uulvmqxnpmzk branch from fb9f6d9 to 971279f Compare August 14, 2026 17:17
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.

9 participants