Skip to content

Instantly share code, notes, and snippets.

@danielgindi
Last active February 24, 2024 01:44
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save danielgindi/db0e0a897d8d920f23e155bb5d59e9c6 to your computer and use it in GitHub Desktop.
Save danielgindi/db0e0a897d8d920f23e155bb5d59e9c6 to your computer and use it in GitHub Desktop.
Bulk delete Bitbucket LFS files
(() => {
// Run this in Chrome's console, while in Bitbucket's website and logged in
const csrftoken = document.cookie.match(/\bcsrftoken=(.*?)(?:;| |$)/)[1];
const repoName = window.__initial_state__.section.repository.currentRepository.full_name;
const expiry = 1000 * 60 * 60; // Delete only files older than an hour
let page = 1;
function iterateNext() {
fetch(`https://bitbucket.org/${repoName}/admin/lfs/file-management/?iframe=true&spa=0&page=${page}`, {
method: 'GET',
headers: {
'x-csrftoken': csrftoken ,
}
}).then(response => {
return response.text();
}).then(response => {
const matches = response.match(/lfs-file-list--content-hash">(.*?)<\/code>(?:.|\n)*?datetime="(.*?)"/g);
let deletedCount = 0;
let promises = [];
if (!matches || !matches.length) return;
for (let match of matches) {
let parts = match.match(/lfs-file-list--content-hash">(.*?)<\/code>(?:.|\n)*?datetime="(.*?)"/);
let id = parts[1];
let date = new Date(parts[2]);
if ((Date.now() - date) < expiry)
continue;
promises.push(fetch(`https://bitbucket.org/!api/internal/repositories/${repoName}/lfs/${id}`, {
method: 'DELETE',
headers: {
'x-csrftoken': csrftoken,
}
}).then(() => { deletedCount++; }).catch(() => {}));
}
return Promise.all(promises).then(() => {
if (deletedCount === 0)
page++;
}).then(() => {
iterateNext();
});
});
}
iterateNext();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment