[Origin] Implement basic git fetch force need to fix up animations

This commit is contained in:
Peter Cottle 2013-05-26 23:44:07 -07:00
parent 3a23973a9a
commit 6080d324ce
9 changed files with 468 additions and 73 deletions

View file

@ -87,6 +87,34 @@ GitEngine.prototype.isOrigin = function() {
return !!this.localRepo;
};
GitEngine.prototype.exportTreeForBranch = function(branchName) {
// this method exports the tree and then prunes everything that
// is not connected to branchname
var tree = this.exportTree();
// get the upstream set
var set = this.getUpstreamSet(branchName);
// now loop through and delete commits
var commitsToLoop = tree.commits;
tree.commits = {};
_.each(commitsToLoop, function(commit, id) {
if (set[id]) {
// if included in target branch
tree.commits[id] = commit;
}
});
var branchesToLoop = tree.branches;
tree.branches = {};
_.each(branchesToLoop, function(branch, id) {
if (id === branchName) {
tree.branches[id] = branch;
}
});
tree.HEAD.target = branchName;
return tree;
};
GitEngine.prototype.exportTree = function() {
// need to export all commits, their connectivity / messages, branches, and state of head.
// this would be simple if didn't have circular structures.... :P
@ -210,17 +238,18 @@ GitEngine.prototype.makeOrigin = function(treeString) {
msg: intl.str('git-error-origin-exists')
});
}
treeString = treeString || this.printTree(this.exportTreeForBranch('master'));
// this is super super ugly but a necessary hack because of the way LGB was
// originally designed. We need to get to the top level visualization from
// the git engine -- aka we need to access our own visuals, then the
// visualization and ask the main vis to create a new vis/git pair. Then
// we grab the gitengine out of that and assign that as our origin repo
// which connects the two
// which connects the two. epic
var masterVis = this.gitVisuals.getVisualization();
var originVis = masterVis.makeOrigin({
localRepo: this,
treeString: treeString || this.printTree()
treeString: treeString
});
// defer the starting of our animation until origin has been created
@ -234,6 +263,17 @@ GitEngine.prototype.makeOrigin = function(treeString) {
this.animationQueue.start();
}, this);
// TODO handle the case where the master target on origin is not present
// locally, so we have to go up the chain. for now we assume the master on
// origin is at least present
var originTree = JSON.parse(unescape(treeString));
var originMasterTarget = originTree.branches.master.target;
var originMaster = this.makeBranch(
'o/master',
this.getCommitFromRef(originMasterTarget)
);
originMaster.set('remote', true);
// add a simple refresh animation
this.animationFactory.refreshTree(this.animationQueue, this.gitVisuals);
};
@ -378,7 +418,7 @@ GitEngine.prototype.validateBranchName = function(name) {
return name;
};
GitEngine.prototype.makeBranch = function(id, target) {
GitEngine.prototype.validateAndMakeBranch = function(id, target) {
id = this.validateBranchName(id);
if (this.refs[id]) {
throw new GitError({
@ -389,6 +429,10 @@ GitEngine.prototype.makeBranch = function(id, target) {
});
}
this.makeBranch(id, target);
};
GitEngine.prototype.makeBranch = function(id, target) {
var branch = new Branch({
target: target,
id: id
@ -439,7 +483,20 @@ GitEngine.prototype.printBranches = function(branches) {
GitEngine.prototype.getUniqueID = function() {
var id = this.uniqueId('C');
while (this.refs[id]) {
var hasID = _.bind(function(idToCheck) {
// loop through and see if we have it locally or
// remotely
if (this.refs[idToCheck]) {
return true;
}
if (this.origin && this.origin.refs[idToCheck]) {
return true;
}
return false;
}, this);
while (hasID(id)) {
id = this.uniqueId('C');
}
return id;
@ -532,10 +589,6 @@ GitEngine.prototype.revertStarter = function() {
}
};
GitEngine.prototype.originInitStarter = function() {
this.makeOrigin(this.printTree());
};
GitEngine.prototype.revert = function(whichCommits) {
// for each commit, we want to revert it
var toRebase = [];
@ -666,7 +719,78 @@ GitEngine.prototype.cherrypickStarter = function() {
this.animationFactory.rebaseAnimation(this.animationQueue, animationResponse, this, this.gitVisuals);
};
/*************************************
* Origin stuff!
************************************/
GitEngine.prototype.fetchStarter = function() {
if (!this.hasOrigin()) {
throw new GitError({
msg: intl.str('git-error-origin-required')
});
}
this.acceptNoGeneralArgs();
this.fetch();
};
GitEngine.prototype.fetch = function() {
// TODO refactor to use rebase animation stuff!!
// ok so we essentially are always in "-force" mode, since we always assume
// the origin commits are downstream of where we are. Here is the outline:
//
// first we get the commits we need by exporting the origin tree and
// walking upwards until we hit the upstream set defined by origin/master.
//
// then we simply set the target of o/master to the target of master on
// the origin branch
var oldCommits = this.exportTree().commits;
// HAX HAX omg we will abuse our tree instantiation here :D
var originTree = this.origin.exportTree();
_.each(originTree.commits, function(commit, id) {
// if we have it, no worries
if (this.refs[id]) {
return;
}
// go make it!
var downloadedCommit = this.getOrMakeRecursive(originTree, this.refs, id);
this.commitCollection.add(downloadedCommit);
}, this);
// since we now might have many commits more than before, lets
// check all the ones that didn't use to exist and make animations
var newCommits = this.exportTree().commits;
var commitsToAnimate = [];
_.each(newCommits, function(commit, id) {
if (oldCommits[id]) {
return;
}
commitsToAnimate.push(this.refs[id]);
}, this);
// now sort by id...
commitsToAnimate.sort(_.bind(this.idSortFunc, this));
_.each(commitsToAnimate, function(newCommit) {
this.animationFactory.genCommitBirthAnimation(
this.animationQueue,
newCommit,
this.gitVisuals
);
}, this);
var originLocation = this.origin.exportTree().branches.master.target;
// yay! now we just set o/master and do a simple refresh
this.setTargetLocation(this.refs['o/master'], this.refs[originLocation]);
this.animationFactory.refreshTree(this.animationQueue, this.gitVisuals);
};
GitEngine.prototype.originInitStarter = function() {
this.acceptNoGeneralArgs();
this.makeOrigin(this.printTree(this.exportTreeForBranch('master')));
};
GitEngine.prototype.fakeTeamworkStarter = function() {
this.acceptNoGeneralArgs();
if (!this.hasOrigin()) {
throw new GitError({
msg: intl.str('git-error-origin-required')
@ -674,9 +798,6 @@ GitEngine.prototype.fakeTeamworkStarter = function() {
}
var id = this.getUniqueID();
// fill refs so it is not grabbed again
this.refs[id] = {};
this.origin.receiveTeamwork(id, this.animationQueue);
};
@ -818,6 +939,7 @@ GitEngine.prototype.resolveRelativeRef = function(commit, relative) {
};
GitEngine.prototype.resolveStringRef = function(ref) {
ref = this.crappyUnescape(ref);
if (this.refs[ref]) {
return this.refs[ref];
}
@ -1396,7 +1518,7 @@ GitEngine.prototype.checkoutStarter = function() {
this.validateArgBounds(this.generalArgs, 1, 1);
this.checkout(this.unescapeQuotes(this.generalArgs[0]));
this.checkout(this.crappyUnescape(this.generalArgs[0]));
};
GitEngine.prototype.checkout = function(idOrTarget) {
@ -1408,6 +1530,11 @@ GitEngine.prototype.checkout = function(idOrTarget) {
}
var type = target.get('type');
// check if this is an origin branch, and if so go to the commit referenced
if (type === 'branch' && target.getIsRemote()) {
target = this.getCommitFromRef(target.get('id'));
}
if (type !== 'branch' && type !== 'commit') {
throw new GitError({
msg: intl.str('git-error-options')
@ -1476,7 +1603,7 @@ GitEngine.prototype.forceBranch = function(branchName, where) {
GitEngine.prototype.branch = function(name, ref) {
var target = this.getCommitFromRef(ref);
this.makeBranch(name, target);
this.validateAndMakeBranch(name, target);
};
GitEngine.prototype.deleteBranch = function(name) {
@ -1504,8 +1631,8 @@ GitEngine.prototype.deleteBranch = function(name) {
}
};
GitEngine.prototype.unescapeQuotes = function(str) {
return str.replace(/'/g, "'");
GitEngine.prototype.crappyUnescape = function(str) {
return str.replace(/'/g, "'").replace(///g, '/');
};
GitEngine.prototype.filterError = function(err) {
@ -1758,11 +1885,11 @@ var Ref = Backbone.Model.extend({
var Branch = Ref.extend({
defaults: {
visBranch: null,
origin: null
remote: false
},
getIsRemote: function() {
return this.get('origin') !== null;
return this.get('remote');
},
initialize: function() {