diff --git a/lib/src/git.rs b/lib/src/git.rs index eaae33eed..a9fd2deff 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -26,7 +26,7 @@ use thiserror::Error; use crate::backend::{CommitId, ObjectId}; use crate::git_backend::NO_GC_REF_NAMESPACE; -use crate::op_store::{BranchTarget, RefTarget}; +use crate::op_store::{BranchTarget, RefTarget, RefTargetExt as _}; use crate::repo::{MutableRepo, Repo}; use crate::revset; use crate::settings::GitSettings; @@ -85,7 +85,7 @@ fn resolve_git_ref_to_commit_id( known_target: Option<&RefTarget>, ) -> Option { // Try fast path if we have a candidate id which is known to be a commit object. - if let Some(RefTarget::Normal(id)) = known_target { + if let Some(id) = known_target.as_normal() { if matches!(git_ref.target(), Some(oid) if oid.as_bytes() == id.as_bytes()) { return Some(id.clone()); } @@ -199,7 +199,7 @@ pub fn import_some_refs( let head_ref_name = RefName::GitRef("HEAD".to_owned()); let head_commit_id = CommitId::from_bytes(head_git_commit.id().as_bytes()); pinned_git_heads.insert(head_ref_name, vec![head_commit_id.clone()]); - if !matches!(mut_repo.git_head(), Some(RefTarget::Normal(id)) if id == head_commit_id) { + if !matches!(mut_repo.git_head().as_normal(), Some(id) if id == &head_commit_id) { let head_commit = store.get_commit(&head_commit_id).unwrap(); prevent_gc(git_repo, &head_commit_id)?; mut_repo.add_head(&head_commit); @@ -409,28 +409,25 @@ pub fn export_some_refs( if new_branch == old_branch { continue; } - let old_oid = match old_branch { - None => None, - Some(RefTarget::Normal(id)) => Some(Oid::from_bytes(id.as_bytes()).unwrap()), - Some(RefTarget::Conflict { .. }) => { - // The old git ref should only be a conflict if there were concurrent import - // operations while the value changed. Don't overwrite these values. - failed_branches.push(jj_known_ref); - continue; - } - }; - if let Some(new_branch) = new_branch { - match new_branch { - RefTarget::Normal(id) => { - let new_oid = Oid::from_bytes(id.as_bytes()); - branches_to_update.insert(jj_known_ref, (old_oid, new_oid.unwrap())); - } - RefTarget::Conflict { .. } => { - // Skip conflicts and leave the old value in git_refs - continue; - } - } + let old_oid = if let Some(id) = old_branch.as_normal() { + Some(Oid::from_bytes(id.as_bytes()).unwrap()) + } else if old_branch.is_conflict() { + // The old git ref should only be a conflict if there were concurrent import + // operations while the value changed. Don't overwrite these values. + failed_branches.push(jj_known_ref); + continue; } else { + assert!(old_branch.is_absent()); + None + }; + if let Some(id) = new_branch.as_normal() { + let new_oid = Oid::from_bytes(id.as_bytes()); + branches_to_update.insert(jj_known_ref, (old_oid, new_oid.unwrap())); + } else if new_branch.is_conflict() { + // Skip conflicts and leave the old value in git_refs + continue; + } else { + assert!(new_branch.is_absent()); branches_to_delete.insert(jj_known_ref, old_oid.unwrap()); } } diff --git a/lib/src/op_store.rs b/lib/src/op_store.rs index b50246780..35e25f64c 100644 --- a/lib/src/op_store.rs +++ b/lib/src/op_store.rs @@ -197,6 +197,38 @@ pub trait RefTargetExt { fn adds(&self) -> &[CommitId]; } +impl RefTargetExt for Option { + fn as_normal(&self) -> Option<&CommitId> { + self.as_ref().and_then(|target| target.as_normal()) + } + + fn is_absent(&self) -> bool { + self.is_none() + } + + fn is_present(&self) -> bool { + self.is_some() + } + + fn is_conflict(&self) -> bool { + self.as_ref() + .map(|target| target.is_conflict()) + .unwrap_or(false) + } + + fn removes(&self) -> &[CommitId] { + self.as_ref() + .map(|target| target.removes()) + .unwrap_or_default() + } + + fn adds(&self) -> &[CommitId] { + self.as_ref() + .map(|target| target.adds()) + .unwrap_or_default() + } +} + impl RefTargetExt for Option<&RefTarget> { fn as_normal(&self) -> Option<&CommitId> { self.and_then(|target| target.as_normal()) diff --git a/src/cli_util.rs b/src/cli_util.rs index 7531f0838..5d415c22a 100644 --- a/src/cli_util.rs +++ b/src/cli_util.rs @@ -39,7 +39,9 @@ use jj_lib::hex_util::to_reverse_hex; use jj_lib::id_prefix::IdPrefixContext; use jj_lib::matchers::{EverythingMatcher, Matcher, PrefixMatcher, Visit}; use jj_lib::op_heads_store::{self, OpHeadResolutionError, OpHeadsStore}; -use jj_lib::op_store::{OpStore, OpStoreError, OperationId, RefTarget, WorkspaceId}; +use jj_lib::op_store::{ + OpStore, OpStoreError, OperationId, RefTarget, RefTargetExt as _, WorkspaceId, +}; use jj_lib::operation::Operation; use jj_lib::repo::{ CheckOutCommitError, EditCommitError, MutableRepo, ReadonlyRepo, Repo, RepoLoader, @@ -735,8 +737,8 @@ impl WorkspaceCommandHelper { let new_git_head = tx.mut_repo().view().git_head().cloned(); // If the Git HEAD has changed, abandon our old checkout and check out the new // Git HEAD. - match new_git_head { - Some(RefTarget::Normal(new_git_head_id)) if new_git_head != old_git_head => { + match new_git_head.as_normal() { + Some(new_git_head_id) if new_git_head != old_git_head => { let workspace_id = self.workspace_id().to_owned(); let op_id = self.repo().op_id().clone(); if let Some(old_wc_commit_id) = @@ -745,7 +747,7 @@ impl WorkspaceCommandHelper { tx.mut_repo() .record_abandoned_commit(old_wc_commit_id.clone()); } - let new_git_head_commit = tx.mut_repo().store().get_commit(&new_git_head_id)?; + let new_git_head_commit = tx.mut_repo().store().get_commit(new_git_head_id)?; tx.mut_repo() .check_out(workspace_id, &self.settings, &new_git_head_commit)?; let mut locked_working_copy = diff --git a/src/commands/branch.rs b/src/commands/branch.rs index 90ca280cd..647bb0daa 100644 --- a/src/commands/branch.rs +++ b/src/commands/branch.rs @@ -372,29 +372,26 @@ fn cmd_branch_list( let print_branch_target = |formatter: &mut dyn Formatter, target: &RefTarget| -> Result<(), CommandError> { - match target { - RefTarget::Normal(id) => { - write!(formatter, ": ")?; + if let Some(id) = target.as_normal() { + write!(formatter, ": ")?; + let commit = repo.store().get_commit(id)?; + workspace_command.write_commit_summary(formatter, &commit)?; + writeln!(formatter)?; + } else { + write!(formatter, " ")?; + write!(formatter.labeled("conflict"), "(conflicted)")?; + writeln!(formatter, ":")?; + for id in target.removes() { let commit = repo.store().get_commit(id)?; + write!(formatter, " - ")?; workspace_command.write_commit_summary(formatter, &commit)?; writeln!(formatter)?; } - RefTarget::Conflict { removes, adds } => { - write!(formatter, " ")?; - write!(formatter.labeled("conflict"), "(conflicted)")?; - writeln!(formatter, ":")?; - for id in removes { - let commit = repo.store().get_commit(id)?; - write!(formatter, " - ")?; - workspace_command.write_commit_summary(formatter, &commit)?; - writeln!(formatter)?; - } - for id in adds { - let commit = repo.store().get_commit(id)?; - write!(formatter, " + ")?; - workspace_command.write_commit_summary(formatter, &commit)?; - writeln!(formatter)?; - } + for id in target.adds() { + let commit = repo.store().get_commit(id)?; + write!(formatter, " + ")?; + workspace_command.write_commit_summary(formatter, &commit)?; + writeln!(formatter)?; } } Ok(()) diff --git a/src/commands/git.rs b/src/commands/git.rs index 8bcc8c062..a957fd985 100644 --- a/src/commands/git.rs +++ b/src/commands/git.rs @@ -12,7 +12,7 @@ use itertools::Itertools; use jj_lib::backend::{CommitId, ObjectId, TreeValue}; use jj_lib::git::{self, parse_gitmodules, GitFetchError, GitPushError, GitRefUpdate}; use jj_lib::git_backend::GitBackend; -use jj_lib::op_store::{BranchTarget, RefTarget}; +use jj_lib::op_store::{BranchTarget, RefTarget, RefTargetExt as _}; use jj_lib::refs::{classify_branch_push_action, BranchPushAction, BranchPushUpdate}; use jj_lib::repo::Repo; use jj_lib::repo_path::RepoPath; @@ -437,10 +437,10 @@ fn cmd_git_clone( .repo() .view() .get_remote_branch(&default_branch, "origin"); - if let Some(RefTarget::Normal(commit_id)) = default_branch_target { + if let Some(commit_id) = default_branch_target.as_normal() { let mut checkout_tx = workspace_command.start_transaction("check out git remote's default branch"); - if let Ok(commit) = checkout_tx.repo().store().get_commit(&commit_id) { + if let Ok(commit) = checkout_tx.repo().store().get_commit(commit_id) { checkout_tx.check_out(&commit)?; } checkout_tx.finish(ui)?; diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 2e5b091fa..821e797a6 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -37,7 +37,7 @@ use jj_lib::conflicts::Conflict; use jj_lib::dag_walk::topo_order_reverse; use jj_lib::git_backend::GitBackend; use jj_lib::matchers::EverythingMatcher; -use jj_lib::op_store::{RefTarget, WorkspaceId}; +use jj_lib::op_store::{RefTargetExt as _, WorkspaceId}; use jj_lib::repo::{ReadonlyRepo, Repo}; use jj_lib::repo_path::RepoPath; use jj_lib::revset::{ @@ -1100,7 +1100,7 @@ fn cmd_init(ui: &mut Ui, command: &CommandHelper, args: &InitArgs) -> Result<(), } else { let mut tx = workspace_command.start_transaction("import git refs"); jj_lib::git::import_refs(tx.mut_repo(), &git_repo, &command.settings().git_settings())?; - if let Some(RefTarget::Normal(git_head_id)) = tx.mut_repo().view().git_head().cloned() { + if let Some(git_head_id) = tx.mut_repo().view().git_head().as_normal().cloned() { let git_head_commit = tx.mut_repo().store().get_commit(&git_head_id)?; tx.check_out(&git_head_commit)?; }