From 680b178a376898d127372dcc301153b4549db444 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Sat, 29 May 2021 14:39:05 +0200 Subject: [PATCH] make revlog sorted by time --- asyncgit/src/sync/branch/merge_commit.rs | 16 +++++-- asyncgit/src/sync/branch/merge_rebase.rs | 60 +++++++++++++++++++----- asyncgit/src/sync/commit.rs | 6 +-- asyncgit/src/sync/logwalker.rs | 5 +- asyncgit/src/sync/mod.rs | 55 +++++++++++++++++++++- 5 files changed, 122 insertions(+), 20 deletions(-) diff --git a/asyncgit/src/sync/branch/merge_commit.rs b/asyncgit/src/sync/branch/merge_commit.rs index 2084bd12..128767ad 100644 --- a/asyncgit/src/sync/branch/merge_commit.rs +++ b/asyncgit/src/sync/branch/merge_commit.rs @@ -94,13 +94,15 @@ pub(crate) fn commit_merge_with_head( #[cfg(test)] mod test { + use git2::Time; + use super::*; use crate::sync::{ branch_compare_upstream, remotes::{fetch, push::push}, tests::{ debug_cmd_print, get_commit_ids, repo_clone, - repo_init_bare, write_commit_file, + repo_init_bare, write_commit_file, write_commit_file_at, }, RepoState, }; @@ -119,8 +121,13 @@ mod test { // clone1 - let commit1 = - write_commit_file(&clone1, "test.txt", "test", "commit1"); + let commit1 = write_commit_file_at( + &clone1, + "test.txt", + "test", + "commit1", + Time::new(1, 0), + ); push( clone1_dir.path().to_str().unwrap(), @@ -134,11 +141,12 @@ mod test { // clone2 - let commit2 = write_commit_file( + let commit2 = write_commit_file_at( &clone2, "test2.txt", "test", "commit2", + Time::new(2, 0), ); //push should fail since origin diverged diff --git a/asyncgit/src/sync/branch/merge_rebase.rs b/asyncgit/src/sync/branch/merge_rebase.rs index c04f12ae..55e09287 100644 --- a/asyncgit/src/sync/branch/merge_rebase.rs +++ b/asyncgit/src/sync/branch/merge_rebase.rs @@ -47,6 +47,13 @@ pub fn merge_upstream_rebase( rebase.commit(None, &signature, None)?; } + if repo.index()?.has_conflicts() { + rebase.abort()?; + return Err(Error::Generic(String::from( + "conflicts while merging", + ))); + } + rebase.finish(Some(&signature))?; Ok(()) @@ -60,11 +67,11 @@ mod test { remotes::{fetch, push::push}, tests::{ debug_cmd_print, get_commit_ids, repo_clone, - repo_init_bare, write_commit_file, + repo_init_bare, write_commit_file, write_commit_file_at, }, RepoState, }; - use git2::Repository; + use git2::{Repository, Time}; fn get_commit_msgs(r: &Repository) -> Vec { let commits = get_commit_ids(r, 10); @@ -90,8 +97,13 @@ mod test { // clone1 - let _commit1 = - write_commit_file(&clone1, "test.txt", "test", "commit1"); + let _commit1 = write_commit_file_at( + &clone1, + "test.txt", + "test", + "commit1", + git2::Time::new(0, 0), + ); assert_eq!(clone1.head_detached().unwrap(), false); @@ -107,11 +119,12 @@ mod test { let clone2_dir = clone2_dir.path().to_str().unwrap(); - let _commit2 = write_commit_file( + let _commit2 = write_commit_file_at( &clone2, "test2.txt", "test", "commit2", + git2::Time::new(1, 0), ); assert_eq!(clone2.head_detached().unwrap(), false); @@ -123,11 +136,12 @@ mod test { // clone1 - let _commit3 = write_commit_file( + let _commit3 = write_commit_file_at( &clone1, "test3.txt", "test", "commit3", + git2::Time::new(2, 0), ); assert_eq!(clone1.head_detached().unwrap(), false); @@ -144,7 +158,7 @@ mod test { 1 ); - // debug_cmd_print(clone1_dir, "git log"); + // debug_cmd_print(clone1_dir, "git status"); assert_eq!(clone1.head_detached().unwrap(), false); @@ -179,7 +193,13 @@ mod test { // clone1 - write_commit_file(&clone1, "test.txt", "test", "commit1"); + write_commit_file_at( + &clone1, + "test.txt", + "test", + "commit1", + Time::new(0, 0), + ); push(clone1_dir, "origin", "master", false, None, None) .unwrap(); @@ -191,15 +211,33 @@ mod test { let clone2_dir = clone2_dir.path().to_str().unwrap(); - write_commit_file(&clone2, "test2.txt", "test", "commit2"); + write_commit_file_at( + &clone2, + "test2.txt", + "test", + "commit2", + Time::new(1, 0), + ); push(clone2_dir, "origin", "master", false, None, None) .unwrap(); // clone1 - write_commit_file(&clone1, "test3.txt", "test", "commit3"); - write_commit_file(&clone1, "test4.txt", "test", "commit4"); + write_commit_file_at( + &clone1, + "test3.txt", + "test", + "commit3", + Time::new(2, 0), + ); + write_commit_file_at( + &clone1, + "test4.txt", + "test", + "commit4", + Time::new(3, 0), + ); //lets fetch from origin diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index ef4204ee..2dc4bda1 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -1,5 +1,5 @@ -use super::{get_head, utils::repo, CommitId}; -use crate::error::Result; +use super::{utils::repo, CommitId}; +use crate::{error::Result, sync::utils::get_head_repo}; use git2::{ErrorCode, ObjectType, Repository, Signature}; use scopetime::scope_time; @@ -68,7 +68,7 @@ pub fn commit(repo_path: &str, msg: &str) -> Result { let tree_id = index.write_tree()?; let tree = repo.find_tree(tree_id)?; - let parents = if let Ok(id) = get_head(repo_path) { + let parents = if let Ok(id) = get_head_repo(&repo) { vec![repo.find_commit(id.into())?] } else { Vec::new() diff --git a/asyncgit/src/sync/logwalker.rs b/asyncgit/src/sync/logwalker.rs index 22ae7865..8ad2b444 100644 --- a/asyncgit/src/sync/logwalker.rs +++ b/asyncgit/src/sync/logwalker.rs @@ -1,6 +1,6 @@ use super::CommitId; use crate::error::Result; -use git2::{Repository, Revwalk}; +use git2::{Repository, Revwalk, Sort}; /// pub struct LogWalker<'a> { @@ -27,7 +27,10 @@ impl<'a> LogWalker<'a> { if self.revwalk.is_none() { let mut walk = self.repo.revwalk()?; + walk.push_head()?; + walk.set_sorting(Sort::TIME)?; + self.revwalk = Some(walk); } diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 7ac89810..ebeb7509 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -79,7 +79,7 @@ mod tests { use super::{ commit, stage_add_file, status::{get_status, StatusType}, - utils::repo_write_file, + utils::{get_head_repo, repo, repo_write_file}, CommitId, LogWalker, }; use crate::error::Result; @@ -128,6 +128,59 @@ mod tests { .unwrap() } + /// write, stage and commit a file giving the commit a specific timestamp + pub fn write_commit_file_at( + repo: &Repository, + file: &str, + content: &str, + commit_name: &str, + time: git2::Time, + ) -> CommitId { + repo_write_file(repo, file, content).unwrap(); + + let path = repo.workdir().unwrap().to_str().unwrap(); + + stage_add_file(path, Path::new(file)).unwrap(); + + commit_at(path, commit_name, time) + } + + fn commit_at( + repo_path: &str, + msg: &str, + time: git2::Time, + ) -> CommitId { + let repo = repo(repo_path).unwrap(); + + let signature = + git2::Signature::new("name", "email", &time).unwrap(); + let mut index = repo.index().unwrap(); + let tree_id = index.write_tree().unwrap(); + let tree = repo.find_tree(tree_id).unwrap(); + + let parents = if let Ok(id) = get_head_repo(&repo) { + vec![repo.find_commit(id.into()).unwrap()] + } else { + Vec::new() + }; + + let parents = parents.iter().collect::>(); + + let commit = repo + .commit( + Some("HEAD"), + &signature, + &signature, + msg, + &tree, + parents.as_slice(), + ) + .unwrap() + .into(); + + commit + } + /// pub fn repo_init_empty() -> Result<(TempDir, Repository)> { sandbox_config_files();