Skip to content

Instantly share code, notes, and snippets.

@creationix
Forked from aaronpowell/find-prev.js
Last active December 28, 2015 04:29
Show Gist options
  • Save creationix/7443198 to your computer and use it in GitHub Desktop.
Save creationix/7443198 to your computer and use it in GitHub Desktop.
// repo is assumed to be in closure
var repo;
// commit - the hash of the current commit
// path - the path to the hash in the current commit
// callback -> the previous blob value
function findPrevious(commit, path, callback) {
var log; // The log stream
var currentBlob; // The current value of the blob
var oldBlob; // The last value of the blob
var changeCommit; // The commit that made the last change to the blob
var oldCommit; // The previous commit
// First get the log stream
repo.logWalk(commit, onLog);
function onLog(err, result) {
if (err) return callback(err);
log = result;
// Read the current commit
log.read(onCurrentCommit);
}
function onCurrentCommit(err, result) {
if (err) return callback(err);
changeCommit = result;
// Find the file by path in the current commit
walkPath(changeCommit.tree, path, onCurrentBlob);
}
function onCurrentBlob(err, result) {
if (err) return callback(err);
currentBlob = result;
// Start our search loop looking for a change in the next commit
log.read(onCommit);
}
function onCommit(err, result) {
if (err) return callback(err);
oldCommit = result
if (oldCommit === undefined) {
// We've reached the beginning of history, this was created in the initial commit
return callback(null, {
oldBlob: undefined,
currentBlob: currentBlob,
changeCommit: changeCommit
});
}
walkPath(oldCommit.tree, path, onBlob);
}
function onBlob(err, result) {
if (err) return callback(err);
oldBlob = result;
if ((oldBlob && oldBlob.hash) !== currentBlob.hash) {
return callback(null, {
oldBlob: oldBlob,
currentBlob: currentBlob,
changeCommit: changeCommit
});
}
changeCommit = oldCommit;
log.read(onCommit);
}
}
function walkPath(tree, path, callback) {
// Remove leading and trailing slashes, '.' entries, and split artifacts.
var names = path.split("/").filter(cleanPath);
repo.loadAs("tree", tree, onTree);
function onTree(err, tree) {
if (err) return callback(err);
var name = names.shift();
var entry = findByName(tree, name);
// return undefined for not-found errors
if (!entry) return callback();
// If there are still segments left, keep reading tree paths
if (names.length) return repo.loadAs("tree", entry.hash, onTree);
// Otherwise, load and return the blob
repo.loadAs("blob", entry.hash, callback);
}
}
function findByName(tree, name) {
for (var i = 0, l = tree.length; i < l; i++) {
var entry = tree[i];
if (entry.name === name) return entry;
}
}
function cleanPath(name) {
return name && name !== ".";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment