Conversation
…y done), streamlined TOML gen (mostly done)
…vendoring git2/gix docs in dev
…ck strategy - Add comprehensive GitOperations trait defining all git operations - Implement GixOperations using gitoxide for read operations - Implement Git2Operations as complete fallback using libgit2 - Add GitOpsManager with automatic fallback mechanism - Create detailed status types with bitflags support - Add configuration types for submodule operations - Update lib.rs to expose new git_ops module - Add bitflags dependency to Cargo.toml - Document implementation details and API capabilities This provides the foundation for eliminating git CLI calls and using proper git libraries with a robust fallback strategy.
we're now reuse compliant
…etter sync up with the gitops structures.
- Updated GitOperations trait write_gitmodules to use &mut self - Fixed borrowing conflicts in git2_ops.rs write_gitmodules implementation - Fixed borrowing conflicts in gitoxide_manager.rs init_submodule method - Fixed mutable borrow issue in stash_submodule method - Fixed unused variable warnings - Updated method signatures for sync_with_git_config and load_with_git_sync Still need to fix SubmoduleEntries field visibility issue in gix_ops.rs
- Fixed SerializableBranch value parser issue by changing branch fields from Branch to String - Fixed path handling by adding proper Option<OsString> to String conversion with fallback - Fixed name parameter handling with fallback to derived path from URL - Added type conversions from CLI types to serializable types (Ignore → SerializableIgnore, etc.) - Added handlers for all missing Commands variants to fix non-exhaustive pattern matching - All compilation errors resolved, project now builds successfully - CLI tool is functional and displays help correctly Phase 2 implementation is now complete with all compilation and linting issues resolved.
- Fixed SubmoduleEntry construction in gix_ops.rs by removing non-existent name field and making fields Optional - Fixed git2 operations by replacing non-existent methods with proper git config updates - Fixed Config::load call to use proper three-argument signature - Fixed sparse checkout configuration to use proper sparse_checkouts() method - Fixed URL setting through git config instead of non-existent set_url method - Fixed mutable borrow issues in git2_ops.rs - Cleaned up unused imports and variables to reduce warnings - Fixed move errors by using proper Option handling with as_ref() The code now compiles with only warnings about unused fields and private field access that need to be addressed next.
- Fixed method signatures to use &mut self for write_gitmodules trait methods - Added proper type conversions from CLI enums to serializable types - Fixed Option handling for name and path parameters with proper derivation logic - Simplified sparse_paths processing since CLI already handles comma separation - Added proper error handling and validation for all parameters - Fixed SubmoduleEntries constructor usage The project now compiles successfully with all commands properly connected to the gitoxide_manager backend.
… value manipulation - Replaced gix::config::tree static keys with direct config file manipulation - Updated config reading to use mutable content for from_bytes_owned - Implemented pattern matching for supported config keys (core.bare, user.name, user.email, protocol.file.allow) - Added proper BStr handling for config values and section names - Fixed type system issues with config value setting - Simplified config access logic to use raw value manipulation instead of tree keys - Added proper error handling for unsupported config keys This addresses Phase 2.1 of the Git Operations Refactoring Plan by moving away from static tree keys to a more direct config manipulation approach.
This commit implements the core submodule operations for Phase 2.2 of the refactoring plan, maximizing the use of gix (gitoxide) APIs: Key implementations: - add_submodule(): Implements submodule addition with .gitmodules updates - init_submodule(): Initializes submodules with config setup - update_submodule(): Updates submodules with fetch and checkout logic - delete_submodule(): Removes submodules from .gitmodules and filesystem - deinit_submodule(): Deinitializes submodules with safety checks Technical approach: - Uses gix::File API for .gitmodules reading/writing (as noted by user) - Implements proper error handling with fallback to git2 for complex operations - Handles gix API limitations gracefully (clone, remote, checkout operations) - Maintains compatibility with existing SubmoduleEntry and options structures The implementation follows the refactoring plan's goal of maximizing gix usage while preserving the fallback architecture for operations that are too complex or unstable in the current gix API. Related to: GIT_OPERATIONS_REFACTORING_PLAN.md Phase 2.2
- Replace final 2 CLI calls in git_manager.rs with GitOperations trait methods - git submodule init → self.git_ops.init_submodule(path_str) - git submodule update → self.git_ops.update_submodule(path_str, &update_opts) - All 17 CLI calls from original code review now eliminated - CLI commands in main.rs properly connected to GitManager → GitOpsManager - Phase 3 objectives fully achieved: architectural integration complete Note: Compilation errors in gix_ops.rs are pre-existing issues for Phase 4
- Detailed analysis of cli-improvements branch implementation status - Assessment against original planning documents (FEATURE_CODE_REVIEW.md and GIT_OPERATIONS_REFACTORING_PLAN.md) - Identified 75% completion with 11 compilation errors blocking progress - Architecture integration (Phase 1) and CLI removal (Phase 3) completed successfully - Gix implementation (Phase 2) partially complete with specific technical issues documented - Provided actionable recommendations for completing the implementation - Includes detailed error analysis, success metrics, and timeline estimates
…ssessment-1758204970
|
@bashandbone I've opened a new pull request, #17, to work on those changes. Once the pull request is ready, I'll request review from you. |
…ommands Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Fix build failures, config loading, and wire remaining CLI commands
|
@copilot it looks like we accidentally introduced a duplicate entry in Cargo.toml on the merge commit. Please address and ensure everything is passing before submitting your PR |
|
@bashandbone I've opened a new pull request, #18, to work on those changes. Once the pull request is ready, I'll request review from you. |
…ust) Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Fix duplicate entries in Cargo.toml introduced by merge commit
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 60 out of 68 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| publish = true | ||
| description = "A headache-free submodule management tool, built on top of gitoxide. Manage sparse checkouts, submodule updates, and adding/removing submodules with ease." | ||
| license = "MIT" # Plain MIT license: plainlicense.org/licenses/permissive/mit/ | ||
| license-file = "LICENSE.md" |
There was a problem hiding this comment.
Cargo manifest metadata: license and license-file are mutually exclusive in Cargo.toml. Having both will cause a manifest validation/publish failure; keep only one (typically license = "MIT" or license-file = "LICENSE.md").
| license-file = "LICENSE.md" |
.roo/mcp.json
Outdated
| "-y", | ||
| "@modelcontextprotocol/server-filesystem", | ||
| "~/submod" | ||
| "~/submod", "~/.cargo" |
There was a problem hiding this comment.
Adding ~/.cargo to the filesystem MCP server allowlist is risky because it can contain sensitive material (e.g., registry credentials/tokens in ~/.cargo/credentials). Please avoid granting access to the entire directory; if needed, whitelist only the minimal subpaths required (or omit entirely).
| "~/submod", "~/.cargo" | |
| "~/submod" |
src/utilities.rs
Outdated
| pub(crate) fn name_from_osstring(os_string: std::ffi::OsString) -> Result<String, anyhow::Error> { | ||
| osstring_to_string(os_string).and_then(|s| { | ||
| if s.is_empty() { | ||
| if s.contains('\0') { | ||
| Err(anyhow::anyhow!("Name cannot contain null bytes")) | ||
| } else { | ||
| Ok(s) | ||
| } |
There was a problem hiding this comment.
name_from_osstring() currently treats an empty string as valid and the null-byte check is unreachable (s.is_empty() implies it can't contain \0). Consider validating null bytes before emptiness, and returning an error for empty names (or deriving the name from the path components instead).
src/git_ops/mod.rs
Outdated
| fn add_submodule(&mut self, opts: &SubmoduleAddOptions) -> Result<()> { | ||
| // Try gix first (not yet implemented → falls through), then git2 which now uses | ||
| // the correct `submodule.clone() + add_finalize()` sequence. | ||
| // CLI is kept as a last-resort safety net and sets current_dir to the superproject | ||
| // workdir so it works regardless of the process's CWD. | ||
| self.try_with_fallback_mut( | ||
| |gix| gix.add_submodule(opts), | ||
| |git2| git2.add_submodule(opts), | ||
| ) | ||
| .or_else(|_| { | ||
| let workdir = self.git2_ops.workdir() | ||
| .ok_or_else(|| anyhow::anyhow!("Repository has no working directory"))?; | ||
| let output = std::process::Command::new("git") | ||
| .current_dir(workdir) | ||
| .arg("submodule") | ||
| .arg("add") | ||
| .arg("--name") | ||
| .arg(&opts.name) | ||
| .arg("--") | ||
| .arg(&opts.url) | ||
| .arg(&opts.path) | ||
| .output() |
There was a problem hiding this comment.
GitOpsManager::add_submodule() falls back to git submodule add and only passes --name, url, and path, dropping options like branch, shallow, no_init, and any git settings. If CLI fallback is kept, it should honor SubmoduleAddOptions (or the fallback will behave differently from gix/git2 paths and the CLI contract).
Cargo.toml
Outdated
| "git2", | ||
| "gitmodules", | ||
| "repository", | ||
| "management", | ||
| "command-line", | ||
| "tool", | ||
| "development", | ||
| "utilities", | ||
| "development-tools", |
There was a problem hiding this comment.
keywords contains more than the crates.io limit (max 5). This will be rejected on publish; reduce to the most relevant 5 keywords.
| "git2", | |
| "gitmodules", | |
| "repository", | |
| "management", | |
| "command-line", | |
| "tool", | |
| "development", | |
| "utilities", | |
| "development-tools", |
| ### `submod delete` | ||
|
|
||
| Delete a submodule from configuration and filesystem: | ||
|
|
||
| ```bash | ||
| submod delete | ||
| ``` | ||
|
|
||
| ### `submod disable` | ||
|
|
||
| Disable a submodule without deleting files (sets `active = false`): | ||
|
|
||
| ```bash | ||
| submod disable | ||
| ``` |
There was a problem hiding this comment.
The examples for submod delete and submod disable omit the required submodule name argument. Update the snippets to include an example name (e.g., submod delete my-lib, submod disable my-lib) so users can copy/paste successfully.
sample_config/submod.toml
Outdated
| # | ||
| # ## `shallow` | ||
| # | ||
| # If `true`, performs a shallow clone of the submodule, which means it only fetchest the most recent commit. Defaults to `false`. This is useful for large repositories where you only need the latest commit. |
There was a problem hiding this comment.
Typo in comment: "fetchest" → "fetches".
src/utilities.rs
Outdated
| use anyhow::Ok; | ||
| use git2::Repository as Git2Repository; | ||
| use gix::open::Options; | ||
| use std::path::PathBuf; | ||
| use std::result::Result; |
There was a problem hiding this comment.
use anyhow::Ok; doesn't compile (anyhow doesn't export an Ok item). Also importing std::result::Result here is confusing since the file returns Result<_, anyhow::Error> everywhere; prefer importing anyhow::Result (or just use std::result::Result without the anyhow Ok import).
src/commands.rs
Outdated
| #[arg(short = 'i', long = "ignore", default_value = "unspecified", help = "What changes in the submodule git should ignore.")] | ||
| ignore: Ignore, | ||
|
|
||
| #[arg( | ||
| short = 'x', | ||
| long = "sparse-paths", | ||
| value_delimiter = ',', | ||
| help = "Sparse checkout paths (comma-separated). Can be globs or paths" | ||
| )] | ||
| sparse_paths: Option<Vec<String>>, | ||
|
|
||
| #[arg(short = 'f', long = "fetch", default_value = "unspecified", help = "Sets the recursive fetch behavior for the submodule (like, if we should fetch its submodules).")] | ||
| fetch: FetchRecurse, | ||
|
|
||
| #[arg(short = 'u', long = "update", default_value = "unspecified", help = "How git should update the submodule when you run `git submodule update`.")] | ||
| update: Update, |
There was a problem hiding this comment.
The CLI exposes internal sentinel values by defaulting --ignore/--fetch/--update to "unspecified" (which the help text elsewhere says users shouldn't set). Prefer making these flags Option<...> and treating None as unspecified, or hide the Unspecified variant from clap (e.g., #[value(skip)]) and use a real default.
| fn add_submodule(&mut self, opts: &SubmoduleAddOptions) -> Result<()> { | ||
| // git2 submodule cloning requires remote callbacks that are complex to configure. | ||
| // Fall through to the CLI fallback which handles this reliably. | ||
| Err(anyhow::anyhow!( | ||
| "Unable to add submodule '{}' using the library API; it will be added using the Git CLI instead", | ||
| opts.name | ||
| )) | ||
| } |
There was a problem hiding this comment.
Git2Operations::add_submodule() always returns an error, which makes the Git CLI fallback in GitOpsManager::add_submodule() effectively the primary implementation whenever gix add isn't implemented. This contradicts the gix→git2 fallback design and the PR goal of not relying on the git CLI as a primary mode.
|
@copilot Please implement the suggestions in this thread: #12 (review) For the license/license-file issue, please retain 'license-file' vice license. |
|
@bashandbone I've opened a new pull request, #19, to work on those changes. Once the pull request is ready, I'll request review from you. |
…ity, utilities fixes, options Unspecified skip, CLI fallback improvements, git2 add_submodule implementation Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
…update after cloning Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Address PR review feedback: security, CLI ergonomics, git2 add_submodule, and correctness fixes
This PR introduces a complete overhaul of submod's fallback trait system, comprehensive CLI improvements, improved testing.
The biggest change: it actually uses its fallbacks. The previous release, v0.1.2 had deferred significant complexity in implementing
gitoxideandgit2operations in favor of fallbacks to direct calls togiton the CLI. Put another way: submod was agitcli wrapper.Not anymore.
submodnow makes native use ofgitoxidewhen available, and when not,git2. No more use of git CLI as a primary mode. This PR includes more improvements too -- improved/fully implemented sparse handling, better error handling