Skip to content

merging a branch #696

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 9, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions asyncgit/src/sync/merge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use crate::{
error::{Error, Result},
sync::{reset_stage, reset_workdir, utils},
};
use git2::{BranchType, MergeOptions};
use scopetime::scope_time;

/// does these steps:
/// * reset all staged changes,
/// * revert all changes in workdir
/// * cleanup repo merge state
pub fn abort_merge(repo_path: &str) -> Result<()> {
scope_time!("cleanup_state");

let repo = utils::repo(repo_path)?;

reset_stage(repo_path, "*")?;
reset_workdir(repo_path, "*")?;

repo.cleanup_state()?;

Ok(())
}

///
pub fn merge_branch(repo_path: &str, branch: &str) -> Result<()> {
scope_time!("merge_branch");

let repo = utils::repo(repo_path)?;

let branch = repo.find_branch(branch, BranchType::Local)?;

let id = branch.into_reference().peel_to_commit()?;

let annotated = repo.find_annotated_commit(id.id())?;

let (analysis, _) = repo.merge_analysis(&[&annotated])?;

//TODO: support merge on unborn
if analysis.is_unborn() {
return Err(Error::Generic("head is unborn".into()));
}

let mut opt = MergeOptions::default();

repo.merge(&[&annotated], Some(&mut opt), None)?;

Ok(())
}
2 changes: 2 additions & 0 deletions asyncgit/src/sync/mod.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ mod hooks;
mod hunks;
mod ignore;
mod logwalker;
mod merge;
mod patches;
pub mod remotes;
mod reset;
@@ -49,6 +50,7 @@ pub use hooks::{
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
pub use ignore::add_to_ignore;
pub use logwalker::LogWalker;
pub use merge::{abort_merge, merge_branch};
pub use remotes::{
get_default_remote, get_remotes, push::AsyncProgress,
tags::PushTagsProgress,
4 changes: 4 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -607,6 +607,10 @@ impl App {
self.pull_popup.try_conflict_free_merge(rebase);
flags.insert(NeedsUpdate::ALL);
}
Action::AbortMerge => {
self.status_tab.abort_merge();
flags.insert(NeedsUpdate::ALL);
}
};

Ok(())
30 changes: 29 additions & 1 deletion src/components/branchlist.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ use crate::{
use anyhow::Result;
use asyncgit::{
sync::{
branch::checkout_remote_branch, checkout_branch,
self, branch::checkout_remote_branch, checkout_branch,
get_branches_info, BranchInfo,
},
CWD,
@@ -150,6 +150,14 @@ impl Component for BranchListComponent {
self.local,
));

out.push(CommandInfo::new(
strings::commands::merge_branch_popup(
&self.key_config,
),
!self.selection_is_cur_branch(),
self.local,
));

out.push(CommandInfo::new(
strings::commands::rename_branch_popup(
&self.key_config,
@@ -222,6 +230,16 @@ impl Component for BranchListComponent {
),
),
);
} else if e == self.key_config.merge_branch
&& !self.selection_is_cur_branch()
&& self.valid_selection()
{
try_or_popup!(
self,
"merge branch error:",
self.merge_branch()
);
self.hide();
} else if e == self.key_config.tab_toggle {
self.local = !self.local;
self.update_branches()?;
@@ -294,6 +312,16 @@ impl BranchListComponent {
!self.branches.is_empty()
}

fn merge_branch(&self) -> Result<()> {
if let Some(branch) =
self.branches.get(usize::from(self.selection))
{
sync::merge_branch(CWD, &branch.name)?;
}

Ok(())
}

fn selection_is_cur_branch(&self) -> bool {
self.branches
.iter()
14 changes: 9 additions & 5 deletions src/components/reset.rs
Original file line number Diff line number Diff line change
@@ -138,8 +138,8 @@ impl ResetComponent {
if let Some(ref a) = self.target {
return match a {
Action::Reset(_) => (
strings::confirm_title_reset(&self.key_config),
strings::confirm_msg_reset(&self.key_config),
strings::confirm_title_reset(),
strings::confirm_msg_reset(),
),
Action::StashDrop(_) => (
strings::confirm_title_stashdrop(
@@ -152,12 +152,12 @@ impl ResetComponent {
strings::confirm_msg_stashpop(&self.key_config),
),
Action::ResetHunk(_, _) => (
strings::confirm_title_reset(&self.key_config),
strings::confirm_title_reset(),
strings::confirm_msg_resethunk(&self.key_config),
),
Action::ResetLines(_, lines) => (
strings::confirm_title_reset(&self.key_config),
strings::confirm_msg_reset_lines(&self.key_config,lines.len()),
strings::confirm_title_reset(),
strings::confirm_msg_reset_lines(lines.len()),
),
Action::DeleteBranch(branch_ref) => (
strings::confirm_title_delete_branch(
@@ -181,6 +181,10 @@ impl ResetComponent {
strings::confirm_title_merge(&self.key_config,*rebase),
strings::confirm_msg_merge(&self.key_config,*incoming,*rebase),
),
Action::AbortMerge => (
strings::confirm_title_abortmerge(),
strings::confirm_msg_abortmerge(),
),
};
}

10 changes: 7 additions & 3 deletions src/keys.rs
Original file line number Diff line number Diff line change
@@ -68,9 +68,11 @@ pub struct KeyConfig {
pub rename_branch: KeyEvent,
pub select_branch: KeyEvent,
pub delete_branch: KeyEvent,
pub merge_branch: KeyEvent,
pub push: KeyEvent,
pub force_push: KeyEvent,
pub pull: KeyEvent,
pub abort_merge: KeyEvent,
}

#[rustfmt::skip]
@@ -121,13 +123,15 @@ impl Default for KeyConfig {
log_tag_commit: KeyEvent { code: KeyCode::Char('t'), modifiers: KeyModifiers::empty()},
commit_amend: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::CONTROL},
copy: KeyEvent { code: KeyCode::Char('y'), modifiers: KeyModifiers::empty()},
create_branch: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::NONE},
rename_branch: KeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::NONE},
select_branch: KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::NONE},
create_branch: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()},
rename_branch: KeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::empty()},
select_branch: KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::empty()},
delete_branch: KeyEvent{code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
merge_branch: KeyEvent{code: KeyCode::Char('m'), modifiers: KeyModifiers::empty()},
push: KeyEvent { code: KeyCode::Char('p'), modifiers: KeyModifiers::empty()},
force_push: KeyEvent { code: KeyCode::Char('P'), modifiers: KeyModifiers::SHIFT},
pull: KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::empty()},
abort_merge: KeyEvent { code: KeyCode::Char('M'), modifiers: KeyModifiers::SHIFT},
}
}
}
1 change: 1 addition & 0 deletions src/queue.rs
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ pub enum Action {
DeleteBranch(String),
ForcePush(String, bool),
PullMerge { incoming: usize, rebase: bool },
AbortMerge,
}

///
38 changes: 32 additions & 6 deletions src/strings.rs
Original file line number Diff line number Diff line change
@@ -86,7 +86,7 @@ pub fn stash_popup_title(_key_config: &SharedKeyConfig) -> String {
pub fn stash_popup_msg(_key_config: &SharedKeyConfig) -> String {
"type name (optional)".to_string()
}
pub fn confirm_title_reset(_key_config: &SharedKeyConfig) -> String {
pub fn confirm_title_reset() -> String {
"Reset".to_string()
}
pub fn confirm_title_stashdrop(
@@ -120,13 +120,17 @@ pub fn confirm_msg_merge(
format!("Merge of {} incoming commits?", incoming)
}
}
pub fn confirm_msg_reset(_key_config: &SharedKeyConfig) -> String {

pub fn confirm_title_abortmerge() -> String {
"Abort merge?".to_string()
}
pub fn confirm_msg_abortmerge() -> String {
"This will revert all changes. Are you sure?".to_string()
}
pub fn confirm_msg_reset() -> String {
"confirm file reset?".to_string()
}
pub fn confirm_msg_reset_lines(
_key_config: &SharedKeyConfig,
lines: usize,
) -> String {
pub fn confirm_msg_reset_lines(lines: usize) -> String {
format!(
"are you sure you want to discard {} selected lines?",
lines
@@ -520,6 +524,16 @@ pub mod commands {
CMD_GROUP_GENERAL,
)
}
pub fn abort_merge(key_config: &SharedKeyConfig) -> CommandText {
CommandText::new(
format!(
"Abort merge [{}]",
key_config.get_hint(key_config.abort_merge),
),
"abort ongoing merge",
CMD_GROUP_GENERAL,
)
}
pub fn select_staging(
key_config: &SharedKeyConfig,
) -> CommandText {
@@ -918,6 +932,18 @@ pub mod commands {
CMD_GROUP_GENERAL,
)
}
pub fn merge_branch_popup(
key_config: &SharedKeyConfig,
) -> CommandText {
CommandText::new(
format!(
"Merge [{}]",
key_config.get_hint(key_config.merge_branch),
),
"merge a branch",
CMD_GROUP_GENERAL,
)
}
pub fn select_branch_popup(
key_config: &SharedKeyConfig,
) -> CommandText {
121 changes: 74 additions & 47 deletions src/tabs/status.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ use crate::{
},
keys::SharedKeyConfig,
queue::{Action, InternalEvent, Queue, ResetItem},
strings,
strings, try_or_popup,
ui::style::SharedTheme,
};
use anyhow::Result;
@@ -465,6 +465,61 @@ impl Status {
.as_ref()
.map_or(true, |state| state.ahead > 0)
}

fn can_abort_merge() -> bool {
sync::repo_state(CWD).unwrap_or(RepoState::Clean)
== RepoState::Merge
}

pub fn abort_merge(&self) {
try_or_popup!(self, "abort merge", sync::abort_merge(CWD))
}

fn commands_nav(
&self,
out: &mut Vec<CommandInfo>,
force_all: bool,
) {
let focus_on_diff = self.is_focus_on_diff();
out.push(
CommandInfo::new(
strings::commands::diff_focus_left(&self.key_config),
true,
(self.visible && focus_on_diff) || force_all,
)
.order(strings::order::NAV),
);
out.push(
CommandInfo::new(
strings::commands::diff_focus_right(&self.key_config),
self.can_focus_diff(),
(self.visible && !focus_on_diff) || force_all,
)
.order(strings::order::NAV),
);
out.push(
CommandInfo::new(
strings::commands::select_staging(&self.key_config),
!focus_on_diff,
(self.visible
&& !focus_on_diff
&& self.focus == Focus::WorkDir)
|| force_all,
)
.order(strings::order::NAV),
);
out.push(
CommandInfo::new(
strings::commands::select_unstaged(&self.key_config),
!focus_on_diff,
(self.visible
&& !focus_on_diff
&& self.focus == Focus::Stage)
|| force_all,
)
.order(strings::order::NAV),
);
}
}

impl Component for Status {
@@ -507,6 +562,12 @@ impl Component for Status {
true,
!focus_on_diff,
));

out.push(CommandInfo::new(
strings::commands::abort_merge(&self.key_config),
true,
Self::can_abort_merge() || force_all,
));
}

{
@@ -519,52 +580,6 @@ impl Component for Status {
},
self.visible || force_all,
));
out.push(
CommandInfo::new(
strings::commands::diff_focus_left(
&self.key_config,
),
true,
(self.visible && focus_on_diff) || force_all,
)
.order(strings::order::NAV),
);
out.push(
CommandInfo::new(
strings::commands::diff_focus_right(
&self.key_config,
),
self.can_focus_diff(),
(self.visible && !focus_on_diff) || force_all,
)
.order(strings::order::NAV),
);
out.push(
CommandInfo::new(
strings::commands::select_staging(
&self.key_config,
),
!focus_on_diff,
(self.visible
&& !focus_on_diff
&& self.focus == Focus::WorkDir)
|| force_all,
)
.order(strings::order::NAV),
);
out.push(
CommandInfo::new(
strings::commands::select_unstaged(
&self.key_config,
),
!focus_on_diff,
(self.visible
&& !focus_on_diff
&& self.focus == Focus::Stage)
|| force_all,
)
.order(strings::order::NAV),
);

out.push(
CommandInfo::new(
@@ -576,6 +591,8 @@ impl Component for Status {
)
.hidden(),
);

self.commands_nav(out, force_all);
}

visibility_blocking(self)
@@ -653,6 +670,16 @@ impl Component for Status {
&& !self.is_focus_on_diff()
{
self.pull();
Ok(EventState::Consumed)
} else if k == self.key_config.abort_merge
&& Self::can_abort_merge()
{
self.queue.borrow_mut().push_back(
InternalEvent::ConfirmAction(
Action::AbortMerge,
),
);

Ok(EventState::Consumed)
} else {
Ok(EventState::NotConsumed)
3 changes: 3 additions & 0 deletions vim_style_key_config.ron
Original file line number Diff line number Diff line change
@@ -72,6 +72,9 @@
rename_branch: ( code: Char('r'), modifiers: ( bits: 0,),),
select_branch: ( code: Char('b'), modifiers: ( bits: 0,),),
delete_branch: ( code: Char('D'), modifiers: ( bits: 1,),),
merge_branch: ( code: Char('m'), modifiers: ( bits: 0,),),
abort_merge: ( code: Char('M'), modifiers: ( bits: 1,),),

push: ( code: Char('p'), modifiers: ( bits: 0,),),
force_push: ( code: Char('P'), modifiers: ( bits: 1,),),
pull: ( code: Char('f'), modifiers: ( bits: 0,),),