A tool to help managing forked repos with their own history
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add a --ignore-uncommitted option to the sync command

webbeef d85ac98a 0419ba9c

+52 -7
+2 -2
src/commands/init.rs
··· 42 42 println!("Created forkme.toml"); 43 43 44 44 // Clone the repository 45 - let repo = git::clone_repo(&url, &branch, depth)?; 45 + let repo = git::clone_repo(&url, branch, depth)?; 46 46 47 47 // Create the forkme branch 48 - git::create_forkme_branch(&repo, &branch)?; 48 + git::create_forkme_branch(&repo, branch)?; 49 49 50 50 // Create patches directory 51 51 patch::ensure_patches_dir()?;
+18 -1
src/commands/sync.rs
··· 5 5 use crate::git::{self, FileContent}; 6 6 use crate::patch::{self, PatchEntry}; 7 7 8 - pub fn run() -> Result<()> { 8 + pub fn run(ignore_uncommitted: bool) -> Result<()> { 9 9 let config = Config::load()?; 10 10 let repo = git::open_repo()?; 11 11 git::ensure_on_forkme_branch(&repo)?; ··· 19 19 20 20 // Track which files have been processed 21 21 let mut processed_files: HashSet<String> = HashSet::new(); 22 + let mut skipped_files: Vec<String> = Vec::new(); 22 23 23 24 // Generate and save patches/binaries 24 25 for change in &changes { 26 + // Check if file has uncommitted changes and should be skipped 27 + if ignore_uncommitted && git::has_uncommitted_changes(&repo, &change.path)? { 28 + skipped_files.push(change.path.clone()); 29 + continue; 30 + } 31 + 25 32 // First, remove any existing entries for this file (clean slate) 26 33 patch::delete_all_for_file(&change.path)?; 27 34 ··· 91 98 patch::cleanup_empty_dirs()?; 92 99 93 100 println!("\nSynced {} files.", processed_files.len()); 101 + 102 + if !skipped_files.is_empty() { 103 + println!( 104 + "Skipped {} file(s) with uncommitted changes:", 105 + skipped_files.len() 106 + ); 107 + for file in &skipped_files { 108 + println!(" {}", file); 109 + } 110 + } 94 111 95 112 Ok(()) 96 113 }
+26 -2
src/git.rs
··· 1 1 use anyhow::{bail, Context, Result}; 2 - use git2::{DiffOptions, Repository, ResetType}; 2 + use git2::{DiffOptions, Repository, ResetType, Status}; 3 3 use std::path::Path; 4 4 5 5 pub const SOURCE_DIR: &str = "source"; ··· 79 79 80 80 pub fn is_working_tree_clean(repo: &Repository) -> Result<bool> { 81 81 let statuses = repo.statuses(None)?; 82 - Ok(statuses.is_empty()) 82 + 83 + if !statuses.is_empty() { 84 + for status in &statuses { 85 + if status.status() != Status::IGNORED { 86 + return Ok(false); 87 + } 88 + } 89 + } 90 + Ok(true) 91 + } 92 + 93 + pub fn has_uncommitted_changes(repo: &Repository, file_path: &str) -> Result<bool> { 94 + let statuses = repo.statuses(None)?; 95 + 96 + for entry in statuses.iter() { 97 + if let Some(path) = entry.path() { 98 + if path == file_path { 99 + // Check if file has any uncommitted changes (modified, added, deleted, etc.) 100 + let status = entry.status(); 101 + return Ok(!status.is_empty()); 102 + } 103 + } 104 + } 105 + 106 + Ok(false) 83 107 } 84 108 85 109 pub fn ensure_on_forkme_branch(repo: &Repository) -> Result<()> {
+6 -2
src/main.rs
··· 36 36 Apply, 37 37 38 38 /// Sync changes from source back to patches 39 - Sync, 39 + Sync { 40 + /// Ignore files that have uncommitted changes in the working tree 41 + #[arg(long)] 42 + ignore_uncommitted: bool, 43 + }, 40 44 41 45 /// Show the current status of the forkme project 42 46 Status, ··· 54 58 match cli.command { 55 59 Commands::Init { url, branch, depth } => commands::init::run(url, &branch, depth)?, 56 60 Commands::Apply => commands::apply::run()?, 57 - Commands::Sync => commands::sync::run()?, 61 + Commands::Sync { ignore_uncommitted } => commands::sync::run(ignore_uncommitted)?, 58 62 Commands::Status => commands::status::run()?, 59 63 Commands::Stats => commands::stats::run()?, 60 64 Commands::Update => commands::update::run()?,