Skip to content

Commit a865432

Browse files
author
Stephan Dilly
committed
allow rebase of a branch (#816)
1 parent f51a3a9 commit a865432

File tree

9 files changed

+202
-120
lines changed

9 files changed

+202
-120
lines changed

asyncgit/src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ pub enum Error {
1111
#[error("git: no head found")]
1212
NoHead,
1313

14+
#[error("git: conflict during rebase")]
15+
RebaseConflict,
16+
1417
#[error("git: remote url not found")]
1518
UnknownRemote,
1619

asyncgit/src/sync/branch/merge_rebase.rs

+2-29
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::{
44
error::{Error, Result},
5-
sync::utils,
5+
sync::{rebase::conflict_free_rebase, utils},
66
};
77
use git2::BranchType;
88
use scopetime::scope_time;
@@ -27,34 +27,7 @@ pub fn merge_upstream_rebase(
2727
let annotated_upstream =
2828
repo.find_annotated_commit(upstream_commit.id())?;
2929

30-
let mut rebase =
31-
repo.rebase(None, Some(&annotated_upstream), None, None)?;
32-
33-
let signature =
34-
crate::sync::commit::signature_allow_undefined_name(&repo)?;
35-
36-
while let Some(op) = rebase.next() {
37-
let _op = op?;
38-
// dbg!(op.id());
39-
40-
if repo.index()?.has_conflicts() {
41-
rebase.abort()?;
42-
return Err(Error::Generic(String::from(
43-
"conflicts while merging",
44-
)));
45-
}
46-
47-
rebase.commit(None, &signature, None)?;
48-
}
49-
50-
if repo.index()?.has_conflicts() {
51-
rebase.abort()?;
52-
return Err(Error::Generic(String::from(
53-
"conflicts while merging",
54-
)));
55-
}
56-
57-
rebase.finish(Some(&signature))?;
30+
conflict_free_rebase(&repo, &annotated_upstream)?;
5831

5932
Ok(())
6033
}

asyncgit/src/sync/merge.rs

+28
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::{
88
use git2::{BranchType, Commit, MergeOptions, Repository};
99
use scopetime::scope_time;
1010

11+
use super::rebase::conflict_free_rebase;
12+
1113
///
1214
pub fn mergehead_ids(repo_path: &str) -> Result<Vec<CommitId>> {
1315
scope_time!("mergehead_ids");
@@ -51,6 +53,17 @@ pub fn merge_branch(repo_path: &str, branch: &str) -> Result<()> {
5153
Ok(())
5254
}
5355

56+
///
57+
pub fn rebase_branch(repo_path: &str, branch: &str) -> Result<()> {
58+
scope_time!("rebase_branch");
59+
60+
let repo = utils::repo(repo_path)?;
61+
62+
rebase_branch_repo(&repo, branch)?;
63+
64+
Ok(())
65+
}
66+
5467
///
5568
pub fn merge_branch_repo(
5669
repo: &Repository,
@@ -75,6 +88,21 @@ pub fn merge_branch_repo(
7588
Ok(())
7689
}
7790

91+
///
92+
pub fn rebase_branch_repo(
93+
repo: &Repository,
94+
branch_name: &str,
95+
) -> Result<()> {
96+
let branch = repo.find_branch(branch_name, BranchType::Local)?;
97+
98+
let annotated =
99+
repo.reference_to_annotated_commit(&branch.into_reference())?;
100+
101+
conflict_free_rebase(repo, &annotated)?;
102+
103+
Ok(())
104+
}
105+
78106
///
79107
pub fn merge_msg(repo_path: &str) -> Result<String> {
80108
scope_time!("merge_msg");

asyncgit/src/sync/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod ignore;
1818
mod logwalker;
1919
mod merge;
2020
mod patches;
21+
mod rebase;
2122
pub mod remotes;
2223
mod reset;
2324
mod staging;
@@ -57,7 +58,8 @@ pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
5758
pub use ignore::add_to_ignore;
5859
pub use logwalker::{LogWalker, LogWalkerFilter};
5960
pub use merge::{
60-
abort_merge, merge_branch, merge_commit, merge_msg, mergehead_ids,
61+
abort_merge, merge_branch, merge_commit, merge_msg,
62+
mergehead_ids, rebase_branch,
6163
};
6264
pub use remotes::{
6365
get_default_remote, get_remotes, push::AsyncProgress,

asyncgit/src/sync/rebase.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use crate::error::{Error, Result};
2+
3+
/// rebase attempt which aborts and undo's rebase if any conflict appears
4+
pub fn conflict_free_rebase(
5+
repo: &git2::Repository,
6+
commit: &git2::AnnotatedCommit,
7+
) -> Result<()> {
8+
let mut rebase = repo.rebase(None, Some(commit), None, None)?;
9+
let signature =
10+
crate::sync::commit::signature_allow_undefined_name(repo)?;
11+
while let Some(op) = rebase.next() {
12+
let _op = op?;
13+
// dbg!(op.id());
14+
15+
if repo.index()?.has_conflicts() {
16+
rebase.abort()?;
17+
return Err(Error::RebaseConflict);
18+
}
19+
20+
rebase.commit(None, &signature, None)?;
21+
}
22+
if repo.index()?.has_conflicts() {
23+
rebase.abort()?;
24+
return Err(Error::RebaseConflict);
25+
}
26+
rebase.finish(Some(&signature))?;
27+
Ok(())
28+
}

src/components/branchlist.rs

+122-90
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ impl Component for BranchListComponent {
180180
self.local,
181181
));
182182

183+
out.push(CommandInfo::new(
184+
strings::commands::branch_popup_rebase(
185+
&self.key_config,
186+
),
187+
!self.selection_is_cur_branch(),
188+
self.local,
189+
));
190+
183191
out.push(CommandInfo::new(
184192
strings::commands::rename_branch_popup(
185193
&self.key_config,
@@ -191,100 +199,91 @@ impl Component for BranchListComponent {
191199
visibility_blocking(self)
192200
}
193201

202+
//TODO: cleanup
203+
#[allow(clippy::cognitive_complexity)]
194204
fn event(&mut self, ev: Event) -> Result<EventState> {
195-
if self.visible {
196-
if let Event::Key(e) = ev {
197-
if e == self.key_config.exit_popup {
198-
self.hide();
199-
} else if e == self.key_config.move_down {
200-
return self
201-
.move_selection(ScrollType::Up)
202-
.map(Into::into);
203-
} else if e == self.key_config.move_up {
204-
return self
205-
.move_selection(ScrollType::Down)
206-
.map(Into::into);
207-
} else if e == self.key_config.page_down {
208-
return self
209-
.move_selection(ScrollType::PageDown)
210-
.map(Into::into);
211-
} else if e == self.key_config.page_up {
212-
return self
213-
.move_selection(ScrollType::PageUp)
214-
.map(Into::into);
215-
} else if e == self.key_config.tab_toggle {
216-
self.local = !self.local;
217-
self.update_branches()?;
218-
} else if e == self.key_config.enter {
219-
try_or_popup!(
220-
self,
221-
"switch branch error:",
222-
self.switch_to_selected_branch()
223-
);
224-
} else if e == self.key_config.create_branch
225-
&& self.local
226-
{
227-
self.queue.push(InternalEvent::CreateBranch);
228-
} else if e == self.key_config.rename_branch
229-
&& self.valid_selection()
230-
{
231-
let cur_branch =
232-
&self.branches[self.selection as usize];
233-
self.queue.push(InternalEvent::RenameBranch(
234-
cur_branch.reference.clone(),
235-
cur_branch.name.clone(),
236-
));
237-
238-
self.update_branches()?;
239-
} else if e == self.key_config.delete_branch
240-
&& !self.selection_is_cur_branch()
241-
&& self.valid_selection()
242-
{
243-
self.queue.push(InternalEvent::ConfirmAction(
244-
Action::DeleteBranch(
245-
self.branches[self.selection as usize]
246-
.reference
247-
.clone(),
248-
self.local,
249-
),
250-
));
251-
} else if e == self.key_config.merge_branch
252-
&& !self.selection_is_cur_branch()
253-
&& self.valid_selection()
254-
{
255-
try_or_popup!(
256-
self,
257-
"merge branch error:",
258-
self.merge_branch()
259-
);
260-
self.queue.push(InternalEvent::Update(
261-
NeedsUpdate::ALL,
262-
));
263-
} else if e == self.key_config.move_right
264-
&& self.valid_selection()
265-
{
266-
self.hide();
267-
if let Some(b) = self.get_selected() {
268-
self.queue.push(
269-
InternalEvent::InspectCommit(b, None),
270-
);
271-
}
272-
} else if e == self.key_config.compare_commits
273-
&& self.valid_selection()
274-
{
275-
self.hide();
276-
if let Some(b) = self.get_selected() {
277-
self.queue.push(
278-
InternalEvent::CompareCommits(b, None),
279-
);
280-
}
205+
if !self.visible {
206+
return Ok(EventState::NotConsumed);
207+
}
208+
209+
if let Event::Key(e) = ev {
210+
if e == self.key_config.exit_popup {
211+
self.hide();
212+
} else if e == self.key_config.move_down {
213+
return self
214+
.move_selection(ScrollType::Up)
215+
.map(Into::into);
216+
} else if e == self.key_config.move_up {
217+
return self
218+
.move_selection(ScrollType::Down)
219+
.map(Into::into);
220+
} else if e == self.key_config.page_down {
221+
return self
222+
.move_selection(ScrollType::PageDown)
223+
.map(Into::into);
224+
} else if e == self.key_config.page_up {
225+
return self
226+
.move_selection(ScrollType::PageUp)
227+
.map(Into::into);
228+
} else if e == self.key_config.tab_toggle {
229+
self.local = !self.local;
230+
self.update_branches()?;
231+
} else if e == self.key_config.enter {
232+
try_or_popup!(
233+
self,
234+
"switch branch error:",
235+
self.switch_to_selected_branch()
236+
);
237+
} else if e == self.key_config.create_branch && self.local
238+
{
239+
self.queue.push(InternalEvent::CreateBranch);
240+
} else if e == self.key_config.rename_branch
241+
&& self.valid_selection()
242+
{
243+
self.rename_branch();
244+
} else if e == self.key_config.delete_branch
245+
&& !self.selection_is_cur_branch()
246+
&& self.valid_selection()
247+
{
248+
self.delete_branch();
249+
} else if e == self.key_config.merge_branch
250+
&& !self.selection_is_cur_branch()
251+
&& self.valid_selection()
252+
{
253+
try_or_popup!(
254+
self,
255+
"merge branch error:",
256+
self.merge_branch()
257+
);
258+
} else if e == self.key_config.rebase_branch
259+
&& !self.selection_is_cur_branch()
260+
&& self.valid_selection()
261+
{
262+
try_or_popup!(
263+
self,
264+
"rebase error:",
265+
self.rebase_branch()
266+
);
267+
} else if e == self.key_config.move_right
268+
&& self.valid_selection()
269+
{
270+
self.hide();
271+
if let Some(b) = self.get_selected() {
272+
self.queue
273+
.push(InternalEvent::InspectCommit(b, None));
274+
}
275+
} else if e == self.key_config.compare_commits
276+
&& self.valid_selection()
277+
{
278+
self.hide();
279+
if let Some(b) = self.get_selected() {
280+
self.queue
281+
.push(InternalEvent::CompareCommits(b, None));
281282
}
282283
}
283-
284-
Ok(EventState::Consumed)
285-
} else {
286-
Ok(EventState::NotConsumed)
287284
}
285+
286+
Ok(EventState::Consumed)
288287
}
289288

290289
fn is_visible(&self) -> bool {
@@ -368,6 +367,20 @@ impl BranchListComponent {
368367
self.branches.get(usize::from(self.selection))
369368
{
370369
sync::merge_branch(CWD, &branch.name)?;
370+
371+
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
372+
}
373+
374+
Ok(())
375+
}
376+
377+
fn rebase_branch(&self) -> Result<()> {
378+
if let Some(branch) =
379+
self.branches.get(usize::from(self.selection))
380+
{
381+
sync::rebase_branch(CWD, &branch.name)?;
382+
383+
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
371384
}
372385

373386
Ok(())
@@ -623,4 +636,23 @@ impl BranchListComponent {
623636

624637
Ok(())
625638
}
639+
640+
fn rename_branch(&mut self) {
641+
let cur_branch = &self.branches[self.selection as usize];
642+
self.queue.push(InternalEvent::RenameBranch(
643+
cur_branch.reference.clone(),
644+
cur_branch.name.clone(),
645+
));
646+
}
647+
648+
fn delete_branch(&mut self) {
649+
self.queue.push(InternalEvent::ConfirmAction(
650+
Action::DeleteBranch(
651+
self.branches[self.selection as usize]
652+
.reference
653+
.clone(),
654+
self.local,
655+
),
656+
));
657+
}
626658
}

0 commit comments

Comments
 (0)