mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-09 05:58:55 +00:00
git: Only reset Git index if non-empty
In chromium/src.git, this gives an approximate ~0.83s speedup for commands if the Git index is empty, and a ~0.14s slowdown if the Git index is non-empty. As most users using jj will likely be using jj to write to a colocated repo - and therefore avoid modifying the Git index - this should be a general speedup for most colocated checkouts.
This commit is contained in:
parent
b31f75bc94
commit
a075a5c6ca
2 changed files with 61 additions and 2 deletions
|
@ -933,7 +933,21 @@ pub fn reset_head(
|
|||
let git_head = mut_repo.view().git_head();
|
||||
let new_git_commit_id = Oid::from_bytes(first_parent_id.as_bytes()).unwrap();
|
||||
let new_git_commit = git_repo.find_commit(new_git_commit_id)?;
|
||||
if git_head != &first_parent {
|
||||
if git_head == &first_parent {
|
||||
// `HEAD@git` already points to the correct commit, so we only need to reset
|
||||
// the Git index. Only do so if it is non-empty (i.e. a user used `git add`).
|
||||
// In large repositories, this is around 2x faster if the Git index is empty
|
||||
// (~0.89s to check the diff, vs. ~1.72s to reset), and around 8% slower if
|
||||
// it isn't (~1.86s to check the diff AND reset).
|
||||
let diff = git_repo.diff_tree_to_index(
|
||||
Some(&new_git_commit.tree()?),
|
||||
None,
|
||||
Some(git2::DiffOptions::new().skip_binary_check(true)),
|
||||
)?;
|
||||
if diff.deltas().len() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
git_repo.set_head_detached(new_git_commit_id)?;
|
||||
mut_repo.set_git_head_target(first_parent);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{mpsc, Arc, Barrier};
|
||||
use std::{fs, iter, thread};
|
||||
|
||||
|
@ -33,6 +33,7 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::op_store::{BranchTarget, RefTarget, RemoteRef, RemoteRefState};
|
||||
use jj_lib::refs::BranchPushUpdate;
|
||||
use jj_lib::repo::{MutableRepo, ReadonlyRepo, Repo};
|
||||
use jj_lib::repo_path::RepoPath;
|
||||
use jj_lib::settings::{GitSettings, UserSettings};
|
||||
use jj_lib::signing::Signer;
|
||||
use jj_lib::str_util::StringPattern;
|
||||
|
@ -2119,6 +2120,50 @@ fn test_reset_head_to_root() {
|
|||
assert!(git_repo.find_reference("refs/jj/root").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reset_head_with_index() {
|
||||
// Create colocated workspace
|
||||
let settings = testutils::user_settings();
|
||||
let temp_dir = testutils::new_temp_dir();
|
||||
let workspace_root = temp_dir.path().join("repo");
|
||||
let git_repo = git2::Repository::init(&workspace_root).unwrap();
|
||||
let (_workspace, repo) =
|
||||
Workspace::init_external_git(&settings, &workspace_root, &workspace_root.join(".git"))
|
||||
.unwrap();
|
||||
|
||||
let mut tx = repo.start_transaction(&settings);
|
||||
let mut_repo = tx.mut_repo();
|
||||
|
||||
let root_commit_id = repo.store().root_commit_id();
|
||||
let tree_id = repo.store().empty_merged_tree_id();
|
||||
let commit1 = mut_repo
|
||||
.new_commit(&settings, vec![root_commit_id.clone()], tree_id.clone())
|
||||
.write()
|
||||
.unwrap();
|
||||
let commit2 = mut_repo
|
||||
.new_commit(&settings, vec![commit1.id().clone()], tree_id.clone())
|
||||
.write()
|
||||
.unwrap();
|
||||
|
||||
// Set Git HEAD to commit2's parent (i.e. commit1)
|
||||
git::reset_head(tx.mut_repo(), &git_repo, &commit2).unwrap();
|
||||
assert!(git_repo.index().unwrap().is_empty());
|
||||
|
||||
// Add "staged changes" to the Git index
|
||||
let file_path = RepoPath::from_internal_string("file.txt");
|
||||
testutils::write_working_copy_file(&workspace_root, file_path, "i am a file\n");
|
||||
git_repo
|
||||
.index()
|
||||
.unwrap()
|
||||
.add_path(&file_path.to_fs_path(Path::new("")))
|
||||
.unwrap();
|
||||
assert!(!git_repo.index().unwrap().is_empty());
|
||||
|
||||
// Reset head to and the Git index
|
||||
git::reset_head(tx.mut_repo(), &git_repo, &commit2).unwrap();
|
||||
assert!(git_repo.index().unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init() {
|
||||
let settings = testutils::user_settings();
|
||||
|
|
Loading…
Reference in a new issue