Refuse to convert to worktree with ignored files
This commit is contained in:
@@ -258,18 +258,22 @@ fn main() {
|
|||||||
process::exit(1);
|
process::exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
let status = repo.status(false).unwrap_or_else(|error| {
|
|
||||||
print_error(&format!("Failed getting repo changes: {}", error));
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
if status.changes.is_some() {
|
|
||||||
print_error("Changes found in repository, refusing to convert");
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
match repo.convert_to_worktree(&cwd) {
|
match repo.convert_to_worktree(&cwd) {
|
||||||
Ok(_) => print_success("Conversion done"),
|
Ok(_) => print_success("Conversion done"),
|
||||||
Err(error) => print_error(&format!("Error during conversion: {}", error)),
|
Err(reason) => {
|
||||||
|
match reason {
|
||||||
|
repo::WorktreeConversionFailureReason::Changes => {
|
||||||
|
print_error("Changes found in repository, refusing to convert");
|
||||||
|
}
|
||||||
|
repo::WorktreeConversionFailureReason::Ignored => {
|
||||||
|
print_error("Ignored files found in repository, refusing to convert. Run git clean -f -d -X to remove them manually.");
|
||||||
|
}
|
||||||
|
repo::WorktreeConversionFailureReason::Error(error) => {
|
||||||
|
print_error(&format!("Error during conversion: {}", error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd::WorktreeAction::Clean(_args) => {
|
cmd::WorktreeAction::Clean(_args) => {
|
||||||
|
|||||||
94
src/repo.rs
94
src/repo.rs
@@ -21,6 +21,12 @@ pub enum WorktreeRemoveFailureReason {
|
|||||||
NotMerged(String),
|
NotMerged(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum WorktreeConversionFailureReason {
|
||||||
|
Changes,
|
||||||
|
Ignored,
|
||||||
|
Error(String),
|
||||||
|
}
|
||||||
|
|
||||||
pub enum GitPushDefaultSetting {
|
pub enum GitPushDefaultSetting {
|
||||||
Upstream,
|
Upstream,
|
||||||
}
|
}
|
||||||
@@ -414,14 +420,40 @@ impl Repo {
|
|||||||
.map_err(|error| format!("Could not set {}: {}", crate::GIT_CONFIG_BARE_KEY, error))
|
.map_err(|error| format!("Could not set {}: {}", crate::GIT_CONFIG_BARE_KEY, error))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_to_worktree(&self, root_dir: &Path) -> Result<(), String> {
|
pub fn convert_to_worktree(
|
||||||
std::fs::rename(".git", crate::GIT_MAIN_WORKTREE_DIRECTORY)
|
&self,
|
||||||
.map_err(|error| format!("Error moving .git directory: {}", error))?;
|
root_dir: &Path,
|
||||||
|
) -> Result<(), WorktreeConversionFailureReason> {
|
||||||
|
if self
|
||||||
|
.status(false)
|
||||||
|
.map_err(WorktreeConversionFailureReason::Error)?
|
||||||
|
.changes
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
return Err(WorktreeConversionFailureReason::Changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self
|
||||||
|
.has_untracked_files(false)
|
||||||
|
.map_err(WorktreeConversionFailureReason::Error)?
|
||||||
|
{
|
||||||
|
return Err(WorktreeConversionFailureReason::Ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::rename(".git", crate::GIT_MAIN_WORKTREE_DIRECTORY).map_err(|error| {
|
||||||
|
WorktreeConversionFailureReason::Error(format!(
|
||||||
|
"Error moving .git directory: {}",
|
||||||
|
error
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
for entry in match std::fs::read_dir(&root_dir) {
|
for entry in match std::fs::read_dir(&root_dir) {
|
||||||
Ok(iterator) => iterator,
|
Ok(iterator) => iterator,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
return Err(format!("Opening directory failed: {}", error));
|
return Err(WorktreeConversionFailureReason::Error(format!(
|
||||||
|
"Opening directory failed: {}",
|
||||||
|
error
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
} {
|
} {
|
||||||
match entry {
|
match entry {
|
||||||
@@ -433,28 +465,41 @@ impl Repo {
|
|||||||
}
|
}
|
||||||
if path.is_file() || path.is_symlink() {
|
if path.is_file() || path.is_symlink() {
|
||||||
if let Err(error) = std::fs::remove_file(&path) {
|
if let Err(error) = std::fs::remove_file(&path) {
|
||||||
return Err(format!("Failed removing {}", error));
|
return Err(WorktreeConversionFailureReason::Error(format!(
|
||||||
|
"Failed removing {}",
|
||||||
|
error
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
} else if let Err(error) = std::fs::remove_dir_all(&path) {
|
} else if let Err(error) = std::fs::remove_dir_all(&path) {
|
||||||
return Err(format!("Failed removing {}", error));
|
return Err(WorktreeConversionFailureReason::Error(format!(
|
||||||
|
"Failed removing {}",
|
||||||
|
error
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
return Err(format!("Error getting directory entry: {}", error));
|
return Err(WorktreeConversionFailureReason::Error(format!(
|
||||||
|
"Error getting directory entry: {}",
|
||||||
|
error
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let worktree_repo = Repo::open(root_dir, true)
|
let worktree_repo = Repo::open(root_dir, true).map_err(|error| {
|
||||||
.map_err(|error| format!("Opening newly converted repository failed: {}", error))?;
|
WorktreeConversionFailureReason::Error(format!(
|
||||||
|
"Opening newly converted repository failed: {}",
|
||||||
|
error
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
worktree_repo
|
worktree_repo
|
||||||
.make_bare(true)
|
.make_bare(true)
|
||||||
.map_err(|error| format!("Error: {}", error))?;
|
.map_err(|error| WorktreeConversionFailureReason::Error(format!("Error: {}", error)))?;
|
||||||
|
|
||||||
worktree_repo
|
worktree_repo
|
||||||
.set_config_push(GitPushDefaultSetting::Upstream)
|
.set_config_push(GitPushDefaultSetting::Upstream)
|
||||||
.map_err(|error| format!("Error: {}", error))?;
|
.map_err(|error| WorktreeConversionFailureReason::Error(format!("Error: {}", error)))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -478,6 +523,33 @@ impl Repo {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_untracked_files(&self, is_worktree: bool) -> Result<bool, String> {
|
||||||
|
match is_worktree {
|
||||||
|
true => Err(String::from(
|
||||||
|
"Cannot get changes as this is a bare worktree repository",
|
||||||
|
)),
|
||||||
|
false => {
|
||||||
|
let statuses = self
|
||||||
|
.0
|
||||||
|
.statuses(Some(git2::StatusOptions::new().include_ignored(true)))
|
||||||
|
.map_err(convert_libgit2_error)?;
|
||||||
|
|
||||||
|
match statuses.is_empty() {
|
||||||
|
true => Ok(false),
|
||||||
|
false => {
|
||||||
|
for status in statuses.iter() {
|
||||||
|
let status_bits = status.status();
|
||||||
|
if status_bits.intersects(git2::Status::IGNORED) {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn status(&self, is_worktree: bool) -> Result<RepoStatus, String> {
|
pub fn status(&self, is_worktree: bool) -> Result<RepoStatus, String> {
|
||||||
let operation = match self.0.state() {
|
let operation = match self.0.state() {
|
||||||
git2::RepositoryState::Clean => None,
|
git2::RepositoryState::Clean => None,
|
||||||
|
|||||||
Reference in New Issue
Block a user