Created
May 31, 2025 10:10
-
-
Save tailot/1db3a2c49bdaf9241b82e27d2c0ea322 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage: node removehistoryfromgit.js <path/to/your/file_to_remove.txt> | |
// Example: node removehistoryfromgit.js assets/images/large_confidential_file.jpg | |
// node removehistoryfromgit.js src/old_module.js | |
// | |
// This script completely removes a file from the Git repository's history. | |
// WARNING: This operation REWRITES HISTORY and is DANGEROUS. | |
// ALWAYS BACK UP YOUR REPOSITORY BEFORE RUNNING THIS SCRIPT. | |
// If the repository is shared, this will cause severe issues for collaborators | |
// who will need to re-clone or perform complex rebasing. | |
const { exec } = require('child_process'); | |
const path = require('path'); | |
const readline = require('readline'); | |
const filePathArg = process.argv[2]; | |
if (!filePathArg) { | |
console.error('\n❌ Error: You must specify the path of the file to remove.'); | |
console.log('Usage: node removehistoryfromgit.js <path/relative/to/repo/root/file.ext>'); | |
console.log('Example: node removehistoryfromgit.js src/confidential_data.txt\n'); | |
process.exit(1); | |
} | |
const normalizedFilePath = path.normalize(filePathArg).replace(/\\/g, '/').replace(/^\/+/, ''); | |
const command = `git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch "${normalizedFilePath}"' --prune-empty --tag-name-filter cat -- --all`; | |
console.log(`\n--- ⚠️ CRITICAL WARNING ⚠️ ---`); | |
console.log(`You are about to attempt to COMPLETELY remove the file "${normalizedFilePath}" from this Git repository's history.`); | |
console.log(`This operation REWRITES THE REPOSITORY'S HISTORY.`); | |
console.log(`\n🛑 BEFORE YOU PROCEED:`); | |
console.log(` 1. ENSURE YOU HAVE A COMPLETE BACKUP OF THE REPOSITORY.`); | |
console.log(` 2. IF THIS REPOSITORY IS SHARED, NOTIFY ALL COLLABORATORS. They will need to handle the rewritten history (usually by re-cloning or performing complex rebases).`); | |
console.log(` 3. Understand that this operation is IRREVERSIBLE on your local repository once completed (aside from restoring from your backup).`); | |
console.log(`\nThe Git command that will be executed is:`); | |
console.log(` ${command}`); | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
rl.question('\nAre you absolutely sure you want to proceed? (yes/no): ', (answer) => { | |
rl.close(); | |
if (answer.toLowerCase() !== 'yes' && answer.toLowerCase() !== 'y') { | |
console.log('\nOperation cancelled by the user. No changes have been made.'); | |
process.exit(0); | |
} | |
console.log('\n🚀 Executing command... This process can take a long time for large repositories.'); | |
console.log('Please wait for the completion or error message.\n'); | |
const gitProcess = exec(command, (error, stdout, stderr) => { | |
if (error) { | |
console.error(`\n❌ Error during git filter-branch execution:`); | |
console.error(error.message); | |
if (stderr) { | |
console.error('\nError output (stderr):'); | |
console.error(stderr); | |
} | |
if (stdout) { | |
console.log('\nStandard output (stdout):'); | |
console.log(stdout); | |
} | |
console.log('\n‼️ Operation failed. The repository history has not been modified or might be in an inconsistent state.'); | |
console.log('Check the error messages to understand the cause.'); | |
return; | |
} | |
console.log('\n✅ --- OPERATION COMPLETED SUCCESSFULLY (locally) ---'); | |
if (stderr) { | |
console.log('\nInformational output from git filter-branch (stderr):'); | |
console.log(stderr); | |
} | |
if (stdout && stdout.trim() !== "") { | |
console.log('\nStandard output from git filter-branch (stdout):'); | |
console.log(stdout); | |
} | |
console.log(`\n\n--- 🔥 IMPORTANT POST-REWRITE ACTIONS (TO BE PERFORMED MANUALLY) 🔥 ---`); | |
console.log(`The LOCAL history of your repository has been rewritten.`); | |
console.log(`The file "${normalizedFilePath}" should have been removed from the entire history.`); | |
console.log(`\n 1. CAREFULLY INSPECT THE REPOSITORY:`); | |
console.log(` - Verify that the file has actually been removed from past commits (e.g., using 'git log --all --full-history -- "${normalizedFilePath}"' which should no longer show the file, or 'git log --name-status HEAD~5' to check recent commits).`); | |
console.log(` - Ensure no other files have been inadvertently altered or lost.`); | |
console.log(`\n 2. LOCAL REPOSITORY CLEANUP (Recommended):`); | |
console.log(` git reflog expire --expire=now --all`); | |
console.log(` git gc --prune=now --aggressive`); | |
console.log(` (Note: 'git filter-branch' moves the original refs to 'refs/original/'. You can remove them manually if you are certain about the outcome, e.g., 'git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin' or by deleting specific refs like 'git update-ref -d refs/original/refs/heads/main' etc.)`); | |
console.log(`\n 3. UPDATING THE REMOTE REPOSITORY (IF IT EXISTS):`); | |
console.log(` WARNING: This will overwrite history on the remote server. This is a destructive action for anyone else using the repository.`); | |
console.log(` git push origin --force --all`); | |
console.log(` git push origin --force --tags`); | |
console.log(` (Replace 'origin' with the name of your remote, if different).`); | |
console.log(`\n 4. COMMUNICATE WITH COLLABORATORS:`); | |
console.log(` - All collaborators will need to re-clone the repository or perform complex procedures to synchronize their local copies (e.g., fetch and forcibly rebase their branches).`); | |
console.log(` - It is crucial to notify them BEFORE force-pushing and coordinate the update.`); | |
console.log(`\nIf something went wrong and you have a backup, restore it now.`); | |
console.log(`If you are unsure about these steps, seek help from someone experienced with Git before proceeding with the force push.`); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment