Skip to content

Commit 3082396

Browse files
authored
Support choosing checkout branch method when status is not empty (#2494)
1 parent 0cce690 commit 3082396

File tree

9 files changed

+382
-32
lines changed

9 files changed

+382
-32
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
* increase MSRV from 1.81 to 1.82 [[@cruessler](https://github.com/cruessler)]
1111

1212
### Added
13+
* support choosing checkout branch method when status is not empty [[@fatpandac](https://github.com/fatpandac)] ([#2404](https://github.com/extrawurst/gitui/issues/2404))
1314
* Support pre-push hook [[@xlai89](https://github.com/xlai89)] ([#1933](https://github.com/extrawurst/gitui/issues/1933))
1415
* Message tab supports pageUp and pageDown [[@xlai89](https://github.com/xlai89)] ([#2623](https://github.com/extrawurst/gitui/issues/2623))
1516
* Files and status tab support pageUp and pageDown [[@fatpandac](https://github.com/fatpandac)] ([#1951](https://github.com/extrawurst/gitui/issues/1951))

asyncgit/src/sync/branch/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ impl BranchInfo {
104104

105105
None
106106
}
107+
108+
/// returns whether branch is local
109+
pub const fn is_local(&self) -> bool {
110+
matches!(self.details, BranchDetails::Local(_))
111+
}
107112
}
108113

109114
///

asyncgit/src/sync/status.rs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,20 +281,59 @@ pub fn get_status(
281281
Ok(res)
282282
}
283283

284-
#[cfg(test)]
285-
mod tests {
286-
use std::{fs::File, io::Write, path::Path};
284+
/// discard all changes in the working directory
285+
pub fn discard_status(repo_path: &RepoPath) -> Result<bool> {
286+
let repo = repo(repo_path)?;
287+
let commit = repo.head()?.peel_to_commit()?;
287288

288-
use tempfile::TempDir;
289+
repo.reset(commit.as_object(), git2::ResetType::Hard, None)?;
289290

291+
Ok(true)
292+
}
293+
294+
#[cfg(test)]
295+
mod tests {
296+
use super::*;
290297
use crate::{
291298
sync::{
299+
commit, stage_add_file,
292300
status::{get_status, StatusType},
293-
tests::repo_init_bare,
301+
tests::{repo_init, repo_init_bare},
294302
RepoPath,
295303
},
296304
StatusItem, StatusItemType,
297305
};
306+
use std::{fs::File, io::Write, path::Path};
307+
use tempfile::TempDir;
308+
309+
#[test]
310+
fn test_discard_status() {
311+
let file_path = Path::new("README.md");
312+
let (_td, repo) = repo_init().unwrap();
313+
let root = repo.path().parent().unwrap();
314+
let repo_path: &RepoPath =
315+
&root.as_os_str().to_str().unwrap().into();
316+
317+
let mut file = File::create(root.join(file_path)).unwrap();
318+
319+
// initial commit
320+
stage_add_file(repo_path, file_path).unwrap();
321+
commit(repo_path, "commit msg").unwrap();
322+
323+
writeln!(file, "Test for discard_status").unwrap();
324+
325+
let statuses =
326+
get_status(repo_path, StatusType::WorkingDir, None)
327+
.unwrap();
328+
assert_eq!(statuses.len(), 1);
329+
330+
discard_status(repo_path).unwrap();
331+
332+
let statuses =
333+
get_status(repo_path, StatusType::WorkingDir, None)
334+
.unwrap();
335+
assert_eq!(statuses.len(), 0);
336+
}
298337

299338
#[test]
300339
fn test_get_status_with_workdir() {

src/app.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ use crate::{
1111
options::{Options, SharedOptions},
1212
popup_stack::PopupStack,
1313
popups::{
14-
AppOption, BlameFilePopup, BranchListPopup, CommitPopup,
15-
CompareCommitsPopup, ConfirmPopup, CreateBranchPopup,
16-
CreateRemotePopup, ExternalEditorPopup, FetchPopup,
17-
FileRevlogPopup, FuzzyFindPopup, GotoLinePopup, HelpPopup,
18-
InspectCommitPopup, LogSearchPopupPopup, MsgPopup,
19-
OptionsPopup, PullPopup, PushPopup, PushTagsPopup,
20-
RemoteListPopup, RenameBranchPopup, RenameRemotePopup,
21-
ResetPopup, RevisionFilesPopup, StashMsgPopup,
22-
SubmodulesListPopup, TagCommitPopup, TagListPopup,
23-
UpdateRemoteUrlPopup,
14+
AppOption, BlameFilePopup, BranchListPopup,
15+
CheckoutOptionPopup, CommitPopup, CompareCommitsPopup,
16+
ConfirmPopup, CreateBranchPopup, CreateRemotePopup,
17+
ExternalEditorPopup, FetchPopup, FileRevlogPopup,
18+
FuzzyFindPopup, GotoLinePopup, HelpPopup, InspectCommitPopup,
19+
LogSearchPopupPopup, MsgPopup, OptionsPopup, PullPopup,
20+
PushPopup, PushTagsPopup, RemoteListPopup, RenameBranchPopup,
21+
RenameRemotePopup, ResetPopup, RevisionFilesPopup,
22+
StashMsgPopup, SubmodulesListPopup, TagCommitPopup,
23+
TagListPopup, UpdateRemoteUrlPopup,
2424
},
2525
queue::{
2626
Action, AppTabs, InternalEvent, NeedsUpdate, Queue,
@@ -99,6 +99,7 @@ pub struct App {
9999
submodule_popup: SubmodulesListPopup,
100100
tags_popup: TagListPopup,
101101
reset_popup: ResetPopup,
102+
checkout_option_popup: CheckoutOptionPopup,
102103
cmdbar: RefCell<CommandBar>,
103104
tab: usize,
104105
revlog: Revlog,
@@ -234,6 +235,7 @@ impl App {
234235
stashing_tab: Stashing::new(&env),
235236
stashlist_tab: StashList::new(&env),
236237
files_tab: FilesTab::new(&env, select_file),
238+
checkout_option_popup: CheckoutOptionPopup::new(&env),
237239
goto_line_popup: GotoLinePopup::new(&env),
238240
tab: 0,
239241
queue: env.queue,
@@ -511,6 +513,7 @@ impl App {
511513
fetch_popup,
512514
tag_commit_popup,
513515
reset_popup,
516+
checkout_option_popup,
514517
create_branch_popup,
515518
create_remote_popup,
516519
rename_remote_popup,
@@ -551,6 +554,7 @@ impl App {
551554
submodule_popup,
552555
tags_popup,
553556
reset_popup,
557+
checkout_option_popup,
554558
create_branch_popup,
555559
rename_branch_popup,
556560
revision_files_popup,
@@ -932,6 +936,9 @@ impl App {
932936
self.blame_file_popup.goto_line(line);
933937
}
934938
}
939+
InternalEvent::CheckoutOption(branch) => {
940+
self.checkout_option_popup.open(branch)?;
941+
}
935942
}
936943

937944
Ok(flags)

src/popups/branchlist.rs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ use asyncgit::{
2020
checkout_remote_branch, BranchDetails, LocalBranch,
2121
RemoteBranch,
2222
},
23-
checkout_branch, get_branches_info, BranchInfo, BranchType,
24-
CommitId, RepoPathRef, RepoState,
23+
checkout_branch, get_branches_info,
24+
status::StatusType,
25+
BranchInfo, BranchType, CommitId, RepoPathRef, RepoState,
2526
},
2627
AsyncGitNotification,
2728
};
@@ -582,23 +583,36 @@ impl BranchListPopup {
582583
anyhow::bail!("no valid branch selected");
583584
}
584585

585-
if self.local {
586-
checkout_branch(
587-
&self.repo.borrow(),
588-
&self.branches[self.selection as usize].name,
589-
)?;
590-
self.hide();
586+
let status = sync::status::get_status(
587+
&self.repo.borrow(),
588+
StatusType::WorkingDir,
589+
None,
590+
)
591+
.expect("Could not get status");
592+
593+
let selected_branch = &self.branches[self.selection as usize];
594+
if status.is_empty() {
595+
if self.local {
596+
checkout_branch(
597+
&self.repo.borrow(),
598+
&selected_branch.name,
599+
)?;
600+
self.hide();
601+
} else {
602+
checkout_remote_branch(
603+
&self.repo.borrow(),
604+
selected_branch,
605+
)?;
606+
self.local = true;
607+
self.update_branches()?;
608+
}
609+
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
591610
} else {
592-
checkout_remote_branch(
593-
&self.repo.borrow(),
594-
&self.branches[self.selection as usize],
595-
)?;
596-
self.local = true;
597-
self.update_branches()?;
611+
self.queue.push(InternalEvent::CheckoutOption(
612+
selected_branch.clone(),
613+
));
598614
}
599615

600-
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
601-
602616
Ok(())
603617
}
604618

0 commit comments

Comments
 (0)