The function used to be larger when we had more reference cycles
between e.g. the `WorkingCopy` and `Repo`. Now there's only
`Evolution` left, so let's inline the function.
This commits makes it so that running commands outside a repo results
in an error message instead of a panic.
We still don't look for a `.jj/` directory in ancestors of the current
directory.
I often (try to) use the command for throwing away all working copy
changes. That currently results in a crash on
`submatches.values_of("paths").unwrap()`. Let's make it revert
everything by default instead, since that seems to be my
intuition. Unlike most VCS's, we have a backup of the working copy and
the user can simply do `jj op undo` if they realized it was a mistake.
I recently renamed the crate from `jj` to `jujube` because `jj` was
taken on crates.io. I didn't realize that that would change the name
of the binary.
I'm preparing to publish an early version before someone takes the
name(s) on crates.io. "jj" has been taken by a seemingly useless
project, but "jujube" and "jujube-lib" are still available, so let's
use those.
The `evolve` command had TODOs about making it update the checkout and
the working copy after evolving commits. I've been running into that
(being left on an obsolete commit) quite often while dogfooding, so
let's fix it.
Until recently, we didn't have support for `.gitignore` files. That
meant that editors (like Emacs) that leave backup files around were
annoying to use, because you'd have to manually remove the backup file
afterwards. For that reason, I had hard-coded the editor to be
`pico`. Now we have support for `.gitignore` files, so we can start
respecting the user's $EDITOR.
I had missed in `git2-rs`'s documentation that you need to check
in a callback if the remote ref(s) got updated by the push or
not. This adds such a check and a new error variant for rejected
branch updates.
I tried to push a commit from my Jujube repo to GitHub using `jj
git push --branch main` and it became clear that we need to pass
SSH credentials. This commit hopefully fixes that. I've only made
it pass credentials for ssh-agent for now, because that seems to
be enough to make it work for me personally. If this commit
becomes visible on GitHub, it should mean that it worked.
When you run e.g. `jj st` outside of a repo, it just
crashes. That'll probably give new users a bad impression, so I
was planning to improve error handling a bit. A good place to
start is by fixing the code I recently added (which obviously
should have been using `thiserror` from the beginning). That's
what this commit does.
Also, this is the first commit in this repo created with
Jujube! I've just started dogfooding it myself.
I've forgotten to close a transaction a few times and while the
message ('assertion failed: self.closed') is clear to me now, it
probably won't be clear to others or to me in the future.
With this commit, you can do `jj git clone
https://github.com/martinvonz/jj jj` and such, which seems like a good
step towards making it easier to get started.
This adds `jj git fetch` for fetching from a git remote. There remote
has to be added in the underlying git repo if it doesn't already
exist. I think command will still be useful on typical small projects
with just a single remote on GitHub. With this and the `jj git push` I
added recently, I think I have enough for my most of my own
interaction with GitHub.
I didn't know about the Clap setting to print help if no subcommand
was given, so I had reimplemented that myself for the top-level
command. However, if the user did e.g. `jj git`, they'd get a
crash. This commit fixes that by turning on the setting.
The fact that no commits from the underlying Git repo were imported
when creating a new Jujube repo from it was quite surprising. This
commit finally fixes that.
When using Git as a store, new commits created in the underlying Git
repo are only made visible by making changes on top of them (e.g by
checking them out, so a working copy commit is created on top). That's
especially confusing when creating a new repo backed by an existing
Git repo, because the commits from that repo don't show up.
This commit prepares for fixing that by adding a function for updating
heads based on git refs. Since we don't yet track git refs (or
anything similar), the function just makes sure the refs are visible
in the Jujube repo by making them (anonymous) heads.
`Transaction::add_head()` and others would let the caller add
non-heads to the set (i.e. ancestors of others heads) and the the
non-heads were filterd out when the transaction was committed. That's
a little surprising, so let's try to keep the set valid even within a
transaction. That will surely make commands that add many commits
noticeably slower in large repos. Hopefully we can improve that
later.
Returning the store's internal `git2::Repository` instance wrapped in
a `Mutex` makes it easy to run into deadlocks. Let's return a freshly
loaded repo instance instead.
It's annoying to have to have the Git repo and Jujube repo in separate
directories. This commit adds `jj init --git`, which creates a new
Jujube repo with an empty, bare git repo in `.jj/git/`. Hopefully the
`jj git` subcommands will eventually provide enough functionality for
working with the Git repo that the user won't have to use Git commands
directly. If they still do, they can run them from inside `.jj/git/`,
or create a new worktree based on that bare repo.
The implementation is quite straight-forward. One thing to note is
that I made `.jj/store` support relative paths to the Git repo. That's
mostly so the Jujube repo can be moved around freely.
This commit starts adding support for working with a Jujube repo's
underlyng Git repo (if there is one). It does so by adding a command
for pushing from the Git repo to a remote, so you can work with your
anonymous branches in Jujube and push to a remote Git repo without
having to switch repos and copy commit hashes.
For example, `jj git push origin main` will push to the "main" branch
on the remote called "origin". The remote name (such as "origin") is
resolved in that repo. Unlike most commands, it defaults to pushing
the working copy's parent, since it is probably a mistake to push a
working copy commit to a Git repo.
I plan to add more `jj git` subcommands later. There will probably be
at least a command (or several?) for making the Git repo's refs
available in the Jujube repo.
This is just a little refactoring to prepare for making `jj split` ask
the user for commit descriptions. It's not actually needed, but it
doesn't make logical sense for the function to be about editing the
description of a particular commit.
This adds `jj edit`, which lets the user edit the content changes in a
commit. It behaves similar to `jj restore` when restoring the parent
commit, except that it edits the change compared to the re-merged
parents if the commit is a merge commit.
Changes to the "before" side of the diff will have no effect, so let's
clarify that by marking it readonly. At least Meld checks the
permissions and shows in the UI that the left side is readonly.
This adds an interactive mode for `jj restore`. It works by first
creating two temporary directories with the contents of the subset of
files that differ between the two trees, and then letting the user
edit the directory representing the right/after side. This has some
advantages compared to the interactive modes in Git and Mercurial:
* It lets the user edit the final state as opposed to the diff itself
(depending on the diff tool, of course). I think most users find it
easier to edit the file contents than to edit the patch
format.
* It delegates the hard work to a tool that is already written (this
is a big advantage for an immature tool like Jujube, but it is not
an advantage from the user's point of view).
Almost all of the work in this commit went into adding a function that
takes two trees, lets the user edit the diff, and returns a new tree
id. I plan to reuse that function for other interactive commands. One
planned command is `jj edit`, which will let the user edit the changes
in a commit. `jj edit -r abc123` will be mostly about providing a more
intuitive name for `jj restore --source abc123^ --destination abc123`,
plus it will be different for merge commits (it will edit only the
changes in the merge commit). I also plan to add `jj split` by letting
the user edit the full diff, leaving only the parts that should go
into the first commit. Perhaps there will also be commands for moving
part of a commit out of or into a parent commit.
This extracts a bit from `Transaction::check_out()` for taking a
Conflict, materializing it, and writing the resulting plain file to
the store. It will soon be reused.
Before this commit, running Git's GC in a Git repo backing a Jujube
repo would risk deleting the conflict data we store as blobs in the
Git repo. This commit fixes that by adding a Git note pointing to the
conflict blob.
I wasn't able to add a test case for this because libgit2 doesn't
support gc [1]. Just testing that the ref is there doesn't seem very
useful.
[1] https://github.com/libgit2/libgit2/issues/3247
Very little code was saved by reusing `write_file()` and it made it
confusing (needed to provide an unused filename). Also, I'll soon want
access to the `locked_repo` variable in `write_conflict()`.
I have never run into this being a problem in practice, but this
change is a stepping stone for two things:
1. Using exponential backoff for other locks (in particular the
working copy).
2. Making the Git store write a ref for conflict objects, so they
don't get GC'd (I want to do that before even I start dogfooding).