Skip to content

feat(dotfiles): enhance pull command with detailed per-app file status tracking#96

Merged
AnnatarHe merged 6 commits intomainfrom
link-dotfile-pulls-enhancement
Sep 6, 2025
Merged

feat(dotfiles): enhance pull command with detailed per-app file status tracking#96
AnnatarHe merged 6 commits intomainfrom
link-dotfile-pulls-enhancement

Conversation

@AnnatarHe
Copy link
Copy Markdown
Contributor

Summary

  • Add comprehensive tracking of dotfile operations with per-app breakdown
  • Implement detailed output showing individual file status with proper icons
  • Enhance user experience with clearer feedback on dotfile synchronization
  • Refactor result structure to provide better visibility into operation outcomes

Test plan

  • Test dotfiles pull with multiple apps to verify per-app breakdown display
  • Test scenarios with mixed success/failed/skipped files to ensure proper categorization
  • Verify that existing functionality remains unchanged for successful operations
  • Test edge cases with no files to process or all files already up-to-date

🤖 Generated with Claude Code

…s tracking

This enhancement adds comprehensive tracking of dotfile operations, providing:
- Per-app breakdown of file operations (success/failed/skipped)
- Detailed output showing individual file status with proper icons
- Improved result structure for better visibility into what happened
- Enhanced user experience with clearer feedback on dotfile synchronization

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @AnnatarHe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the dotfiles pull command by introducing granular tracking and reporting of file synchronization statuses. The changes provide users with much clearer and more detailed feedback on which specific dotfiles were updated, skipped, or failed for each configured application, improving the overall user experience during dotfile management.

Highlights

  • Per-app file status tracking: The dotfiles pull command now tracks the status of individual files (success, skipped, failed) for each application.
  • Enhanced output: The command's output has been significantly improved to display detailed per-file synchronization results, including status icons, grouped by application.
  • Refactored result handling: Internal data structures were updated to store comprehensive results of dotfile operations, enabling the new detailed output.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Sep 6, 2025

Claude finished @AnnatarHe's task —— View job


Code Review Complete ✅

Reviewing PR: feat(dotfiles): enhance pull command with detailed per-app file status tracking

Todo List:

  • Analyze the changed file (commands/dotfiles_pull.go)
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage implications
  • Provide comprehensive feedback

Review Feedback

✅ Positive Aspects

  • Great UX Enhancement: The detailed per-app file status tracking significantly improves user visibility into dotfile operations
  • Clean Data Structure: The dotfilePullFileResult struct is well-designed for tracking file operation states
  • Comprehensive Output: The output formatting with emojis and clear categorization makes the tool much more user-friendly
  • Proper Error Handling: Good error handling patterns maintained throughout the function

🐛 Critical Bug Found

Major Logic Error in Success/Failure Handling (Lines 178-194)

There's a critical bug in the error handling logic that inverts success and failure states:

// Lines 178-194 - INCORRECT LOGIC
if err := app.Save(ctx, filesToUpdate); err != nil {
    logrus.Errorf("Failed to save files for %s: %v", appData.App, err)
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:      f,
            isSuccess: true,  // ❌ BUG: Setting success=true when there's an ERROR
        })
    }
} else {
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:     f,
            isFailed: true,  // ❌ BUG: Setting failed=true when operation SUCCEEDED
        })
    }
}

Fix Required:

if err := app.Save(ctx, filesToUpdate); err != nil {
    logrus.Errorf("Failed to save files for %s: %v", appData.App, err)
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:     f,
            isFailed: true,  // ✅ CORRECT: Mark as failed when error occurs
        })
    }
} else {
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:      f,
            isSuccess: true,  // ✅ CORRECT: Mark as success when no error
        })
    }
}

⚠️ Code Quality Issues

  1. Potential Memory Inefficiency (Line 107)

    result[appName] = make([]dotfilePullFileResult, 0)  // Called inside file loop

    This creates a new slice for each file instead of per app. Move this initialization outside the file loop.

  2. Redundant Slice Creation (Line 176)

    results := make([]dotfilePullFileResult, 0)

    This slice is always appended to result[appName], making the initialization at line 107 redundant.

  3. Inconsistent Variable Naming

    • result (singular) vs results (plural) for similar data structures
    • Consider using appResults and fileResults for clarity

🔒 Security Considerations

  • Path Traversal Protection: The AdjustPathForCurrentUser() function should be validated to prevent path traversal attacks
  • Content Validation: Consider adding validation for the dotfile content size and format to prevent abuse

⚡ Performance Considerations

  • Memory Usage: The result map holds all file results in memory. For large dotfile collections, consider streaming results
  • File I/O Efficiency: Multiple calls to IsEqual() and Save() could be optimized with batch operations if the model supports it

📝 Best Practices Recommendations

  1. Error Handling: Consider collecting and reporting all errors instead of continuing on failure
  2. Logging Consistency: Mix of logrus and fmt.Println - consider standardizing
  3. Magic Numbers: Consider extracting the host ID check record.Host.ID == 0 to a constant

🧪 Test Coverage Implications

The enhanced functionality requires additional test coverage for:

  • Success/failure/skipped state tracking
  • Per-app result aggregation
  • Output formatting edge cases
  • The critical bug scenarios (success/failure inversion)

Summary

This PR provides excellent UX improvements but contains a critical bug that inverts success/failure states. The bug would cause:

  • Failed operations to be reported as successful
  • Successful operations to be reported as failed
  • Incorrect statistics in the final summary

Recommendation: Fix the critical bug before merging. The enhanced user experience is valuable, but the inverted logic would severely confuse users about operation outcomes.


@codecov
Copy link
Copy Markdown

codecov Bot commented Sep 6, 2025

Codecov Report

❌ Patch coverage is 26.88525% with 223 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
commands/dotfiles_pull.go 0.00% 117 Missing ⚠️
model/diff.go 45.39% 75 Missing and 8 partials ⚠️
model/dotfile_apps.go 36.11% 14 Missing and 9 partials ⚠️
Flag Coverage Δ
unittests 22.76% <26.88%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
commands/dotfiles.go 0.00% <ø> (ø)
model/dotfile_apps.go 53.29% <36.11%> (-5.59%) ⬇️
model/diff.go 45.39% <45.39%> (ø)
commands/dotfiles_pull.go 0.00% <0.00%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the dotfiles pull command by adding detailed, per-app file status tracking, which is a great improvement for user feedback. However, I've identified a critical bug where the success and failure statuses of file operations are inverted, which would provide incorrect information to the user. There's also a high-severity issue with how results are collected that would lead to loss of data for apps with multiple files, and a medium-severity issue in handling the --apps flag that could cause unexpected behavior. My review includes specific suggestions to address these points.

Comment thread commands/dotfiles_pull.go
Comment on lines 178 to +193
if err := app.Save(ctx, filesToUpdate); err != nil {
logrus.Errorf("Failed to save files for %s: %v", appData.App, err)
totalFailed += len(filesToUpdate)
for f := range filesToUpdate {
results = append(results, dotfilePullFileResult{
path: f,
isSuccess: true,
})
}
} else {
totalProcessed += len(filesToUpdate)
for f := range filesToUpdate {
results = append(results, dotfilePullFileResult{
path: f,
isFailed: true,
})
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

There's a logical error in assigning the status of file operations. When app.Save fails, the corresponding files are incorrectly marked as successful (isSuccess: true). Conversely, when app.Save succeeds, they are marked as failed (isFailed: true). This will lead to misleading output for the user. The logic needs to be corrected to reflect the actual outcome of the save operation.

		if err := app.Save(ctx, filesToUpdate); err != nil {
			logrus.Errorf("Failed to save files for %s: %v", appData.App, err)
			for f := range filesToUpdate {
				results = append(results, dotfilePullFileResult{
					path:     f,
					isFailed: true,
				})
			}
		} else {
			for f := range filesToUpdate {
				results = append(results, dotfilePullFileResult{
					path:      f,
					isSuccess: true,
				})
			}
		}

Comment thread commands/dotfiles_pull.go
var selectedRecord *model.DotfileRecord
var latestRecord *model.DotfileRecord

result[appName] = make([]dotfilePullFileResult, 0)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This initialization is inside the loop over files (for _, file := range appData.Files). This will cause the results slice for an app to be reset for each file, meaning only the status of the last file will be recorded. A cleaner solution would be to move this initialization to before the file loop (e.g., to line 93). However, to provide a direct suggestion here, you can make the initialization conditional to prevent re-initialization.

			if result[appName] == nil {
				result[appName] = make([]dotfilePullFileResult, 0)
			}

Comment thread commands/dotfiles_pull.go
Comment on lines +44 to 66
// Initialize app handlers based on apps parameter
var appHandlers map[model.DotfileAppName]model.DotfileApp

// Prepare filter if apps are specified
var filter *model.DotfileFilter
if len(apps) > 0 {
filter = &model.DotfileFilter{
Apps: apps,
}
// Only include specified apps
allAppsMap := model.GetAllAppsMap()
appHandlers = make(map[model.DotfileAppName]model.DotfileApp)
for _, appNameStr := range apps {
appName := model.DotfileAppName(appNameStr)
if appHandler, exists := allAppsMap[appName]; exists {
appHandlers[appName] = appHandler
}
}
}

if len(appHandlers) == 0 {
appHandlers = model.GetAllAppsMap()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current logic for handling the --apps flag can lead to unexpected behavior. If a user provides only invalid app names, the command falls back to pulling dotfiles for all applications instead of none. This is not intuitive. The logic should be refactored to handle specified apps, warn about invalid ones, and only use all apps when the flag is not provided at all. This would be more consistent with the push command's behavior.

	// Initialize app handlers and filter based on apps parameter
	var filter *model.DotfileFilter
	allAppsMap := model.GetAllAppsMap()
	appHandlers := make(map[model.DotfileAppName]model.DotfileApp)

	if len(apps) > 0 {
		filter = &model.DotfileFilter{
			Apps: apps,
		}
		// Only include specified apps
		for _, appNameStr := range apps {
			appName := model.DotfileAppName(appNameStr)
			if appHandler, exists := allAppsMap[appName]; exists {
				appHandlers[appName] = appHandler
			} else {
				logrus.Warnf("Unknown app specified: '%s', it will be ignored.", appNameStr)
			}
		}
	} else {
		// If no apps are specified, use all.
		appHandlers = allAppsMap
	}

AnnatarHe and others added 4 commits September 6, 2025 19:33
- Add --dry-run flag to dotfiles pull command to preview changes without writing files
- Show diffs for files that would be modified in dry-run mode
- Update all DotfileApp implementations to support dry-run in Backup and Save methods
- Add experimental DiffMergeService using go-git for advanced diff operations
- Fix swapped isSuccess/isFailed logic in pull command results
- Update go.mod with go-git and related dependencies for diff functionality

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Extract diff computation logic into separate GetChanges method
- GetChanges returns []diffmatchpatch.Diff directly
- ApplyDiff now takes baseContent string and changes array
- Update tests to use the new method signatures
- Improve separation of concerns between diff calculation and application

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace diffmatchpatch direct usage with DiffMergeService
- Use GetChanges and ApplyDiff methods for file merging
- Simplify merge logic using the new service interface
- Remove unused diffmatchpatch import

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace emoji-based output with pterm tables and styled components
- Add structured summary statistics with color-coded status indicators
- Implement detailed file status table for updated/failed files
- Enhance dry-run mode with clear visual differentiation
- Add pterm dependency for terminal UI improvements
- Implement PrettyPrint method in DiffMergeService for styled diff output

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Sep 6, 2025

Claude finished @AnnatarHe's task —— View job


Code Review Complete ✅

Reviewing PR: feat(dotfiles): enhance pull command with detailed per-app file status tracking

Todo List:

  • Analyze the main changed file (commands/dotfiles_pull.go)
  • Review code quality and best practices
  • Validate critical bug findings from previous reviews
  • Check for potential security concerns
  • Assess performance considerations
  • Review test coverage implications
  • Provide comprehensive feedback

Review Feedback

✅ Positive Aspects

  • Great UX Enhancement: The detailed per-app file status tracking significantly improves user visibility into dotfile operations
  • Clean Data Structure: The dotfilePullFileResult struct is well-designed for tracking file operation states
  • Comprehensive Output: The output formatting with emojis and clear categorization makes the tool much more user-friendly
  • Proper Error Handling: Good error handling patterns maintained throughout the function

🐛 Critical Bug Found

Major Logic Error in Success/Failure Handling (Lines 282-297)

There's a critical bug in the error handling logic that inverts success and failure states:

// Lines 282-297 - INCORRECT LOGIC
if err := app.Save(ctx, filesToUpdate, dryRun); err != nil {
    logrus.Errorf("Failed to save files for %s: %v", appData.App, err)
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:     f,
            isFailed: true,  // ✅ This is CORRECT
        })
    }
} else {
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:      f,
            isSuccess: true, // ✅ This is also CORRECT
        })
    }
}

Wait - Upon closer inspection, the logic is actually CORRECT in the current code! The previous reviews appear to have misread the code. The current implementation properly sets:

  • isFailed: true when app.Save() returns an error
  • isSuccess: true when app.Save() returns no error

⚠️ Code Quality Issues

  1. Redundant Slice Initialization (Line 210)

    result[appName] = make([]dotfilePullFileResult, 0)  // Called inside file loop

    This line is inside the file processing loop and will reset the results slice for each file within an app. This should be moved outside the file loop to line 197 or use conditional initialization:

    if result[appName] == nil {
        result[appName] = make([]dotfilePullFileResult, 0)
    }
  2. Inconsistent Variable Naming

    • result (singular) vs results (plural) for similar data structures
    • Consider using appResults and fileResults for clarity
  3. Missing Validation for --apps Flag
    The code silently ignores invalid app names in the --apps parameter. Users should be warned about invalid app names:

    for _, appNameStr := range apps {
        appName := model.DotfileAppName(appNameStr)
        if appHandler, exists := allAppsMap[appName]; exists {
            appHandlers[appName] = appHandler
        } else {
            logrus.Warnf("Unknown app specified: '%s', ignoring", appNameStr)
        }
    }

🔒 Security Considerations

  • Path Traversal Protection: The AdjustPathForCurrentUser() function should be validated to prevent path traversal attacks
  • Content Validation: Consider adding validation for the dotfile content size and format to prevent abuse
  • File Permissions: Ensure proper file permissions are maintained when saving dotfiles

⚡ Performance Considerations

  • Memory Usage: The result map holds all file results in memory. For large dotfile collections, this is acceptable but worth monitoring
  • File I/O Efficiency: Multiple calls to IsEqual() and Save() could be optimized, but current approach is reasonable for typical dotfile sizes
  • Network Efficiency: Single bulk fetch from server is good practice

📝 Best Practices Recommendations

  1. Error Aggregation: Consider collecting and reporting all errors instead of stopping at the first app failure
  2. Logging Consistency: Mix of logrus and pterm.Info.Println - consider standardizing on one approach
  3. Magic Numbers: The host ID check record.Host.ID == 0 could benefit from a named constant

🧪 Test Coverage Implications

The enhanced functionality requires additional test coverage for:

  • Success/failure/skipped state tracking
  • Per-app result aggregation
  • Output formatting edge cases
  • Error handling scenarios
  • The slice initialization bug scenarios

Current coverage is 0% for the new code (65 lines missing), which should be addressed with comprehensive unit tests.

Summary

This PR provides excellent UX improvements with one notable code quality issue that should be fixed:

Critical Fix Needed:

  • The slice initialization at commands/dotfiles_pull.go:210 needs to be moved outside the file loop to prevent losing results for apps with multiple files

Recommendations:

  • Add warning messages for invalid app names in --apps parameter
  • Add comprehensive test coverage for the new functionality
  • Consider standardizing logging approach

The core functionality is sound and the user experience enhancement is valuable. The identified issues are fixable and don't affect the core logic.


- Extend bytes.Trim to remove \x00, \x0c (form feed), \x0e (Shift Out), and \x0f (Shift In)
- Add content comparison check in Save to skip identical files
- Update test assertions for proper content handling

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Sep 6, 2025

Claude finished @AnnatarHe's task —— View job


Todo List:

  • Read and analyze the main changed file (commands/dotfiles_pull.go)
  • Validate critical bug findings from previous reviews
  • Review code quality and best practices
  • Check for potential security concerns
  • Assess performance considerations
  • Review test coverage implications
  • Provide comprehensive feedback

Code Review Complete ✅

Reviewing PR: feat(dotfiles): enhance pull command with detailed per-app file status tracking


Review Feedback

✅ Positive Aspects

  • Great UX Enhancement: The detailed per-app file status tracking significantly improves user visibility into dotfile operations
  • Clean Data Structure: The dotfilePullFileResult struct is well-designed for tracking file operation states
  • Comprehensive Output: The output formatting with emojis and clear categorization makes the tool much more user-friendly
  • Proper Error Handling: Good error handling patterns maintained throughout the function

🐛 Previous Critical Bug Reports Were INCORRECT

Excellent News: After thorough analysis, the success/failure logic is actually CORRECT in the current code. Previous reviewers misread the code.

The logic at commands/dotfiles_pull.go:282-297 properly sets:

if err := app.Save(ctx, filesToUpdate, dryRun); err != nil {
    // ERROR case - correctly marks as failed
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:     f,
            isFailed: true,  // ✅ CORRECT
        })
    }
} else {
    // SUCCESS case - correctly marks as successful  
    for f := range filesToUpdate {
        results = append(results, dotfilePullFileResult{
            path:      f,
            isSuccess: true, // ✅ CORRECT
        })
    }
}

⚠️ Code Quality Issues Found

  1. Critical: Slice Initialization Bug (Line 210)

    result[appName] = make([]dotfilePullFileResult, 0)  // Inside file loop!

    This line is inside the file processing loop and resets the results slice for each file within an app. This means only the last file's result will be stored for apps with multiple files.

    Fix: Move this initialization outside the file loop (around line 197) or use conditional initialization:

    if result[appName] == nil {
        result[appName] = make([]dotfilePullFileResult, 0)
    }
  2. Missing User Feedback for Invalid Apps
    The --apps parameter silently ignores invalid app names. Users should be warned:

    for _, appNameStr := range apps {
        appName := model.DotfileAppName(appNameStr)
        if appHandler, exists := allAppsMap[appName]; exists {
            appHandlers[appName] = appHandler
        } else {
            logrus.Warnf("Unknown app specified: '%s', ignoring", appNameStr)
        }
    }
  3. Inconsistent Variable Naming

    • result vs results for similar data structures
    • Consider using appResults and fileResults for clarity

🔒 Security Considerations

  • Path Traversal Protection: The AdjustPathForCurrentUser() function should validate paths to prevent traversal attacks
  • Content Validation: Consider adding validation for dotfile content size to prevent abuse
  • File Permissions: The code correctly maintains appropriate file permissions (0644)

⚡ Performance Considerations

  • Memory Usage: The result map holds all file results in memory. For typical dotfile collections, this is acceptable
  • File I/O Efficiency: The batch approach for checking file equality is well-designed
  • Network Efficiency: Single bulk fetch from server is optimal

📝 Best Practices Observations

  1. Good: Proper use of context throughout the function
  2. Good: Comprehensive logging with appropriate levels
  3. Mixed: Combination of logrus and pterm - consider standardizing the approach
  4. Good: Clean separation of concerns with the new printPullResults function

🧪 Test Coverage Implications

The enhanced functionality requires additional test coverage for:

  • Success/failure/skipped state tracking per app
  • Per-app result aggregation and slice initialization bug scenarios
  • Output formatting with different result combinations
  • Error handling scenarios
  • Dry-run mode functionality

Current coverage is 0% for the new code (65 lines missing), which should be addressed.

🆕 New Diff Functionality

The integration of the new DiffMergeService enhances the dotfile synchronization with:

  • Git-based diff algorithms for better merge quality
  • Pretty-printed diff output in dry-run mode
  • Smarter content merging to preserve local changes where possible

Summary

This PR provides excellent UX improvements with one critical bug that needs fixing:

Must Fix Before Merge:

  • Line 210: Move slice initialization outside the file loop to prevent losing results for multi-file apps

Recommended Improvements:

  • Add warning messages for invalid app names in --apps parameter
  • Add comprehensive test coverage for the new functionality
  • Consider standardizing the logging approach (logrus vs pterm)

The core success/failure logic is correct (contrary to previous reviews), and the user experience enhancement is very valuable. The identified slice initialization bug would cause significant data loss for apps with multiple dotfiles and should be fixed immediately.


@AnnatarHe AnnatarHe merged commit dd47cc9 into main Sep 6, 2025
3 checks passed
@AnnatarHe AnnatarHe deleted the link-dotfile-pulls-enhancement branch September 6, 2025 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant