Skip to content

Commit 2e8db47

Browse files
committed
feat: checkout branch/revision with picker
The checkout action shows an interactive picker to select a branch to checkout using fuzzy matching. Checking out a custom revision not found in the branch list, e.g. a commit hash, is also possible. If the checkout is started from a previously selected revision, e.g. by selecting one in Show Refs or from the recent commits section, the revision is put at the top, allowing users to continue by just hitting <enter> like before.
1 parent 329a7c1 commit 2e8db47

File tree

7 files changed

+92
-23
lines changed

7 files changed

+92
-23
lines changed

src/item_data.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ impl ItemData {
5959
| ItemData::BranchStatus(_, _, _)
6060
)
6161
}
62+
63+
pub(crate) fn to_ref_kind(&self) -> Option<RefKind> {
64+
match self {
65+
Self::Reference { kind, .. } => Some(kind.clone()),
66+
_ => None,
67+
}
68+
}
6269
}
6370

6471
impl Default for ItemData {

src/ops/branch.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Action, OpTrait, selected_rev};
1+
use super::{Action, OpTrait};
22
use crate::{
33
Res,
44
app::{App, PromptParams, State},
@@ -9,6 +9,7 @@ use crate::{
99
},
1010
item_data::{ItemData, RefKind},
1111
menu::arg::Arg,
12+
picker::{BranchesAndTagsOptions, PickerState},
1213
term::Term,
1314
};
1415
use std::{process::Command, rc::Rc};
@@ -19,19 +20,24 @@ pub(crate) fn init_args() -> Vec<Arg> {
1920

2021
pub(crate) struct Checkout;
2122
impl OpTrait for Checkout {
22-
fn get_action(&self, _target: &ItemData) -> Option<Action> {
23+
fn get_action(&self, target: &ItemData) -> Option<Action> {
24+
let default_ref = target.to_ref_kind();
25+
2326
Some(Rc::new(move |app: &mut App, term: &mut Term| {
24-
let rev = app.prompt(
25-
term,
26-
&PromptParams {
27-
prompt: "Checkout",
28-
create_default_value: Box::new(selected_rev),
29-
..Default::default()
27+
// Allow custom input to support checking out other revisions not in the list
28+
let picker = PickerState::for_branches_and_tags(
29+
"Checkout",
30+
&app.state.repo,
31+
BranchesAndTagsOptions {
32+
exclude_head: true,
33+
allow_custom_input: true,
34+
default: default_ref.clone(),
3035
},
3136
)?;
32-
33-
checkout(app, term, &rev)?;
34-
Ok(())
37+
match app.picker(term, picker)? {
38+
Some(data) => checkout(app, term, data.display()),
39+
None => Ok(()), // picker got cancelled
40+
}
3541
}))
3642
}
3743

src/ops/merge.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,7 @@ pub(crate) struct Merge;
6868
impl OpTrait for Merge {
6969
fn get_action(&self, target: &ItemData) -> Option<Action> {
7070
// Extract default ref from target if it's a Reference
71-
let default_ref = if let ItemData::Reference { kind, .. } = target {
72-
Some(kind.clone())
73-
} else {
74-
None
75-
};
71+
let default_ref = target.to_ref_kind();
7672

7773
Some(Rc::new(move |app: &mut App, term: &mut Term| {
7874
// Allow custom input to support commit hashes, relative refs (e.g., HEAD~3),

src/tests/branch.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ fn switch_branch_input() {
2323
snapshot!(setup(setup_clone!()), "Ybbmerged<enter>");
2424
}
2525

26+
#[test]
27+
fn switch_branch_picker() {
28+
snapshot!(setup(setup_clone!()), "bb");
29+
}
30+
31+
#[test]
32+
fn switch_branch_selected_revision_picker() {
33+
snapshot!(setup(setup_clone!()), "Yjjbb");
34+
}
35+
2636
#[test]
2737
fn checkout_new_branch() {
2838
snapshot!(setup(setup_clone!()), "bcnew<enter>");
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
source: src/tests/branch.rs
3+
expression: ctx.redact_buffer()
4+
---
5+
On branch main |
6+
Your branch is up to date with 'origin/main'. |
7+
|
8+
Recent commits |
9+
b66a0bf main merged origin/main add initial-file |
10+
|
11+
|
12+
|
13+
────────────────────────────────────────────────────────────────────────────────|
14+
4/4 Checkout › █ |
15+
merged |
16+
unmerged |
17+
origin/HEAD |
18+
origin/main |
19+
|
20+
|
21+
|
22+
|
23+
|
24+
|
25+
styles_hash: a64f5b0f5c87b3e5
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
source: src/tests/branch.rs
3+
expression: ctx.redact_buffer()
4+
---
5+
Branches |
6+
* main |
7+
merged |
8+
unmerged |
9+
|
10+
Remote origin |
11+
origin/HEAD |
12+
origin/main |
13+
────────────────────────────────────────────────────────────────────────────────|
14+
4/4 Checkout › █ |
15+
merged |
16+
unmerged |
17+
origin/HEAD |
18+
origin/main |
19+
|
20+
|
21+
|
22+
|
23+
|
24+
|
25+
styles_hash: 2cac6f3d25b0271c

src/tests/snapshots/gitu__tests__editor__re_enter_prompt_from_menu.snap

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
source: src/tests/editor.rs
33
expression: ctx.redact_buffer()
44
---
5-
On branch main |
6-
Your branch is up to date with 'origin/main'. |
5+
On branch main |
6+
Your branch is up to date with 'origin/main'. |
77
|
88
Recent commits |
99
b66a0bf main origin/main add initial-file |
1010
|
1111
|
1212
|
13+
────────────────────────────────────────────────────────────────────────────────|
14+
2/2 Checkout › █ |
15+
origin/HEAD |
16+
origin/main |
1317
|
1418
|
1519
|
@@ -18,8 +22,4 @@ expression: ctx.redact_buffer()
1822
|
1923
|
2024
|
21-
|
22-
|
23-
────────────────────────────────────────────────────────────────────────────────|
24-
? Checkout: › █ |
25-
styles_hash: 43da189f53b3be3d
25+
styles_hash: 49e995be810c0237

0 commit comments

Comments
 (0)