Skip to content

Commit 4a41bf9

Browse files
author
Stephan Dilly
committed
resolve conflicts
1 parent f8bad7d commit 4a41bf9

File tree

5 files changed

+208
-25
lines changed

5 files changed

+208
-25
lines changed

asyncgit/src/sync/merge.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
use crate::{
22
error::{Error, Result},
33
sync::{
4-
branch::merge_commit::commit_merge_with_head, reset_stage,
5-
reset_workdir, utils, CommitId,
4+
branch::merge_commit::commit_merge_with_head,
5+
rebase::get_rebase_progress, reset_stage, reset_workdir,
6+
utils, CommitId,
67
},
78
};
89
use git2::{BranchType, Commit, MergeOptions, Repository};
910
use scopetime::scope_time;
1011

12+
use super::rebase::RebaseProgress;
13+
1114
///
1215
pub fn mergehead_ids(repo_path: &str) -> Result<Vec<CommitId>> {
1316
scope_time!("mergehead_ids");
@@ -51,6 +54,15 @@ pub fn merge_branch(repo_path: &str, branch: &str) -> Result<()> {
5154
Ok(())
5255
}
5356

57+
///
58+
pub fn rebase_progress(repo_path: &str) -> Result<RebaseProgress> {
59+
scope_time!("rebase_progress");
60+
61+
let repo = utils::repo(repo_path)?;
62+
63+
get_rebase_progress(&repo)
64+
}
65+
5466
///
5567
pub fn merge_branch_repo(
5668
repo: &Repository,

asyncgit/src/sync/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
5858
pub use ignore::add_to_ignore;
5959
pub use logwalker::{LogWalker, LogWalkerFilter};
6060
pub use merge::{
61-
abort_merge, merge_branch, merge_commit, merge_msg, mergehead_ids,
61+
abort_merge, merge_branch, merge_commit, merge_msg,
62+
mergehead_ids, rebase_progress,
6263
};
6364
pub use rebase::rebase_branch;
6465
pub use remotes::{

asyncgit/src/sync/rebase.rs

Lines changed: 155 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ use super::CommitId;
1111
fn rebase_branch_repo(
1212
repo: &Repository,
1313
branch_name: &str,
14-
) -> Result<CommitId> {
14+
) -> Result<RebaseState> {
1515
let branch = repo.find_branch(branch_name, BranchType::Local)?;
1616

1717
let annotated =
1818
repo.reference_to_annotated_commit(&branch.into_reference())?;
1919

20-
conflict_free_rebase(repo, &annotated)
20+
rebase(repo, &annotated)
2121
}
2222

2323
///
2424
pub fn rebase_branch(
2525
repo_path: &str,
2626
branch: &str,
27-
) -> Result<CommitId> {
27+
) -> Result<RebaseState> {
2828
scope_time!("rebase_branch");
2929

3030
let repo = utils::repo(repo_path)?;
@@ -67,16 +67,85 @@ pub fn conflict_free_rebase(
6767
})
6868
}
6969

70-
#[cfg(test)]
71-
mod tests {
72-
use crate::sync::{
73-
checkout_branch, create_branch,
74-
rebase::rebase_branch,
75-
repo_state,
76-
tests::{repo_init, write_commit_file},
77-
CommitId, RepoState,
70+
///
71+
#[derive(PartialEq, Debug)]
72+
pub enum RebaseState {
73+
///
74+
Finished,
75+
///
76+
Conflicted,
77+
}
78+
79+
/// rebase
80+
#[allow(dead_code)]
81+
fn rebase(
82+
repo: &git2::Repository,
83+
commit: &git2::AnnotatedCommit,
84+
) -> Result<RebaseState> {
85+
let mut rebase = repo.rebase(None, Some(commit), None, None)?;
86+
let signature =
87+
crate::sync::commit::signature_allow_undefined_name(repo)?;
88+
89+
while let Some(op) = rebase.next() {
90+
let _op = op?;
91+
// dbg!(op.id());
92+
93+
if repo.index()?.has_conflicts() {
94+
return Ok(RebaseState::Conflicted);
95+
}
96+
97+
rebase.commit(None, &signature, None)?;
98+
}
99+
100+
if repo.index()?.has_conflicts() {
101+
return Ok(RebaseState::Conflicted);
102+
}
103+
104+
rebase.finish(Some(&signature))?;
105+
106+
Ok(RebaseState::Finished)
107+
}
108+
109+
///
110+
#[derive(PartialEq, Debug)]
111+
pub struct RebaseProgress {
112+
///
113+
pub steps: usize,
114+
///
115+
pub current: usize,
116+
}
117+
118+
///
119+
#[allow(dead_code)]
120+
pub fn get_rebase_progress(
121+
repo: &git2::Repository,
122+
) -> Result<RebaseProgress> {
123+
let mut rebase = repo.open_rebase(None)?;
124+
125+
let progress = RebaseProgress {
126+
steps: rebase.len(),
127+
current: rebase.operation_current().unwrap_or_default(),
78128
};
79-
use git2::Repository;
129+
130+
Ok(progress)
131+
}
132+
133+
///
134+
#[allow(dead_code)]
135+
pub fn abort_rebase(repo: &git2::Repository) -> Result<()> {
136+
let mut rebase = repo.open_rebase(None)?;
137+
138+
rebase.abort()?;
139+
140+
Ok(())
141+
}
142+
143+
#[cfg(test)]
144+
mod test_conflict_free_rebase {
145+
use crate::sync::{CommitId, RepoState, checkout_branch, create_branch, rebase::{RebaseState, rebase_branch}, repo_state, tests::{repo_init, write_commit_file}, utils};
146+
use git2::{BranchType, Repository};
147+
148+
use super::conflict_free_rebase;
80149

81150
fn parent_ids(repo: &Repository, c: CommitId) -> Vec<CommitId> {
82151
let foo = repo
@@ -89,6 +158,23 @@ mod tests {
89158
foo
90159
}
91160

161+
///
162+
fn test_rebase_branch_repo(
163+
repo_path: &str,
164+
branch_name: &str,
165+
) -> CommitId {
166+
let repo = utils::repo(repo_path).unwrap();
167+
168+
let branch =
169+
repo.find_branch(branch_name, BranchType::Local).unwrap();
170+
171+
let annotated = repo
172+
.reference_to_annotated_commit(&branch.into_reference())
173+
.unwrap();
174+
175+
conflict_free_rebase(&repo, &annotated).unwrap()
176+
}
177+
92178
#[test]
93179
fn test_smoke() {
94180
let (_td, repo) = repo_init().unwrap();
@@ -112,7 +198,7 @@ mod tests {
112198

113199
checkout_branch(repo_path, "refs/heads/foo").unwrap();
114200

115-
let r = rebase_branch(repo_path, "master").unwrap();
201+
let r = test_rebase_branch_repo(repo_path, "master");
116202

117203
assert_eq!(parent_ids(&repo, r), vec![c3]);
118204
}
@@ -137,7 +223,62 @@ mod tests {
137223

138224
let res = rebase_branch(repo_path, "master");
139225

140-
assert!(res.is_err());
226+
assert!(matches!(res.unwrap(), RebaseState::Conflicted));
227+
228+
assert_eq!(repo_state(repo_path).unwrap(), RepoState::Rebase);
229+
}
230+
}
231+
232+
#[cfg(test)]
233+
mod test_rebase {
234+
use crate::sync::{
235+
checkout_branch, create_branch,
236+
rebase::{
237+
abort_rebase, get_rebase_progress, RebaseProgress,
238+
RebaseState,
239+
},
240+
rebase_branch, repo_state,
241+
tests::{repo_init, write_commit_file},
242+
RepoState,
243+
};
244+
245+
#[test]
246+
fn test_conflicted_abort() {
247+
let (_td, repo) = repo_init().unwrap();
248+
let root = repo.path().parent().unwrap();
249+
let repo_path = root.as_os_str().to_str().unwrap();
250+
251+
write_commit_file(&repo, "test.txt", "test1", "commit1");
252+
253+
create_branch(repo_path, "foo").unwrap();
254+
255+
write_commit_file(&repo, "test.txt", "test2", "commit2");
256+
257+
checkout_branch(repo_path, "refs/heads/master").unwrap();
258+
259+
write_commit_file(&repo, "test.txt", "test3", "commit3");
260+
261+
checkout_branch(repo_path, "refs/heads/foo").unwrap();
262+
263+
assert!(get_rebase_progress(&repo).is_err());
264+
265+
// rebase
266+
267+
let r = rebase_branch(repo_path, "master").unwrap();
268+
269+
assert_eq!(r, RebaseState::Conflicted);
270+
assert_eq!(repo_state(repo_path).unwrap(), RepoState::Rebase);
271+
assert_eq!(
272+
get_rebase_progress(&repo).unwrap(),
273+
RebaseProgress {
274+
current: 0,
275+
steps: 1
276+
}
277+
);
278+
279+
// abort
280+
281+
abort_rebase(&repo).unwrap();
141282

142283
assert_eq!(repo_state(repo_path).unwrap(), RepoState::Clean);
143284
}

asyncgit/src/sync/state.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub enum RepoState {
1010
///
1111
Merge,
1212
///
13+
Rebase,
14+
///
1315
Other,
1416
}
1517

@@ -18,6 +20,7 @@ impl From<RepositoryState> for RepoState {
1820
match state {
1921
RepositoryState::Clean => Self::Clean,
2022
RepositoryState::Merge => Self::Merge,
23+
RepositoryState::RebaseMerge => Self::Rebase,
2124
_ => Self::Other,
2225
}
2326
}
@@ -29,5 +32,9 @@ pub fn repo_state(repo_path: &str) -> Result<RepoState> {
2932

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

32-
Ok(repo.state().into())
35+
let state = repo.state();
36+
37+
// dbg!(&state);
38+
39+
Ok(state.into())
3340
}

src/tabs/status.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,12 @@ impl Status {
215215
}
216216
}
217217

218-
fn draw_repo_state<B: tui::backend::Backend>(
219-
f: &mut tui::Frame<B>,
220-
r: tui::layout::Rect,
221-
) -> Result<()> {
222-
if let Ok(state) = sync::repo_state(CWD) {
223-
if state != RepoState::Clean {
218+
fn repo_state_text(state: RepoState) -> String {
219+
match state {
220+
RepoState::Merge => {
224221
let ids =
225222
sync::mergehead_ids(CWD).unwrap_or_default();
223+
226224
let ids = format!(
227225
"({})",
228226
ids.iter()
@@ -231,7 +229,31 @@ impl Status {
231229
))
232230
.join(",")
233231
);
234-
let txt = format!("{:?} {}", state, ids);
232+
233+
format!("{:?} {}", state, ids)
234+
}
235+
RepoState::Rebase => {
236+
let progress =
237+
if let Ok(p) = sync::rebase_progress(CWD) {
238+
format!("{}/{}", p.current + 1, p.steps)
239+
} else {
240+
String::new()
241+
};
242+
243+
format!("{:?} ({})", state, progress)
244+
}
245+
_ => format!("{:?}", state),
246+
}
247+
}
248+
249+
fn draw_repo_state<B: tui::backend::Backend>(
250+
f: &mut tui::Frame<B>,
251+
r: tui::layout::Rect,
252+
) -> Result<()> {
253+
if let Ok(state) = sync::repo_state(CWD) {
254+
if state != RepoState::Clean {
255+
let txt = Self::repo_state_text(state);
256+
235257
let txt_len = u16::try_from(txt.len())?;
236258
let w = Paragraph::new(txt)
237259
.style(Style::default().fg(Color::Red))

0 commit comments

Comments
 (0)