Support for push refspecs with colon, aka master:master or :foo

This commit is contained in:
Peter Cottle 2013-10-09 22:29:05 -07:00
parent 748eddbd86
commit f930bae005
8 changed files with 203 additions and 76 deletions

View file

@ -11,6 +11,10 @@ var crappyUnescape = function(str) {
return str.replace(/'/g, "'").replace(///g, "/");
};
function isColonRefspec(str) {
return str.indexOf(':') !== -1 && str.split(':').length === 2;
}
var assertOriginSpecified = function(generalArgs) {
if (generalArgs[0] !== 'origin') {
throw new GitError({
@ -283,7 +287,7 @@ var commandConfig = {
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
_.each(names, function(name) {
engine.deleteBranch(name);
engine.validateAndDeleteBranch(name);
});
return;
}
@ -557,15 +561,24 @@ var commandConfig = {
assertOriginSpecified(generalArgs);
var tracking;
if (generalArgs[1]) {
tracking = assertBranchIsRemoteTracking(engine, generalArgs[1]);
var source;
var firstArg = generalArgs[1];
if (firstArg) {
if (isColonRefspec(firstArg)) {
var refspecParts = firstArg.split(':');
source = refspecParts[0];
tracking = assertBranchIsRemoteTracking(engine, refspecParts[1]);
} else {
tracking = assertBranchIsRemoteTracking(engine, firstArg);
}
} else {
var oneBefore = engine.getOneBeforeCommit('HEAD');
tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id'));
}
engine.push({
destination: tracking
destination: tracking,
source: source
});
}
}

View file

@ -860,16 +860,22 @@ GitEngine.prototype.descendSortDepth = function(objects) {
GitEngine.prototype.push = function(options) {
options = options || {};
var localBranch = this.getOneBeforeCommit('HEAD');
var remoteBranch = this.refs[options.destination];
var branchOnRemote = this.origin.refs[remoteBranch.getBaseID()];
if (options.source === "") {
// delete case
this.pushDeleteRemoteBranch(remoteBranch, branchOnRemote);
return;
}
var sourceLocation = this.getOneBeforeCommit(options.source || 'HEAD');
// first check if this is even allowed by checking the sync between
this.checkUpstreamOfSource(
this,
this.origin,
branchOnRemote,
localBranch,
sourceLocation,
intl.str('git-error-origin-push-no-ff')
);
@ -877,7 +883,7 @@ GitEngine.prototype.push = function(options) {
this.origin,
this,
branchOnRemote,
localBranch
sourceLocation
);
// now here is the tricky part -- the difference between local master
@ -926,7 +932,7 @@ GitEngine.prototype.push = function(options) {
}, this);
chain = chain.then(_.bind(function() {
var localLocationID = localBranch.get('target').get('id');
var localLocationID = sourceLocation.get('target').get('id');
var remoteCommit = this.origin.refs[localLocationID];
this.origin.setTargetLocation(branchOnRemote, remoteCommit);
// unhighlight local
@ -936,7 +942,7 @@ GitEngine.prototype.push = function(options) {
// HAX HAX update master and remote tracking for master
chain = chain.then(_.bind(function() {
var localCommit = this.getCommitFromRef(localBranch);
var localCommit = this.getCommitFromRef(sourceLocation);
this.setTargetLocation(remoteBranch, localCommit);
return this.animationFactory.playRefreshAnimation(this.gitVisuals);
}, this));
@ -946,6 +952,32 @@ GitEngine.prototype.push = function(options) {
}
};
GitEngine.prototype.pushDeleteRemoteBranch = function(
remoteBranch,
branchOnRemote
) {
if (branchOnRemote.get('id') === 'master') {
throw new GitError({
msg: intl.todo('You cannot delete master branch on remote!')
});
}
// ok so this isn't too bad -- we basically just:
// 1) instruct the remote to delete the branch
// 2) kill off the remote branch locally
// 3) find any branches tracking this remote branch and set them to not track
var id = remoteBranch.get('id');
this.origin.deleteBranch(branchOnRemote);
this.deleteBranch(remoteBranch);
this.branchCollection.each(function(branch) {
if (branch.getRemoteTrackingBranchID() === id) {
branch.setRemoteTrackingBranchID(null);
}
}, this);
// animation needs to be triggered on origin directly
this.origin.externalRefresh();
};
GitEngine.prototype.fetch = function(options) {
options = options || {};
@ -2147,7 +2179,7 @@ GitEngine.prototype.isRemoteBranchRef = function(ref) {
return resolved.getIsRemote();
};
GitEngine.prototype.deleteBranch = function(name) {
GitEngine.prototype.validateAndDeleteBranch = function(name) {
// trying to delete, lets check our refs
var target = this.resolveID(name);
@ -2167,7 +2199,10 @@ GitEngine.prototype.deleteBranch = function(name) {
msg: intl.str('git-error-remote-branch')
});
}
this.deleteBranch(branch);
};
GitEngine.prototype.deleteBranch = function(branch) {
this.branchCollection.remove(branch);
this.refs[branch.get('id')] = undefined;
delete this.refs[branch.get('id')];