mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-27 23:06:45 +00:00
revset: for short hash, look up both commit and change ids to disambiguate
Because the use of the change id is recommended, any operation should abort if a valid change id happens to match a commit id. We still try the commit id lookup first as the change id lookup is more costly. Ambiguous change/commit id is reported as AmbiguousCommitIdPrefix for now. Maybe we can merge AmbiguousCommit/ChangeIdPrefix errors into one? Closes #799
This commit is contained in:
parent
1fa0392a3e
commit
c5ed3e1477
3 changed files with 52 additions and 22 deletions
|
@ -46,8 +46,7 @@ Jujutsu attempts to resolve a symbol in the following order:
|
||||||
3. Tag name
|
3. Tag name
|
||||||
4. Branch name
|
4. Branch name
|
||||||
5. Git ref
|
5. Git ref
|
||||||
6. Commit ID
|
6. Commit ID or change ID
|
||||||
7. Change ID
|
|
||||||
|
|
||||||
|
|
||||||
## Operators
|
## Operators
|
||||||
|
|
|
@ -83,30 +83,37 @@ fn resolve_branch(repo: RepoRef, symbol: &str) -> Option<Vec<CommitId>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_commit_id(repo: RepoRef, symbol: &str) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
fn resolve_full_commit_id(
|
||||||
// First check if it's a full commit id.
|
repo: RepoRef,
|
||||||
|
symbol: &str,
|
||||||
|
) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
||||||
if let Ok(binary_commit_id) = hex::decode(symbol) {
|
if let Ok(binary_commit_id) = hex::decode(symbol) {
|
||||||
let commit_id = CommitId::new(binary_commit_id);
|
let commit_id = CommitId::new(binary_commit_id);
|
||||||
match repo.store().get_commit(&commit_id) {
|
match repo.store().get_commit(&commit_id) {
|
||||||
Ok(_) => return Ok(Some(vec![commit_id])),
|
Ok(_) => Ok(Some(vec![commit_id])),
|
||||||
Err(BackendError::NotFound) => {} // fall through
|
Err(BackendError::NotFound) => Ok(None),
|
||||||
Err(err) => return Err(RevsetError::StoreError(err)),
|
Err(err) => Err(RevsetError::StoreError(err)),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_short_commit_id(
|
||||||
|
repo: RepoRef,
|
||||||
|
symbol: &str,
|
||||||
|
) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
||||||
if let Some(prefix) = HexPrefix::new(symbol.to_owned()) {
|
if let Some(prefix) = HexPrefix::new(symbol.to_owned()) {
|
||||||
match repo.index().resolve_prefix(&prefix) {
|
match repo.index().resolve_prefix(&prefix) {
|
||||||
PrefixResolution::NoMatch => {
|
PrefixResolution::NoMatch => Ok(None),
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
PrefixResolution::AmbiguousMatch => {
|
PrefixResolution::AmbiguousMatch => {
|
||||||
return Err(RevsetError::AmbiguousCommitIdPrefix(symbol.to_owned()));
|
Err(RevsetError::AmbiguousCommitIdPrefix(symbol.to_owned()))
|
||||||
}
|
}
|
||||||
PrefixResolution::SingleMatch(commit_id) => return Ok(Some(vec![commit_id])),
|
PrefixResolution::SingleMatch(commit_id) => Ok(Some(vec![commit_id])),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_change_id(
|
fn resolve_change_id(
|
||||||
|
@ -177,17 +184,24 @@ pub fn resolve_symbol(
|
||||||
return Ok(ids);
|
return Ok(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to resolve as a commit id.
|
// Try to resolve as a full commit id. We assume a full commit id is unambiguous
|
||||||
if let Some(ids) = resolve_commit_id(repo, symbol)? {
|
// even if it's shorter than change id.
|
||||||
|
if let Some(ids) = resolve_full_commit_id(repo, symbol)? {
|
||||||
return Ok(ids);
|
return Ok(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to resolve as a change id.
|
// Try to resolve as a commit/change id.
|
||||||
if let Some(ids) = resolve_change_id(repo, symbol)? {
|
match (
|
||||||
return Ok(ids);
|
resolve_short_commit_id(repo, symbol)?,
|
||||||
|
resolve_change_id(repo, symbol)?,
|
||||||
|
) {
|
||||||
|
// Likely a root_commit_id, but not limited to it.
|
||||||
|
(Some(ids1), Some(ids2)) if ids1 == ids2 => Ok(ids1),
|
||||||
|
// TODO: maybe unify Ambiguous*IdPrefix error variants?
|
||||||
|
(Some(_), Some(_)) => Err(RevsetError::AmbiguousCommitIdPrefix(symbol.to_owned())),
|
||||||
|
(Some(ids), None) | (None, Some(ids)) => Ok(ids),
|
||||||
|
(None, None) => Err(RevsetError::NoSuchRevision(symbol.to_owned())),
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(RevsetError::NoSuchRevision(symbol.to_owned()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ fn test_resolve_symbol_change_id() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let git_tree = git_repo.find_tree(empty_tree_id).unwrap();
|
let git_tree = git_repo.find_tree(empty_tree_id).unwrap();
|
||||||
let mut git_commit_ids = vec![];
|
let mut git_commit_ids = vec![];
|
||||||
for i in &[133, 664, 840] {
|
for i in &[133, 664, 840, 5085] {
|
||||||
let git_commit_id = git_repo
|
let git_commit_id = git_repo
|
||||||
.commit(
|
.commit(
|
||||||
Some(&format!("refs/heads/branch{}", i)),
|
Some(&format!("refs/heads/branch{}", i)),
|
||||||
|
@ -205,6 +205,11 @@ fn test_resolve_symbol_change_id() {
|
||||||
// "04e1c7082e4e34f3f371d8a1a46770b861b9b547" reversed
|
// "04e1c7082e4e34f3f371d8a1a46770b861b9b547" reversed
|
||||||
"e2ad9d861d0ee625851b8ecfcf2c727410e38720"
|
"e2ad9d861d0ee625851b8ecfcf2c727410e38720"
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
hex::encode(git_commit_ids[3]),
|
||||||
|
// "911d7e52fd5ba04b8f289e14c3d30b52d38c0020" reversed
|
||||||
|
"040031cb4ad0cbc3287914f1d205dabf4a7eb889"
|
||||||
|
);
|
||||||
|
|
||||||
// Test lookup by full change id
|
// Test lookup by full change id
|
||||||
let repo_ref = repo.as_repo_ref();
|
let repo_ref = repo.as_repo_ref();
|
||||||
|
@ -254,6 +259,18 @@ fn test_resolve_symbol_change_id() {
|
||||||
Err(RevsetError::NoSuchRevision("04e13".to_string()))
|
Err(RevsetError::NoSuchRevision("04e13".to_string()))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Test commit/changed id conflicts.
|
||||||
|
assert_eq!(
|
||||||
|
resolve_symbol(repo_ref, "040b", None),
|
||||||
|
Ok(vec![CommitId::from_hex(
|
||||||
|
"5339432b8e7b90bd3aa1a323db71b8a5c5dcd020"
|
||||||
|
)])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
resolve_symbol(repo_ref, "040", None),
|
||||||
|
Err(RevsetError::AmbiguousCommitIdPrefix("040".to_string()))
|
||||||
|
);
|
||||||
|
|
||||||
// Test non-hex string
|
// Test non-hex string
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_symbol(repo_ref, "foo", None),
|
resolve_symbol(repo_ref, "foo", None),
|
||||||
|
|
Loading…
Reference in a new issue