New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cli: add jj operation show
and jj operation diff
commands
#3617
base: main
Are you sure you want to change the base?
Conversation
7e11943
to
eb59a88
Compare
jj operation diff
commandjj operation show
and jj operation diff
commands
eb59a88
to
c82584f
Compare
7ae89e3
to
c3343eb
Compare
I'm not particularly sure what to test, any suggestions on test cases to add? Maybe some common operations like squash, rebase, git fetch and push? |
I'm also thinking that templates are a good idea, maybe something like |
I think you need to exercise the code for each option that the command handles. |
c3343eb
to
dbb9cec
Compare
Sorry, I missed this event. GitHub doesn't send an email for it. I'll try to remember to review this later today. |
dbb9cec
to
33ee8dd
Compare
I think this really should have some tests. I'll review the code now. |
I'll try to add some testcases when I have the time. Here's the list of operations I think we should test (feel free to suggest more):
I'm not sure how to structure it though: I guess I should add a single test beginning from an empty repo for each of these operations? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems useful, but I haven't reviewed the last patch thoroughly. It's a bit hard to comment on the features without snapshot tests.
Missing, | ||
Direct, | ||
Indirect, | ||
} | ||
|
||
fn reachable_targets(edges: &[RevsetGraphEdge]) -> impl DoubleEndedIterator<Item = &CommitId> { | ||
fn reachable_targets<N: Clone>(edges: &[GraphEdge<N>]) -> impl DoubleEndedIterator<Item = &N> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: N: Clone
isn't needed here
pub fn new(input: impl IntoIterator<Item = (CommitId, Vec<RevsetGraphEdge>)>) -> Self { | ||
impl<N> ReverseGraphIterator<N> | ||
where | ||
N: Hash + Eq + PartialEq + Clone, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: PartialEq
is implied by Eq
(two more places that can be simplified)
_ => None, | ||
}; | ||
let op = op_walk::resolve_op_for_load(repo_loader, &args.operation)?; | ||
let parent_op = merge_operations(repo_loader, command.settings(), op.parents())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can simply error out if the operation is a merge?
Since operation can't be merged manually by user, auto-merge result would be identical to the merge operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here was the quick question I asked on Discord:
bnjmnt4n (04/05/2024 19:43)
What should jj op show with an operation with multiple parents be? Should it merge the parents and attempt to diff with the child? afaik the result of this diff would always be empty, but perhaps that might be different if there are operations which are manually merged?
banana (04/05/2024 20:06)
the operation log isn't really a general purpose tree, i think it would be ok to tailor the output to the assumption that the merges are ones created by jj merging op heads
Martin von Zweigbergk (04/05/2024 20:14)
What should jj op show with an operation with multiple parents be? Should it merge the parents and attempt to diff with the child? afaik the result of this diff would always be empty, but perhaps that might be different if there are operations which are manually merged?
I think so. That would be consistent with what we do for the commit log
I guess it's also possible for a user to manually merge operations using jj_lib
, which is why it might be useful to diff with the merged operation parents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's technically correct. I was just wondering how we can reduce the amount of the custom code. Maybe we can make RepoLoader::_resolve_op_heads()
public in some form?
// Create a new transaction starting from `to_repo`. | ||
let mut workspace_command = | ||
command.for_loaded_repo(ui, command.load_workspace()?, to_repo.clone())?; | ||
let mut tx = workspace_command.start_transaction(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be better to use low-level repo.start_transaction()
. WorkspaceCommandHelper
assumes that the loaded repo is synchronized with the working copy, and things might get weird if we committed the transaction by mistake.
let mut tx = workspace_command.start_transaction(); | ||
// Merge index from `from_repo` to `to_repo`, so commits in `from_repo` are | ||
// accessible. | ||
tx.mut_repo().merge_index(from_repo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps, we can use the current (head) repo.index()
? It should contain all historical commits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTOH, doing it the current way means it works even if --from
or --to
point to an operation that was never "published" (made an op head).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doing it the current way means it works even if
--from
or--to
point to an operation that was never "published" (made an op head).
I don't know if such functionality is needed, but there might be (current_repo, from_repo, to_repo)
tuple instead of (from_repo, to_repo)
. The current_repo
provides a context (or visible heads + index) where repo-level templates will be evaluated.
I'm not sure if current_repo
should be selected by --at-op
or --to
, but jj op show
doesn't need to merge indexes. jj op diff
will have to merge if visible heads are controlled by --to
, not by --at-op
.
Thanks for taking a look @yuja. I'll try to work on adding some tests to make it easier to see what the expected output is like, perhaps further reviews can be put on hold if you'd like.
I'd also like to see if there's any desire to change the output displayed. |
As @joyously said, it's probably best to instead focus on what the code does and the different cases it handles. For example, there's some logic for displaying how refs moved, so there should be some tests demonstrating that, and ideally some including conflicted refs. It doesn't matter which commands you use to create the refs, so use whatever is easiest for that (for creating conflicted branches, it's probably easiest to use
I don't think these two need to be tested. They don't do much you can't test by making the same changes explicitly.
SGTM. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(If this makes your life easier): I would consider splitting this commit into a separate PR, finishing it up, and merging it, so that you don't have to worry about merge conflicts if somebody else edits the renamed files. At least, that's what I tend to do. (I'm assuming this is a good change on its own, @yuja can correct me if I'm wrong)
pub struct OperationShowArgs { | ||
/// Show repository changes in this operation, compared to its parent(s) | ||
#[arg(default_value = "@")] | ||
operation: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been using these (thank you!), but I always want to use --op
instead of --operation
. I think it'd be good to add an alias visible_alias="op"
for --operation
. (Also for op diff)
Checklist
If applicable:
CHANGELOG.md