From e5de32f977433c00388b54ee362307f2b9d03e62 Mon Sep 17 00:00:00 2001 From: Aaron Schrab Date: Wed, 20 Feb 2013 17:57:13 -0500 Subject: [PATCH] Improve parsing of relative references Support parsing of references like HEAD~^2~3^ . Previously, ~ required a following number, ^ didn't allow a following number, and chaining wasn't supported. If at any point in the resolving of the chain the requested parent isn't found report the error by specifying the id of the last commit that was found along with the parent specification to help the user to figure out where the problem arose. --- src/js/git/index.js | 68 ++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/src/js/git/index.js b/src/js/git/index.js index 5c622745..b6bd8c4d 100644 --- a/src/js/git/index.js +++ b/src/js/git/index.js @@ -621,6 +621,36 @@ GitEngine.prototype.resolveID = function(idOrTarget) { return this.resolveStringRef(idOrTarget); }; +GitEngine.prototype.resolveRelativeRef = function(commit, relative) { + var regex = /([~^])(\d*)/g; + var matches; + + while (matches = regex.exec(relative)) { + var next = commit; + var num = matches[2] ? parseInt(matches[2], 10) : 1; + + if (matches[1] == '^') { + next = commit.getParent(num-1); + } + else { + while(next && num--) { + next = next.getParent(0); + } + } + + if (!next) { + var msg = "Commit " + commit.id + " doesn't have a " + matches[0]; + throw new GitError({ + msg: msg + }); + } + + commit = next; + } + + return commit; +}; + GitEngine.prototype.resolveStringRef = function(ref) { if (this.refs[ref]) { return this.refs[ref]; @@ -630,33 +660,21 @@ GitEngine.prototype.resolveStringRef = function(ref) { return this.refs[ref.toUpperCase()]; } - // may be something like HEAD~2 or master^^ - var relativeRefs = [ - [/^([a-zA-Z0-9]+)~(\d+)\s*$/, function(matches) { - return parseInt(matches[2], 10); - }], - [/^([a-zA-Z0-9]+)(\^+)\s*$/, function(matches) { - return matches[2].length; - }] - ]; - + // Attempt to split ref string into a reference and a string of ~ and ^ modifiers. var startRef = null; - var numBack = null; - _.each(relativeRefs, function(config) { - var regex = config[0]; - var parse = config[1]; - if (regex.test(ref)) { - var matches = regex.exec(ref); - numBack = parse(matches); - startRef = matches[1]; - } - }, this); - - if (!startRef) { + var relative = null; + var regex = /^([a-zA-Z0-9]+)(([~^]\d*)*)/; + var matches = regex.exec(ref); + if (matches) { + startRef = matches[1]; + relative = matches[2]; + } + else { throw new GitError({ msg: 'unknown ref ' + ref }); } + if (!this.refs[startRef]) { throw new GitError({ msg: 'the ref ' + startRef +' does not exist.' @@ -664,7 +682,11 @@ GitEngine.prototype.resolveStringRef = function(ref) { } var commit = this.getCommitFromRef(startRef); - return this.numBackFrom(commit, numBack); + if (relative) { + commit = this.resolveRelativeRef( commit, relative ); + } + + return commit; }; GitEngine.prototype.getCommitFromRef = function(ref) {