This makes the graph compact. Short change ids are usually printed as a part
of commit summary. The --no-graph output is a bit harder to parse, but we can
still discriminate entries by change ids.
This is a middle ground. An inline table can still be overwritten or deleted
because it's syntactically a value. It would be annoying if "jj config set
colors.<name> '{ .. }'" couldn't be executed more than once because the existing
item was a table.
#5255
If many files are conflicted, it would be nice to be able to resolve all
conflicts at once without having to run `jj resolve` multiple times.
This is especially nice for merge tools which try to automatically
resolve conflicts without user input, but it is also good for regular
merge editors like VS Code.
This change makes the behavior of `jj resolve` more consistent with
other commands which accept filesets since it will use the entire
fileset instead of picking an arbitrary file from the fileset.
Since we don't support passing directories to merge tools yet, the
current implementation just calls the merge tool repeatedly in a loop
until every file is resolved, or until an error occurs. If an error
occurs after successfully resolving at least one file, the transaction
is committed with all of the successful changes before returning the
error. This means the user can just close the editor at any point to
cancel resolution on all remaining files.
Certain tools (`diff`, `delta`) exit with code 1 to indicate there was
a difference. This allows selectively suppressing the "Tool exited with
... status" warning from jj when generating a diff.
example:
```toml
[merge.tools.delta]
diff-expected-exit-codes = [0, 1]
```
This backs out commit 0de36918e4. Documentation,
tests, and comments are updated accordingly. I also add ConfigTableLike type
alias as we decided to abstract table-like items away.
Closes#5255
If the parent tree contains conflicts, we want the index to also contain
a conflict to ensure that the use can't accidentally commit conflict
markers using `git commit`. Since we can't represent conflicts with more
than 2 sides in the Git index, we need to add a dummy conflict in this
case. We use ".jj-do-not-resolve-this-conflict" as the dummy conflict to
indicate to the user that they should not attempt to resolve this
conflict using Git.
Instead of setting the index to match the tree of HEAD, we now set the
index to the merged parent tree of the working copy commit. This means
that if you edit a merge commit, it will make the Git index look like it
would in the middle of a `git merge` operation (with all of the
successfully-merged files staged in the index).
If there are any 2-sided conflicts in the merged parent tree, then they
will be added to the index as conflicts. Since Git doesn't support
conflicts with more than 2 sides, many-sided conflicts are staged as the
first side of the conflict. The following commit will improve this.
These tests should still pass after we switch to gix for resetting the
index, so we need to make sure they don't rely on the cached index from
the `git2::Repository` instance.
This patch doesn't fix DiffEditor::edit() API, which is fundamentally broken
if matcher argument is specified. I'm not sure if the builtin behavior is
correct or not. Suppose we add "jj diffedit FILESETS..", it would probably make
sense to leave unmatched paths unmodified because it is the command to edit the
destination (or right) tree. This is the edit_diff_external() behavior.
Fixes#5252
Disclaimer: this is the work of @necauqua and @julienvincent (see
#3141). I simply materialized the changes by rebasing them on latest
`main` and making the necessary adjustments to pass CI.
---
I had to fix an issue in `TestSignatureBackend::sign()`.
The following test was failing:
```
---- test_signature_templates::test_signature_templates stdout ----
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Snapshot Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Snapshot: signature_templates
Source: cli/tests/test_signature_templates.rs:28
────────────────────────────────────────────────────────────────────────────────
Expression: stdout
────────────────────────────────────────────────────────────────────────────────
-old snapshot
+new results
────────────┬───────────────────────────────────────────────────────────────────
0 0 │ @ Commit ID: 05ac066d05701071af20e77506a0f2195194cbc9
1 1 │ │ Change ID: qpvuntsmwlqtpsluzzsnyyzlmlwvmlnu
2 2 │ │ Author: Test User <test.user@example.com> (2001-02-03 08:05:07)
3 3 │ │ Committer: Test User <test.user@example.com> (2001-02-03 08:05:07)
4 │-│ Signature: Good test signature
4 │+│ Signature: Bad test signature
5 5 │ │
6 6 │ │ (no description set)
7 7 │ │
8 8 │ ◆ Commit ID: 0000000000000000000000000000000000000000
────────────┴───────────────────────────────────────────────────────────────────
```
Print debugging revealed that the signature was bad, because of a
missing trailing `\n` in `TestSignatureBackend::sign()`.
```diff
diff --git a/lib/src/test_signing_backend.rs b/lib/src/test_signing_backend.rs
index d47fef1086..0ba249e358 100644
--- a/lib/src/test_signing_backend.rs
+++ b/lib/src/test_signing_backend.rs
@@ -59,6 +59,8 @@
let key = (!key.is_empty()).then_some(std::str::from_utf8(key).unwrap().to_owned());
let sig = self.sign(data, key.as_deref())?;
+ dbg!(&std::str::from_utf8(&signature).unwrap());
+ dbg!(&std::str::from_utf8(&sig).unwrap());
if sig == signature {
Ok(Verification::new(
SigStatus::Good,
```
```
[lib/src/test_signing_backend.rs:62:9] &std::str::from_utf8(&signature).unwrap() = \"--- JJ-TEST-SIGNATURE ---\\nKEY: \\n5300977ff3ecda4555bd86d383b070afac7b7459c07f762af918943975394a8261d244629e430c8554258904f16dd9c18d737f8969f2e7d849246db0d93cc004\\n\"
[lib/src/test_signing_backend.rs:63:9] &std::str::from_utf8(&sig).unwrap() = \"--- JJ-TEST-SIGNATURE ---\\nKEY: \\n5300977ff3ecda4555bd86d383b070afac7b7459c07f762af918943975394a8261d244629e430c8554258904f16dd9c18d737f8969f2e7d849246db0d93cc004\"
```
Thankfully, @yuja pointed out that libgit2 appends a trailing newline
(see bfb7613d5d).
Co-authored-by: necauqua <him@necauq.ua>
Co-authored-by: julienvincent <m@julienvincent.io>
The idea is the same as diff_editor()/selector() API. This object will be passed
in to edit_*description() functions in place of (repo_path, settings) pair.
"ui.editor" isn't specific to editing commit descriptions, but it's mainly used
for that purpose. So I put the wrapper type in description_util.rs.
This implements "scissor" lines. For example:
this text is included in the commit message
JJ: ignore-rest
this text is not, and is encouraged to be rendered as a diff
JJ: ignore-rest
this text is *still not* included in the commit message
When editing multiple commit messages, the `JJ: describe {}` lines
are parsed before the description is cleaned up. That means that the
following will correctly add descriptions to multiple commits:
JJ: describe aaaaaaaaaaaa
this text is included in the first commit message
JJ: ignore-rest
scissored...
JJ: describe bbbbbbbbbbbb
this text is included in the first commit message
JJ: ignore-rest
scissored...
Git supports passing the conflict marker length to merge drivers using
"%L". It would be useful if we also had a way to pass the marker length
to merge tools, since it would allow Git merge drivers to be used with
`jj resolve` in more cases. Without this variable, any merge tool that
parses or generates conflict markers could fail on files which require
conflict markers longer than 7 characters.
https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver
I often do "jj log -rREV" to preview the commits to abandon, and it's annoying
that I have to remove -r or insert space to "jj abandon ..".
The implementation is basically the same as b0c7d0a7e2.
Since source.contains(':') can't be used for non-local path detection on
Windows, we now use gix::url for parsing. It might be stricter, but I assume it
would be more reliable.
Closes#4188
Currently, `jj resolve` always sets the file to be non-executable
whenever a conflict is fully resolved. This is confusing, because it can
cause the executable bit to be lost even if every side agrees that the
file is executable.
These paths may be printed, compared with user inputs, or passed to external
programs. It's probably better to avoid unusual "\\?\C:\" paths on Windows.
Fixes#5143
Storing the conflict marker length in the working copy makes conflict
parsing more consistent, and it allows us to parse valid conflict hunks
even if the user left some invalid conflict markers in the file while
resolving the conflicts.
I don't think we need --keep-emptied flag. IIRC, "jj squash" has that flag in
order not to squash commit description to the destination commits. Since
"jj absorb" never moves commit description, the source commit is preserved in
that situation.
Closes#5141
This patch moves max_new_file_size() and conflict_marker_style() to CLI, but
there isn't a clear boundary whether the configuration should be managed by
UserSettings or not. I decided to move them to CLI just because we can eliminate
.optional() handling. The default parameters are defined in config/misc.toml.
This is an alternative way to achieve includeIf of Git without adding "include"
directive. Conditional include (or include in general) is a bit trickier to
implement than loading all files and filtering the contents.
Closes#616
We can usually omit quotes in --config=NAME=VALUE, but an RFC3339 string is a
valid TOML date-time expression. It's weird that quoting is required to specify
a date-time value.