ok/jj
1
0
Fork 0
forked from mirrors/jj
Commit graph

195 commits

Author SHA1 Message Date
Martin von Zweigbergk
ea82340654 working_copy: preserve conflicts in the working copy until markers are removed
I realized only recently that we can try to parse conflict markers in
files and leave them as conflicted if they haven't changed. If they
have changed and some conflict markers have been removed, we can even
update the conflict with that partial resolution.

This change teaches the working copy to write conflicts to the working
copy. It used to expect that the caller had already updated the tree
by materializing conflicts. With this change, we also start parsing
the conflict markers and leave the conflicts unresolved in the working
copy if the conflict markers remain.

There are some cases that we don't handle yet. For example, we don't
even try to set the executable bit correctly when we write
conflicts. OTOH, we didn't do that even before this change.

We still never actually write conflicts to the working copy (outside
of tests) because we currently materialize conflicts in
`MutRepo::check_out()`. I'll change that next.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
cea6061f3d conflicts: add a function for parsing a materialized conflict
I initially made the working copy materialize conflicts in its
`check_out()` method. Then I changed it later (exactly a year ago, on
Halloween of 2020, actually) so that the working copy expected
conflicts to already have been materalized, which happens in
`MutableRepo::check_out`().

I think my reasoning then was that the file system cannot represent a
conflict. While it's true that the file system itself doesn't have
information to know whether a file represents a conflict, we can
record that ourselves. We already record whether a file is executable
or not and then preserve that if we're on a file system that isn't
able to record it. It's not that different to do the same for
conflicts if we're on a file system that doesn't understand conflicts
(i.e. all file systems).

The plan is to have the working copy remember whether a file
represents a conflict. When we check if it has changed, we parse the
file, including conflict markers, and recreate the conflict from
it. We should be able to do that losslessly (and we should adjust
formats to make it possible if we find cases where it's not).

Having the working copy preserve conflict states has several
advantages:

 * Because conflicts are not materialized in the working copy, you can
   rebase the conflicted commit and the working copy without causing
   more conflicts (that's currently a UX bug I run into every now and
   then).

 * If you don't change anything in the working copy, it will be
   unchanged compared to its parent, which means we'll automatically
   abandon it if you update away from it.

 * The user can choose to resolve only some of the conflicts in a file
   and squash those in, and it'll work they way you'd hope.

 * It should make it easier to implement support for external merge
   tools (#18) without having them treat the working copy differently.

This patch prepares for that work by adding support for parsing
materialized conflicts.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
9abee0096f conflicts: propagate errors from materialize_conflict()
All current callers pass in a buffer, so it should never fail, but the
function itself can't know that.
2021-10-24 23:02:00 -07:00
Martin von Zweigbergk
b4a0e513dd revset graph: make order of edges stable
While working on demos, I noticed that `jj log` output in the
octocat/Hello-World repo was unstable: sometimes the first parent of
the merge was on the left and sometimes it was on the right. This
patch fixes that by sorting the edges by position in the index just
before returning them. It seems that most applications would want
stable output so I put it in the `RevsetGraphIterator` rather than
doing at the call site in the CLI. I ordered them with the reverse
index position rather than forward because it seemed to make the
graphs in the git.git repo slight nicer, with the left-most edge going
between subsequent releases.

There performance difference is within the noise level.
2021-10-23 20:33:59 -07:00
Martin von Zweigbergk
33bf6ce1d5 view: don't force commits pointed to by refs to be current heads
If you rewrite a commit that's also available on some remote, you'll
currently see both the old version and the new version in the view,
which means they're divergent. They're not logically divergent (the
rewritten version should replace the old version), so this is a UX
bug. I think it indicates that the set of current heads should be
redefined to be the *desired* heads. That's also what I had suspected
in the TODO removed by this change.  I think another indication that
we should hide the old heads even if they have e.g. a remote branch
pointing to them is that we don't want them to be rebased if we
rewrite an ancestor.

So that's what I decided to do: let the view's heads be the desired
heads. The user can still define revsets for showing non-current
commits pointed to by e.g. remote branches.
2021-10-23 09:15:05 -07:00
Martin von Zweigbergk
c0ae4b16e8 trees: try to resolve file conflicts after simplifying conflicts
This fixes a bug I've run into somewhat frequently. What happens is
that if you have a conflict on top of another conflict and you resolve
the conflict in the bottom commit, we just simplify the `Conflict`
object in the second commit, but we don't try to resolve the new
conflict. That shows up as an unexpected "conflict" in `jj log`
output, and when you check out the commit, there are actually no
conflicts, so you can just `jj squash` right away.

This patch fixes that bug. It also teaches the code to work with more
than 3 parts in the merge, so if there's a 5-way conflict, for
example, we still try to resolve it if possible.
2021-10-22 09:20:50 -07:00
Martin von Zweigbergk
2e4dc019d9 git: don't update public heads for now 2021-10-20 14:23:58 -07:00
Martin von Zweigbergk
c0a26f7642 conflicts: work around rust-lang/rust#89716 2021-10-13 13:41:09 -07:00
Martin von Zweigbergk
b4b64eb7e5 conflicts: add tests of conflict materialization 2021-10-13 13:40:25 -07:00
Martin von Zweigbergk
d8c0282873 revset: make head() accept candidate set to find heads within
With this change, you can do e.g. `heads(remote_branches())`. That
should currently be the same as `public_heads()`, except that we don't
yet remove public heads when remote branches have been updated. Having
this support should be generally useful, but I may use it in the short
term specifically for depending less on the public heads, until I get
around to keeping them up to date.
2021-10-13 09:41:20 -07:00
Martin von Zweigbergk
aebdd4e8fd revset: add all() function 2021-10-13 09:28:11 -07:00
Martin von Zweigbergk
5874d5abfb revset: add none() function 2021-10-13 09:24:08 -07:00
Martin von Zweigbergk
8465a578be revset: split out a new remote_branches() from branches()
It seems useful to be able to use `remote_branches()` in revsets
e.g. for filtering out commits known on remotes.
2021-10-10 12:24:48 -07:00
Martin von Zweigbergk
fdb861b957 backend: remove unused Commit::is_pruned (#32) 2021-10-06 23:53:15 -07:00
Martin von Zweigbergk
4c4e436f38 evolution: delete it now that we don't use it anymore (#32)
It's been a lot of work, but now we're finally able to remove the
`Evolution` state! `jj obslog` still works as before (it just walks
the predecessor pointers).
2021-10-06 23:28:30 -07:00
Martin von Zweigbergk
4c8beee81c Transaction: don't remove hidden heads on commit
The removal of hidden heads was just there to help with the transition
away from evolution (#32). Now that we no longer depend on evolution
for removing old heads, we can remove the hack.
2021-10-06 23:20:23 -07:00
Martin von Zweigbergk
108c38d816 evolution: don't create pruned commits (#32)
Now that we rebase descendants and remove old heads as appropriate
(without using evolution), we don't need to create pruned commits
anymore.
2021-10-06 23:20:23 -07:00
Martin von Zweigbergk
b7acbae168 DescendantRebaser: also remove old heads
This patch teaches `DescendantRebaser` to also update heads. That's
done at the end of the rebase (when `rebase_next()` starts returning
`None`), which is a little weird. We should probably change the
interface, but this will do for now.

With this change, we should no longer need to remove hidden heads when
the transaction commits. That will remove one of the last bits of
dependence on evolution from most commands (#32).
2021-10-06 22:01:39 -07:00
Martin von Zweigbergk
e26d21dc18 revset: add .commit_ids() and .commits() to RevsetIterator
This makes it a little easier to iterate over commits or commit ids.
2021-10-06 14:18:11 -07:00
Martin von Zweigbergk
9ec27645cf revsets: remove all_heads()
Now that we remove hidden heads whenever a transaction commits,
`non_obsolete_heads()` should always be the same as `all_heads()`,
except during a transaction. I don't think we depend on the difference
even during a transaction. Let's simplify a bit by removing the revset
function `all_heads()` and renaming `non_obsolete_heads()` to
`heads()`. This is part of issue #32.
2021-10-06 12:21:18 -07:00
Martin von Zweigbergk
f3bee0b12e evolution: remove support evolving orphans and divergent commits (#32) 2021-10-03 22:38:49 -07:00
Martin von Zweigbergk
fcb79ef0a6 DescendantRebaser: also update checkout (#32)
This is similar to how a recent change taught `DescendantRebaser` to
update branches pointing to rewritten commits. Now we also update the
checkout if it pointed to a rewritten commit.
2021-10-03 22:38:49 -07:00
Martin von Zweigbergk
5be75d0e31 DescendantRebaser: also update branches
This patch moves the logic for updating branches from
`update_branches_after_rewrite()` into `DescendantRebaser`. The
branches are now updated along with each rebased commit rather than
all being updated at the end. The new code uses the information about
rewritten and abandoned commits that `DescendantRebaser` gets from
`MutableRepo`. That is different from the old code, which used the
evolution state. This patch thus moves us one step closer to removing
evolution (#32).
2021-10-03 10:07:09 -07:00
Martin von Zweigbergk
a78976cd29 DescendantRebaser: allow passing divergent changes as input
I'm going to teach `DescendantRebaser` to also update local branches
pointing to rewritten commits, taking over the responsibility from
`rewrite::update_branches_after_rewrite()`. For commits that have been
rewritten as multiple new commits (divergent, not split), that
function makes local branches pointing to the old commit point to all
the new commits. To replicate that behavior in `DescendantRebaser`, it
needs to know about divergent changes. This change addresses that.
2021-10-02 23:12:46 -07:00
Martin von Zweigbergk
de0df90b66 tests: use letters instead of numbers for commits in test_rewrite
Letters let you make it clearer by using e.g. "X2" for a rewritten
commit "X"..
2021-10-02 23:12:46 -07:00
Martin von Zweigbergk
1c55c02106 Transaction: remove hidden heads on commit
I recently made the CLI remove hidden heads when a transaction is
committed (38474a9). Let's move that to `Transaction::commit()`, so
the library crate becomes more similar to how the CLI behaves and more
similar to our evolution-less future (#32).
2021-10-02 23:12:46 -07:00
Martin von Zweigbergk
41ebdea415 tests: update a test to not point a branch to an unreachable commit
The next patch would otherwise make this test fail because
"transaction 2" tries to point a branch to a commit that's not visible
(because it's created by the concurrent "transaction 1").
2021-10-02 23:08:45 -07:00
Martin von Zweigbergk
76352564ad CommitBuilder: record rewritten commits in MutableRepo
This is part of removing support for evolution (#32). Since
`CommitBuilder` now records rewritten commits in `MutableRepo`, we can
use that recorded information to automatically rebase descendants.
2021-09-29 15:45:38 -07:00
Martin von Zweigbergk
d00b805d97 MutableRepo: add support for recording rewritten and abandoned commits
When we remove support for evolution (#32), we need to still make it
easy for application code to rebase descendants of rewritten and
abandoned commits. The way applications currently do that is by using
e.g.  `CommitBuilder::for_rewrite_from()` followed by
`evolve_orphans()`. This patch puts some bookkeeping in `MutableRepo`
for rewritten and abandoned commits, along with a function for
creating a `DescendantRebaser` based on it. I'll then make
`CommitBuilder` record rewritten commits there.
2021-09-29 15:24:04 -07:00
Martin von Zweigbergk
23c3b503c0 tests: move assert_rebased() function to testutils 2021-09-29 11:41:51 -07:00
Martin von Zweigbergk
ff71af1e11 MutableRepo: accept just CommitId instead of whole Commit where possible 2021-09-29 10:13:32 -07:00
Martin von Zweigbergk
eb00981aca git: also test imported refs and branches after fetch 2021-09-24 22:42:37 -07:00
Waleed Khan
bfb5e55cfd git: properly detect default branch
The default branch relies on checking the value of `HEAD`. The `empty_git_commit` function updates the ref `refs/heads/main`, but since `HEAD` was never updated to point to that ref, the default branch can't be determined. The fix is to explicitly set `HEAD`.

Personally, this test failed reliably for me on macOS. I don't know why this behavior would be non-deterministic on other platforms.
2021-09-22 16:45:04 -07:00
Martin von Zweigbergk
a69096a4d4 git: remove test of default branch because of issue #30 2021-09-22 15:22:53 -07:00
Martin von Zweigbergk
eed715dc51 git: try to fix flaky (?) fetch tests by keeping connection open longer
It seems it wasn't Windows that behaved differently when it comes
getting the remote's default branch; the test failed on Ubuntu
too.

The documentation for `Remote::default_branch()` says that it can be
called even after the connection has been closed, but let's see if
calling it while the connection is open helps anyway. To do that, we
have to replicate what `Remote::fetch()` does.
2021-09-22 11:48:42 -07:00
Martin von Zweigbergk
2086d1a84d git: make fetch-test pass on Windows by expecting no default branch 2021-09-22 10:56:53 -07:00
Martin von Zweigbergk
f56262ce85 git: add test for default branch after fetch
This adds tests I should have added in 48f237e33e.
2021-09-22 10:28:28 -07:00
Martin von Zweigbergk
d4004fcb6f rewrite: teach DescendantRebaser to handle abandoned commits specially
Descendants of abandoned commits should be rebased onto their parents,
or the rewritten parents if they had been rewritten. This patch
teaches `DescendantRebaser` to do that. It updates `jj rebase -r` to
use the functionality. I plan to also use it in `jj abandon`
(naturally, given the name), and for rebasing descendants of deleted
refs imported from `jj git refresh/fetch/push`.
2021-09-19 22:51:12 -07:00
Martin von Zweigbergk
439fe1cfd3 rewrite: don't report skipped commits when rebasing descendants
The fact that `DescendantRebaser` visits some commits that don't need
to be rebased is mostly an implementation detail. I can't think of a
reason that callers would care about these commits.
2021-09-19 22:51:12 -07:00
Martin von Zweigbergk
ae7f00e7b1 cli: rename jj prune to jj abandon
The command's help text says "Abandon a revision", which I think is a
good indication that the command's name should be `abandon`. This
patch renames the command and other user-facing occurrences of the
word. The remaining occurrences should be removed when I remove
support for evolution.
2021-09-19 22:51:12 -07:00
Martin von Zweigbergk
ef4cb663ae cli: move logic for updating branches after rewrite to lib crate
This patch moves the function for updating branches after rewrite from
`commands.rs` into `rewrite.rs`.

It also changes the function to update branches even if they were
conflicted or become conflicted. I think that seems better than
leaving branches on old commits. For example, let's say you have start
with this:

```
C main
|
B origin@main
|
A
```

You now pull from origin, which has updated the main branch from B to
B'. We apply that change to both the remote branch and the local
branch, which results in a conflict in the local branch:

```
C main?
|
B B' main? origin@main
|/
A
```

If you now rewrite C to C', the conflicted main branch will still
point to C, which is just weird. This patch changes that so the
conflicted side of main gets repointed to C'.

I also refactored the code to reuse our existing
`MutableRepo::merge_single_ref()`, which improves the behavior in
several cases, such as the conflict-resolution case in the last test
case.
2021-09-18 10:03:26 -07:00
Martin von Zweigbergk
ca114d6d7e rewrite: add support for rebasing descendants of multiple rewritten commits
I plan to use this for rebasing descendants of rewritten remote
branches (on fetch).
2021-09-15 22:13:40 -07:00
Martin von Zweigbergk
30bcf6508e rewrite: when rebasing forward, also rebase "side branches"
As the updates test case shows, when rebasing forward, we missed
commits that fork off from the section between the source and the
destination.

As part of the fix, I also restructured the code a bit to prepare for
support for rebasing descendants of multiple rewritten commits.
2021-09-15 22:08:32 -07:00
Martin von Zweigbergk
e4bc8f5b4c tests: extract helpers to reduce repetition in test_rewrite 2021-09-15 22:02:58 -07:00
Martin von Zweigbergk
ce5e95fa80 store: rename Store to Backend and StoreWrapper to Store
For what's currently called `Store` in the code, I have been using
"backend" in plain text. That probably means that `Backend` is a good
name for it.
2021-09-12 12:02:10 -07:00
Martin von Zweigbergk
344435e90f git: add support for pushing multiple ref updates at once 2021-09-11 22:54:29 -07:00
Martin von Zweigbergk
11c0130303 index: squash an index segment into its parent more aggressively
Before this change, you could end up with an index segment with 10
commits, then a child segment with 9 commits, then another child with
8 commits, and so on. That's not what I had intended. This changes
makes it so we squash if a segment has more than half as many commits
as its parent instead.
2021-09-11 22:51:13 -07:00
Martin von Zweigbergk
20e9d29c4b CommitBuilder: remove write_to_new_transaction(), which was only used in tests 2021-09-11 10:11:15 -07:00
Martin von Zweigbergk
88fef10eac cleanup: use literal newlines in string literals
I'm about to enable `rustfmt`'s formatting of string literals, and
that makes these string literals with escaped newlines harder to read.
2021-09-02 11:01:02 -07:00
Martin von Zweigbergk
ccdd651953 working_copy: ignore .git directory/file when writing tree to store
Git doesn't want `.git` entries in its trees, so at least when using
the Git backend, we need to ignore such paths. Let's just ignore
`.git` paths regardless of backend to keep it simple.

Closes #24.
2021-09-01 08:40:28 -07:00