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

Ignore Git LFS files #5480

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: remove

3 changes: 3 additions & 0 deletions CHANGELOG.md
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: squash this into the first commit which successfully implements this.

Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
* `[diff.<format>]` configuration now applies to `.diff().<format>()` commit
template methods.

* Add support for just ignoring Git LFS files by parsing `.gitattribute` files and automatically
adding the relevant files to the internal ignore list

## [0.25.0] - 2025-01-01

### Release highlights
Expand Down
27 changes: 27 additions & 0 deletions cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,32 @@ to the current parents may contain changes from multiple commits.
self.path_converter().parse_file_path(input)
}

/// Parses the given strings as file patterns, convert it to a matcher and
/// apply GIT LFS exclusions if requested
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Its Git LFS

pub fn file_matcher(
&self,
ui: &Ui,
values: &[String],
) -> Result<Box<dyn Matcher>, CommandError> {
let mut matcher = self.parse_file_patterns(ui, values)?.to_matcher();
if self.settings().git_settings()?.ignore_lfs_files {
let root = self.workspace().workspace_root();
if let Some(wc_commit) = self
.get_wc_commit_id()
.map(|id| self.repo().store().get_commit(id))
.transpose()?
{
let tree = wc_commit.tree()?;
matcher = Box::new(jj_lib::matchers::DifferenceMatcher::new(
matcher,
jj_lib::matchers::GitAttributesMatcher::new(tree.as_merge().first(), root)
.expect("gitattributes matcher failed"),
));
}
}
Ok(matcher)
}

/// Parses the given strings as file patterns.
pub fn parse_file_patterns(
&self,
Expand Down Expand Up @@ -1350,6 +1376,7 @@ to the current parents may contain changes from multiple commits.
start_tracking_matcher,
max_new_file_size,
conflict_marker_style,
skip_git_lfs_files: self.settings().git_settings()?.ignore_lfs_files,
})
}

Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/absorb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ pub(crate) fn cmd_absorb(
.parse_union_revsets(ui, &args.into)?
.resolve()?;

let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;

let repo = workspace_command.repo().as_ref();
let source = AbsorbSource::from_commit(repo, source_commit)?;
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ pub(crate) fn cmd_commit(
.get_wc_commit_id()
.ok_or_else(|| user_error("This command requires a working copy"))?;
let commit = workspace_command.repo().store().get_commit(commit_id)?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let advanceable_bookmarks = workspace_command.get_advanceable_bookmarks(commit.parent_ids())?;
let diff_selector =
workspace_command.diff_selector(ui, args.tool.as_deref(), args.interactive)?;
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/debug/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ pub fn cmd_debug_tree(
.resolve_single_rev(ui, args.revision.as_ref().unwrap_or(&RevisionArg::AT))?;
commit.tree()?
};
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
for (path, value) in tree.entries_matching(matcher.as_ref()) {
let ui_path = workspace_command.format_file_path(&path);
writeln!(ui.stdout(), "{ui_path}: {value:?}")?;
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub(crate) fn cmd_diff(
let workspace_command = command.workspace_helper(ui)?;
let repo = workspace_command.repo();
let fileset_expression = workspace_command.parse_file_patterns(ui, &args.paths)?;
let matcher = fileset_expression.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let resolve_revision = |r: &Option<RevisionArg>| {
workspace_command.resolve_single_rev(ui, r.as_ref().unwrap_or(&RevisionArg::AT))
};
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/file/chmod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub(crate) fn cmd_file_chmod(
// TODO: No need to add special case for empty paths when switching to
// parse_union_filesets(). paths = [] should be "none()" if supported.
let fileset_expression = workspace_command.parse_file_patterns(ui, &args.paths)?;
let matcher = fileset_expression.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
print_unmatched_explicit_paths(ui, &workspace_command, &fileset_expression, [&tree])?;

let mut tx = workspace_command.start_transaction();
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/file/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ pub(crate) fn cmd_file_list(
let workspace_command = command.workspace_helper(ui)?;
let commit = workspace_command.resolve_single_rev(ui, &args.revision)?;
let tree = commit.tree()?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let template = {
let language = workspace_command.commit_template_language();
let text = match &args.template {
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/file/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub(crate) fn cmd_file_show(
}
}

let matcher = fileset_expression.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
ui.request_pager();
write_tree_entries(
ui,
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/file/track.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ pub(crate) fn cmd_file_track(
args: &FileTrackArgs,
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let options = workspace_command.snapshot_options_with_start_tracking_matcher(&matcher)?;

let mut tx = workspace_command.start_transaction().into_inner();
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/file/untrack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ pub(crate) fn cmd_file_untrack(
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let store = workspace_command.repo().store().clone();
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let auto_tracking_matcher = workspace_command.auto_tracking_matcher(ui)?;
let options =
workspace_command.snapshot_options_with_start_tracking_matcher(&auto_tracking_matcher)?;
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ pub(crate) fn cmd_fix(
.evaluate_to_commit_ids()?
.try_collect()?;
workspace_command.check_rewritable(root_commits.iter())?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;

let mut tx = workspace_command.start_transaction();

Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/interdiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ pub(crate) fn cmd_interdiff(
workspace_command.resolve_single_rev(ui, args.from.as_ref().unwrap_or(&RevisionArg::AT))?;
let to =
workspace_command.resolve_single_rev(ui, args.to.as_ref().unwrap_or(&RevisionArg::AT))?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let diff_renderer = workspace_command.diff_renderer_for(&args.format)?;
ui.request_pager();
diff_renderer.show_inter_diff(
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ pub(crate) fn cmd_log(
};

let repo = workspace_command.repo();
let matcher = fileset_expression.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let revset = revset_expression.evaluate()?;

let store = repo.store();
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ pub(crate) fn cmd_resolve(
args: &ResolveArgs,
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let commit = workspace_command.resolve_single_rev(ui, &args.revision)?;
let tree = commit.tree()?;
let conflicts = tree
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,7 @@ pub(crate) fn cmd_restore(
}
workspace_command.check_rewritable([to_commit.id()])?;

let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let diff_selector =
workspace_command.diff_selector(ui, args.tool.as_deref(), args.interactive)?;
let to_tree = to_commit.tree()?;
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ pub(crate) fn cmd_split(
}

workspace_command.check_rewritable([commit.id()])?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let diff_selector = workspace_command.diff_selector(
ui,
args.tool.as_deref(),
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/squash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ pub(crate) fn cmd_squash(
destination = parents.pop().unwrap();
}

let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
let diff_selector =
workspace_command.diff_selector(ui, args.tool.as_deref(), args.interactive)?;
let text_editor = workspace_command.text_editor()?;
Expand Down
4 changes: 1 addition & 3 deletions cli/src/commands/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ pub(crate) fn cmd_status(
.get_wc_commit_id()
.map(|id| repo.store().get_commit(id))
.transpose()?;
let matcher = workspace_command
.parse_file_patterns(ui, &args.paths)?
.to_matcher();
let matcher = workspace_command.file_matcher(ui, &args.paths)?;
ui.request_pager();
let mut formatter = ui.stdout_formatter();
let formatter = formatter.as_mut();
Expand Down
71 changes: 27 additions & 44 deletions cli/src/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@
"conflict-marker-style": {
"type": "string",
"description": "Conflict marker style to use when materializing conflicts in the working copy",
"enum": [
"diff",
"snapshot",
"git"
],
"enum": ["diff", "snapshot", "git"],
"default": "diff"
}
},
Expand Down Expand Up @@ -85,21 +81,13 @@
},
"color": {
"description": "Whether to colorize command output",
"enum": [
"always",
"never",
"debug",
"auto"
],
"enum": ["always", "never", "debug", "auto"],
"default": "auto"
},
"paginate": {
"type": "string",
"description": "Whether or not to use a pager",
"enum": [
"never",
"auto"
],
"enum": ["never", "auto"],
"default": "auto"
},
"pager": {
Expand All @@ -113,11 +101,7 @@
"properties": {
"format": {
"description": "The diff format to use",
"enum": [
"color-words",
"git",
"summary"
],
"enum": ["color-words", "git", "summary"],
"default": "color-words"
},
"tool": {
Expand Down Expand Up @@ -191,11 +175,11 @@
"watchman": {
"type": "object",
"properties": {
"register_snapshot_trigger": {
"type": "boolean",
"default": false,
"description": "Whether to use triggers to monitor for changes in the background."
}
"register_snapshot_trigger": {
"type": "boolean",
"default": false,
"description": "Whether to use triggers to monitor for changes in the background."
}
}
}
}
Expand Down Expand Up @@ -230,14 +214,14 @@
"pattern": "^#[0-9a-fA-F]{6}$"
},
"colors": {
"oneOf": [
{
"$ref": "#/properties/colors/definitions/colorNames"
},
{
"$ref": "#/properties/colors/definitions/hexColor"
}
]
"oneOf": [
{
"$ref": "#/properties/colors/definitions/colorNames"
},
{
"$ref": "#/properties/colors/definitions/hexColor"
}
]
},
"basicFormatterLabels": {
"enum": [
Expand Down Expand Up @@ -389,6 +373,11 @@
"type": "string",
"description": "Path to the git executable",
"default": "git"
},
"ignore-lfs-files": {
"type": "boolean",
"description": "Whether jj ignores files handled by git lfs or not",
"default": false
}
}
},
Expand Down Expand Up @@ -416,12 +405,9 @@
"default": [0]
},
"diff-invocation-mode": {
"description": "Invoke the tool with directories or individual files",
"enum": [
"dir",
"file-by-file"
],
"default": "dir"
"description": "Invoke the tool with directories or individual files",
"enum": ["dir", "file-by-file"],
"default": "dir"
},
"edit-args": {
"type": "array",
Expand Down Expand Up @@ -529,10 +515,7 @@
"default": "false"
},
"max-new-file-size": {
"type": [
"integer",
"string"
],
"type": ["integer", "string"],
"description": "New files with a size in bytes above this threshold are not snapshotted, unless the threshold is 0",
"default": "1MiB"
}
Expand Down Expand Up @@ -616,7 +599,7 @@
}
}
},
"fix": {
"fix": {
"type": "object",
"description": "Settings for jj fix",
"properties": {
Expand Down
1 change: 1 addition & 0 deletions cli/src/merge_tools/diff_working_copies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ diff editing in mind and be a little inaccurate.
start_tracking_matcher: &EverythingMatcher,
max_new_file_size: u64::MAX,
conflict_marker_style,
skip_git_lfs_files: false,
})?;
Ok(output_tree_state.current_tree_id().clone())
}
Expand Down
11 changes: 11 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,17 @@ particular binary, you can:
executable-path = "/path/to/git"
```

### Ignore Git LFS Files

By default Git LFS files are **not** handled by `jj`. This will result in `jj` showing
changes in these files, even if they are unchanged. You can configure `jj` to ignore these
files by instructing it to parse the relevant `.gitattributes` files

```tom

Choose a reason for hiding this comment

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

Suggested change
```tom
```toml

[git]
ignore-lfs-files = -rue

Choose a reason for hiding this comment

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

Suggested change
ignore-lfs-files = -rue
ignore-lfs-files = true

```

## Filesystem monitor

In large repositories, it may be beneficial to use a "filesystem monitor" to
Expand Down
Loading
Loading