Infer the default hidden base for relative travel targets and exclude its boundary ancestry from navigation. This makes --to first select the oldest displayed commit above the base.
Unified · Split
| @@ -58,8 +58,10 @@ pub(super) fn run(repository: gix::Repository, args: Args) -> Result<()> { · 57 unmodified lines | |||
| 58 | let (selected, resolved_graph) = match (&args.revision, args.to) { | 58 | let (selected, resolved_graph) = match (&args.revision, args.to) { |
| 59 | (Some(revision), None) => super::resolve_commit(&repository, revision, "time-travel destination")?, | 59 | (Some(revision), None) => super::resolve_commit(&repository, revision, "time-travel destination")?, |
| 60 | (None, Some(to)) => { | 60 | (None, Some(to)) => { |
| 61 | let graph = crate::edit::loaded_view_graph(&repository)?; | 61 | let hidden = crate::history::available_hidden_revisions(&repository, &[], true)?.0; |
| 62 | let selected = relative_destination(&repository, &graph, head_id, to)?; | 62 | let hidden_tips = crate::history::snapshot(&repository, &[], &hidden, false)?.hidden_tips; |
| 63 | let graph = crate::edit::loaded_view_graph_with_hidden(&repository, &[], &hidden)?; | ||
| 64 | let selected = relative_destination(&repository, &graph, &hidden_tips, head_id, to)?; | ||
| 63 | (selected, Some(graph)) | 65 | (selected, Some(graph)) |
| 64 | } | 66 | } |
| 65 | _ => anyhow::bail!("exactly one time-travel destination is required"), | 67 | _ => anyhow::bail!("exactly one time-travel destination is required"), |
| @@ -131,10 +133,14 @@ pub(super) fn run(repository: gix::Repository, args: Args) -> Result<()> { · 65 unmodified lines | |||
| 131 | fn relative_destination( | 133 | fn relative_destination( |
| 132 | repository: &gix::Repository, | 134 | repository: &gix::Repository, |
| 133 | graph: &crate::history::HistoryGraph, | 135 | graph: &crate::history::HistoryGraph, |
| 136 | hidden_tips: &[gix::ObjectId], | ||
| 134 | head: gix::ObjectId, | 137 | head: gix::ObjectId, |
| 135 | to: To, | 138 | to: To, |
| 136 | ) -> Result<gix::ObjectId> { | 139 | ) -> Result<gix::ObjectId> { |
| 137 | let order = graph.stored_commit_ids().collect::<Vec<_>>(); | 140 | let order = graph |
| 141 | .stored_commit_ids() | ||
| 142 | .filter(|id| !hidden_tips.iter().any(|hidden| graph.is_ancestor(*id, *hidden))) | ||
| 143 | .collect::<Vec<_>>(); | ||
| 138 | let stored = order.iter().copied().collect::<HashSet<_>>(); | 144 | let stored = order.iter().copied().collect::<HashSet<_>>(); |
| 139 | if !stored.contains(&head) { | 145 | if !stored.contains(&head) { |
| 140 | anyhow::bail!("HEAD is not present in the default Tix view"); | 146 | anyhow::bail!("HEAD is not present in the default Tix view"); |
| @@ -487,6 +493,35 @@ mod tests { · 346 unmodified lines | |||
| 487 | Ok(()) | 493 | Ok(()) |
| 488 | } | 494 | } |
| 489 | 495 | ||
| 496 | #[test] | ||
| 497 | fn first_stops_above_the_inferred_hidden_base() -> gix_testtools::Result { | ||
| 498 | let fixture = gix_testtools::scripted_fixture_writable("rebase_edit.sh")?; | ||
| 499 | let path = fixture.path(); | ||
| 500 | git(path, &["config", "remote.origin.url", "."])?; | ||
| 501 | git( | ||
| 502 | path, | ||
| 503 | &["config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*"], | ||
| 504 | )?; | ||
| 505 | git(path, &["update-ref", "refs/remotes/origin/main", "main"])?; | ||
| 506 | git( | ||
| 507 | path, | ||
| 508 | &["symbolic-ref", "refs/remotes/origin/HEAD", "refs/remotes/origin/main"], | ||
| 509 | )?; | ||
| 510 | git(path, &["checkout", "-q", "-b", "topic"])?; | ||
| 511 | git(path, &["commit", "-q", "--allow-empty", "-m", "first topic commit"])?; | ||
| 512 | let first = crate::test_repository::open(path)?.head_id()?.detach(); | ||
| 513 | git(path, &["commit", "-q", "--allow-empty", "-m", "topic tip"])?; | ||
| 514 | |||
| 515 | run(crate::test_repository::open(path)?, relative_args(To::First))?; | ||
| 516 | |||
| 517 | assert_eq!( | ||
| 518 | crate::test_repository::open(path)?.head_id()?.detach(), | ||
| 519 | first, | ||
| 520 | "first selects the oldest commit displayed above the inferred base" | ||
| 521 | ); | ||
| 522 | Ok(()) | ||
| 523 | } | ||
| 524 | |||
| 490 | #[test] | 525 | #[test] |
| 491 | fn relative_target_ambiguity_lists_every_candidate() -> gix_testtools::Result { | 526 | fn relative_target_ambiguity_lists_every_candidate() -> gix_testtools::Result { |
| 492 | let fixture = gix_testtools::scripted_fixture_writable("rebase_edit.sh")?; | 527 | let fixture = gix_testtools::scripted_fixture_writable("rebase_edit.sh")?; |