Skip to content

Commit d5d36de

Browse files
author
Stephan Dilly
authored
implement reverting commit from revlog (#1057)
1 parent 508ee35 commit d5d36de

File tree

17 files changed

+227
-58
lines changed

17 files changed

+227
-58
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Added
11+
- allow reverting a commit from the commit log ([#927](https://github.com/extrawurst/gitui/issues/927))
12+
1013
### Fixed
1114
- Keep commit message when pre-commit hook fails ([#1035](https://github.com/extrawurst/gitui/issues/1035))
1215
- honor `pushurl` when checking credentials for pushing ([#953](https://github.com/extrawurst/gitui/issues/953))

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ These are the high level goals before calling out `1.0`:
7979
* notify-based change detection ([#1](https://github.com/extrawurst/gitui/issues/1))
8080
* interactive rebase ([#32](https://github.com/extrawurst/gitui/issues/32))
8181
* popup history and back button ([#846](https://github.com/extrawurst/gitui/issues/846))
82-
* support reverting a commit ([#927](https://github.com/extrawurst/gitui/issues/927))
8382

8483
## 5. <a name="limitations"></a> Known Limitations <small><sup>[Top ▲](#table-of-contents)</sup></small>
8584

asyncgit/src/sync/commit_revert.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use super::{CommitId, RepoPath};
2+
use crate::{
3+
error::Result,
4+
sync::{repository::repo, utils::read_file},
5+
};
6+
use scopetime::scope_time;
7+
8+
const GIT_REVERT_HEAD_FILE: &str = "REVERT_HEAD";
9+
10+
///
11+
pub fn revert_commit(
12+
repo_path: &RepoPath,
13+
commit: CommitId,
14+
) -> Result<()> {
15+
scope_time!("revert");
16+
17+
let repo = repo(repo_path)?;
18+
19+
let commit = repo.find_commit(commit.into())?;
20+
21+
repo.revert(&commit, None)?;
22+
23+
Ok(())
24+
}
25+
26+
///
27+
pub fn revert_head(repo_path: &RepoPath) -> Result<CommitId> {
28+
scope_time!("revert_head");
29+
30+
let path = repo(repo_path)?.path().join(GIT_REVERT_HEAD_FILE);
31+
32+
let file_content = read_file(&path)?;
33+
34+
let id = git2::Oid::from_str(file_content.trim())?;
35+
36+
Ok(id.into())
37+
}
38+
39+
///
40+
pub fn commit_revert(
41+
repo_path: &RepoPath,
42+
msg: &str,
43+
) -> Result<CommitId> {
44+
scope_time!("commit_revert");
45+
46+
let id = crate::sync::commit(repo_path, msg)?;
47+
48+
repo(repo_path)?.cleanup_state()?;
49+
50+
Ok(id)
51+
}

asyncgit/src/sync/merge.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ pub fn mergehead_ids(repo_path: &RepoPath) -> Result<Vec<CommitId>> {
3636
/// * reset all staged changes,
3737
/// * revert all changes in workdir
3838
/// * cleanup repo merge state
39-
pub fn abort_merge(repo_path: &RepoPath) -> Result<()> {
40-
scope_time!("cleanup_state");
39+
pub fn abort_pending_state(repo_path: &RepoPath) -> Result<()> {
40+
scope_time!("abort_pending_state");
4141

4242
let repo = repo(repo_path)?;
4343

asyncgit/src/sync/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod branch;
88
mod commit;
99
mod commit_details;
1010
mod commit_files;
11+
mod commit_revert;
1112
mod commits_info;
1213
mod config;
1314
pub mod cred;
@@ -44,6 +45,7 @@ pub use commit_details::{
4445
get_commit_details, CommitDetails, CommitMessage, CommitSignature,
4546
};
4647
pub use commit_files::get_commit_files;
48+
pub use commit_revert::{commit_revert, revert_commit, revert_head};
4749
pub use commits_info::{
4850
get_commit_info, get_commits_info, CommitId, CommitInfo,
4951
};
@@ -60,9 +62,9 @@ pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
6062
pub use ignore::add_to_ignore;
6163
pub use logwalker::{LogWalker, LogWalkerFilter};
6264
pub use merge::{
63-
abort_merge, abort_pending_rebase, continue_pending_rebase,
64-
merge_branch, merge_commit, merge_msg, mergehead_ids,
65-
rebase_progress,
65+
abort_pending_rebase, abort_pending_state,
66+
continue_pending_rebase, merge_branch, merge_commit, merge_msg,
67+
mergehead_ids, rebase_progress,
6668
};
6769
pub use rebase::rebase_branch;
6870
pub use remotes::{

asyncgit/src/sync/state.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub enum RepoState {
1313
///
1414
Rebase,
1515
///
16+
Revert,
17+
///
1618
Other,
1719
}
1820

@@ -21,6 +23,7 @@ impl From<RepositoryState> for RepoState {
2123
match state {
2224
RepositoryState::Clean => Self::Clean,
2325
RepositoryState::Merge => Self::Merge,
26+
RepositoryState::Revert => Self::Revert,
2427
RepositoryState::RebaseMerge => Self::Rebase,
2528
_ => {
2629
log::warn!("state not supported yet: {:?}", state);
@@ -38,7 +41,5 @@ pub fn repo_state(repo_path: &RepoPath) -> Result<RepoState> {
3841

3942
let state = repo.state();
4043

41-
// dbg!(&state);
42-
4344
Ok(state.into())
4445
}

asyncgit/src/sync/utils.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,17 @@ pub(crate) fn repo_write_file(
187187
Ok(())
188188
}
189189

190+
///
191+
pub fn read_file(path: &Path) -> Result<String> {
192+
use std::io::Read;
193+
194+
let mut file = File::open(path)?;
195+
let mut buffer = Vec::new();
196+
file.read_to_end(&mut buffer)?;
197+
198+
Ok(String::from_utf8(buffer)?)
199+
}
200+
190201
#[cfg(test)]
191202
pub(crate) fn repo_read_file(
192203
repo: &Repository,

src/app.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ impl App {
701701
InternalEvent::Tags => {
702702
self.tags_popup.open()?;
703703
}
704-
InternalEvent::TabSwitch => self.set_tab(0)?,
704+
InternalEvent::TabSwitchStatus => self.set_tab(0)?,
705705
InternalEvent::InspectCommit(id, tags) => {
706706
self.inspect_commit_popup.open(id, tags)?;
707707
flags
@@ -879,8 +879,8 @@ impl App {
879879
self.pull_popup.try_conflict_free_merge(rebase);
880880
flags.insert(NeedsUpdate::ALL);
881881
}
882-
Action::AbortMerge => {
883-
self.status_tab.abort_merge();
882+
Action::AbortRevert | Action::AbortMerge => {
883+
self.status_tab.revert_pending_state();
884884
flags.insert(NeedsUpdate::ALL);
885885
}
886886
Action::AbortRebase => {

src/components/branchlist.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ impl BranchListComponent {
446446

447447
if sync::repo_state(&self.repo.borrow())? != RepoState::Clean
448448
{
449-
self.queue.push(InternalEvent::TabSwitch);
449+
self.queue.push(InternalEvent::TabSwitchStatus);
450450
}
451451

452452
Ok(())

src/components/commit.rs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ enum Mode {
3939
Normal,
4040
Amend(CommitId),
4141
Merge(Vec<CommitId>),
42+
Revert,
4243
}
4344

4445
pub struct CommitComponent {
@@ -227,6 +228,9 @@ impl CommitComponent {
227228
Mode::Merge(ids) => {
228229
sync::merge_commit(&self.repo.borrow(), &msg, ids)?
229230
}
231+
Mode::Revert => {
232+
sync::commit_revert(&self.repo.borrow(), &msg)?
233+
}
230234
};
231235

232236
if let HookResult::NotOk(e) =
@@ -380,31 +384,40 @@ impl Component for CommitComponent {
380384

381385
self.mode = Mode::Normal;
382386

383-
self.mode = if sync::repo_state(&self.repo.borrow())?
384-
== RepoState::Merge
385-
{
386-
let ids = sync::mergehead_ids(&self.repo.borrow())?;
387-
self.input.set_title(strings::commit_title_merge());
388-
self.input
389-
.set_text(sync::merge_msg(&self.repo.borrow())?);
390-
Mode::Merge(ids)
391-
} else {
392-
self.commit_template = get_config_string(
393-
&self.repo.borrow(),
394-
"commit.template",
395-
)
396-
.ok()
397-
.flatten()
398-
.and_then(|path| read_to_string(path).ok());
399-
400-
if self.is_empty() {
401-
if let Some(s) = &self.commit_template {
402-
self.input.set_text(s.clone());
403-
}
387+
let repo_state = sync::repo_state(&self.repo.borrow())?;
388+
389+
self.mode = match repo_state {
390+
RepoState::Merge => {
391+
let ids = sync::mergehead_ids(&self.repo.borrow())?;
392+
self.input.set_title(strings::commit_title_merge());
393+
self.input
394+
.set_text(sync::merge_msg(&self.repo.borrow())?);
395+
Mode::Merge(ids)
396+
}
397+
RepoState::Revert => {
398+
self.input.set_title(strings::commit_title_revert());
399+
self.input
400+
.set_text(sync::merge_msg(&self.repo.borrow())?);
401+
Mode::Revert
404402
}
403+
_ => {
404+
self.commit_template = get_config_string(
405+
&self.repo.borrow(),
406+
"commit.template",
407+
)
408+
.ok()
409+
.flatten()
410+
.and_then(|path| read_to_string(path).ok());
405411

406-
self.input.set_title(strings::commit_title());
407-
Mode::Normal
412+
if self.is_empty() {
413+
if let Some(s) = &self.commit_template {
414+
self.input.set_text(s.clone());
415+
}
416+
}
417+
418+
self.input.set_title(strings::commit_title());
419+
Mode::Normal
420+
}
408421
};
409422

410423
self.input.show()?;

0 commit comments

Comments
 (0)