Commit Graph

51 Commits

Author SHA1 Message Date
Martin von Zweigbergk
8377000fd9 git: add a function for updating heads from git refs
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.
2020-12-29 23:30:34 -08:00
Martin von Zweigbergk
905a5c97d6 transaction: make sure set of heads has only 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.
2020-12-29 20:44:17 -08:00
Martin von Zweigbergk
0d85850017 git: return a new repo instance from the store instead of the store's instance
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.
2020-12-28 23:38:20 -08:00
Martin von Zweigbergk
a8a9f7dedd init: add support for creating new repo backed by bare git repo in .jj/git/
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.
2020-12-28 00:54:03 -08:00
Martin von Zweigbergk
e82197d981 git: extract function for pushing commit to remote branch, and test it 2020-12-28 00:53:41 -08:00
Martin von Zweigbergk
55a7621c45 commands: fix a formatting error
I had fixed this in the working copy but forgot to `git add` it. I'm
not used to Git's staging area yet...
2020-12-27 17:07:54 -08:00
Martin von Zweigbergk
d481001271 commands: add a jj git push command
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.
2020-12-27 00:59:05 -08:00
Martin von Zweigbergk
09e474a05a commands: split up definition of Clap App to help rustfmt
It seems the definition had gotten too large for rustfmt.
2020-12-26 19:03:52 -08:00
Erjan Kalybek
06401fc30d Fix typo 2020-12-26 12:12:24 -08:00
Martin von Zweigbergk
67d496a668 commands: add a command for splitting a commit in two
Unlike Mercurial's version of the command, it can currently only
create exactly two parts.
2020-12-26 11:55:06 -08:00
Martin von Zweigbergk
c04aa43232 commands: make edit_description() take just the initial description
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.
2020-12-26 11:54:16 -08:00
Martin von Zweigbergk
a39b44f5cc commands: add command for editing contents of a 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.
2020-12-26 11:47:52 -08:00
Martin von Zweigbergk
3280d75ff4 diff_edit: mark "before" directory readonly to clarify to user
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.
2020-12-26 11:47:52 -08:00
Martin von Zweigbergk
b6192a7ed5 diff_edit: add missing copyright header 2020-12-26 11:47:52 -08:00
Martin von Zweigbergk
b820eddde3 commands: add an interactive mode for jj restore
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.
2020-12-26 01:16:19 -08:00
Martin von Zweigbergk
fa44ef8d1b conflicts: add another helper for writing materialized conflict to store
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.
2020-12-26 00:35:45 -08:00
Martin von Zweigbergk
9ade41078a working_copy: remove a working_copy_path argument I missed earlier
This should clearly have been removed in 4734eb6.
2020-12-26 00:35:45 -08:00
Martin von Zweigbergk
4ce2aed17f lock: use exponential backoff 2020-12-25 15:08:49 -08:00
Martin von Zweigbergk
9138de6ff2 git_store: prevent conflict data from being GC'd
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
2020-12-25 00:52:09 -08:00
Martin von Zweigbergk
3613fe3f59 git_store: avoid confusing delegation from write_conflict() to write_file()
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()`.
2020-12-25 00:26:28 -08:00
Martin von Zweigbergk
8cca56ee77 git_store: extract function for retrying note-writing
I'll add a second call to it very soon.
2020-12-25 00:23:27 -08:00
Martin von Zweigbergk
ddf8416d92 git_store: use exponential backoff when retrying note-writing
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).
2020-12-24 23:22:07 -08:00
Martin von Zweigbergk
210405b21a cargo: update dependencies
For no reason other than to stay up to date.
2020-12-24 01:16:55 -08:00
Martin von Zweigbergk
9c8f13608f cargo: update blake2
For no reason other than to stay up to date.
2020-12-24 01:15:38 -08:00
Martin von Zweigbergk
c7ee24727a protobuf: generate code at build-time
I had tried to generate the protobuf code at build time many months
ago, but decided against it because it slowed down the build too
much. I didn't realize there was the
"cargo:rerun-if-changed=<filename>" feature that time. Given that that
exists, it seems like an obvious win to generate the source code at
build time.

I put the generated sources in `$OUT_DIR` (where [1] says they should
be), then include them in the `protos` module by using the `include!`
macro. The biggest problem with that is that I couldn't get IntelliJ
to understand it, even after enabling the experimental features
described in [2].

 [1] https://doc.rust-lang.org/cargo/reference/build-script-examples.html#code-generation

 [2] https://github.com/intellij-rust/intellij-rust/issues/1908#issuecomment-592773865
2020-12-24 01:05:17 -08:00
Martin von Zweigbergk
4619942a57 evolution: add support for updating state incrementally
We currently recalculate the entire evolution state whenever a new
commit is added within a transaction. That's clearly wasteful. This
commit makes the state-update incremental.
2020-12-23 18:37:55 -08:00
Martin von Zweigbergk
ea7a6b9ce1 evolution: keep track of non-obsolete commits per change id
I'm about to make the evolution state updated incrementally. To be
able to tell if a new commit is divergent, we'll need to keep track of
already existing, non-obsolete commits in the change, even if they're
not divergent before the new commit is added.
2020-12-23 18:10:03 -08:00
Martin von Zweigbergk
6807407814 evolution: fix it so pruned commits can be divergent
A pruned commit just indicates that its predecessors should be evolved
onto the pruned commit's parent instead of onto the pruned commit
itself. The pruned commit itself can be divergent. For example, if
there are several pruned sucessors of a commit, then it's unclear
where the predecessor's children should be rebased to.
2020-12-23 18:01:01 -08:00
Martin von Zweigbergk
cc9008c6bb evolution: create State struct in place
I'm about to add more fields to the type and this will help to
slightly reduce the boilerplate for initializing and the maps and sets
and creating the struct.
2020-12-23 17:32:32 -08:00
Martin von Zweigbergk
66ba74cf5a evolution: use updated state when resolving descendants of orphans
Before this commit, when the `evolve()` evolved a stack of orphans, it
would use the evolve state from the beginning of the function to
calculate where they should go. That meant that only the bottom-most
orphan(s) would get evolved to their right place. This commit fixes
that by use the Transaction's evolution state.
2020-12-23 17:32:32 -08:00
Martin von Zweigbergk
0219dbb359 transaction: make evolution_mut() return a mutable reference
This includes fixing a lifetime bound on `MutableEvolution` that was
reversed.
2020-12-23 17:32:32 -08:00
Martin von Zweigbergk
110c083e78 evolution: don't wrap State in Mutex<Option<>> 2020-12-23 17:32:31 -08:00
Martin von Zweigbergk
fce5ec21f6 evolution: make MutableEvolution own its state
Before this commit, it could share its state with the
`ReadonlyEvolution`. That makes no sense when the state is modified,
and would crash if we tried to get a mutable reference to the
state. It only "worked" because the state is not yet updated within a
transaction (a known bug). I'm about to fix that bug, so we need to
fix the ownership, which this commit does.
2020-12-23 17:32:31 -08:00
Martin von Zweigbergk
648ec34a4c evolution: move shared implementation onto the State struct
There was some duplicate between `ReadonlyEvolution` and
`MutableEvolution` that could be extracted. It will help to have this
shared code on the `State` object for the next few patches.
2020-12-23 17:32:31 -08:00
Martin von Zweigbergk
88e7f4a30c tests: start using the maplit crate 2020-12-23 17:32:31 -08:00
Martin von Zweigbergk
c41251eaff working_copy: fix test to show that already tracked files are not ignored
The point of having the `modified` and `removed` files in the test was
to show that they don't get untracked, but I forgot to include them in
the `.gitignores`, so there was no reason they would have gotten
untracked anyway.
2020-12-22 10:03:42 -08:00
Martin von Zweigbergk
3b326a942c working_copy: add support for .gitignore files
The project's source of truth is now in Git and I really miss support
for anonymous heads and evolution (compared to when the code was in
Mercurial). I'm therefore more motivated to make the tool useful for
day-to-day work on small repos, so I can use it myself. Until now, I
had been more focused on improving performance when it was used as a
read-only client for medium-to-large repos.

One important feature for my day-to-day work is support for
ignores. This commit adds simple and effective, but somewhat hacky
support for that. libgit2 requires a repo to check if a file should be
ignored (presumably so it can respect `.git/info/excludes`). To work
around that, we create a temporary git repo in `/tmp/` whenever the
working copy is committed. We set that temporary git repo's working
copy to be shared with our own working copy. Due to
https://github.com/libgit2/libgit2sharp/issues/1716 (which seems to
apply to the non-.NET version as well), this workaround unfortunately
leaves a .git file (pointing to the deleted temporary git repo) around
in every Jujube repo. That's always ignored by libgit2, so it's not
much of a problem.
2020-12-20 00:37:43 -08:00
Martin von Zweigbergk
9ad225b3b5 trees: make entries() function be the recursive one, since it's more common 2020-12-20 00:26:06 -08:00
Martin von Zweigbergk
8ec100713d tree: for walking tree, replace function with callback by iterator
Iterators are a lot easier to use.
2020-12-20 00:16:05 -08:00
Martin von Zweigbergk
4734eb6493 working_copy: let WorkingCopy and TreeState have the working copy path
I don't know why I didn't do it this way from the beginning.
2020-12-18 23:56:32 -08:00
Martin von Zweigbergk
14e7df995a index: move static functions from Index to IndexFile and delete it
The Index struct no longer has any state, so it's not needed.
2020-12-18 16:12:45 -08:00
Martin von Zweigbergk
00fb670c9c index: make Index::load() return Arc<IndexFile> instead of Index
This removes one level of indirection, which is nice because it was
visible to the callers. The `Index` struct is now empty. The next step
is obviously to delete it (and perhaps rename `IndexFile` to `Index`
or `ReadonlyIndex`).
2020-12-18 16:12:45 -08:00
Martin von Zweigbergk
af1760b02e index: load index file eagerly in Index::load() now that Repo::index() is lazy 2020-12-18 16:12:45 -08:00
Martin von Zweigbergk
2d9aa08334 readme: fix two more little typos 2020-12-18 15:46:49 -08:00
Martin von Zweigbergk
9f4c3bab5e readme: drop repeated "a merge commit" 2020-12-18 14:35:12 -08:00
Martin von Zweigbergk
6721b576b7 releasing: add copyright header also to generated files
This doesn't seem right to me, but it seems the release tool (`cross`)
requires it.
2020-12-15 18:36:23 -08:00
Martin von Zweigbergk
4f045561e6 replace placeholder README.md with real content 2020-12-14 08:41:52 -08:00
Martin von Zweigbergk
6f182fbea4 add .gitignore 2020-12-12 00:23:56 -08:00
Martin von Zweigbergk
6b1427cb46 import commit 0f15be02bf4012c116636913562691a0aaa7aed2 from my hg repo 2020-12-12 00:23:38 -08:00
Martin von Zweigbergk
1fa53a13b0 releasing: add missing trailing newlines to .github/ files 2020-12-11 23:44:55 -08:00