martinvonz / jj Goto Github PK
View Code? Open in Web Editor NEWA Git-compatible VCS that is both simple and powerful
Home Page: https://martinvonz.github.io/jj/
License: Apache License 2.0
A Git-compatible VCS that is both simple and powerful
Home Page: https://martinvonz.github.io/jj/
License: Apache License 2.0
We'll probably want to support at least the eol
attribute. I noticed while using jj in a working copy shared with git that some files appeared modified because they had LF in the commit and CRLF in the working copy.
We'll want to have better support for git-like branches at least for interop with git. I've been thinking a lot about branching recently and I plan to add native support for git-like branches to jj. By "native support", I mean that they can be used regardless of backend.
jj git clone
uses HTTP proxy according to the http_proxy
and https_proxy
environment variables.
Failure to clone behind proxy.
Error: Fetch failed: Error { code: -1, klass: 2, message: "failed to connect to github.com: Connection timed out" }
jj git clone https://github.com/martinvonz/jj.git jj-jj
I know most people and yourself probably don't have proxies, so I'll probably be the one to work on this if I get the time. ๐
Interested to see a VCS tool compatible with Git, I decided to play with it, starting with this bit from the docs:
With Jujutsu, you'd instead use jj split to split the working copy commit into two commits
I did jj init --git-repo=.
in a checkout of this very repo and edited two files:
% jj st
Parent commit: 03e6b8c0e6a4 working_copy: take `Tree`, not `CommitId`, as argument to `check_out()`
Working copy : d6382403c415
Working copy changes:
M README.md
M rustfmt.toml
Now I run jj split
. Say I want to commit rustfmt.toml
first, so I copy README.md
left-to-right in Meld and enter the obvious descriptions and it seems to work:
% jj split
First part: 62cb2d07bc52 first part
Second part: 949b4659aee9 second part
Working copy now at: 949b4659aee9 second part
Working copy actually being at 949b4659aee9
like the message said?
The log and status command act like the split did not happen:
% jj status
Parent commit: 03e6b8c0e6a4 working_copy: take `Tree`, not `CommitId`, as argument to `check_out()`
Working copy : 16178fc092a1 first part
Working copy changes:
M README.md
M rustfmt.toml
% jj log
@ 16178fc092a1 e612ec30d5df [email protected] 2022-02-18 01:06:53.000 +03:00
| first part
o 03e6b8c0e6a4 37df45dd7108 [email protected] 2022-02-12 23:46:38.000 -08:00 main
| working_copy: take `Tree`, not `CommitId`, as argument to `check_out()`
The split commits do exist:
% jj show 62cb2d07bc52
Commit ID: 62cb2d07bc52b1345cced9acf003c73e84435086
Change ID: e612ec30d5df4d2b848c81d9f7078a7b
Author: Greg V <[email protected]> (2022-02-18 01:06:53.000 +03:00)
Committer: Greg V <[email protected]> (2022-02-18 01:12:57.000 +03:00)
first part
Modified regular file rustfmt.toml:
1 1: max_width = 10069
2 2: wrap_comments = true
3 3: format_strings = true
4 4: error_on_line_overflow = true
...
but are seemingly just lost from the jj log
perspective.
jj diff
and equivalently jj show 16178fc092a1
(the hash at the top of the log) show both changes together, i.e. what was there before the split, but with the same "first part" description as the actual first part (62cb2d07bc52
). But the hash is new.
Looking at the git repo, actually the real first part is committed.
% g log --oneline | head
62cb2d0 first part
03e6b8c working_copy: take `Tree`, not `CommitId`, as argument to `check_out()`
And after fiddling with the git CLI (no write commands, only viewing the log) the jj log
is messed up? o_0
@ 16178fc092a1 e612ec30d5df [email protected] 2022-02-18 01:06:53.000 +03:00 divergent
| first part
| o 62cb2d07bc52 e612ec30d5df [email protected] 2022-02-18 01:06:53.000 +03:00 HEAD@git divergent
|/ first part
o 03e6b8c0e6a4 37df45dd7108 [email protected] 2022-02-12 23:46:38.000 -08:00 main
| working_copy: take `Tree`, not `CommitId`, as argument to `check_out()`
Maybe I misunderstood something but it sounds like a bug?
(above โ I don't think steps should be below the story)
jj prune
, like most commands, first commit the working copy. When using the Git backend, that produces a Git commit with some hash. The next step for jj prune
is to prune the commit. That's done by creating a successor commit with a is_pruned
flag set. The problem is that both the predecessors
field and the is_pruned
field are stored outside of the Git commit and the timestamps are typically the same as well (it happens in much less than a second), so the resulting Git commit remains the same. The Git backend then fails the write (it doesn't allow two Git commits with different non-Git metadata).
I've known about this bug for a long time, but I figured it can be useful to track it. I'm working on removing support for evolution. The bug should be resolved by that work.
I suspect I would usually want to refer to change ids instead of commit ids if it was easy to do that. That might reduce the amount of copying from jj log
output. Perhaps we should make =abc123
or something like that resolve to any non-obsolete commits with change id abc123
. Part of such support would be to accept unique prefixes just like we do for commit ids. (We probably also want to index change ids, but that can come later.)
It doesn't make sense to push commits with conflicts to Git remotes (which are the only remotes we support yet). We should prevent such pushes from happening.
I bet this is a lot easier to do than it is in Git and Mercurial thanks to almost everything being done without updating the working copy (including conflicts in paths outside the sparse config).
We currently resolve repo-level conflicts (such as divergent updates of git refs) arbitrarily. We should instead have the user resolve them. I think it would sense to present them in jj status
and have a command for resolving them.
You probably have thought about this. I was trying to compare the current conflict representation (two lists, (adds, removes)
) with a conservative recursive struct (a tree of (local, other, base)
).
To simplify the problem, only file modifications are considered, no deletions.
Consider these recursive structs:
(local: (local: A, other: B, base: C), other: D, base: E)
(local: (local: A, other: D, base: C), other: B, base: E)
(local: (local: A, other: B, base: E), other: D, base: C)
They map to a same flat list representation (IIUC):
(adds: [A, B, D], removes: [C, E])
Apparently some information (ex. relations between merge base and local/other) is lost in this representation but does it matter? To reason about it, here is a question I tried to answer:
(adds: [A, B, D], removes: [C, E])
and produces a similar conflict-free merge result?I couldn't come up with such an algorithm easily. I wonder if that indicates a recursive representation is more practical. It seems there are other benefits, too, such as easier to integrate with existing merge tools and easier to store resolve progress.
It seems useful to highlight commits with conflicts (or at least the fact that there are such commits) in jj status
. We currently don't have that information available cheaply, so part of this would involve adding that information to the commit index.
Repository is cloned successful.
Application crashes.
Fetching into new repo in "/home/pjamar/prj/l/pusharrow"
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Other("note for '34d090b9239bf59911ef5365911d2322ae854e19' exists already; class=Repository (6); code=Exists (-4)")', lib/src/store_wrapper.rs:157:58
stack backtrace:
0: 0x55ad2c3abadc - std::backtrace_rs::backtrace::libunwind::trace::h788b2853b7016c32
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/../../backtrace/src/backtrace/libunwind.rs:90:5
1: 0x55ad2c3abadc - std::backtrace_rs::backtrace::trace_unsynchronized::h3626590e16510efa
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x55ad2c3abadc - std::sys_common::backtrace::_print_fmt::ha76294ed367b5eb6
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/sys_common/backtrace.rs:67:5
3: 0x55ad2c3abadc - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h4244b134876ede81
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/sys_common/backtrace.rs:46:22
4: 0x55ad2c3d311c - core::fmt::write::h9a6d9c74526a6c1b
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/core/src/fmt/mod.rs:1150:17
5: 0x55ad2c3a6815 - std::io::Write::write_fmt::h7f8a2ef72f011ad9
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/io/mod.rs:1667:15
6: 0x55ad2c3adb00 - std::sys_common::backtrace::_print::h4b3c9553c91f7522
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/sys_common/backtrace.rs:49:5
7: 0x55ad2c3adb00 - std::sys_common::backtrace::print::h36fb46a493801fb8
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/sys_common/backtrace.rs:36:9
8: 0x55ad2c3adb00 - std::panicking::default_hook::{{closure}}::hf28f6810f0e04677
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:210:50
9: 0x55ad2c3ad6bb - std::panicking::default_hook::hadb819fa279f9d7b
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:227:9
10: 0x55ad2c3ae1b4 - std::panicking::rust_panic_with_hook::h015085c4aa271d26
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:624:17
11: 0x55ad2c3adc90 - std::panicking::begin_panic_handler::{{closure}}::h15a8a2888dd1ba59
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:521:13
12: 0x55ad2c3abf84 - std::sys_common::backtrace::__rust_end_short_backtrace::h673e204498e49379
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/sys_common/backtrace.rs:141:18
13: 0x55ad2c3adbf9 - rust_begin_unwind
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:517:5
14: 0x55ad2be56e01 - core::panicking::panic_fmt::hcf5f6d96e1dd7099
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/core/src/panicking.rs:101:14
15: 0x55ad2be56ef3 - core::result::unwrap_failed::he898b02f57993c42
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/core/src/result.rs:1617:5
16: 0x55ad2bfb09e5 - jujutsu_lib::store_wrapper::StoreWrapper::write_commit::h9b4109d36480039e
17: 0x55ad2bfa2216 - jujutsu_lib::commit_builder::CommitBuilder::write_to_repo::h3d4a0ec6ef15a7ee
18: 0x55ad2bfca9d6 - jujutsu_lib::repo::MutableRepo::check_out::h9dfbc2734f8d444a
19: 0x55ad2bea559f - jujutsu::commands::cmd_git::h0d1a626b077d18bc
20: 0x55ad2be6983c - jujutsu::commands::dispatch::h02e220f6b48def76
21: 0x55ad2be5fdbd - jj::main::h34cd1dbad16e65e9
22: 0x55ad2be5f193 - std::sys_common::backtrace::__rust_begin_short_backtrace::h829bc614a367e7e5
23: 0x55ad2be6aa89 - std::rt::lang_start::{{closure}}::h2077ed056203f4bb
24: 0x55ad2c3ae7ba - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h61c8e7c7ad965d8f
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/core/src/ops/function.rs:259:13
25: 0x55ad2c3ae7ba - std::panicking::try::do_call::ha62fd0271612a1de
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:403:40
26: 0x55ad2c3ae7ba - std::panicking::try::hedc869fcd25323d8
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:367:19
27: 0x55ad2c3ae7ba - std::panic::catch_unwind::h19fc164e1562e43f
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panic.rs:129:14
28: 0x55ad2c3ae7ba - std::rt::lang_start_internal::{{closure}}::hb7a70d47e691e1da
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/rt.rs:45:48
29: 0x55ad2c3ae7ba - std::panicking::try::do_call::h7af85a6c8d4e17cd
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:403:40
30: 0x55ad2c3ae7ba - std::panicking::try::h2006fd79c11839e7
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panicking.rs:367:19
31: 0x55ad2c3ae7ba - std::panic::catch_unwind::h554c0031cfe57735
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/panic.rs:129:14
32: 0x55ad2c3ae7ba - std::rt::lang_start_internal::h0a872604597b44c0
at /rustc/29ef6cf1637aa8317f8911f93f14e18d404c1b0e/library/std/src/rt.rs:45:20
33: 0x55ad2be5fe42 - main
34: 0x7fc7ab8060b3 - __libc_start_main
35: 0x55ad2be575de - _start
36: 0x0 - <unknown>
Edit: Added full backtrace
The git backend gets really slow after many commits have been created. Profiling has shown that the problem is git notes. One problem is that libgit2 doesn't do sharding. Manually editing a note from the command line using git notes
helps, but it's still very slow. We should consider moving the extra metadata to some other storage, perhaps a custom format.
Another option might be for the git backend to simply cache the notes tree. I don't know how much that would help.
One advantage of the current storage in git notes is that it lets us exchange the data using regular git commands.
Mercurial has a ::
operator, which returns the ancestors when used as a prefix (::foo
), descendants when used as a suffix (foo::
), and the intersection of the two when used as infix (foo::bar
). I like that and I tried to extend it by using the same operator for parents and children. That's how I ended up with :foo
meaning "parents of foo" and foo:
meaning "children" of foo
. However, it hasn't worked very well in practice.
One problem with it is that we don't have a simple way of saying "N generations back/forward". Git and Mercurial have foo~10
for saying "ten generations back from foo". However, because we use :
as either prefix or suffix, 11:22
becomes ambiguous (is it 22 generations after a commit with hex prefix 11 or 11 generations before a commit with hex prefix 22?).
Another problem, which is just small annoyance, is that by using :
as prefix for the very common case of specifying parents, we make it harder to go one more step back, because the user needs to move the input cursor to before the symbol. For example, if you've entered jj diff -r :@
and realized that you wanted to go one more step back, you need to move the cursor left before you can insert an extra :
.
So, we should probably switch to foo~
for "parents of foo" and maybe foo+
for "children of foo". Then we free up :
to be used in other operators. We could probably use :
for Mercurial's ::
operator (we don't want its :
operator). Maybe we should also support Git's ..
operator (not sure about ...
-- I almost never want it myself).
I think it would be nice to also have a syntax for a range of generations. Perhaps foo[-5:2]
could mean "from 5 generations back to 2 generations forward from foo".
I wonder if we should use an operator for commit ID and/or change ID. Maybe =abc
could be the commit ID with prefix abc
and %abc
could be the change ID with prefix abc
. I'm not sure it's worth spending two characters on that. We should definitely have revset functions for it.
I think that among docs/related_work.md
Breezy (previously known as Bazaar) should also be mentioned, as it is also both a distinct VCS with its own native storage backend(s), and a backend to the .git
storage format, with several interesting features (according to Mark Shuttleworth its unique selling point is accurate history of file renames, for example).
https://www.breezy-vcs.org/
http://bazaar.canonical.com/en/
I think that it is rather more interesting than Mercurial, in particular because its latest native storage layer is much more reasonable, in part because of having a .git
storage backend, in part because of keeping well a history of renames (it is file+patch oriented rather than content oriented like git
).
We currently don't support symlinks on Windows (in fact, the project doesn't even build on Windows because of that). The advice I got from [email protected] and former hg contributor "bmp" was (please correct me if I'm wrong):
symlink
creates, because it creates "junctions", which is not what we want.Rust's standard library has std::os::windows::fs::symlink_file
and std::os::windows::fs::symlink_dir
, which both seem to call CreateSymbolicLinkW
, only with different flags. Perhaps we can always use the symlink_file
version? It's still unclear to me what the effect would be if a "file symbolic link" points to a target that's actually a directory.
Since I enabled auto-rebase after every command ~5 months ago (commit 6a5f9dd), I have never used jj evolve
. I therefore plan to remove support for evolution in general (not just the command). I think that will make both UX and code simpler. We currently have three kinds of DAGs: the commit graph, the obsolescence graph, and the operation graph. Removing one of them should be positive.
My repo currently has ~8.5k hidden heads and even though I haven't noticed it causing any slowness, I think we should be able to make things faster by not having all those extra heads that we mostly ignore.
We'll want to have a replacement for jj obslog
. I hope to do that based on the operation log. jj op log --change <change-id>
or something like that would be conceptually similar to jj log <path>
(which currently doesn't exist :)) in that it filters the log. However, diffing repo states is somewhat slow, so we'll probably need to do some indexing to make it useful.
Of course the big difference between evolution and auto-rebase is that the latter is local. It won't handle all cases where developers cooperate in developing a stack of commits. However, I plan to make it so at least simple cases will be handled:
Log is displayed correctly.
jj crashes
xxx@think ~/prj [1]> jj git clone [email protected]:simonw/museums.git museums
Fetching into new repo in "/home/xxx/prj/museums"
Working copy now at: b0941e40a8f0
xxx@think ~/prj> cd museums/
xxx@think ~/p/museums (main)> jj log
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -1, klass: 14, message: "failed to insert entry: invalid name for a tree entry - .git" }', lib/src/git_store.rs:310:18
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
git clone [email protected]:simonw/museums.git museums
cd museums
jj log
You follow installation instructions and it should be installed without any errors.
I was following installation instructions, but I had several errors.
These fixed the problem:
brew install pkg-config
brew install openssl
export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@3/lib/pkgconfig"
I guess openssl was not needed, but setting PKG_CONFIG_PATH is required
rustup
rustup install nightly
cargo +nightly install --git https://github.com/martinvonz/jj.git
Does this currently have a git worktree
equivalent? Or can it be used with git worktrees somehow?
Currently the project doesn't build on Rust stable, this means the Nix derivation requires a Rust overlay which supplies the nightly version.
The code which requires the nightly features could be changed, or the nightly features could be stabilized, in which case the nixpkgs overlay should probably be removed such that the Rust compiler from nixpkgs is used instead.
At the time of writing, these nightly features are used:
See also: #66 (comment)
The tool is currently hard-coded to be Meld
The diff format produced by jj diff
is supposed to be more human readable, but it makes it harder to collaborate with copy/pasted patch files etc when that becomes an efficient way to share with others. It's also slower to digest for me, as I've got 20 years invested in reading unidiffs natively and colors aren't a great visual cue for me.
(I'd kind of like to do this work, but figured I should track it in a bug anyway.)
It should be very easy to implement a command that shows the diff between two commits after rebasing the first command to the second commit's parent(s). This would be useful as part of jj obslog -p/--diff
output (that command doesn't accept such a flag yet). (Mercurial's hg obslog -p
currently gives up when a commit has been rebased.)
I have no experience with Nix yet, so I'd appreciate help with this.
As I wrote in this discussion, I think it should be possible to make it work reasonably well to run jj
commands and git
commands in the same workspace. I'm adding this issue for tracking the work to improve that.
jj
would honor the existing .git/info/exclude
in addition to .gitignore
, to allow easier coexistence with git
jj status
adds local files even if they are excluded by .git/info/exclude
git clone https://github.com/martinvonz/jj.git
cd jj && jj init --git-repo .
jj st
echo secret-password >> .git/info/exclude
touch secret-password
jj status
secret-password
I also tried it with jj git clone
and then editing .jj/repo/store/git/info/exclude
with the same outcome
The problem this is trying to solve is when one does not wish to make formal edits to the upstream repo's .gitignore
but also needs jj
to stop adding local log files, editor metadata, etc, on any random jj operation
I don't know if this is related, but setting the diff_editor
under [ui]
(in my case to "vimdiff"
) as instructed in the tutorial doesn't seem to work:
$ jj split -r 3dac3f00b3ad
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: invalid TOML value, did you mean to use a quoted string? at line 4 column 15 in ../.jjconfig', src/main.rs:23:50
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ RUST_BACKTRACE=full jj split -r 3dac3f00b3ad
thread 'main' panicked at 'failed to run diff editor: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/diff_edit.rs:143:10
stack backtrace:
0: 0x7fe018879fbc - std::backtrace_rs::backtrace::libunwind::trace::he080dbb637fa4641
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
1: 0x7fe018879fbc - std::backtrace_rs::backtrace::trace_unsynchronized::h44a0cce058c40994
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x7fe018879fbc - std::sys_common::backtrace::_print_fmt::hc4aa1034724314cb
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/sys_common/backtrace.rs:66:5
3: 0x7fe018879fbc - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h2b790f8be1985180
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/sys_common/backtrace.rs:45:22
4: 0x7fe0188a4dec - core::fmt::write::h84736921f2ac5f8d
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/core/src/fmt/mod.rs:1190:17
5: 0x7fe018873a58 - std::io::Write::write_fmt::hfe23991a8d7fa4a7
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/io/mod.rs:1657:15
6: 0x7fe01887c1e7 - std::sys_common::backtrace::_print::h67116a2d44eae1b1
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/sys_common/backtrace.rs:48:5
7: 0x7fe01887c1e7 - std::sys_common::backtrace::print::h994f9a0072a4b217
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/sys_common/backtrace.rs:35:9
8: 0x7fe01887c1e7 - std::panicking::default_hook::{{closure}}::h8f96a84dcab30cf8
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:295:22
9: 0x7fe01887beaf - std::panicking::default_hook::hb573e2c3be78272d
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:314:9
10: 0x7fe01887c94a - std::panicking::rust_panic_with_hook::h76b4576d8ac3b270
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:698:17
11: 0x7fe01887c637 - std::panicking::begin_panic_handler::{{closure}}::h966318ad4399ecd3
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:588:13
12: 0x7fe01887a464 - std::sys_common::backtrace::__rust_end_short_backtrace::h64a1117353180ced
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/sys_common/backtrace.rs:138:18
13: 0x7fe01887c339 - rust_begin_unwind
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:584:5
14: 0x7fe0182cb213 - core::panicking::panic_fmt::h1e67b42cef1db7f9
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/core/src/panicking.rs:143:14
15: 0x7fe0182cb303 - core::result::unwrap_failed::h1b1ad46cede6e9f5
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/core/src/result.rs:1749:5
16: 0x7fe01834275c - jujutsu::diff_edit::edit_diff::h11f5f947fdd89247
17: 0x7fe018306340 - jujutsu::commands::cmd_split::hbe0ab831be98217b
18: 0x7fe0182cd006 - jujutsu::commands::dispatch::h215fb838a384e92c
19: 0x7fe0182cddc1 - jj::main::h124478dc1575244a
20: 0x7fe0182cded3 - std::sys_common::backtrace::__rust_begin_short_backtrace::hec8c8455cb2b9a37
21: 0x7fe0182cdec9 - std::rt::lang_start::{{closure}}::h11f6c49c99dcd502
22: 0x7fe0188796a1 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h9d346f7455a6c7fd
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/core/src/ops/function.rs:259:13
23: 0x7fe0188796a1 - std::panicking::try::do_call::h8ec1a9b8203a1bbc
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:492:40
24: 0x7fe0188796a1 - std::panicking::try::h695a82b534df1aab
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:456:19
25: 0x7fe0188796a1 - std::panic::catch_unwind::h6743ebe0ff045bfe
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panic.rs:137:14
26: 0x7fe0188796a1 - std::rt::lang_start_internal::{{closure}}::h6e3fc46ec5fb4576
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/rt.rs:128:48
27: 0x7fe0188796a1 - std::panicking::try::do_call::h5c849f12890c52cc
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:492:40
28: 0x7fe0188796a1 - std::panicking::try::h2c36151dbc2fb3e1
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panicking.rs:456:19
29: 0x7fe0188796a1 - std::panic::catch_unwind::h5cca8e7db56bc46a
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/panic.rs:137:14
30: 0x7fe0188796a1 - std::rt::lang_start_internal::h0e034746b466501e
at /rustc/75d9a0ae210dcd078b3985e3550b59064e6603bc/library/std/src/rt.rs:128:20
31: 0x7fe0182cdf02 - main
32: 0x7fe017b06d0a - __libc_start_main
33: 0x7fe0182cba4a - _start
34: 0x0 - <unknown>
$ cat ~/.jjconfig
[user]
name = [REDACTED]
email = [REDACTED]
diff-editor = "vimdiff"
Originally posted by @EyeCon in #18 (comment)
The evolution state currently expects all predecessors of a commit to be visible in the repo. That's clearly not a good assumption, especially given that a user should be able to receive a commit from another repo without getting all the predecessors. That can't happen yet because we don't support exchange yet (other than using Git's protocol, which doesn't include our metadata), but predecessor commits can become hidden when using e.g. jj undo
of an earlier operation (not the most recent operation).
I've known about this bug for a long time, but I figured it can be useful to track it. I'm working on removing support for evolution. The bug should be resolved by that work.
The current support for .gitignore
files is a hack that relies on git2::Repository::status_should_ignore()
. It's unnecessarily slow to call that for every file in target/
when the .gitignore
file contains /target/
-- we should be able to look at the directory and skip all of it.
We may want to fix this by parsing .gitignore
files ourselves.
I've very happy with how the separation between ReadonlyRepo
and MutableRepo
turned out. I think it makes sense to continue that idea by also splitting up Store
into ReadonlyStore
and MutableStore
. The same separation would have to be done in the backends. The idea is that when you load a ReadonlyRepo
, it comes with a ReadonlyStore
, which in turn has a ReadonlyBackend
(Git or native backend). You can't make any writes to the store without starting a transaction. Creating a transaction creates a MutableRepo
(as is already the case). That would have a MutableStore
, which in turn has a MutableBackend
.
Advantages:
All writes within a transaction are grouped, which means they can
go to a single packfile or similar. That means there's no need to have
loose objects. No special treatment is needed for e.g. fetch
and
fast-import
like git does. I suspect it would also make e.g. large
rebase operations much faster.
When you have a ReadonlyRepo
pointing to a ReadonlyStore
and a
ReadonlyBackend
, the backend can be made more efficient by not
checking for changes on disk.
Objects added within a transaction can go to a temporary file and
then be discarded if the transaction is discarded (assuming they've
been written to a place where other processes/threads can't see
them).
To be clear, the goal (right now anyway) is not to make backend writes transactional. In particular, I don't aim for isolation or atomicity.
Let's say there are two concurrent processes that add commits. They will both try to update the refs/notes/jj/commits
(and possibly refs/notes/jj/conflicts
) git notes ref when using the git backend. We already retry when that happens, but that's not enough on file systems with poor locking. Perhaps we should record the notes refs and their target in the view object and then update the underlying git repo when resolving conflicts.
no crash
jj commands all fail with this error:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', lib/src/git_backend.rs:95:87
With RUST_BACKTRACE=1
:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', lib/src/git_backend.rs:95:87
stack backtrace:
0: rust_begin_unwind
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/core/src/panicking.rs:142:14
2: core::result::unwrap_failed
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/core/src/result.rs:1749:5
3: jujutsu_lib::git_backend::GitBackend::load
4: jujutsu_lib::store::Store::load_store
5: jujutsu_lib::repo::RepoLoader::init
6: jujutsu_lib::workspace::Workspace::load
7: jujutsu::commands::CommandHelper::workspace_helper
8: jujutsu::commands::cmd_status
9: jujutsu::commands::dispatch
10: jj::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
with RUST_BACKTRACE=full
:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', lib/src/git_backend.rs:95:87
stack backtrace:
0: 0x55e0d0f2f2bc - std::backtrace_rs::backtrace::libunwind::trace::hede7dd98ee70976c
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
1: 0x55e0d0f2f2bc - std::backtrace_rs::backtrace::trace_unsynchronized::hbe38aeb3ff19fa80
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x55e0d0f2f2bc - std::sys_common::backtrace::_print_fmt::h8d729be0339480ac
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/sys_common/backtrace.rs:66:5
3: 0x55e0d0f2f2bc - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h44d89a7c637ba906
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/sys_common/backtrace.rs:45:22
4: 0x55e0d0f58dcc - core::fmt::write::haccb55fe49c41c09
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/core/src/fmt/mod.rs:1190:17
5: 0x55e0d0f28b08 - std::io::Write::write_fmt::h50fec3265e31260a
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/io/mod.rs:1657:15
6: 0x55e0d0f314f7 - std::sys_common::backtrace::_print::h5147f75d54ad7c1f
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/sys_common/backtrace.rs:48:5
7: 0x55e0d0f314f7 - std::sys_common::backtrace::print::hc83faab68ce2b380
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/sys_common/backtrace.rs:35:9
8: 0x55e0d0f314f7 - std::panicking::default_hook::{{closure}}::ha61fc22abb98b6b0
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:295:22
9: 0x55e0d0f311af - std::panicking::default_hook::h89b0e33dd598a21f
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:314:9
10: 0x55e0d0f31c4b - std::panicking::rust_panic_with_hook::h7e9579ddfea6f147
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:698:17
11: 0x55e0d0f31937 - std::panicking::begin_panic_handler::{{closure}}::h1e78bb9730f8cca8
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:588:13
12: 0x55e0d0f2f784 - std::sys_common::backtrace::__rust_end_short_backtrace::h3c102b80f36ee941
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/sys_common/backtrace.rs:138:18
13: 0x55e0d0f31649 - rust_begin_unwind
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:584:5
14: 0x55e0d0989e63 - core::panicking::panic_fmt::hd296f17a12340ce5
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/core/src/panicking.rs:142:14
15: 0x55e0d0989f53 - core::result::unwrap_failed::hdc2a9475cf94f36c
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/core/src/result.rs:1749:5
16: 0x55e0d0a6bab3 - jujutsu_lib::git_backend::GitBackend::load::h8e00b520cb2414d6
17: 0x55e0d0a550a5 - jujutsu_lib::store::Store::load_store::hd78181dba576da40
18: 0x55e0d0aceb3c - jujutsu_lib::repo::RepoLoader::init::hd62d9b61aa18d3fe
19: 0x55e0d0a8cb6f - jujutsu_lib::workspace::Workspace::load::h48d2ebfe0b508579
20: 0x55e0d0995aea - jujutsu::commands::CommandHelper::workspace_helper::h0ee8ceb4aacc4b23
21: 0x55e0d09b6dba - jujutsu::commands::cmd_status::hc1dcdccdc68451e6
22: 0x55e0d098b8a8 - jujutsu::commands::dispatch::hf5768c8e6ca2007b
23: 0x55e0d098cbd4 - jj::main::h9fc62cf2aaf605c0
24: 0x55e0d098f603 - std::sys_common::backtrace::__rust_begin_short_backtrace::h7ef9afa5a98051d7
25: 0x55e0d098d039 - std::rt::lang_start::{{closure}}::h79f91634bb8322dc
26: 0x55e0d0f2e971 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hd05d8982c002a1a9
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/core/src/ops/function.rs:259:13
27: 0x55e0d0f2e971 - std::panicking::try::do_call::ha2de91ec45a309aa
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:492:40
28: 0x55e0d0f2e971 - std::panicking::try::hf5d233d56c71d201
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:456:19
29: 0x55e0d0f2e971 - std::panic::catch_unwind::h10747b5e8afc13e6
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panic.rs:137:14
30: 0x55e0d0f2e971 - std::rt::lang_start_internal::{{closure}}::hcfc4e0221f952948
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/rt.rs:128:48
31: 0x55e0d0f2e971 - std::panicking::try::do_call::h1bb4ffc2cf7b3c03
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:492:40
32: 0x55e0d0f2e971 - std::panicking::try::h73c86487a3602c03
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panicking.rs:456:19
33: 0x55e0d0f2e971 - std::panic::catch_unwind::h81db875d526be813
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/panic.rs:137:14
34: 0x55e0d0f2e971 - std::rt::lang_start_internal::hc35357b91ce50efe
at /rustc/03a8cc7df1d65554a4d40825b0490c93ac0f0236/library/std/src/rt.rs:128:20
35: 0x55e0d098cf62 - main
36: 0x7f051dbbeb25 - __libc_start_main
37: 0x55e0d098a69e - _start
38: 0x0 - <unknown>
Here's what I did:
cp -ar foo foo-test
cd foo-test
jj init --git-repo=.
cd ..
mv foo-test foo-jj-test
cd foo-jj-test
jj status #crash happens here
cd ..
mv foo-jj-test foo-test
cd foo-test
jj status #commands work again
Something about how we get the default branch from the remote causes the tests to be unreliable. They have failed on Windows and Ubuntu so far. I have not gotten them to fail on Debian. I suspect it's related to cloning from a local-disk remote. The Remote::default_branch()
call has failed for me outside of tests in many different ways:
Error { code: -3, klass: 2, message: "could not find '<path to missing included gitconfig file>' to stat: No such file or directory" }
Error { code: -3, klass: 4, message: "reference 'refs/remotes/origin/main' not found" }
Error { code: -3, klass: 0, message: "an unknown git error occurred" }
See e.g. failure on Windows at commit f56262c: https://github.com/martinvonz/jj/runs/3678330357
I don't know if word-level merging will too often resolve merges incorrectly, but I want to experiment with it. It should be easy to test on existing git repos (like git.git, which has lots of merge commits).
jj git clone
should respect the SSH config (~/.ssh/config
).
The SSH config is not respected, which may be problematic in some cases. In this case, ProxyCommand
is to communicate with a private Git server.
~/.ssh/config
to work.jj git clone
hang.0.2.0.r917.2916cb2-1
Auto-completions are sourced into the shell.
And error message appears and auto-completions are not sourced.
Here are different attempts and their results:
~ > source <(jj debug completion --zsh)
_arguments:comparguments:325: can only be called from completion function
~ > source (jj debug completion --zsh)
zsh: unknown file attribute: j
~ > source $(jj debug completion --zsh)
source: no such file or directory: #compdef
~ > source jj debug completion --zsh
/Users/me/.cargo/bin/jj:2: parse error near `)'
~ > jj debug completion --zsh | source
source: not enough arguments
If you add a file to the repo and it doesn't match the .gitignore, it will currently be automatically tracked. I think that feature has worked pretty well. However, we need to make it easier to untrack the file if you don't want it to be tracked. You currently have to move it out of the working copy, run some command to refresh the working copy, add the file to the .gitignores, then move the file back.
My machine at work doesn't allow any own install.
Can you provide a musl binary>
Many thanks
We should use rename detection at least when diffing and merging.
The footnote on https://blog.palantir.com/optimizing-gits-merge-machinery-2-d81391b97878 has some information about how Git does it.
Surprisingly, there doesn't seem to be a good TUI tool for editing diffs. We need this for jj touchup
, jj split
, etc. We want a tool that can present the diff and let the user edit the right side of it. It should ideally support diffing directories. vimdiff
might be the closest, but it doesn't support directories by default (it seems you need to install some plugin) and it's not intuitive.
jj close -S
would sign the commit enabling compatibility with workflows which require verified commits
There currently is no support for signing commits
Implementing this feature will require careful consideration given how much jj
appears to silently create commits under the covers, since some workflows will prompt for the GPG keyphrase either on every commit action, or every so often if the gpg-agent is running
We currently only support using ssh agent (
Lines 143 to 145 in ccdd651
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.