In order for the governance working group to make progress establishing
jj's governance structure, we need the approval of the jj community.
Set up a temporary voting process to get that approval.
Additionally, set up a governance dir for other governance-related
documentation to sit in.
Later, when we have a permanent governance structure and enough policy
to let the community make changes without needing the governance working
group, we can delete this document.
Jujutsu's branches do not behave like Git branches, which is a major
hurdle for people adopting it from Git. They rather behave like
Mercurial's (hg) bookmarks.
We've had multiple discussions about it in the last ~1.5 years about this rename in the Discord,
where multiple people agreed that this _false_ familiarity does not help anyone. Initially we were
reluctant to do it but overtime, more and more users agreed that `bookmark` was a better for name
the current mechanism. This may be hard break for current `jj branch` users, but it will immensly
help Jujutsu's future, by defining it as our first own term. The `[experimental-moving-branches]`
config option is currently left alone, to force not another large config update for
users, since the last time this happened was when `jj log -T show` was removed, which immediately
resulted in breaking users and introduced soft deprecations.
This name change will also make it easier to introduce Topics (#3402) as _topological branches_
with a easier model.
This was mostly done via LSP, ripgrep and sed and a whole bunch of manual changes either from
me being lazy or thankfully pointed out by reviewers.
It's a pretty frequent request to have support for turning off
auto-tracking of new files and to have a command to manually track
them instead. This patch adds a `snapshot.auto-track` config to decide
which paths to auto-track (defaults to `all()`). It also adds a `jj
track` command to manually track the untracked paths.
This patch does not include displaying the untracked paths in `jj
status`, so for now this is probably only useful in colocated repos
where you can run `git status` to find the untracked files.
#323
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").
MkDocs did not render this list in
https://martinvonz.github.io/jj/prerelease/config/#node-style properly
before.
I don't understand the reason; we have other lists that are formatted
similarly to how this one was, and they look fine in MkDocs. This might
be a bug in one of the MkDocs extensions for lists that we use.
The question "How do I avoid committing changes to files?" comes up a lot in
chat, and the solution is not obvious. It will be useful to have a description
with an example we can link to.
The wording of the similar question "How can I keep my scratch files in the
repository?" was tweaked to emphasize the difference between keeping untracked
files in the workspace and keeping changes tracked files out of published
history.
"Concurrent" operations are not necessarily actually concurrent, so
"divergent" seems like a better name. And "reconcile" seems like a
better term for merging them, though we also sometimes use "merge".
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)
}
```
[VSCodium](https://vscodium.com/) is a free/libre distribution of
Microsoft's Visual Studio Code editor, it's functionally more or less
the same, but distributed under a FOSS license, unlike VS Code.
This adds VSCodium as a merge tool.
* 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 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.
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")
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
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
It's inconvenient that we have to quote glob patterns as 'glob:"*.rs"'. Suppose
filesets are usually specified in shell, it's better to allow unquoted strings
if possible. This change also means we'll probably abandon #2101 "make the
parsing of string arguments stricter."
Note that we can no longer introduce ? operator or [] subscript syntax in
filesets.
Closes#4053
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).
The output looks somewhat similar to color-words diffs. Unified diffs are
verbose, but are easier to follow if adjacent lines are added/removed + modified
for example.
Word-level diffing is forcibly enabled. We can also add a config knob (or
!color condition) to turn it off to save CPU time.
I originally considered disabling highlights in block insertion/deletion, but
that wasn't always great. This can be addressed separately as it also applies
to color-words diffs. #3958
The default style is compatible with various terminal emulators, but I suspect
that many people wouldn't like underlines. Let's add an example to override it.
This adds the basic outline of _when_ a Design Doc should be written. See the next
commit in the stack for the blueprint.
By adding this we hopefully can prevent unnecessary churn from new and longtime contributors,
when they want to add a major feature or rewrite a core part of Jujutsu. The text is written
as a guideline, not a rule.
- make an internal set of watchman extensions until the client api gets
updates with triggers
- add a config option to enable using triggers in watchman
Co-authored-by: Waleed Khan <me@waleedkhan.name>
There's been a lot of questions about the subtle differences between
`..` and `::`. I hope these examples will help with that.
We should also add examples to the revset functions (e.g. `heads()` is
not obvious how it works), but that can come later.
`..` is shorthand for `root()..visible_head()`, for example. We don't
seem to explain that anywhere. I hope mentioning that will help
readers understand the relationship between the shorthands and the
full `x..y`, and also to see the correspondence between `..` and `::`
(in how their default left and right operands are the same).
I am currently not aware of any severe differences between the generated
markdown and `jj help`, though this could change if we look over the
text carefully or if we start using `clap` features we weren't using
before.
Still alias function shadows builtin function (of any arity) by name. This
allows to detect argument error as such, but might be a bit inconvenient if
user wants to overload heads() for example. If needed, maybe we can add some
config/revset syntax to import builtin function to alias namespace.
The functions table is keyed by name, not by (name, arity) pair. That's mainly
because std collections require keys to be Borrow, and a pair of borrowed
values is incompatible with owned pair. Another reason is it makes easy to look
up overloads by name.
Alias overloading could also be achieved by adding default parameters, but that
will complicate the implementation a bit more, and can't prevent shadowing of
0-ary immutable_heads().
Closes#2966
I just added "can be empty" since it seems obvious when it becomes empty if it
can be empty. AFAICT, the confusion in #3821 is whether or not "no parents"
falls back to root().
We can add a separate precedence/associativity table, but I think the ordered
list is good enough. Nullary :: and .. have no binding, but inserted after the
infix versions for brevity.
On Windows `code` works in the shell, but not when specified to jj, because the
executable is actually named `code.cmd`! This is a feature of Windows, where
certain file extensions (defined by the PATHEXT environment variable) are
automatically treated as executable and can have their extensions omitted.
Presumably, jj doesn't support this feature on Windows, though perhaps it
should. For now, avoid adding an explanation of PATHEXT so as to not clutter
things too much, and just suggest `code.cmd` on Windows. Most readers should be
able to put two and two together from there.
I feel like recommending people install Poetry via a package manager was
a mistake. Poetry only supports its latest version, and while newer
versions are sort-of backward-compatible, they print warnings in
different situations and have different bugs. Installing `pipx` via a
package manager, OTOH, works fine, and its older versions work fine.
Using Poetry 1.8+ allows us to use Poetry's new "non-package" mode,
which would no longer print warnings if the user does `poetry install`
instead of `poetry install --no-root`. It's likely that in newer
versions of Poetry, it will become an error.
I add them as aliases, since a user may instead choose to define `immutable_heads()`, for example, as `heads(immutable())`, and the define `immutable()` instead.
This revset correctly implements "reachability" from a set of source commits following both parent and child edges as far as they can go within a domain set. This type of 'bfs' query is currently impossible to express with existing revset functions.
When using `ui.color = "debug"`, changes in the output style
additionally include delimiters << and >>, as well as all active labels
at this point separated by ::. The output is otherwise unformatted and
the delimiters and labels inherit the style of the content they apply
to.
More tests will be added later as "branch list" templates.
In "log" template, we might want to see the number of "local" commits ahead
of any tracked remotes. It can be implemented later in a similar way (or as a
nested remote_refs list.)
We'll probably add binary comparison operators at some point, but this patch
also adds size_hint.zero() method. Otherwise, we'll have to write
"if(x.upper() && x.upper() == 0, ..)" to deal with None.
The resulting "branch list" template will look like:
```
separate(", ",
if(!ref.tracking_ahead_count().zero(),
if(ref.tracking_ahead_count().exact(),
"ahead by " ++ ref.tracking_ahead_count().exact() ++ " commits",
"ahead by at least " ++ ref.tracking_ahead_count().lower() ++ " commits")),
if(!ref.tracking_behind_count().zero(),
if(ref.tracking_behind_count().exact(),
"behind by " ++ ref.tracking_behind_count().exact() ++ " commits",
"behind by at least " ++ ref.tracking_behind_count().lower() ++ " commits")),
)
```
This is instead of https://github.com/martinvonz/jj/pull/3292, which would make
`diffedit3` built into `jj`. I still have some hope of eventually making
`diffedit3` into the default diff editor that is available without any
configuration, which probably requires building it into `jj`, but this may not
happen, and it wouldn't hurt to test `diffedit3` first. Some examples of
concerns (see also the discussion in that PR):
- It is only a guess on my part that this would make a good default. The editor
might not be polished enough, and most users are not used to 3-pane diff
editing. I think most users would like it if they tried it, but this might be
plain wrong.
- There are concerns about adding a heavyweight dependency on `jj`. While I
tried to make it as lightweight as possible, it still unavoidably includes a web
server.
- There may be ways to bundle `diffedit3` with `jj` without combining them in a
single binary.
I wanted to have a reference point for the built-in revsets,
but `jj config get revsets.log` doesn't turn anything up since
it has special handling for the legacy config key
`ui.default-revset`. So I had to dig into the source code of jj
to get it.
I think it might help others to be able to reason about revsets
to have the log default shown in the settings documentation.
I considered adding RefTarget template type, but some of the methods naturally
fit to RefName. For example, a conflicted branch name is decorated as "??", so
it makes sense to add branch.conflict() instead of branch.target().conflict().
I'm not pretty sure how many RefName methods we'll need to add to port the
current branch listing, but there will be .tracked(), .tracking_local_present(),
.ahead_by(), and .behind_by().