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

Group (topological) branches in log output #242

Closed
martinvonz opened this issue Apr 25, 2022 · 7 comments
Closed

Group (topological) branches in log output #242

martinvonz opened this issue Apr 25, 2022 · 7 comments

Comments

@martinvonz
Copy link
Owner

martinvonz commented Apr 25, 2022

Description

Parallel branches are interleaved in the (ASCII-)graphical log output, making it hard to read.

Actual Behavior

o 2e4dc019d943 e8c23f0ee5e2 martinvonz@google.com 2021-10-20 14:21:01.000 -07:00
: git: don't update public heads for now
: o 77b94b593d68 bb3b69138188 martinvonz@google.com 2021-10-13 12:29:47.000 -07:00
: | git: move logic for adding remote to git module
: | o cfd9255b94d3 c48b95a17bdf martinvonz@google.com 2021-10-13 16:17:40.000 -07:00
: |/  index: start indexing file-level conflicts
:/|
o | ca796b49f06f b4323a1a35b6 martinvonz@google.com 2021-10-13 20:38:39.000 -07:00
:/  docs: describe how to set up commmand-line completion
o c0a26f76426e 543967befc73 martinvonz@google.com 2021-10-13 11:08:01.000 -07:00

Expected Behavior

It's much easier to read like this:

o 2e4dc019d943 e8c23f0ee5e2 martinvonz@google.com 2021-10-20 14:21:01.000 -07:00
: git: don't update public heads for now
: o cfd9255b94d3 c48b95a17bdf martinvonz@google.com 2021-10-13 16:17:40.000 -07:00
:/  index: start indexing file-level conflicts
o ca796b49f06f b4323a1a35b6 martinvonz@google.com 2021-10-13 20:38:39.000 -07:00
: docs: describe how to set up commmand-line completion
: o 77b94b593d68 bb3b69138188 martinvonz@google.com 2021-10-13 12:29:47.000 -07:00
:/ git: move logic for adding remote to git module
o c0a26f76426e 543967befc73 martinvonz@google.com 2021-10-13 11:08:01.000 -07:00

I think the idea is to print all commits on one side of a fork point before the other side(s) of the fork point. The fork points in this graph are ca796b49f06f and c0a26f76426e, although only the latter matters in this case (because there's only one commit on each side before ca796b49f06f)

Specifications

  • Platform: All
  • Version: 0.4.0
@martinvonz
Copy link
Owner Author

@avamsi
Copy link
Collaborator

avamsi commented Jan 14, 2023

Sorry, haven't read through that Github blog in detail so maybe I have this wrong but it seems to me like a simple DFS like approach would work well (enough) here? I personally find this much easier to read --

o c0a26f76426e 543967befc73 martinvonz@google.com 2021-10-13 11:08:01.000 -07:00
|
|...o ca796b49f06f b4323a1a35b6 martinvonz@google.com 2021-10-13 20:38:39.000 -07:00
|   | docs: describe how to set up commmand-line completion
|   |
|   |---o cfd9255b94d3 c48b95a17bdf martinvonz@google.com 2021-10-13 16:17:40.000 -07:00
|   |     index: start indexing file-level conflicts
|   |
|   |...o 2e4dc019d943 e8c23f0ee5e2 martinvonz@google.com 2021-10-20 14:21:01.000 -07:00
|         git: don't update public heads for now
|
>---@ 77b94b593d68 bb3b69138188 martinvonz@google.com 2021-10-13 12:29:47.000 -07:00
      git: move logic for adding remote to git module

I originally did not differentiate between children vs descendants but then later shoehorned it with --- vs ..., I personally don't have much of a use for that differentiation but I'm not sure if people do.

Also, I'm not really sure how jj handles those relations in code but in the DFS, we could just prefer to render most recently touched subtrees towards the end (or the beginning, if you don't reverse the output), with the working copy getting special preference to be considered most recently touched (and hence get rendered at the last for better visibility). Thoughts?

@avamsi
Copy link
Collaborator

avamsi commented Jan 14, 2023

Just to make the above log more compact (like jj log now),

o c0a26f76426e 543967befc73 martinvonz@google.com 2021-10-13 11:08:01.000 -07:00
|...o ca796b49f06f b4323a1a35b6 martinvonz@google.com 2021-10-13 20:38:39.000 -07:00
|   | docs: describe how to set up commmand-line completion
|   |---o cfd9255b94d3 c48b95a17bdf martinvonz@google.com 2021-10-13 16:17:40.000 -07:00
|   |     index: start indexing file-level conflicts
|   |...o 2e4dc019d943 e8c23f0ee5e2 martinvonz@google.com 2021-10-20 14:21:01.000 -07:00
|         git: don't update public heads for now
>---@ 77b94b593d68 bb3b69138188 martinvonz@google.com 2021-10-13 12:29:47.000 -07:00
      git: move logic for adding remote to git module

@martinvonz
Copy link
Owner Author

The code is in revset_graph_iterator.rs. What makes it complicated is the laziness - we shouldn't walk the whole graph before we start displaying output. That would be fine to do in small repos, but it would make jj log unusably slow on very large repos. That's also the reason Git uses that algorithm they describe there.

@yuja
Copy link
Collaborator

yuja commented Jan 14, 2023

Segmented changelog (or similar) might help the scalability issue?
https://raw.githubusercontent.com/facebook/sapling/main/eden/scm/slides/201904-segmented-changelog/segmented-changelog.pdf

Just for reference. I don't know if it applies here, but it contains some readable graph examples saying "use depth-first search" to assign numbers.

@martinvonz
Copy link
Owner Author

Segmented changelog (or similar) might help the scalability issue?

Hmm, I think that's a good point whether or not we use segmented changelog. Unlike Git 1, we could quite efficiently find common ancestors using the commit index. Maybe that would perform well enough and be simpler, but I haven't thought much about it.

Footnotes

  1. Before they added their commit graph anyway, which came long after their algorithm for ordering commits nicely in the graph, I think.

@quark-zju
Copy link
Contributor

quark-zju commented Jan 17, 2023

It sounds like this function might be useful. It's used by smartlog rendering (via the sort(..., topo) revset).

It's a bit more aggressive than the old sort(topo) implementation: it sorts branches forking off a same commit by length, and sorts branches that merge too. It might be a bit more flexible - if you want to sort branches by date, then it is probably doable via priorities.

yuja added a commit to yuja/jj that referenced this issue Jul 16, 2023
…WIP)

May be buggy. Not yet ready for production use. I'm just dogfooding to see
if I like this more than Sapling's beautify_graph(), which reorders commits
more aggressively.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 16, 2023
…WIP)

May be buggy. Not yet ready for production use. I'm just dogfooding to see
if I like this more than Sapling's beautify_graph(), which reorders commits
more aggressively.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 18, 2023
This is similar to Mercurial's "topo" sorting, but merge handling seems
different. Mercurial's dagop.toposort() tracks [(roots, descendants)], and
merge parents are combined into a single tracking record. OTOH, ours tracks
{root: descendants}, and merge ancestors are split to separate tracking
records. I don't know which would produce a better result, but I think
the latter is easier to implement.

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
merge-heavy history (or branchy history in reverse order), beautify_graph()
will produce significantly better result.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 19, 2023
This is similar to Mercurial's "topo" sorting, but merge handling seems
different. Mercurial's dagop.toposort() tracks [(roots, descendants)], and
merged ancestors are combined into a single tracking record. OTOH, ours tracks
{root: descendants}, and merged ancestors are split into separate tracking
records. I don't know which one will produce a better result, but I think
the latter is easier to implement.

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
merge-heavy history (or branchy history in reverse order), beautify_graph()
will produce significantly better result. For my wip branches (~30 branches,
a couple of commits per branch), this works pretty well.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 19, 2023
This is similar to Mercurial's "topo" sorting, but merge handling seems
different. Mercurial's dagop.toposort() tracks [(roots, descendants)], and
merged ancestors are combined into a single tracking record. OTOH, ours tracks
{root: descendants}, and merged ancestors are split into separate tracking
records. I don't know which one will produce a better result, but I think
the latter is easier to implement.

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
merge-heavy history (or branchy history in reverse order), beautify_graph()
will produce significantly better result. For my wip branches (~30 branches,
a couple of commits per branch), this works pretty well.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 21, 2023
The original idea was similar to Mercurial's "topo" sorting, but it couldn't
reorder merge-heavy history. In order to render merges of topic branches
nicely, we need to roughly reorder branches at merge point, not at fork point.
To achieve that, we build a graph of linear segments, and walk them from
the head towards the root of the second branch. While walking, descendant
segments of the current segment will also be visited.

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
merge-heavy history, beautify_graph() will produce a better result. For my wip
branches (~30 branches, a couple of commits per branch), this works pretty well.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 21, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
To achieve that, we build a graph of linear segments, and walk them from
the head towards the root of the second branch. While walking, descendant
segments of the current segment are also visited.

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
merge-heavy history, beautify_graph() would produce a better result. For my wip
branches (~30 branches, a couple of commits per branch), this works pretty well.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
OTOH, we do also want to place unmerged branches as close to the fork point
as possible. This commit implements the former requirement, and the latter
will be addressed by the next commit.

I think this is similar to Git's sorting logic described in the following blog
post. In our case, the in-degree walk can be dumb since topological order is
guaranteed by the index. We keep HashSet<CommitId> instead of an in-degree
integer value, which will be used in the next commit to resolve new heads as
late as possible.

https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
more complex history, beautify_graph() would produce a better result. For my
wip branches (~30 branches, a couple of commits per branch), this works pretty
well.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The idea is simple. New heads are ignored until the node dependency resolution
stuck. Then, only heads that will unblock the visit will be queued.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
OTOH, we do also want to place unmerged branches as close to the fork point
as possible. This commit implements the former requirement, and the latter
will be addressed by the next commit.

I think this is similar to Git's sorting logic described in the following blog
post. In our case, the in-degree walk can be dumb since topological order is
guaranteed by the index. We keep HashSet<CommitId> instead of an in-degree
integer value, which will be used in the next commit to resolve new heads as
late as possible.

https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
more complex history, beautify_graph() would produce a better result. For my
wip branches (~30 branches, a couple of commits per branch), this works pretty
well.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The idea is simple. New heads are ignored until the node dependency resolution
stuck. Then, only heads that will unblock the visit will be queued.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
OTOH, we do also want to place unmerged branches as close to the fork point
as possible. This commit implements the former requirement, and the latter
will be addressed by the next commit.

I think this is similar to Git's sorting logic described in the following blog
post. In our case, the in-degree walk can be dumb since topological order is
guaranteed by the index. We keep HashSet<CommitId> instead of an in-degree
integer value, which will be used in the next commit to resolve new heads as
late as possible.

https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
more complex history, beautify_graph() would produce a better result. For my
wip branches (~30 branches, a couple of commits per branch), this works pretty
well.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The idea is simple. New heads are ignored until the node dependency resolution
stuck. Then, only heads that will unblock the visit will be queued.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
OTOH, we do also want to place unmerged branches as close to the fork point
as possible. This commit implements the former requirement, and the latter
will be addressed by the next commit.

I think this is similar to Git's sorting logic described in the following blog
post. In our case, the in-degree walk can be dumb since topological order is
guaranteed by the index. We keep HashSet<CommitId> instead of an in-degree
integer value, which will be used in the next commit to resolve new heads as
late as possible.

https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
more complex history, beautify_graph() would produce a better result. For my
wip branches (~30 branches, a couple of commits per branch), this works pretty
well.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 23, 2023
The idea is simple. New heads are ignored until the node dependency resolution
stuck. Then, only heads that will unblock the visit will be queued.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 24, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
OTOH, we do also want to place unmerged branches as close to the fork point
as possible. This commit implements the former requirement, and the latter
will be addressed by the next commit.

I think this is similar to Git's sorting logic described in the following blog
post. In our case, the in-degree walk can be dumb since topological order is
guaranteed by the index. We keep HashSet<CommitId> instead of an in-degree
integer value, which will be used in the next commit to resolve new heads as
late as possible.

https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
more complex history, beautify_graph() would produce a better result. For my
wip branches (~30 branches, a couple of commits per branch), this works pretty
well.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 24, 2023
The idea is simple. New heads are ignored until the node dependency resolution
stuck. Then, only the first head that will unblock the visit will be queued.

Closes martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 24, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
OTOH, we do also want to place unmerged branches as close to the fork point
as possible. This commit implements the former requirement, and the latter
will be addressed by the next commit.

I think this is similar to Git's sorting logic described in the following blog
post. In our case, the in-degree walk can be dumb since topological order is
guaranteed by the index. We keep HashSet<CommitId> instead of an in-degree
integer value, which will be used in the next commit to resolve new heads as
late as possible.

https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
more complex history, beautify_graph() would produce a better result. For my
wip branches (~30 branches, a couple of commits per branch), this works pretty
well.

martinvonz#242
yuja added a commit to yuja/jj that referenced this issue Jul 24, 2023
The idea is simple. New heads are ignored until the node dependency resolution
stuck. Then, only the first head that will unblock the visit will be queued.

Closes martinvonz#242
yuja added a commit that referenced this issue Jul 24, 2023
The original idea was similar to Mercurial's "topo" sorting, but it was bad
at handling merge-heavy history. In order to render merges of topic branches
nicely, we need to prioritize branches at merge point, not at fork point.
OTOH, we do also want to place unmerged branches as close to the fork point
as possible. This commit implements the former requirement, and the latter
will be addressed by the next commit.

I think this is similar to Git's sorting logic described in the following blog
post. In our case, the in-degree walk can be dumb since topological order is
guaranteed by the index. We keep HashSet<CommitId> instead of an in-degree
integer value, which will be used in the next commit to resolve new heads as
late as possible.

https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting

Compared to Sapling's beautify_graph(), this is lazy, and can roughly preserve
the index (or chronological) order. I tried beautify_graph() with prioritizing
the @ commit, but the result seemed too aggressively reordered. Perhaps, for
more complex history, beautify_graph() would produce a better result. For my
wip branches (~30 branches, a couple of commits per branch), this works pretty
well.

#242
@yuja yuja closed this as completed in a382e96 Jul 24, 2023
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue Oct 12, 2023
[0.10.0] - 2023-10-04

### Breaking changes

* A default revset-alias function `trunk()` now exists. If you previously defined
  your own `trunk()` alias it will continue to overwrite the built-in one.
  Check [revsets.toml](cli/src/config/revsets.toml) and [revsets.md](docs/revsets.md)
  to understand how the function can be adapted.

### New features

* The `ancestors()` revset function now takes an optional `depth` argument
  to limit the depth of the ancestor set. For example, use `jj log -r
  'ancestors(@, 5)` to view the last 5 commits.

* Support for the Watchman filesystem monitor is now bundled by default. Set
  `core.fsmonitor = "watchman"` in your repo to enable.

* You can now configure the set of immutable commits via
  `revset-aliases.immutable_heads()`. For example, set it to
  `"remote_branches() | tags()"` to prevent rewriting those those. Their
  ancestors are implicitly also immutable.

* `jj op log` now supports `--no-graph`.

* Templates now support an additional escape: `\0`. This will output a literal
  null byte. This may be useful for e.g.
  `jj log -T 'description ++ "\0"' --no-graph` to output descriptions only, but
  be able to tell where the boundaries are

* jj now bundles a TUI tool to use as the default diff and merge editors. (The
  previous default was `meld`.)

* `jj split` supports the `--interactive` flag. (This is already the default if
  no paths are provided.)

* `jj commit` accepts an optional list of paths indicating a subset of files to
  include in the first commit

* `jj commit` accepts the `--interactive` flag.

### Fixed bugs

### Contributors

Thanks to the people who made this release happen!

* Austin Seipp (@thoughtpolice)
* Emily Kyle Fox (@emilykfox)
* glencbz (@glencbz)
* Hong Shin (@honglooker)
* Ilya Grigoriev (@ilyagr)
* James Sully (@sullyj3)
* Martin von Zweigbergk (@martinvonz)
* Philip Metzger (@PhilipMetzger)
* Ruben Slabbert (@rslabbert)
* Vamsi Avula (@avamsi)
* Waleed Khan (@arxanas)
* Willian Mori (@wmrmrx))
* Yuya Nishihara (@yuja)
* Zachary Dremann (@Dr-Emann)


[0.9.0] - 2023-09-06

### Breaking changes

* The minimum supported Rust version (MSRV) is now 1.71.0.

* The storage format of branches, tags, and git refs has changed. Newly-stored
  repository data will no longer be loadable by older binaries.

* The `:` revset operator is deprecated. Use `::` instead. We plan to delete the
  `:` form in jj 0.15+.

* The `--allow-large-revsets` flag for `jj rebase` and `jj new` was replaced by
  a `all:` before the revset. For example, use `jj rebase -d 'all:foo-'`
  instead of `jj rebase --allow-large-revsets -d 'foo-'`.

* The `--allow-large-revsets` flag for `jj rebase` and `jj new` can no longer be
  used for allowing duplicate destinations. Include the potential duplicates
  in a single expression instead (e.g. `jj new 'all:x|y'`).

* The `push.branch-prefix` option was renamed to `git.push-branch-prefix`.

* The default editor on Windows is now `Notepad` instead of `pico`.

* `jj` will fail attempts to snapshot new files larger than 1MiB by default.
  This behavior can be customized with the `snapshot.max-new-file-size`
  config option.

* Author and committer signatures now use empty strings to represent unset
  names and email addresses. The `author`/`committer` template keywords and
  methods also return empty strings.
  Older binaries may not warn user when attempting to `git push` commits
  with such signatures.

* In revsets, the working-copy or remote symbols (such as `@`, `workspace_id@`,
  and `branch@remote`) can no longer be quoted as a unit. If a workspace or
  branch name contains whitespace, quote the name like `"branch name"@remote`.
  Also, these symbols will not be resolved as revset aliases or function
  parameters. For example, `author(foo@)` is now an error, and the revset alias
  `'revset-aliases.foo@' = '@'` will be failed to parse.

* The `root` revset symbol has been converted to function `root()`.

* The `..x` revset is now evaluated to `root()..x`, which means the root commit
  is no longer included.

* `jj git push` will now push all branches in the range `remote_branches()..@`
  instead of only branches pointing to `@` or `@-`.

* It's no longer allowed to create a Git remote named "git". Use `jj git remote
  rename` to rename the existing remote.
  [#1690](martinvonz/jj#1690)

* Revset expression like `origin/main` will no longer resolve to a
  remote-tracking branch. Use `main@origin` instead.

### New features

* Default template for `jj log` now does not show irrelevant information
  (timestamp, empty, message placeholder etc.) about the root commit.

* Commit templates now support the `root` keyword, which is `true` for the root
  commit and `false` for every other commit.

* `jj init --git-repo` now works with bare repositories.

* `jj config edit --user` and `jj config set --user` will now pick a default
  config location if no existing file is found, potentially creating parent
  directories.

* `jj log` output is now topologically grouped.
  [#242](martinvonz/jj#242)

* `jj git clone` now supports the `--colocate` flag to create the git repo
  in the same directory as the jj repo.

* `jj restore` gained a new option `--changes-in` to restore files
  from a merge revision's parents. This undoes the changes that `jj diff -r`
  would show.

* `jj diff`/`log` now supports `--tool <name>` option to generate diffs by
  external program. For configuration, see [the documentation](docs/config.md).
  [#1886](martinvonz/jj#1886)

* A new experimental diff editor `meld-3` is introduced that sets up Meld to
  allow you to see both sides of the original diff while editing. This can be
  used with `jj split`, `jj move -i`, etc.

* `jj log`/`obslog`/`op log` now supports `--limit N` option to show the first
  `N` entries.

* Added the `ui.paginate` option to enable/disable pager usage in commands

* `jj checkout`/`jj describe`/`jj commit`/`jj new`/`jj squash` can take repeated
  `-m/--message` arguments. Each passed message will be combined into paragraphs
  (separated by a blank line)

* It is now possible to set a default description using the new
  `ui.default-description` option, to use when describing changes with an empty
  description.

* `jj split` will now leave the description empty on the second part if the
  description was empty on the input commit.

* `branches()`/`remote_branches()`/`author()`/`committer()`/`description()`
  revsets now support exact matching. For example, `branch(exact:main)`
  selects the branch named "main", but not "maint". `description(exact:"")`
  selects commits whose description is empty.

* Revsets gained a new function `mine()` that aliases `author(exact:"your_email")`.

* Added support for `::` and `..` revset operators with both left and right
  operands omitted. These expressions are equivalent to `all()` and `~root()`
  respectively.

* `jj log` timestamp format now accepts `.utc()` to convert a timestamp to UTC.

* templates now support additional string methods `.starts_with(x)`, `.ends_with(x)`
  `.remove_prefix(x)`, `.remove_suffix(x)`, and `.substr(start, end)`.

* `jj next` and `jj prev` are added, these allow you to traverse the history
  in a linear style. For people coming from Sapling and `git-branchles`
  see [#2126](martinvonz/jj#2126) for
  further pending improvements.

* `jj diff --stat` has been implemented. It shows a histogram of the changes,
  same as `git diff --stat`. Fixes [#2066](martinvonz/jj#2066)

* `jj git fetch --all-remotes` has been implemented. It fetches all remotes
  instead of just the default remote

### Fixed bugs

* Fix issues related to .gitignore handling of untracked directories
  [#2051](martinvonz/jj#2051).

* `jj config set --user` and `jj config edit --user` can now be used outside of
  any repository.

* SSH authentication could hang when ssh-agent couldn't be reached
  [#1970](martinvonz/jj#1970)

* SSH authentication can now use ed25519 and ed25519-sk keys. They still need
  to be password-less.

* Git repository managed by the repo tool can now be detected as a "colocated"
  repository.
  [#2011](martinvonz/jj#2011)

### Contributors

Thanks to the people who made this release happen!

* Alexander Potashev (@aspotashev)
* Anton Bulakh (@necauqua)
* Austin Seipp (@thoughtpolice)
* Benjamin Brittain (@benbrittain)
* Benjamin Saunders (@Ralith)
* Christophe Poucet (@poucet)
* Emily Kyle Fox (@emilykfox)
* Glen Choo (@chooglen)
* Ilya Grigoriev (@ilyagr)
* Kevin Liao (@kevincliao)
* Linus Arver (@listx)
* Martin Clausen (@maacl)
* Martin von Zweigbergk (@martinvonz)
* Matt Freitas-Stavola (@mbStavola)
* Oscar Bonilla (@ob)
* Philip Metzger (@PhilipMetzger)
* Piotr Kufel (@qfel)
* Preston Van Loon (@prestonvanloon)
* Tal Pressman (@talpr)
* Vamsi Avula (@avamsi)
* Vincent Breitmoser (@Valodim)
* Vladimir (@0xdeafbeef)
* Waleed Khan (@arxanas)
* Yuya Nishihara (@yuja)
* Zachary Dremann (@Dr-Emann)
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

No branches or pull requests

5 participants