mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-06-27 16:38:50 +02:00
Merge pull request #565 from eatdrinksleepcode/revision-range
More robust support for revision ranges
This commit is contained in:
commit
06e0f29acf
6 changed files with 240 additions and 47 deletions
|
@ -574,25 +574,26 @@ var commandConfig = {
|
|||
}
|
||||
},
|
||||
|
||||
revlist: {
|
||||
dontCountForGolf: true,
|
||||
displayName: 'rev-list',
|
||||
regex: /^git +rev-list($|\s)/,
|
||||
execute: function(engine, command) {
|
||||
var generalArgs = command.getGeneralArgs();
|
||||
command.validateArgBounds(generalArgs, 1);
|
||||
|
||||
engine.revlist(generalArgs);
|
||||
}
|
||||
},
|
||||
|
||||
log: {
|
||||
dontCountForGolf: true,
|
||||
regex: /^git +log($|\s)/,
|
||||
execute: function(engine, command) {
|
||||
var generalArgs = command.getGeneralArgs();
|
||||
|
||||
if (generalArgs.length == 2) {
|
||||
// do fancy git log branchA ^branchB
|
||||
if (generalArgs[1][0] == '^') {
|
||||
engine.logWithout(generalArgs[0], generalArgs[1]);
|
||||
} else {
|
||||
throw new GitError({
|
||||
msg: intl.str('git-error-options')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
command.oneArgImpliedHead(generalArgs);
|
||||
engine.log(generalArgs[0]);
|
||||
command.impliedHead(generalArgs, 0);
|
||||
engine.log(generalArgs);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ HeadlessGit.prototype.sendCommand = function(value, entireCommandPromise) {
|
|||
var chain = deferred.promise;
|
||||
var startTime = new Date().getTime();
|
||||
|
||||
var commands = [];
|
||||
|
||||
util.splitTextCommand(value, function(commandStr) {
|
||||
chain = chain.then(function() {
|
||||
var commandObj = new Command({
|
||||
|
@ -117,6 +119,7 @@ HeadlessGit.prototype.sendCommand = function(value, entireCommandPromise) {
|
|||
|
||||
var thisDeferred = Q.defer();
|
||||
this.gitEngine.dispatch(commandObj, thisDeferred);
|
||||
commands.push(commandObj);
|
||||
return thisDeferred.promise;
|
||||
}.bind(this));
|
||||
}, this);
|
||||
|
@ -124,7 +127,7 @@ HeadlessGit.prototype.sendCommand = function(value, entireCommandPromise) {
|
|||
chain.then(function() {
|
||||
var nowTime = new Date().getTime();
|
||||
if (entireCommandPromise) {
|
||||
entireCommandPromise.resolve();
|
||||
entireCommandPromise.resolve(commands);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -2740,37 +2740,26 @@ GitEngine.prototype.logWithout = function(ref, omitBranch) {
|
|||
this.log(ref, Graph.getUpstreamSet(this, omitBranch));
|
||||
};
|
||||
|
||||
GitEngine.prototype.log = function(ref, omitSet) {
|
||||
// omit set is for doing stuff like git log branchA ^branchB
|
||||
omitSet = omitSet || {};
|
||||
// first get the commit we referenced
|
||||
var commit = this.getCommitFromRef(ref);
|
||||
GitEngine.prototype.revlist = function(refs) {
|
||||
var range = new RevisionRange(this, refs);
|
||||
|
||||
// then get as many far back as we can from here, order by commit date
|
||||
var toDump = [];
|
||||
var pQueue = [commit];
|
||||
// now go through and collect ids
|
||||
var bigLogStr = range.formatRevisions(function(c) {
|
||||
return c.id + '\n';
|
||||
});
|
||||
|
||||
var seen = {};
|
||||
throw new CommandResult({
|
||||
msg: bigLogStr
|
||||
});
|
||||
};
|
||||
|
||||
while (pQueue.length) {
|
||||
var popped = pQueue.shift(0);
|
||||
if (seen[popped.get('id')] || omitSet[popped.get('id')]) {
|
||||
continue;
|
||||
}
|
||||
seen[popped.get('id')] = true;
|
||||
|
||||
toDump.push(popped);
|
||||
|
||||
if (popped.get('parents') && popped.get('parents').length) {
|
||||
pQueue = pQueue.concat(popped.get('parents'));
|
||||
}
|
||||
}
|
||||
GitEngine.prototype.log = function(refs) {
|
||||
var range = new RevisionRange(this, refs);
|
||||
|
||||
// now go through and collect logs
|
||||
var bigLogStr = '';
|
||||
toDump.forEach(function (c) {
|
||||
bigLogStr += c.getLogEntry();
|
||||
}, this);
|
||||
var bigLogStr = range.formatRevisions(function(c) {
|
||||
return c.getLogEntry();
|
||||
});
|
||||
|
||||
throw new CommandResult({
|
||||
msg: bigLogStr
|
||||
|
@ -3079,6 +3068,79 @@ var Tag = Ref.extend({
|
|||
}
|
||||
});
|
||||
|
||||
function RevisionRange(engine, specifiers) {
|
||||
this.engine = engine;
|
||||
this.included = {};
|
||||
this.excluded = {};
|
||||
this.revisions = [];
|
||||
|
||||
this.processSpecifiers(specifiers);
|
||||
}
|
||||
|
||||
RevisionRange.prototype.isExclusion = function(specifier) {
|
||||
return specifier.startsWith('^');
|
||||
};
|
||||
|
||||
RevisionRange.prototype.processSpecifiers = function(specifiers) {
|
||||
var self = this;
|
||||
var inclusions = [];
|
||||
var exclusions = [];
|
||||
|
||||
specifiers.forEach(function(specifier) {
|
||||
if(self.isExclusion(specifier)) {
|
||||
exclusions.push(specifier.slice(1));
|
||||
} else {
|
||||
inclusions.push(specifier);
|
||||
}
|
||||
});
|
||||
|
||||
exclusions.forEach(function(exclusion) {
|
||||
self.addExcluded(Graph.getUpstreamSet(self.engine, exclusion));
|
||||
});
|
||||
|
||||
inclusions.forEach(function(inclusion) {
|
||||
self.addIncluded(Graph.getUpstreamSet(self.engine, inclusion));
|
||||
});
|
||||
|
||||
var includedKeys = Array.from(Object.keys(self.included));
|
||||
|
||||
self.revisions = includedKeys.map(function(revision) {
|
||||
return self.engine.resolveStringRef(revision);
|
||||
});
|
||||
self.revisions.sort(self.engine.dateSortFunc);
|
||||
self.revisions.reverse();
|
||||
};
|
||||
|
||||
RevisionRange.prototype.isExcluded = function(revision) {
|
||||
return this.excluded.hasOwnProperty(revision);
|
||||
};
|
||||
|
||||
RevisionRange.prototype.addExcluded = function(setToExclude) {
|
||||
var self = this;
|
||||
Object.keys(setToExclude).forEach(function(toExclude) {
|
||||
if(!self.isExcluded(toExclude)) {
|
||||
self.excluded[toExclude] = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
RevisionRange.prototype.addIncluded = function(setToInclude) {
|
||||
var self = this;
|
||||
Object.keys(setToInclude).forEach(function(toInclude) {
|
||||
if(!self.isExcluded(toInclude)) {
|
||||
self.included[toInclude] = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
RevisionRange.prototype.formatRevisions = function(revisionFormatter) {
|
||||
var output = "";
|
||||
this.revisions.forEach(function(c) {
|
||||
output += revisionFormatter(c);
|
||||
});
|
||||
return output;
|
||||
};
|
||||
|
||||
exports.GitEngine = GitEngine;
|
||||
exports.Commit = Commit;
|
||||
exports.Branch = Branch;
|
||||
|
|
|
@ -126,18 +126,14 @@ var Command = Backbone.Model.extend({
|
|||
oneArgImpliedHead: function(args, option) {
|
||||
this.validateArgBounds(args, 0, 1, option);
|
||||
// and if it's one, add a HEAD to the back
|
||||
if (args.length === 0) {
|
||||
args.push('HEAD');
|
||||
}
|
||||
this.impliedHead(args, 0);
|
||||
},
|
||||
|
||||
twoArgsImpliedHead: function(args, option) {
|
||||
// our args we expect to be between 1 and 2
|
||||
this.validateArgBounds(args, 1, 2, option);
|
||||
// and if it's one, add a HEAD to the back
|
||||
if (args.length == 1) {
|
||||
args.push('HEAD');
|
||||
}
|
||||
this.impliedHead(args, 1);
|
||||
},
|
||||
|
||||
oneArgImpliedOrigin: function(args) {
|
||||
|
@ -151,6 +147,12 @@ var Command = Backbone.Model.extend({
|
|||
this.validateArgBounds(args, 0, 2);
|
||||
},
|
||||
|
||||
impliedHead: function(args, min) {
|
||||
if(args.length == min) {
|
||||
args.push('HEAD');
|
||||
}
|
||||
},
|
||||
|
||||
// this is a little utility class to help arg validation that happens over and over again
|
||||
validateArgBounds: function(args, lower, upper, option) {
|
||||
var what = (option === undefined) ?
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue