uninstall static method
Removes FRX-managed hooks from .git/hooks/.
If hookName is provided, removes only that hook.
Otherwise removes all FRX-managed hooks.
Non-FRX hooks are never touched.
Implementation
static Future<void> uninstall({
String? hookName,
String? projectDir,
}) async {
final gitDir = await _findGitDir(projectDir ?? Directory.current.path);
if (gitDir == null) {
print('❌ No .git directory found.');
exit(1);
}
final hooksDir = Directory('${gitDir.path}${Platform.pathSeparator}hooks');
if (!hooksDir.existsSync()) {
print('ℹ️ No .git/hooks/ directory found — nothing to uninstall.');
return;
}
final toRemove = <String>[];
if (hookName != null) {
toRemove.add(hookName.trim().toLowerCase());
} else {
// Find all FRX-managed hook files
for (final entity in hooksDir.listSync()) {
if (entity is File) {
try {
final content = entity.readAsStringSync();
if (content.contains(_kFrxHookMarker)) {
toRemove.add(entity.path.split(Platform.pathSeparator).last);
}
} catch (_) {
// Ignore unreadable files
}
}
}
}
if (toRemove.isEmpty) {
print('ℹ️ No FRX-managed hooks found to uninstall.');
return;
}
print('');
print('🗑️ Uninstalling ${toRemove.length} hook(s)...');
print('');
int removed = 0;
for (final name in toRemove) {
final hookFile = File('${hooksDir.path}${Platform.pathSeparator}$name');
if (!hookFile.existsSync()) {
print(' ⚠️ "$name" not found — skipping.');
continue;
}
final content = hookFile.readAsStringSync();
if (!content.contains(_kFrxHookMarker)) {
print(
' ⚠️ "$name" was not installed by FRX — skipping to avoid data loss.');
continue;
}
hookFile.deleteSync();
print(' 🗑️ Removed: .git/hooks/$name');
removed++;
}
print('');
print('✅ Done! $removed hook(s) removed.');
print('');
}