Skip to content

Commit 4f6aceb

Browse files
author
Stephan Dilly
authored
merging a branch (#696)
* merging arbitrary branch * cleanup intermediate in-merge state
1 parent 9f37835 commit 4f6aceb

File tree

10 files changed

+210
-62
lines changed

10 files changed

+210
-62
lines changed

asyncgit/src/sync/merge.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use crate::{
2+
error::{Error, Result},
3+
sync::{reset_stage, reset_workdir, utils},
4+
};
5+
use git2::{BranchType, MergeOptions};
6+
use scopetime::scope_time;
7+
8+
/// does these steps:
9+
/// * reset all staged changes,
10+
/// * revert all changes in workdir
11+
/// * cleanup repo merge state
12+
pub fn abort_merge(repo_path: &str) -> Result<()> {
13+
scope_time!("cleanup_state");
14+
15+
let repo = utils::repo(repo_path)?;
16+
17+
reset_stage(repo_path, "*")?;
18+
reset_workdir(repo_path, "*")?;
19+
20+
repo.cleanup_state()?;
21+
22+
Ok(())
23+
}
24+
25+
///
26+
pub fn merge_branch(repo_path: &str, branch: &str) -> Result<()> {
27+
scope_time!("merge_branch");
28+
29+
let repo = utils::repo(repo_path)?;
30+
31+
let branch = repo.find_branch(branch, BranchType::Local)?;
32+
33+
let id = branch.into_reference().peel_to_commit()?;
34+
35+
let annotated = repo.find_annotated_commit(id.id())?;
36+
37+
let (analysis, _) = repo.merge_analysis(&[&annotated])?;
38+
39+
//TODO: support merge on unborn
40+
if analysis.is_unborn() {
41+
return Err(Error::Generic("head is unborn".into()));
42+
}
43+
44+
let mut opt = MergeOptions::default();
45+
46+
repo.merge(&[&annotated], Some(&mut opt), None)?;
47+
48+
Ok(())
49+
}

asyncgit/src/sync/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod hooks;
1515
mod hunks;
1616
mod ignore;
1717
mod logwalker;
18+
mod merge;
1819
mod patches;
1920
pub mod remotes;
2021
mod reset;
@@ -49,6 +50,7 @@ pub use hooks::{
4950
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
5051
pub use ignore::add_to_ignore;
5152
pub use logwalker::LogWalker;
53+
pub use merge::{abort_merge, merge_branch};
5254
pub use remotes::{
5355
get_default_remote, get_remotes, push::AsyncProgress,
5456
tags::PushTagsProgress,

src/app.rs

+4
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,10 @@ impl App {
607607
self.pull_popup.try_conflict_free_merge(rebase);
608608
flags.insert(NeedsUpdate::ALL);
609609
}
610+
Action::AbortMerge => {
611+
self.status_tab.abort_merge();
612+
flags.insert(NeedsUpdate::ALL);
613+
}
610614
};
611615

612616
Ok(())

src/components/branchlist.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
use anyhow::Result;
1313
use asyncgit::{
1414
sync::{
15-
branch::checkout_remote_branch, checkout_branch,
15+
self, branch::checkout_remote_branch, checkout_branch,
1616
get_branches_info, BranchInfo,
1717
},
1818
CWD,
@@ -150,6 +150,14 @@ impl Component for BranchListComponent {
150150
self.local,
151151
));
152152

153+
out.push(CommandInfo::new(
154+
strings::commands::merge_branch_popup(
155+
&self.key_config,
156+
),
157+
!self.selection_is_cur_branch(),
158+
self.local,
159+
));
160+
153161
out.push(CommandInfo::new(
154162
strings::commands::rename_branch_popup(
155163
&self.key_config,
@@ -222,6 +230,16 @@ impl Component for BranchListComponent {
222230
),
223231
),
224232
);
233+
} else if e == self.key_config.merge_branch
234+
&& !self.selection_is_cur_branch()
235+
&& self.valid_selection()
236+
{
237+
try_or_popup!(
238+
self,
239+
"merge branch error:",
240+
self.merge_branch()
241+
);
242+
self.hide();
225243
} else if e == self.key_config.tab_toggle {
226244
self.local = !self.local;
227245
self.update_branches()?;
@@ -294,6 +312,16 @@ impl BranchListComponent {
294312
!self.branches.is_empty()
295313
}
296314

315+
fn merge_branch(&self) -> Result<()> {
316+
if let Some(branch) =
317+
self.branches.get(usize::from(self.selection))
318+
{
319+
sync::merge_branch(CWD, &branch.name)?;
320+
}
321+
322+
Ok(())
323+
}
324+
297325
fn selection_is_cur_branch(&self) -> bool {
298326
self.branches
299327
.iter()

src/components/reset.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ impl ResetComponent {
138138
if let Some(ref a) = self.target {
139139
return match a {
140140
Action::Reset(_) => (
141-
strings::confirm_title_reset(&self.key_config),
142-
strings::confirm_msg_reset(&self.key_config),
141+
strings::confirm_title_reset(),
142+
strings::confirm_msg_reset(),
143143
),
144144
Action::StashDrop(_) => (
145145
strings::confirm_title_stashdrop(
@@ -152,12 +152,12 @@ impl ResetComponent {
152152
strings::confirm_msg_stashpop(&self.key_config),
153153
),
154154
Action::ResetHunk(_, _) => (
155-
strings::confirm_title_reset(&self.key_config),
155+
strings::confirm_title_reset(),
156156
strings::confirm_msg_resethunk(&self.key_config),
157157
),
158158
Action::ResetLines(_, lines) => (
159-
strings::confirm_title_reset(&self.key_config),
160-
strings::confirm_msg_reset_lines(&self.key_config,lines.len()),
159+
strings::confirm_title_reset(),
160+
strings::confirm_msg_reset_lines(lines.len()),
161161
),
162162
Action::DeleteBranch(branch_ref) => (
163163
strings::confirm_title_delete_branch(
@@ -181,6 +181,10 @@ impl ResetComponent {
181181
strings::confirm_title_merge(&self.key_config,*rebase),
182182
strings::confirm_msg_merge(&self.key_config,*incoming,*rebase),
183183
),
184+
Action::AbortMerge => (
185+
strings::confirm_title_abortmerge(),
186+
strings::confirm_msg_abortmerge(),
187+
),
184188
};
185189
}
186190

src/keys.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ pub struct KeyConfig {
6868
pub rename_branch: KeyEvent,
6969
pub select_branch: KeyEvent,
7070
pub delete_branch: KeyEvent,
71+
pub merge_branch: KeyEvent,
7172
pub push: KeyEvent,
7273
pub force_push: KeyEvent,
7374
pub pull: KeyEvent,
75+
pub abort_merge: KeyEvent,
7476
}
7577

7678
#[rustfmt::skip]
@@ -121,13 +123,15 @@ impl Default for KeyConfig {
121123
log_tag_commit: KeyEvent { code: KeyCode::Char('t'), modifiers: KeyModifiers::empty()},
122124
commit_amend: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::CONTROL},
123125
copy: KeyEvent { code: KeyCode::Char('y'), modifiers: KeyModifiers::empty()},
124-
create_branch: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::NONE},
125-
rename_branch: KeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::NONE},
126-
select_branch: KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::NONE},
126+
create_branch: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()},
127+
rename_branch: KeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::empty()},
128+
select_branch: KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::empty()},
127129
delete_branch: KeyEvent{code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
130+
merge_branch: KeyEvent{code: KeyCode::Char('m'), modifiers: KeyModifiers::empty()},
128131
push: KeyEvent { code: KeyCode::Char('p'), modifiers: KeyModifiers::empty()},
129132
force_push: KeyEvent { code: KeyCode::Char('P'), modifiers: KeyModifiers::SHIFT},
130133
pull: KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::empty()},
134+
abort_merge: KeyEvent { code: KeyCode::Char('M'), modifiers: KeyModifiers::SHIFT},
131135
}
132136
}
133137
}

src/queue.rs

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub enum Action {
3333
DeleteBranch(String),
3434
ForcePush(String, bool),
3535
PullMerge { incoming: usize, rebase: bool },
36+
AbortMerge,
3637
}
3738

3839
///

src/strings.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub fn stash_popup_title(_key_config: &SharedKeyConfig) -> String {
8686
pub fn stash_popup_msg(_key_config: &SharedKeyConfig) -> String {
8787
"type name (optional)".to_string()
8888
}
89-
pub fn confirm_title_reset(_key_config: &SharedKeyConfig) -> String {
89+
pub fn confirm_title_reset() -> String {
9090
"Reset".to_string()
9191
}
9292
pub fn confirm_title_stashdrop(
@@ -120,13 +120,17 @@ pub fn confirm_msg_merge(
120120
format!("Merge of {} incoming commits?", incoming)
121121
}
122122
}
123-
pub fn confirm_msg_reset(_key_config: &SharedKeyConfig) -> String {
123+
124+
pub fn confirm_title_abortmerge() -> String {
125+
"Abort merge?".to_string()
126+
}
127+
pub fn confirm_msg_abortmerge() -> String {
128+
"This will revert all changes. Are you sure?".to_string()
129+
}
130+
pub fn confirm_msg_reset() -> String {
124131
"confirm file reset?".to_string()
125132
}
126-
pub fn confirm_msg_reset_lines(
127-
_key_config: &SharedKeyConfig,
128-
lines: usize,
129-
) -> String {
133+
pub fn confirm_msg_reset_lines(lines: usize) -> String {
130134
format!(
131135
"are you sure you want to discard {} selected lines?",
132136
lines
@@ -520,6 +524,16 @@ pub mod commands {
520524
CMD_GROUP_GENERAL,
521525
)
522526
}
527+
pub fn abort_merge(key_config: &SharedKeyConfig) -> CommandText {
528+
CommandText::new(
529+
format!(
530+
"Abort merge [{}]",
531+
key_config.get_hint(key_config.abort_merge),
532+
),
533+
"abort ongoing merge",
534+
CMD_GROUP_GENERAL,
535+
)
536+
}
523537
pub fn select_staging(
524538
key_config: &SharedKeyConfig,
525539
) -> CommandText {
@@ -918,6 +932,18 @@ pub mod commands {
918932
CMD_GROUP_GENERAL,
919933
)
920934
}
935+
pub fn merge_branch_popup(
936+
key_config: &SharedKeyConfig,
937+
) -> CommandText {
938+
CommandText::new(
939+
format!(
940+
"Merge [{}]",
941+
key_config.get_hint(key_config.merge_branch),
942+
),
943+
"merge a branch",
944+
CMD_GROUP_GENERAL,
945+
)
946+
}
921947
pub fn select_branch_popup(
922948
key_config: &SharedKeyConfig,
923949
) -> CommandText {

0 commit comments

Comments
 (0)