feat: default diffs to branch changes
This commit is contained in:
+202
-5
@@ -16,7 +16,7 @@ use std::{
|
||||
},
|
||||
};
|
||||
use vamp::{
|
||||
diff::{Category, Comparison, FileStatus, RepoKind, Revision, RevisionTarget},
|
||||
diff::{Category, Comparison, ComparisonMode, FileStatus, RepoKind, Revision, RevisionTarget},
|
||||
repository::Repository,
|
||||
};
|
||||
|
||||
@@ -134,7 +134,8 @@ fn compare_loaded(
|
||||
after: &Revision,
|
||||
buffers: &[(PathBuf, String)],
|
||||
) -> Result<Comparison, String> {
|
||||
let mut comparison = repository.compare(1, before, after, buffers)?;
|
||||
let mut comparison =
|
||||
repository.compare(1, before, after, ComparisonMode::Snapshots, buffers)?;
|
||||
for (index, file) in comparison.files.iter_mut().enumerate() {
|
||||
*file = repository.load_file(1, index)?;
|
||||
if file
|
||||
@@ -381,7 +382,13 @@ fn git_working_reads_disk_and_handles_ranges_ignored_files_binary_links_and_odd_
|
||||
);
|
||||
assert!(
|
||||
repository
|
||||
.compare(1, &working(RepoKind::Git), &working(RepoKind::Git), &[])
|
||||
.compare(
|
||||
1,
|
||||
&working(RepoKind::Git),
|
||||
&working(RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[]
|
||||
)
|
||||
.unwrap()
|
||||
.files
|
||||
.is_empty()
|
||||
@@ -574,6 +581,40 @@ fn jj_catalog_and_working_comparisons_prefer_jj_and_never_snapshot_or_merge_oper
|
||||
.iter()
|
||||
.any(|f| f.path == Path::new("ignored-untracked"))
|
||||
);
|
||||
let synthetic_root = revision(&"0".repeat(40), RepoKind::Jujutsu);
|
||||
let branch = repository
|
||||
.compare(
|
||||
20,
|
||||
&synthetic_root,
|
||||
baseline,
|
||||
ComparisonMode::BranchChanges,
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(branch.before.ends_with(&"0".repeat(40)));
|
||||
assert!(
|
||||
branch
|
||||
.files
|
||||
.iter()
|
||||
.any(|file| file.path == Path::new("file"))
|
||||
);
|
||||
let reversed = repository
|
||||
.compare(
|
||||
21,
|
||||
baseline,
|
||||
&synthetic_root,
|
||||
ComparisonMode::BranchChanges,
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(reversed.files.is_empty());
|
||||
assert!(
|
||||
repository
|
||||
.compare(22, baseline, baseline, ComparisonMode::BranchChanges, &[])
|
||||
.unwrap()
|
||||
.files
|
||||
.is_empty()
|
||||
);
|
||||
assert_eq!(disk_state(&active), state);
|
||||
}
|
||||
}
|
||||
@@ -657,6 +698,15 @@ fn jj_private_fetch_discovers_never_fetched_bookmark_and_searchable_remote_chang
|
||||
.iter()
|
||||
.any(|r| r.target == RevisionTarget::Commit(ancestor.clone()))
|
||||
);
|
||||
let local = catalog.entries.iter().find(|revision| {
|
||||
matches!(&revision.target, RevisionTarget::Commit(id) if id.bytes().any(|byte| byte != b'0'))
|
||||
}).unwrap();
|
||||
let branch = repository
|
||||
.compare(60, local, &remote, ComparisonMode::BranchChanges, &[])
|
||||
.unwrap();
|
||||
assert!(branch.before.ends_with(&"0".repeat(40)));
|
||||
assert_eq!(branch.files.len(), 1);
|
||||
assert_eq!(repository.load_file(60, 0).unwrap().after, ["remote tip"]);
|
||||
let comparison =
|
||||
compare_loaded(&mut repository, &remote, &working(RepoKind::Jujutsu), &[]).unwrap();
|
||||
assert_eq!(
|
||||
@@ -682,6 +732,14 @@ fn jj_private_fetch_discovers_never_fetched_bookmark_and_searchable_remote_chang
|
||||
changed(&comparison, Path::new("file")).after,
|
||||
["remote tip"]
|
||||
);
|
||||
let branch = repository
|
||||
.compare(61, historic, &remote, ComparisonMode::BranchChanges, &[])
|
||||
.unwrap();
|
||||
assert!(branch.before.ends_with(&ancestor));
|
||||
assert_eq!(
|
||||
repository.load_file(61, 0).unwrap().before,
|
||||
["remote ancestor"]
|
||||
);
|
||||
let store = active.join(".jj/repo/store");
|
||||
let active_store =
|
||||
fs::canonicalize(store.join(fs::read_to_string(store.join("git_target")).unwrap().trim()))
|
||||
@@ -747,6 +805,7 @@ fn errors_are_explicit_and_do_not_modify_active_repository() {
|
||||
1,
|
||||
&revision("--bad", RepoKind::Git),
|
||||
&working(RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[]
|
||||
)
|
||||
.unwrap_err()
|
||||
@@ -758,6 +817,7 @@ fn errors_are_explicit_and_do_not_modify_active_repository() {
|
||||
1,
|
||||
&revision(&"f".repeat(40), RepoKind::Git),
|
||||
&working(RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[],
|
||||
)
|
||||
.unwrap_err()
|
||||
@@ -769,7 +829,13 @@ fn errors_are_explicit_and_do_not_modify_active_repository() {
|
||||
};
|
||||
assert!(
|
||||
repository
|
||||
.compare(1, &loader, &revision(&id, RepoKind::Git), &[])
|
||||
.compare(
|
||||
1,
|
||||
&loader,
|
||||
&revision(&id, RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[]
|
||||
)
|
||||
.unwrap_err()
|
||||
.contains("history loader")
|
||||
);
|
||||
@@ -813,6 +879,7 @@ fn unchanged_submodules_are_not_false_changes_and_changed_pointers_are_explicit(
|
||||
1,
|
||||
&revision(&baseline, RepoKind::Git),
|
||||
&working(RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[]
|
||||
)
|
||||
.unwrap()
|
||||
@@ -1033,6 +1100,29 @@ fn jj_conflicted_revisions_show_cli_projection_and_keep_ordinary_files_navigable
|
||||
assert_eq!(ordinary.before, ["old"]);
|
||||
assert_eq!(ordinary.after, ["left ordinary"]);
|
||||
assert!(ordinary.notice.is_none());
|
||||
let branch = repository
|
||||
.compare(
|
||||
30,
|
||||
&revision(&base, RepoKind::Jujutsu),
|
||||
&revision(&merged, RepoKind::Jujutsu),
|
||||
ComparisonMode::BranchChanges,
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
let index = branch
|
||||
.files
|
||||
.iter()
|
||||
.position(|file| file.path == Path::new("conflict"))
|
||||
.unwrap();
|
||||
let conflict = repository.load_file(30, index).unwrap();
|
||||
assert_eq!(conflict.after, expected);
|
||||
assert!(
|
||||
conflict
|
||||
.notice
|
||||
.as_deref()
|
||||
.unwrap()
|
||||
.contains("conflict projection")
|
||||
);
|
||||
let working_comparison = compare_loaded(
|
||||
&mut repository,
|
||||
&revision(&merged, RepoKind::Jujutsu),
|
||||
@@ -1112,7 +1202,7 @@ fn unsaved_overlays_are_working_after_only_and_cannot_follow_nonregular_paths()
|
||||
);
|
||||
assert!(
|
||||
repository
|
||||
.compare(1, &base, &base, &buffers)
|
||||
.compare(1, &base, &base, ComparisonMode::Snapshots, &buffers)
|
||||
.unwrap()
|
||||
.files
|
||||
.is_empty()
|
||||
@@ -1152,6 +1242,7 @@ fn immutable_catalog_skips_unchanged_blobs_and_prepares_only_requested_details()
|
||||
100,
|
||||
&revision(&before, RepoKind::Git),
|
||||
&revision(&after, RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1176,6 +1267,7 @@ fn immutable_catalog_skips_unchanged_blobs_and_prepares_only_requested_details()
|
||||
101,
|
||||
&revision(&after, RepoKind::Git),
|
||||
&revision(&after, RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1198,6 +1290,7 @@ fn deferred_file_details_keep_frozen_checkout_and_unsaved_after() {
|
||||
50,
|
||||
&working(RepoKind::Git),
|
||||
&working(RepoKind::Git),
|
||||
ComparisonMode::Snapshots,
|
||||
&[(root.join("file"), "unsaved after\n".into())],
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1211,3 +1304,107 @@ fn deferred_file_details_keep_frozen_checkout_and_unsaved_after() {
|
||||
assert_eq!(again.before, details.before);
|
||||
assert_eq!(again.after, details.after);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_changes_resolves_local_and_private_remote_ancestry_without_active_mutation() {
|
||||
let fixture = Fixture::new();
|
||||
let active = fixture.dir("active\nquoted\"\\");
|
||||
init_git(&active);
|
||||
fs::write(active.join("common"), "base\n").unwrap();
|
||||
git(&active, &["add", "."]);
|
||||
git(&active, &["commit", "-m", "base"]);
|
||||
let base = git(&active, &["rev-parse", "HEAD"]);
|
||||
let source = fixture.0.join("source");
|
||||
git(
|
||||
&fixture.0,
|
||||
&["clone", active.to_str().unwrap(), source.to_str().unwrap()],
|
||||
);
|
||||
git(&source, &["config", "user.name", "Diff Test"]);
|
||||
git(&source, &["config", "user.email", "diff@example.invalid"]);
|
||||
fs::write(source.join("remote-only"), "remote\n").unwrap();
|
||||
git(&source, &["add", "."]);
|
||||
git(&source, &["commit", "-m", "remote"]);
|
||||
fs::write(active.join("local-only"), "local\n").unwrap();
|
||||
git(&active, &["add", "."]);
|
||||
git(&active, &["commit", "-m", "local"]);
|
||||
let local = revision(&git(&active, &["rev-parse", "HEAD"]), RepoKind::Git);
|
||||
git(
|
||||
&active,
|
||||
&["remote", "add", "origin", source.to_str().unwrap()],
|
||||
);
|
||||
let state = disk_state(&active);
|
||||
let mut repository = open(&active);
|
||||
let catalog = repository.list_remote("origin").unwrap();
|
||||
let remote = catalog
|
||||
.entries
|
||||
.iter()
|
||||
.find(|r| matches!(r.target, RevisionTarget::Remote { .. }))
|
||||
.unwrap();
|
||||
let branch = repository
|
||||
.compare(40, &local, remote, ComparisonMode::BranchChanges, &[])
|
||||
.unwrap();
|
||||
assert_eq!(branch.files.len(), 1);
|
||||
assert_eq!(branch.files[0].path, Path::new("remote-only"));
|
||||
assert!(branch.before.ends_with(&base));
|
||||
assert_eq!(repository.load_file(40, 0).unwrap().after, ["remote"]);
|
||||
let reverse = repository
|
||||
.compare(41, remote, &local, ComparisonMode::BranchChanges, &[])
|
||||
.unwrap();
|
||||
assert_eq!(reverse.files.len(), 1);
|
||||
assert_eq!(reverse.files[0].path, Path::new("local-only"));
|
||||
assert_eq!(repository.load_file(41, 0).unwrap().after, ["local"]);
|
||||
assert!(
|
||||
repository
|
||||
.compare(42, &local, &local, ComparisonMode::BranchChanges, &[])
|
||||
.unwrap()
|
||||
.files
|
||||
.is_empty()
|
||||
);
|
||||
assert_eq!(disk_state(&active), state);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_changes_rejects_missing_and_multiple_merge_bases_without_snapshot_fallback() {
|
||||
let fixture = Fixture::new();
|
||||
let root = fixture.dir("graphs");
|
||||
init_git(&root);
|
||||
fs::write(root.join("file"), "base\n").unwrap();
|
||||
git(&root, &["add", "."]);
|
||||
git(&root, &["commit", "-m", "base"]);
|
||||
let base = git(&root, &["rev-parse", "HEAD"]);
|
||||
let tree = git(&root, &["rev-parse", "HEAD^{tree}"]);
|
||||
let left = git(&root, &["commit-tree", &tree, "-p", &base, "-m", "left"]);
|
||||
let right = git(&root, &["commit-tree", &tree, "-p", &base, "-m", "right"]);
|
||||
let one = git(
|
||||
&root,
|
||||
&["commit-tree", &tree, "-p", &left, "-p", &right, "-m", "one"],
|
||||
);
|
||||
let two = git(
|
||||
&root,
|
||||
&["commit-tree", &tree, "-p", &right, "-p", &left, "-m", "two"],
|
||||
);
|
||||
let unrelated = git(&root, &["commit-tree", &tree, "-m", "unrelated"]);
|
||||
let state = disk_state(&root);
|
||||
let mut repository = open(&root);
|
||||
for (before, after, message) in [
|
||||
(&base, &unrelated, "no merge base"),
|
||||
(&one, &two, "multiple merge bases"),
|
||||
] {
|
||||
let before = revision(before, RepoKind::Git);
|
||||
let after = revision(after, RepoKind::Git);
|
||||
assert!(
|
||||
repository
|
||||
.compare(50, &before, &after, ComparisonMode::BranchChanges, &[])
|
||||
.unwrap_err()
|
||||
.contains(message)
|
||||
);
|
||||
assert!(
|
||||
repository
|
||||
.compare(51, &before, &after, ComparisonMode::Snapshots, &[])
|
||||
.unwrap()
|
||||
.files
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
assert_eq!(disk_state(&root), state);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user