- 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).
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
Forgetting a workspace removes its working-copy commit, so it makes
sense for it to be abandoned if it is discardable just like editing a
new commit will cause the old commit to be abandoned if it is
discardable.
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.
Fixes#2476.
Previously, if there was a change id match within the short prefix
lookup set, `jj` would not look for commits with that same change id
outside the short prefix set. So, it wouldn't find the conflicted
commits for a commit with a divergent (AKA conflicted) change id.
It's common to create empty working-copy commits while using jj, and
currently the author timestamp for a commit is only set when it is first
created. If you create an empty commit, then don't work on a repo for a
few days, and then start working on a new feature without abandoning the
working-copy commit, the author timestamp will remain as the time the
commit was created rather than being updated to the time that work began
or finished.
This commit changes the behavior so that discardable commits (empty
commits with no description) by the current user have their author
timestamps reset when they are rewritten, meaning that the author
timestamp will become finalized whenever a commit is given a description
or becomes non-empty.
We now have two `cmd_show` in the repo. I think this one should become
`cmd_file_show`, but this should be done uniformly over all the commands
for consistency.
I did *not* keep `print` as an alias (I couldn't find a compelling
reason to do it), but let me know if anyone feels like keeping it.
Since "set <thing>" often adds a <thing> if not exists, it make some sense
that "branch set" does upsert. The current "branch set" use case is now covered
by "branch move", so it's okay to change the "set" behavior.
If new branch is created by "branch set", status message and hint will be
printed to help migration. The user should be able to undo creation if it was
a mistake.
Closes#3584
This allows users to jump to the next conflict in the ancestors or children of
the start commit.
Continues work on #2126
Co-Authored-By: Noah Mayr <dev@noahmayr.com>
In a repo of mine I wanted to do something like the following to push all of my
leaves to the remote as backup:
jj git push -c 'all:heads(base::) & mine() ~ empty()'
But couldn't, because `jj git push` doesn't handle large revsets, even though
it does handle multiple `-c` arguments, so I had to work out some pipe-to-xargs
command instead.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
This basically supersedes the current "branch set" command. The plan is to turn
"branch set" into an "upsert" command, and deprecate "branch create". (#3584)
Maybe we can also add "branch set --new" flag to only allow creation of new
branches. One reason behind this proposed change is that "set" usually allows
both "creation" and "update". However, we also need a typo-safe version of
"set" to not create new branches by accident.
"jj branch move" is useful when advancing ancestor branches. Let's say you've
added a couple of commits on top of an existing PR branch, you can advance the
branch by "jj branch move --from 'heads(::@- & branches())' --to @-". If this
pattern is super common, maybe we can add --advance flag for short.
One drawback of this change is that "git branch --move" is equivalent to
"jj branch rename". I personally don't find this is confusing, but it's true
that "move" sometimes means "rename".
- 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>
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
Most of the value of `jj fix` over a shell script is in formatting commits
other than `@`. `@::` often doesn't contain those other commits, so `-s @` is a
bad default.
We could get the same effect from `-s 'mutable() & ::@'`, but `reachable()` is
a bit more explicit and simple to read.
We could also base this on excluding `trunk()`, but that just seems like an
indirection for `mutable()` that might ignore the user's intent if they have
configured part of trunk to be mutable.
It's been more than 6 months since we added support for dynamically
selecting the working copy implementation. This patch drops support
for selecting the default implementation of that and other stores.
This addresses issue #3317, where as discussed we want to show the paths to
configuration files if they contain errors, to make it easier for the user to
locate them.
The goal is to remove special case from parsing functions and provide slightly
better error message. I don't know if we'd want to use "all:" in aliases, but
there are no strong reasons to disable it.
This commit adds an optional flag to be able to push commits with an
empty description to a remote git repo. While the default behavior is
ideal we might need to interact with a repo that has an empty commit
description in it. I ran into this issue a few weeks ago pushing commits
from an open source repo to an empty repo and had to go back to using
git for that push as I would not want to rewrite the history which was
many many years long just for that.
This flag allows users an escape hatch for pushing empty descriptions
for commits and they're sure that they want that behavior.
This commit adds the flag to the `git push` command and updates the docs
for the command. It also updates the original test to make sure that the
flag works as intended to reject the commit when not set and to allow
the commit when the flag is set.
Closes#2633
Clear the rest of the cursor line (from the cursor to the end of the
row) after drawing the progress bar rather than clearing the entire line
before drawing. This reduces flickering on terminal emulators which are
able to redraw rapidly.
I recently needed to test something on top of a two branches at the
same time, so I created a new commit on top of both of them (i.e. a
merge commit). I then ran tests and made some adjustments to the
code. These adjustments belonged in one of the parent branches, so I
used `jj squash --into` to squash it in there. Unfortunately, that
meant that my working copy became a single-parent commit based on one
of the branches only. We already had #2859 for tracking this issue.
This patch changes the behavior so we create a new working-copy commit
with all of the previous parents.
As explained in the commit, our logic is a bit more complicated than
that of `git push --force-with-lease`. This is to match the behavior of
`jj git fetch` and branch conflict resolution rules.
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.
previously, aliases to built-in commands were silently ignored. this matches git's behavior, but seems unhelpful, especially if the user doesn't know that a command with that name already exists.
give a warning rather than silently ignoring it.
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.
Perhaps, this can be used to generate parsable branches list.
The hint for deleted branches isn't migrated to the template. I'm thinking of
moving it out of the loop and printed once at the end. If we want to generate
a hint in template, we'll probably need local_ref.tracking_remote_refs(), etc.
that return a list of RefNames.
For example,
```
<<<<<<< Conflict 1 of 3
+++++++ Contents of side #1
left 3.1
left 3.2
left 3.3
%%%%%%% Changes from base to side #2
-line 3
+right 3.1
>>>>>>>
```
or
```
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-line 3
+right 3.1
+++++++ Contents of side #2
left 3.1
left 3.2
left 3.3
>>>>>>>
```
Currently, there is no way to disable these, this is TODO for a future
PR. Other TODOs for future PRs: make these labels configurable. After
that, we could support a `diff3/git`-like conflict format as well, in
principle.
Counting conflicts helps with knowing whether you fixed all the
conflicts while you are in the editor.
While labeling "side #1", etc, does not tell you the commit id or
description as requested in #1176, I still think it's an improvement.
Most importantly, I hope this will make `jj`'s conflict format less
scary-looking for new users.
I've used this for a bit, and I like it. Without the labels, I would see
that the two conflicts have a different order of conflict markers, but I
wouldn't be able to remember what that means. For longer diffs, it can
be tricky for me to quickly tell that it's a diff as opposed to one of
the sides. This also creates some hope of being able to navigate a
conflict with more than 2 sides.
Another not-so-secret goal for this is explained in
https://github.com/martinvonz/jj/pull/3109#issuecomment-2014140627. The
idea is a little weird, but I *think* it could be helpful, and I'd like
to experiment with it.
Thanks to everyone who's contributed!
Unlike previous releases, I went through the changelog entries and
reorganized them a bit.
We didn't have anything under "Deprecations" this time, but I moved
the heading after "Breaking changes" for next release. I think
breaking changes are more important because deprecations are just
about giving a heads up before it actually breaks.
Since fileset/revset/template expressions are specified as command-line
arguments, it's sometimes convenient to use single quotes instead of double
quotes. Various scripting languages parse single-quoted strings in various ways,
but I choose the TOML rule because it's simple and practically useful. TOML is
our config language, so copying the TOML syntax would be less surprising than
borrowing it from another language.
https://github.com/toml-lang/toml/issues/188
Previously, this command would work:
jj --config-toml='snapshot.max-new-file-size="1"' st
And is equivalent to this:
jj --config-toml='snapshot.max-new-file-size="1B"' st
But this would not work, despite looking like it should:
jj --config-toml='snapshot.max-new-file-size=1' st
This is extremely confusing for users.
This config value is deserialized via serde; and while the `HumanByteSize`
struct allegedly implemented Serde's `visit_u64` method, it was not called by
the deserialize visitor. Strangely, adding an `visit_i64` method *did* work, but
then requires handling of overflow, etc. This is likely because TOML integers
are naturally specified in `i64`.
Instead, just don't bother with any of that; implement a `TryFrom<String>`
instance for `HumanByteSize` that uses `u64::from_str` to try parsing the string
immediately; *then* fall back to `parse_human_byte_size` if that doesn't work.
This not only fixes the behavior but, IMO, is much simpler to reason about; we
get our `Deserialize` instance for free from the `TryFrom` instance.
Finally, this adjusts the test for `max-new-file-size` to now use a raw integer
literal, to ensure it doesn't regress. (There are already in-crate tests for
parsing the human readable strings.)
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: I8dafa2358d039ad1c07e9a512c1d10fed5845738
This fixes several issues that made working with empty files difficult using
the builtin diff editor.
1. The scm-record library used for the editor expects each file to have at
least one section. For new empty files this should be a file mode section. jj
wasn't rendering this mode section, which prevented empty files from being
selected at all.
2. The scm-record library returns `SelectedContents::Absent` if the file has no
contents after the diff editor is invoked. This can be because of several
reasons: 1) the file is new and empty; 2) the file was empty before and is
still empty; 3) the file has been deleted. Perhaps this is a bug in scm-record
and it should return `SelectedContents::Unchanged` or
`SelectedContents::Present` if the file hasn't been deleted. Until this is
patched upstream, we can work around it by disambiguating these cases.
See https://github.com/arxanas/scm-record/issues/26 for the upstream bug.
Fixes#3016
if `--use-destination-message/-u` is passed to `jj squash`, the resulting
revision will use the description of the destination revision and the
description(s) of the source revision(s) will be discarded.
If this doesn't work out, maybe we can try one of these:
a. fall back to bare file name if expression doesn't contain any operator-like
characters (e.g. "f(x" is an error, but "f x" can be parsed as bare string)
b. introduce command-line flag to opt in (e.g. -e FILESET)
c. introduce pattern prefix to opt in (e.g. set:FILESET)
Closes#3239, #2915, #2286
This command checks not only whether Watchman works, but also whether
it's enabled in the config. Also, the output is easier to understand
than that of the other `jj debug watchman` commands.
It would be nice if `jj debug watchman` called `jj debug watchman
status`, but it's not trivial in `clap` to have a default subcommand.
Ilya reported this in https://github.com/martinvonz/jj/issues/3483.
The bug was introduced in 976320726d.
Before this fix, `jj split` dropped any parents what weren't involved in the
split when it rebased the children of the commit being split. This meant that
any children which were merge commits lost their other parents unintentionally.
Fixes#3483
Before this commit `jj prev` fails if the current working copy commit is a
merge commit. After this commit it will prompt the user to choose the ancestor
they want to select.
#2126
Expose the information we now record, to allow changing the default "snapshot
working copy" message or to make snapshots more compact/less distracting in
the log
This is basically the same as string kind:pattern syntax in CLI. This will
hopefully be superseded by filesets, but I'm not sure if that will work out.
A file name is more likely to contain whitespaces, which will have to be
quoted as '"Documents and Settings"'.
Parallelize revisions by making them siblings
Running `jj parallelize 1::2` will transform the history like this:
```text
3
| 3
2 / \
| -> 1 2
1 \ /
| 0
0
```
Each of the target revisions is rebased onto the parents of the root(s) of
the target revset (not to be confused with the repo root). The children of
the head(s) of the target revset are rebased onto the target revisions.
The target revset is the union of the REVISIONS arguments.
The target revset being parallelized must satisfy several conditions,
otherwise the command will fail.
1. The heads of the target revset must not have different children.
2. The roots of the target revset must not have different parents.
3. The parents of all target revisions except the roots must also be
parallelized. This means that the target revisions must be connected.
This lets users use "large" revsets in commands such as `jj rebase`, without
needing the `all:` modifier.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: Ica80927324f3d634413d3cc79fbc73057ccefd8a
I keep typing `--to` since I'm used to `jj move` interface. It is
also shorter.
Currently, if I type `--to`, clap unhelpfully suggests whether I
meant `--tool`.
Like -r/--revisions, it should be okay to filter synced/non-tracking remote
branches by name.
conflicts_with_all = "tracked" is redundant, so removed as well. The tracked
field declares that it conflicts with --all-remotes.
If the --siblings option is used, the target commit is split into two sibling
commits instead of parent and child commits. Any children of the original
commit will have both siblings as their new parents.
#2274
Note that `jj resolve` already had its own `--quiet` flag. The output
with `--quiet` for that command got a lot quieter with the global
`--quiet` also taking effect. That seems reasonable to me.
Commands like `new`, `duplicate`, and `abandon` can take multiple revset
arguments which results in their collective union. They take the revisions
directly as arguments. But for consistency with many other commands, they can
also take the `-r` argument, which is a no-op. However, due to the flag being
specified as a `bool`, the `-r` option can only be specified once, so e.g.
`abandon -r x -r y` often fails. I normally use `-r` for consistency and muscle
memory, so this bites me often.
Instead, use `clap::ArgAction::Count` in order to allow `-r` to be specified
multiple times. It remains unused, of course.
With this change, all the following invocations are equivalent. Before this
change, the second example would fail due to giving `-r` multiple times.
jj abandon x y
jj abandon -r x -r y
jj abandon -r 'x | y'
Note: `jj new` already supported this exact case actually, but it used an
awkward trick where it used `.overrides_with()` in order to override *itself* so
it could be specified multiple times. I believe this is a bit clearer.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: Ib36cf81d46dae4f698f06d0a32e8fd3120bfb4a4
This can be used to flatten nested "if()"s. It's not exactly the same as "case"
or "switch" expression, but works reasonably well in template. It's not uncommon
to show placeholder text in place of an empty content, and a nullish value
(e.g. empty string, list, option) is usually rendered as an empty text.
As requested in #1471, I added a new flag for `jj branch list` to only show branches that are conflicted.
Adds a unit test to check for listing only conflicted branches and regenerates the cli output to incorporate the new flag.
Closes#1471
reformat
As discussed in #2900, the milliseconds are rarely useful, and it can
be confusing with different timezones because it makes harder to
compare timestamps.
I added an environment variable to control the timestamp in a
cross-platform way. I didn't document because it exists only for tests
(like `JJ_RANDOMNESS_SEED`).
Closes#2900
Changes the formatter to accept not only existing color names (such as "red" or
"green") but also those in the form #rrggbb, where rr, gg, and bb are two-digit
hexadecimal numbers. This allows much finer control over colors used.
Now you can do e.g. `jj squash --from 'foo+::' --into foo` to squash a
whole series into one commit. It doesn't need to be linear; you can
squash a bunch of siblings into another siblings, for example.
This was proposed by @Brixy in
https://github.com/martinvonz/jj/discussions/2882 a while ago. There
seems to be pretty strong consensus that it's a good idea.
I've copied the added test cases from `test_move_command.rs`, just
replacing `move` by `squash`, `--to` by `--into`, and deleting the
test of a no-arg invocation (`jj move` fails, `jj squash` does not -
it defaults to squashing into the parent).
Commit b4c4d911 introduced this entry in the changelog, but put it in the 0.15.0
section rather than the new unreleased section.
This was probably just because the original commit was authored before the
0.15.0 release, but merged after. Such is life.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
This release is just so we can publish the crates to crates.io. We
couldn't publish the 0.15.0 crates because `jj-lib-proc-macros` had
`publish = false`.
There's a caveat: "jj config list -Tname" will concatenate all names in a
single line. That's correct but useless. We might want some option or config
knob to complete missing "\n". This also applies to "log --no-graph".
Add an option to list tracked branches only
This option keeps most of the current `--all` printing logic, but:
- Omits local Git-tracking branches by default (can be extended to
support filtering by remote).
- Skip over the branch altogether if it doesn't contain tracked remotes
- Don't print the untracked_remote_refs at the end
Usage:
`jj branch list -t`
`jj branch list --tracked`
`jj branch list --tracked <branch name>`
I think the user usually wants to abandon only newly empty commits. I
think they should use `jj abandon` if they want to get rid of already
empty commits. By keeping already empty commits, we don't need to
special-case the working copy and merge commits.
This allows us to call alias function with the top-level object.
For convenience, all self.<method>()s are available as keywords. I don't think
we'll want to deprecate them. It would be tedious if we had to specify
-T'self.commit_id()' instead of -Tcommit_id.
The default immutable_heads() includes tags(), which makes sense, but computing
heads(tags()) can be expensive because the tags() set is usually sparse. For
example, "jj bench revset 'heads(tags())'" took 157ms in my linux stable
mirror. We can of course optimize the heads evaluation by using bit set or
segmented index, but the query includes many historical heads if the repository
has per-release branches, which are uninteresting anyway. So, this patch
replaces heads(immutable_heads()) with trunk().
The reason we include heads(immutable_heads()) is to mitigate the following
problem. Suppose trunk() is the branch to be based off, I think using trunk()
here is pretty good.
```
A B
*---*----* trunk() ⊆ immutable_heads()
\
* C
```
https://github.com/martinvonz/jj/pull/2247#discussion_r1335078879
I think I prefer this behavior because it's less lossy. The user can
manually simplify the history with `jj rebase -s <merge commit> -d
<one of the parents>` afterwards. We can roll this change back later
if we find it annoying.
The legacy parsing rules are turned into compatibility errors. The x:y rule
is temporarily enabled when parsing string patterns. It's weird, but we can't
isolate the parsing function because a string pattern may be defined in an
alias.
This adds a config to render a synthetic node with a "(elided
revisions)" description for elided segments of the graph.
I didn't add any templating support for the elided nodes because I'm
not sure how we would want that to work. In particular, I don't know
what `commit_id` and most other keywords should return for elided
revisions.
Users who edit non-head commits usually expect `jj next/prev` to
continue to edit the next/previous commit, so let's make that the
default behavior. This should not confuse users who don't edit
non-head commits since they will simply not be in this state. My main
concern is that doing `jj next; jj prev` will now usually take you
back to the previous commit, but not if you started on the parent of a
head commit.
I'm going to introduce breaking changes in index format. Some of them will
affect the file size, so version number or signature won't be needed. However,
I think it's safer to detect the format change as early as possible.
I have no idea if embedded version number is the best way. Because segment
files are looked up through the operation links, the version number could be
stored there and/or the "segments" directory could be versioned. If we want to
support multiple format versions and clients, it might be better to split the
tables into data chunks (e.g. graph entries, commit id table, change id table),
and add per-chunk version/type tag. I choose the per-file version just because
it's simple and would be non-controversial.
As I'm going to introduce format change pretty soon, this patch doesn't
implement data migration. The existing index files will be deleted and new
files will be created from scratch.
Planned index format changes include:
1. remove unused "flags" field
2. inline commit parents up to two
3. add sorted change ids table
I was a bit surprised to learn (or be reminded?) that checking out
symlinks on Windows leads to a panic. This patch fixes the crash by
materializing symlinks from the repo as regular files. It also updates
the snapshotting code so we preserve the symlink-ness of a path. The
user can update the symlink in the repo by updating the regular file
in the working copy. This seems to match Git's behavior on Windows
when symlinks are disabled.
I'll probably add infix logical operators later, but the surround() function
is still useful because we don't have to repeat the condition:
if(x || y, "<" ++ separate(" ", x, y) ++ ">")
surround("<", ">", separate(" ", x, y))
It can't be used if we want to add placeholder text, though:
if(x || y, "<" ++ separate(" ", x, y) ++ ">", "(none)")
Closes#2924