forked from mirrors/jj
working_copy: make reset() take a commit instead of a tree
Our virtual file system at Google (CitC) would like to know the commit so it can scan backwards and find the closest mainline tree based on it. Since we always record an operation id (which resolves to a working-copy commit) when we write the working-copy state, it doesn't seem like a restriction to require a commit.
This commit is contained in:
parent
9feffa54c8
commit
b343289238
6 changed files with 23 additions and 22 deletions
|
@ -23,7 +23,6 @@ use jj_lib::backend::{Backend, MergedTreeId};
|
|||
use jj_lib::commit::Commit;
|
||||
use jj_lib::git_backend::GitBackend;
|
||||
use jj_lib::local_working_copy::LocalWorkingCopy;
|
||||
use jj_lib::merged_tree::MergedTree;
|
||||
use jj_lib::op_store::{OperationId, WorkspaceId};
|
||||
use jj_lib::repo::ReadonlyRepo;
|
||||
use jj_lib::repo_path::RepoPathBuf;
|
||||
|
@ -237,8 +236,8 @@ impl LockedWorkingCopy for LockedConflictsWorkingCopy {
|
|||
self.inner.check_out(commit)
|
||||
}
|
||||
|
||||
fn reset(&mut self, new_tree: &MergedTree) -> Result<(), ResetError> {
|
||||
self.inner.reset(new_tree)
|
||||
fn reset(&mut self, commit: &Commit) -> Result<(), ResetError> {
|
||||
self.inner.reset(commit)
|
||||
}
|
||||
|
||||
fn sparse_patterns(&self) -> Result<&[RepoPathBuf], WorkingCopyStateError> {
|
||||
|
|
|
@ -925,8 +925,7 @@ impl WorkspaceCommandHelper {
|
|||
// The working copy was presumably updated by the git command that updated
|
||||
// HEAD, so we just need to reset our working copy
|
||||
// state to it without updating working copy files.
|
||||
let new_git_head_tree = new_git_head_commit.tree()?;
|
||||
locked_ws.locked_wc().reset(&new_git_head_tree)?;
|
||||
locked_ws.locked_wc().reset(&new_git_head_commit)?;
|
||||
tx.mut_repo().rebase_descendants(&self.settings)?;
|
||||
self.user_repo = ReadonlyUserRepo::new(tx.commit("import git head"));
|
||||
locked_ws.finish(self.user_repo.repo.op_id().clone())?;
|
||||
|
|
|
@ -55,9 +55,13 @@ pub(crate) fn cmd_untrack(
|
|||
tree_builder.set_or_remove(path, Merge::absent());
|
||||
}
|
||||
let new_tree_id = tree_builder.write_tree(&store)?;
|
||||
let new_tree = store.get_root_tree(&new_tree_id)?;
|
||||
// Reset the working copy to the new tree
|
||||
locked_ws.locked_wc().reset(&new_tree)?;
|
||||
let new_commit = tx
|
||||
.mut_repo()
|
||||
.rewrite_commit(command.settings(), &wc_commit)
|
||||
.set_tree_id(new_tree_id)
|
||||
.write()?;
|
||||
// Reset the working copy to the new commit
|
||||
locked_ws.locked_wc().reset(&new_commit)?;
|
||||
// Commit the working copy again so we can inform the user if paths couldn't be
|
||||
// untracked because they're not ignored.
|
||||
let wc_tree_id = locked_ws.locked_wc().snapshot(SnapshotOptions {
|
||||
|
@ -66,7 +70,7 @@ pub(crate) fn cmd_untrack(
|
|||
progress: None,
|
||||
max_new_file_size: command.settings().max_new_file_size()?,
|
||||
})?;
|
||||
if wc_tree_id != new_tree_id {
|
||||
if wc_tree_id != *new_commit.tree_id() {
|
||||
let wc_tree = store.get_root_tree(&wc_tree_id)?;
|
||||
let added_back = wc_tree.entries_matching(matcher.as_ref()).collect_vec();
|
||||
if !added_back.is_empty() {
|
||||
|
@ -90,13 +94,9 @@ Make sure they're ignored, then try again.",
|
|||
} else {
|
||||
// This means there were some concurrent changes made in the working copy. We
|
||||
// don't want to mix those in, so reset the working copy again.
|
||||
locked_ws.locked_wc().reset(&new_tree)?;
|
||||
locked_ws.locked_wc().reset(&new_commit)?;
|
||||
}
|
||||
}
|
||||
tx.mut_repo()
|
||||
.rewrite_commit(command.settings(), &wc_commit)
|
||||
.set_tree_id(new_tree_id)
|
||||
.write()?;
|
||||
let num_rebased = tx.mut_repo().rebase_descendants(command.settings())?;
|
||||
if num_rebased > 0 {
|
||||
writeln!(ui.stderr(), "Rebased {num_rebased} descendant commits")?;
|
||||
|
|
|
@ -1739,14 +1739,15 @@ impl LockedWorkingCopy for LockedLocalWorkingCopy {
|
|||
Ok(stats)
|
||||
}
|
||||
|
||||
fn reset(&mut self, new_tree: &MergedTree) -> Result<(), ResetError> {
|
||||
fn reset(&mut self, commit: &Commit) -> Result<(), ResetError> {
|
||||
let new_tree = commit.tree()?;
|
||||
self.wc
|
||||
.tree_state_mut()
|
||||
.map_err(|err| ResetError::Other {
|
||||
message: "Failed to read the working copy state".to_string(),
|
||||
err: err.into(),
|
||||
})?
|
||||
.reset(new_tree)
|
||||
.reset(&new_tree)
|
||||
.block_on()?;
|
||||
self.tree_state_dirty = true;
|
||||
Ok(())
|
||||
|
|
|
@ -26,7 +26,6 @@ use crate::backend::{BackendError, MergedTreeId};
|
|||
use crate::commit::Commit;
|
||||
use crate::fsmonitor::FsmonitorKind;
|
||||
use crate::gitignore::GitIgnoreFile;
|
||||
use crate::merged_tree::MergedTree;
|
||||
use crate::op_store::{OperationId, WorkspaceId};
|
||||
use crate::repo_path::{RepoPath, RepoPathBuf};
|
||||
use crate::settings::HumanByteSize;
|
||||
|
@ -105,8 +104,8 @@ pub trait LockedWorkingCopy {
|
|||
/// Check out the specified commit in the working copy.
|
||||
fn check_out(&mut self, commit: &Commit) -> Result<CheckoutStats, CheckoutError>;
|
||||
|
||||
/// Update to another tree without touching the files in the working copy.
|
||||
fn reset(&mut self, new_tree: &MergedTree) -> Result<(), ResetError>;
|
||||
/// Update to another commit without touching the files in the working copy.
|
||||
fn reset(&mut self, commit: &Commit) -> Result<(), ResetError>;
|
||||
|
||||
/// See `WorkingCopy::sparse_patterns()`
|
||||
fn sparse_patterns(&self) -> Result<&[RepoPathBuf], WorkingCopyStateError>;
|
||||
|
|
|
@ -414,10 +414,12 @@ fn test_reset() {
|
|||
let gitignore_path = RepoPath::from_internal_string(".gitignore");
|
||||
|
||||
let tree_without_file = create_tree(repo, &[(gitignore_path, "ignored\n")]);
|
||||
let commit_without_file = commit_with_tree(repo.store(), tree_without_file.id().clone());
|
||||
let tree_with_file = create_tree(
|
||||
repo,
|
||||
&[(gitignore_path, "ignored\n"), (ignored_path, "code")],
|
||||
);
|
||||
let commit_with_file = commit_with_tree(repo.store(), tree_with_file.id().clone());
|
||||
|
||||
let ws = &mut test_workspace.workspace;
|
||||
let commit = commit_with_tree(repo.store(), tree_with_file.id());
|
||||
|
@ -432,7 +434,7 @@ fn test_reset() {
|
|||
// but it should not be in the tree state, and it should not get added when we
|
||||
// commit the working copy (because it's ignored).
|
||||
let mut locked_ws = ws.start_working_copy_mutation().unwrap();
|
||||
locked_ws.locked_wc().reset(&tree_without_file).unwrap();
|
||||
locked_ws.locked_wc().reset(&commit_without_file).unwrap();
|
||||
locked_ws.finish(op_id.clone()).unwrap();
|
||||
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
|
@ -444,7 +446,7 @@ fn test_reset() {
|
|||
// tracked. The file should become tracked (even though it's ignored).
|
||||
let ws = &mut test_workspace.workspace;
|
||||
let mut locked_ws = ws.start_working_copy_mutation().unwrap();
|
||||
locked_ws.locked_wc().reset(&tree_with_file).unwrap();
|
||||
locked_ws.locked_wc().reset(&commit_with_file).unwrap();
|
||||
locked_ws.finish(op_id.clone()).unwrap();
|
||||
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
|
@ -694,11 +696,12 @@ fn test_gitignores_in_ignored_dir() {
|
|||
(nested_gitignore_path, "!file\n"),
|
||||
],
|
||||
);
|
||||
let commit2 = commit_with_tree(test_workspace.repo.store(), tree2.id().clone());
|
||||
let mut locked_ws = test_workspace
|
||||
.workspace
|
||||
.start_working_copy_mutation()
|
||||
.unwrap();
|
||||
locked_ws.locked_wc().reset(&tree2).unwrap();
|
||||
locked_ws.locked_wc().reset(&commit2).unwrap();
|
||||
locked_ws.finish(OperationId::from_hex("abc123")).unwrap();
|
||||
|
||||
let new_tree = test_workspace.snapshot().unwrap();
|
||||
|
|
Loading…
Reference in a new issue