Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Worktrees tab #1541

Draft
wants to merge 39 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1e97c96
worktrees tab
heiskane Oct 21, 2022
8635b63
worktree component
heiskane Oct 21, 2022
4a7fd71
list worktrees
heiskane Oct 21, 2022
bb6ea6c
selection kinda implemented
heiskane Oct 22, 2022
63411fd
worktree selection
heiskane Oct 23, 2022
0b693fc
log worktree branchnames
heiskane Oct 23, 2022
3847e3b
worktree branch names
heiskane Oct 23, 2022
cd38ac6
autoformat
heiskane Feb 8, 2023
faaa317
fix scroll
heiskane Feb 8, 2023
3a4f1e5
asd1
heiskane Feb 8, 2023
6d8f9d7
asd2
heiskane Feb 8, 2023
c17cba3
asd3
heiskane Feb 8, 2023
2a52d77
asd4
heiskane Feb 8, 2023
0a5d172
asd5
heiskane Feb 8, 2023
50c1fd9
asd6
heiskane Feb 8, 2023
910984d
asd7
heiskane Feb 8, 2023
d090045
asd8
heiskane Feb 8, 2023
e646cdc
asd9
heiskane Feb 8, 2023
aa5aaae
asd10
heiskane Feb 8, 2023
f53a752
swap from worktree to worktree
heiskane Feb 8, 2023
d95036d
cleanup
heiskane Feb 8, 2023
6f2d43c
optimize performance and implement OpenWorktree event
heiskane Feb 8, 2023
9d9735c
simple worktree creation
heiskane Feb 9, 2023
9703196
key config info strings
heiskane Feb 9, 2023
039b643
validate worktree and display error when trying to open a worktree th…
heiskane Feb 9, 2023
0acfe18
color valid/invalid worktrees green/red
heiskane Feb 10, 2023
90d4908
prune worktree button
heiskane Feb 10, 2023
4c440a5
toggle worktree lock
heiskane Feb 10, 2023
a3c0c52
remove the ugly
heiskane Feb 10, 2023
02a32fb
allow force worktree prune
heiskane Feb 10, 2023
3870f37
mostly fix worktree creation path
heiskane Feb 10, 2023
90a6866
better error handling
heiskane Feb 10, 2023
76c07ff
responsive updates in worktrees
heiskane Feb 10, 2023
06385d1
better error handling
heiskane Feb 10, 2023
c345343
currently selected worktree
heiskane Feb 10, 2023
b18b523
fix current worktree detection
heiskane Feb 10, 2023
e569105
format
heiskane Feb 10, 2023
ec9259c
update scrollbar
heiskane Feb 15, 2023
fcef968
prevent crashes during mysterious sender errors
heiskane Feb 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions asyncgit/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ mod submodules;
mod tags;
mod tree;
pub mod utils;
mod worktree;

pub use blame::{blame_file, BlameHunk, FileBlame};
pub use branch::{
Expand Down Expand Up @@ -96,6 +97,10 @@ pub use utils::{
stage_add_file, stage_addremoved, Head,
};

pub use worktree::{
create_worktree, find_worktree, prune_worktree,
toggle_worktree_lock, worktrees, WorkTree,
};
pub use git2::ResetType;

#[cfg(test)]
Expand Down
8 changes: 7 additions & 1 deletion asyncgit/src/sync/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use std::{
io::Write,
path::{Path, PathBuf},
};

///
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Head {
Expand Down Expand Up @@ -48,6 +47,13 @@ pub fn repo_dir(repo_path: &RepoPath) -> Result<PathBuf> {
///
pub fn repo_work_dir(repo_path: &RepoPath) -> Result<String> {
let repo = repo(repo_path)?;

// TODO: Is this safe?
// Allow Bare repositories
if repo.is_bare() {
return Ok(repo_path.gitpath().to_str().unwrap().to_string());
};

work_dir(&repo)?.to_str().map_or_else(
|| Err(Error::Generic("invalid workdir".to_string())),
|workdir| Ok(workdir.to_string()),
Expand Down
150 changes: 150 additions & 0 deletions asyncgit/src/sync/worktree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use crate::error::Result;
use crate::sync::repository::repo;
use git2::{WorktreeLockStatus, WorktreePruneOptions};
use scopetime::scope_time;
use std::path::{Path, PathBuf};

use super::RepoPath;

/// Represents a worktree
#[derive(Debug)]
pub struct WorkTree {
/// Worktree name (wich is also the folder i think)
pub name: String,
// Worktree branch name
// pub branch: String,
/// Is the worktree valid
pub is_valid: bool,
/// Worktree path
pub path: PathBuf,
/// Is worktree locked
pub is_locked: bool,
/// Can worktree be pruned
pub is_prunable: bool,
/// Is worktree the current worktree
pub is_current: bool,
}

/// Get all worktrees
pub fn worktrees(repo_path: &RepoPath) -> Result<Vec<WorkTree>> {
scope_time!("worktrees");

let repo_obj = repo(repo_path)?;

Ok(repo_obj
.worktrees()?
.iter()
.filter_map(|s| {
if s.is_none() {
log::error!("Error getting worktree: {:?}", s);
};
s
})
.map(|s| {
let wt = repo_obj.find_worktree(s)?;
Ok(WorkTree {
name: s.to_string(),
// branch: worktree_branch(s.unwrap(), &repo_obj).unwrap(),
is_valid: wt.validate().is_ok(),
path: wt.path().to_path_buf(),
is_locked: match wt.is_locked()? {
WorktreeLockStatus::Unlocked => false,
WorktreeLockStatus::Locked(_) => true,
},
is_prunable: wt.is_prunable(None)?,
is_current: wt.path().canonicalize()?
== repo_path.gitpath().canonicalize()?,
})
})
.filter_map(|s: Result<WorkTree>| {
if s.is_err() {
log::error!("Error getting worktree: {:?}", s);
}
s.ok()
})
.collect())
}

/// Find a worktree path
pub fn find_worktree(
repo_path: &RepoPath,
name: &str,
) -> Result<RepoPath> {
scope_time!("find_worktree");

let repo_obj = repo(repo_path)?;

let wt = repo_obj.find_worktree(name)?;
wt.validate()?;

Ok(RepoPath::Path(wt.path().to_path_buf()))
}

/// Create worktree
pub fn create_worktree(
repo_path: &RepoPath,
name: &str,
) -> Result<()> {
scope_time!("create_worktree");

let repo_obj = repo(repo_path)?;
let path_str = repo_path.gitpath().to_str().unwrap();

// WARNING:
// if we are in a worktree assume we want to create a worktree in the parent directory
// This is not always accurate but it should work in most cases
let real_path = match repo_obj.is_worktree() {
true => format!("{}/../{}", path_str, &name),
false => format!("{}{}", path_str, &name),
};

log::trace!("creating worktree in {:?}", real_path);
repo_obj.worktree(name, &Path::new(&real_path), None)?;

Ok(())
}

/// Prune a worktree
pub fn prune_worktree(
repo_path: &RepoPath,
name: &str,
force: bool,
) -> Result<()> {
scope_time!("prune_worktree");

let repo_obj = repo(repo_path)?;

let wt = repo_obj.find_worktree(name)?;
wt.is_prunable(None)?;

wt.prune(Some(
WorktreePruneOptions::new()
.valid(force)
.locked(force)
.working_tree(force),
))?;

Ok(())
}

/// Toggle lock on a worktree
pub fn toggle_worktree_lock(
repo_path: &RepoPath,
name: &str,
) -> Result<()> {
scope_time!("toggle_lock_worktree");

let repo_obj = repo(repo_path)?;

let wt = repo_obj.find_worktree(name)?;

// fails to create is branch already exists
wt.validate()?;

match wt.is_locked().unwrap() {
WorktreeLockStatus::Unlocked => wt.lock(None)?,
WorktreeLockStatus::Locked(_) => wt.unlock()?,
}

Ok(())
}
Loading