This flag implements three modes:
- `copy`: copy sparse patterns from parent
- `full`: do not copy sparse patterns from parent
- `empty`: clear all paths, equal to `set --clear`
This is useful for various tooling like tools that want to run a parallel
process that queries the build system (without running into locks/blocking.)
I think continuing to copy sparse patterns makes sense as the default behavior.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
This enables workflows like "insert a commit that reformats the code in one of
my project directories".
`jj fix --include-unchanged-files` is an easy way to fix everything in the repo.
`jj fix --include-unchanged-files <file...>` fixes all of the `<files>` even if they are
unchanged.
This is mostly orthogonal to other features, so not many tests are added.
This is a significant and simple enough improvement that I think it's
appropriate to make it here instead of waiting for a `jj run`-based solution.
It seems everyone agrees that `obslog` is not an intuitive name. There
was some discussion about alternatives in #3592 and on #4146. The
alternatives included `evolution`, `evolutionlog`, `evolog`,
`rewritelog`, `revlog`, and `changelog`. It seemed like
`evolution-log`/`evolog` was the most popular option. That also
matches the command's current help text ("Show how a change has
evolved over time").
I played with max-inline-alternation = 3 for a couple of weeks, and it's pretty
good. I think somewhere between 2 and 4 is good default because one or two
remove + add sequences are easy to parse.
In this patch, I use the number of adds<->removes alternation as a threshold,
which approximates the visual complexity of diff hunks. I don't think user can
choose the threshold intuitively, but we need a config knob to try out some.
I set `max-inline-alternation = 3` locally. 0 and 1 mean "disable inlining"
and "inline adds-only/removes-only lines" respectively.
I've added "diff.<format>" config namespace assuming "ui.diff" will be
reorganized as "ui.diff-formatter" or something. #3327
Some other metrics I've tried:
```
// Per-line alternation. This also works well, but can't measure complexity of
// changes across lines.
fn count_max_diff_alternation_per_line(diff_lines: &[DiffLine]) -> usize {
diff_lines
.iter()
.map(|line| {
let sides = line.hunks.iter().map(|&(side, _)| side);
sides
.filter(|&side| side != DiffLineHunkSide::Both)
.dedup() // omit e.g. left->both->left
.count()
})
.max()
.unwrap_or(0)
}
// Per-line occupancy of changes. Large diffs don't always look complex.
fn max_diff_token_ratio_per_line(diff_lines: &[DiffLine]) -> f32 {
diff_lines
.iter()
.filter_map(|line| {
let [both_len, left_len, right_len] =
line.hunks.iter().fold([0, 0, 0], |mut acc, (side, data)| {
let index = match side {
DiffLineHunkSide::Both => 0,
DiffLineHunkSide::Left => 1,
DiffLineHunkSide::Right => 2,
};
acc[index] += data.len();
acc
});
// left/right-only change is readable
(left_len != 0 && right_len != 0).then(|| {
let diff_len = left_len + right_len;
let total_len = both_len + left_len + right_len;
(diff_len as f32) / (total_len as f32)
})
})
.reduce(f32::max)
.unwrap_or(0.0)
}
// Total occupancy of changes. Large diffs don't always look complex.
fn total_change_ratio(diff_lines: &[DiffLine]) -> f32 {
let (diff_len, total_len) = diff_lines
.iter()
.flat_map(|line| &line.hunks)
.fold((0, 0), |(diff_len, total_len), (side, data)| {
let l = data.len();
match side {
DiffLineHunkSide::Both => (diff_len, total_len + l),
DiffLineHunkSide::Left => (diff_len + l, total_len + l),
DiffLineHunkSide::Right => (diff_len + l, total_len + l),
}
});
(diff_len as f32) / (total_len as f32)
}
```
* We started with a tristate flag where:
- Auto - Maintain current behaviour. This edits if
the wc parent is not a head commit. Else, it will
create a new commit on the parent of the wc in
the direction of movement.
- Always - Always edit
- Never - Never edit, prefer the new+squash workflow.
However, consensus the review thread is that `auto` mode where we try to infer when to
switch to `edit mode`, should be removed. So `ui.movement.edit` is a boolean flag now.
- true: edit mode
- false: new+squash mode
* Also add a `--no-edit` flag as the explicit inverse of `--edit` and
ensure both flags take precedence over the config.
* Update tests that assumed edit mode inference, to specify `--edit` explicitly.
NOTE: #4302 was squashed into this commit, so see that closed PR for review history.
Part of #3947
We all noticed that x86 macOS binaries are no longer being provided on release,
due to `macos-11` runners going the way of the Dodo a while back. Nobody
alterted us to this, funny enough.
After some quick discussion, we concluded some things:
- x86 macOS runners are likely oversubscribed, and hurt CI latency badly
- `macos-12` is also deprecated; `macos-13` is the best x86 runner available
- GitHub probably isn't going to expand macOS runner capacity; `macos-13` will
one day go away
- Some people are still using `jj` on Intel Macs. We didn't get alerted because
they do their own builds for now, but may not always do that.
- We can just try to build on `macos-13` and make it optional for merges.
So that's what this does. It might be mergeable outright, but we can also use it
to measure build latency impacts.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
* Add `builtin_immutable_heads()` in the `revsets.toml`.
* Redefine `immutable_heads()` in terms of `builtin_immutable_heads()`
* Warn if user redefines `builtin_immutable_heads()`, `mutable()` or
`immutable()`.
* Update module constant in revset_util.rs from BUILTIN_IMMUTABLE_HEADS
to USER_IMMUTABLE_HEADS to avoid confusion since it points at
`immutable_heads()` **and** we now have a revset-alias
literally named `builtin_immutable_heads()`.
* Add unittest
* Update CHANGELOG
* Update documentation.
Fixes: #4162
- add support for copy tracking to `diff --stat`
- switch `--summary` to match git's output more closely
- rework `show_diff_summary` signature to be more consistent
Add home directory expansion for SSH key filepaths. This allows the
`signing.key` configuration value to work more universally across both
Linux and macOS without requiring an absolute path.
This moved and renamed the previous `expand_git_path` function to a more
generic location, and the prior use was updated accordingly.
- force each diff command to explicitly enable copy tracking
- enable copy tracking in diff_summary
- post-process for diff iterator
- post-process for diff stream
- update changelog
Suppose a squash node in obslog is analogous to a merge in revisions log, it
makes sense to show diffs from auto-merge (or auto-squash) parents. This
basically means a non-partial squash node no longer shows diffs.
This also fixes missing diffs at the root predecessors if there were.
The idea is that --at-op specifies a certain operation, so --at-op=@ can be
interpreted as the option to select _the_ known head operation. This helps
eliminate special cases from "op log" which doesn't snapshot nor merge
concurrent ops.
Author dates and committer dates can be filtered like so:
committer_date(before:"1 hour ago") # more than 1 hour ago
committer_date(after:"1 hour ago") # 1 hour ago or less
A date range can be created by combining revsets. For example, to see any
revisions committed yesterday:
committer_date(after:"yesterday") & committer_date(before:"today")
To avoid always printing the rebase instructions to fix a conflict
even when a child commit to fix the conflict already exists, implement
the following:
* If working commit has conflicts:
* Continue printing the same message we print today.
* If working commit has no conflicts:
* If any parent has conflicts, we print: "Conflict in parent is resolved in working copy".
Also explicitly not printing the "conflicting parent" here, since a merge commit
could have conflict in multiple parents.
* If no parent has any conflicts: exit quietly.
* Update unittests for conflict hinting update.
* Update CHANGELOG
This changes less than it seems. Our CI builds already mostly linked a vendored
copy of libgit2. This is because before this commit, it turns out that `git2`
could link `libgit2` *either* statically or dynamically based on whether it could
find a version of libgit2 it liked to link dynamically. Our CI builds usually did
not provide such a version AFAIK.
This made the kind of binary `cargo install` would produce unpredictable and may
have contributed to #2896. I was once very surprised when I did `brew upgrade libgit2` and then
`cargo build --release` suddenly switched from building dynamically linked `jj` to the vendored version.
Instead, if a packager wants to link `libgit2` dynamically, they should set an
environment variable, as described inside the diff of this commit. I also think
we should recommend static linking as `git2` is quite picky about the versions of
`libgit2` it supports. See also https://github.com/rust-lang/git2-rs/pull/1073
This might be related to #4115.
The high level changes include:
- Reworking `fix_file_ids()` to loop over multiple candidate tools per file,
piping file content between them. Only the final file content is written to
the store, and content is no longer read for changed files that don't match
any of the configured patterns.
- New struct `ToolsConfig` to represent the parsed/validated configuration.
- New function `get_tools_config()` to create a `ToolsConfig` from a `Config`.
- New tests; the only old behavior that has changed is that we don't require
`fix.tool-command` if `fix.tools` defines one or more tools. The general
approach to validating the config is to fail early if anything is weird.
Co-Authored-By: Josh Steadmon <steadmon@google.com>
This implements a building block of "signed-off-by line" #1399 and "commit
--verbose" #1946. We'll probably need an easy way to customize the diff part,
but I'm not sure if it can be as simple as a template alias function. User
might want to embed diffs without "JJ: " prefixes?
Perhaps, we can deprecate "ui.default-description", but it's not addressed in
this patch. It could be replaced with "default_description" template alias,
but we might want to configure default per command. Suppose we add a default
"backout_description" template, it would have to be rendered against the
source commit, not the newly-created backout commit.
The template key is named as "draft_commit_description" because it is the
template to generate an editor template. "templates.commit_description_template"
sounds a bit odd.
There's one minor behavior change: the default description is now terminated
by "\n".
Closes#1354
This basically reverts 20eb9ecec1 "git: don't abandon HEAD commit when it
loses a branch." I think the new behavior is more consistent because the Git
HEAD is equivalent to @- in jj, so it shouldn't be considered a named ref.
Note that we've made old HEAD branch not considered at 92cfffd843 "git: on
external HEAD move, do not abandon old branch."
#4108
The user can define the setting `git.private-commits` as they desire. For
example:
git.private-commits = 'description(glob:"wip:*")'
If any commits are in this revset, then the push is aborted.
If a commit would be private but already exists on the remote, then it does
not block pushes, nor do its descendents block pushes unless they are also
contained in `git.private-commits`.
Closes#3376
Prevents a warning from being printed when renaming branches in a
colocated repo, since git tracking branches were being considered as
remote tracking branches.
The text pattern is applied prior to comparison as we do in Mercurial. This
might affect hunk selection, but is much faster than computing diff of full
file contents. For example, the following hunk wouldn't be caught by
diff_contains("a") because the line "b\n" is filtered out:
- a
b
+ a
Closes#2933
This patch adds TreeDiff template type to host formatting options. The main
reason of this API design is that diff formats have various incompatible
parameters, so a single .diff(files, format[, options..]) method would become
messy pretty quickly. Another reason is that we can probably add custom
summary templating support as diff.files().map(|file| file.path()..).
RepoPathUiConverter is passed to templater explicitly because the one stored
in RevsetParseContext is behind Option<_>.
Since fileset and revset languages are syntactically close, we can reparse
revset expression as a fileset. This might sound a bit scary, but helps
eliminate nested quoting like file("~glob:'*.rs'"). One oddity exists in alias
substitution, though. Another possible problem is that we'll need to add fake
operator parsing rules if we introduce incompatibility in fileset, or want to
embed revset expressions in a fileset.
Since "file(x, y)" is equivalent to "file(x|y)", the former will be deprecated.
I'll probably add a mechanism to collect warnings during parsing.
I used to use "remote_branches() & ~mine()" to exclude "their" branches from
the default log, and I don't think that's uncommon requirement. Suppose
untracked branches are usually read-only, it's probably okay to make them
immutable by default.
Adds support for revset functions `tracked_remote_branches()` and
`untracked_remote_branches()`. I think this would be especially useful
for configuring `immutable_heads()` because rewriting untracked remote
branches usually wouldn't be desirable (since it wouldn't update the
remote branch). It also makes it easy to hide branches that you don't
care about from the log, since you could hide untracked branches and
then only track branches that you care about.
Partially resolve a 1.5‐year‐old TODO comment.
Add opt‐in syntax for case‐insensitive matching, suffixing the
pattern kind with `-i`. Not every context supports case‐insensitive
patterns (e.g. Git branch fetch settings). It may make sense to make
this the default in at least some contexts (e.g. the commit signature
and description revsets), but it would require some thought to avoid
more confusing context‐sensitivity.
Make `mine()` match case‐insensitively unconditionally, since email
addresses are conventionally case‐insensitive and it doesn’t take
a pattern anyway.
This currently only handles ASCII case folding, due to the complexities
of case‐insensitive Unicode comparison and the `glob` crate’s lack
of support for it. This is unlikely to matter for email addresses,
which very rarely contain non‐ASCII characters, but is unfortunate
for names and descriptions. However, the current matching behaviour is
already seriously deficient for non‐ASCII text due to the lack of any
normalization, so this hopefully shouldn’t be a blocker to adding the
interface. An expository comment has been left in the code for anyone
who wants to try and address this (perhaps a future version of myself).