mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-06-25 15:38:33 +02:00
Support for push refspecs with colon, aka master:master or :foo
This commit is contained in:
parent
748eddbd86
commit
f930bae005
8 changed files with 203 additions and 76 deletions
180
build/bundle.js
180
build/bundle.js
|
@ -7602,7 +7602,6 @@ GitEngine.prototype.makeOrigin = function(treeString) {
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.setLocalToTrackRemote = function(localBranch, remoteBranch) {
|
GitEngine.prototype.setLocalToTrackRemote = function(localBranch, remoteBranch) {
|
||||||
remoteBranch.addLocalBranchThatTracksThis(localBranch.get('id'));
|
|
||||||
localBranch.setRemoteTrackingBranchID(remoteBranch.get('id'));
|
localBranch.setRemoteTrackingBranchID(remoteBranch.get('id'));
|
||||||
|
|
||||||
if (!this.command) {
|
if (!this.command) {
|
||||||
|
@ -8087,16 +8086,22 @@ GitEngine.prototype.descendSortDepth = function(objects) {
|
||||||
|
|
||||||
GitEngine.prototype.push = function(options) {
|
GitEngine.prototype.push = function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var localBranch = this.getOneBeforeCommit('HEAD');
|
|
||||||
var remoteBranch = this.refs[options.destination];
|
var remoteBranch = this.refs[options.destination];
|
||||||
var branchOnRemote = this.origin.refs[remoteBranch.getBaseID()];
|
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
|
// first check if this is even allowed by checking the sync between
|
||||||
this.checkUpstreamOfSource(
|
this.checkUpstreamOfSource(
|
||||||
this,
|
this,
|
||||||
this.origin,
|
this.origin,
|
||||||
branchOnRemote,
|
branchOnRemote,
|
||||||
localBranch,
|
sourceLocation,
|
||||||
intl.str('git-error-origin-push-no-ff')
|
intl.str('git-error-origin-push-no-ff')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -8104,7 +8109,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
this.origin,
|
this.origin,
|
||||||
this,
|
this,
|
||||||
branchOnRemote,
|
branchOnRemote,
|
||||||
localBranch
|
sourceLocation
|
||||||
);
|
);
|
||||||
|
|
||||||
// now here is the tricky part -- the difference between local master
|
// now here is the tricky part -- the difference between local master
|
||||||
|
@ -8153,7 +8158,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
chain = chain.then(_.bind(function() {
|
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];
|
var remoteCommit = this.origin.refs[localLocationID];
|
||||||
this.origin.setTargetLocation(branchOnRemote, remoteCommit);
|
this.origin.setTargetLocation(branchOnRemote, remoteCommit);
|
||||||
// unhighlight local
|
// unhighlight local
|
||||||
|
@ -8163,7 +8168,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
|
|
||||||
// HAX HAX update master and remote tracking for master
|
// HAX HAX update master and remote tracking for master
|
||||||
chain = chain.then(_.bind(function() {
|
chain = chain.then(_.bind(function() {
|
||||||
var localCommit = this.getCommitFromRef(localBranch);
|
var localCommit = this.getCommitFromRef(sourceLocation);
|
||||||
this.setTargetLocation(remoteBranch, localCommit);
|
this.setTargetLocation(remoteBranch, localCommit);
|
||||||
return this.animationFactory.playRefreshAnimation(this.gitVisuals);
|
return this.animationFactory.playRefreshAnimation(this.gitVisuals);
|
||||||
}, this));
|
}, this));
|
||||||
|
@ -8173,6 +8178,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) {
|
GitEngine.prototype.fetch = function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
@ -9374,7 +9405,7 @@ GitEngine.prototype.isRemoteBranchRef = function(ref) {
|
||||||
return resolved.getIsRemote();
|
return resolved.getIsRemote();
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.deleteBranch = function(name) {
|
GitEngine.prototype.validateAndDeleteBranch = function(name) {
|
||||||
// trying to delete, lets check our refs
|
// trying to delete, lets check our refs
|
||||||
var target = this.resolveID(name);
|
var target = this.resolveID(name);
|
||||||
|
|
||||||
|
@ -9394,7 +9425,10 @@ GitEngine.prototype.deleteBranch = function(name) {
|
||||||
msg: intl.str('git-error-remote-branch')
|
msg: intl.str('git-error-remote-branch')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.deleteBranch(branch);
|
||||||
|
};
|
||||||
|
|
||||||
|
GitEngine.prototype.deleteBranch = function(branch) {
|
||||||
this.branchCollection.remove(branch);
|
this.branchCollection.remove(branch);
|
||||||
this.refs[branch.get('id')] = undefined;
|
this.refs[branch.get('id')] = undefined;
|
||||||
delete this.refs[branch.get('id')];
|
delete this.refs[branch.get('id')];
|
||||||
|
@ -9665,7 +9699,6 @@ var Branch = Ref.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
visBranch: null,
|
visBranch: null,
|
||||||
remoteTrackingBranchID: null,
|
remoteTrackingBranchID: null,
|
||||||
localBranchesThatTrackThis: null,
|
|
||||||
remote: false
|
remote: false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -9692,20 +9725,6 @@ var Branch = Ref.extend({
|
||||||
return this.get('remoteTrackingBranchID');
|
return this.get('remoteTrackingBranchID');
|
||||||
},
|
},
|
||||||
|
|
||||||
addLocalBranchThatTracksThis: function(localBranch) {
|
|
||||||
this.setLocalBranchesThatTrackThis(
|
|
||||||
this.getLocalBranchesThatTrackThis().concat([localBranch])
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
setLocalBranchesThatTrackThis: function(branches) {
|
|
||||||
this.set('localBranchesThatTrackThis', branches);
|
|
||||||
},
|
|
||||||
|
|
||||||
getLocalBranchesThatTrackThis: function() {
|
|
||||||
return this.get('localBranchesThatTrackThis') || [];
|
|
||||||
},
|
|
||||||
|
|
||||||
getPrefixedID: function() {
|
getPrefixedID: function() {
|
||||||
if (this.getIsRemote()) {
|
if (this.getIsRemote()) {
|
||||||
throw new Error('im already remote');
|
throw new Error('im already remote');
|
||||||
|
@ -10534,13 +10553,11 @@ TreeCompare.reduceTreeFields = function(trees) {
|
||||||
var branchSaveFields = [
|
var branchSaveFields = [
|
||||||
'target',
|
'target',
|
||||||
'id',
|
'id',
|
||||||
'remoteTrackingBranchID',
|
'remoteTrackingBranchID'
|
||||||
'localBranchesThatTrackThis'
|
|
||||||
];
|
];
|
||||||
// for backwards compatibility, fill in some fields if missing
|
// for backwards compatibility, fill in some fields if missing
|
||||||
var defaults = {
|
var defaults = {
|
||||||
remoteTrackingBranchID: null,
|
remoteTrackingBranchID: null
|
||||||
localBranchesThatTrackThis: null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// this function saves only the specified fields of a tree
|
// this function saves only the specified fields of a tree
|
||||||
|
@ -10823,6 +10840,10 @@ var crappyUnescape = function(str) {
|
||||||
return str.replace(/'/g, "'").replace(///g, "/");
|
return str.replace(/'/g, "'").replace(///g, "/");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isColonRefspec(str) {
|
||||||
|
return str.indexOf(':') !== -1 && str.split(':').length === 2;
|
||||||
|
}
|
||||||
|
|
||||||
var assertOriginSpecified = function(generalArgs) {
|
var assertOriginSpecified = function(generalArgs) {
|
||||||
if (generalArgs[0] !== 'origin') {
|
if (generalArgs[0] !== 'origin') {
|
||||||
throw new GitError({
|
throw new GitError({
|
||||||
|
@ -11095,7 +11116,7 @@ var commandConfig = {
|
||||||
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
|
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
|
||||||
|
|
||||||
_.each(names, function(name) {
|
_.each(names, function(name) {
|
||||||
engine.deleteBranch(name);
|
engine.validateAndDeleteBranch(name);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -11369,15 +11390,24 @@ var commandConfig = {
|
||||||
assertOriginSpecified(generalArgs);
|
assertOriginSpecified(generalArgs);
|
||||||
|
|
||||||
var tracking;
|
var tracking;
|
||||||
if (generalArgs[1]) {
|
var source;
|
||||||
tracking = assertBranchIsRemoteTracking(engine, generalArgs[1]);
|
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 {
|
} else {
|
||||||
var oneBefore = engine.getOneBeforeCommit('HEAD');
|
var oneBefore = engine.getOneBeforeCommit('HEAD');
|
||||||
tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id'));
|
tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.push({
|
engine.push({
|
||||||
destination: tracking
|
destination: tracking,
|
||||||
|
source: source
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26122,6 +26152,10 @@ var crappyUnescape = function(str) {
|
||||||
return str.replace(/'/g, "'").replace(///g, "/");
|
return str.replace(/'/g, "'").replace(///g, "/");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isColonRefspec(str) {
|
||||||
|
return str.indexOf(':') !== -1 && str.split(':').length === 2;
|
||||||
|
}
|
||||||
|
|
||||||
var assertOriginSpecified = function(generalArgs) {
|
var assertOriginSpecified = function(generalArgs) {
|
||||||
if (generalArgs[0] !== 'origin') {
|
if (generalArgs[0] !== 'origin') {
|
||||||
throw new GitError({
|
throw new GitError({
|
||||||
|
@ -26394,7 +26428,7 @@ var commandConfig = {
|
||||||
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
|
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
|
||||||
|
|
||||||
_.each(names, function(name) {
|
_.each(names, function(name) {
|
||||||
engine.deleteBranch(name);
|
engine.validateAndDeleteBranch(name);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -26668,15 +26702,24 @@ var commandConfig = {
|
||||||
assertOriginSpecified(generalArgs);
|
assertOriginSpecified(generalArgs);
|
||||||
|
|
||||||
var tracking;
|
var tracking;
|
||||||
if (generalArgs[1]) {
|
var source;
|
||||||
tracking = assertBranchIsRemoteTracking(engine, generalArgs[1]);
|
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 {
|
} else {
|
||||||
var oneBefore = engine.getOneBeforeCommit('HEAD');
|
var oneBefore = engine.getOneBeforeCommit('HEAD');
|
||||||
tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id'));
|
tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.push({
|
engine.push({
|
||||||
destination: tracking
|
destination: tracking,
|
||||||
|
source: source
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27323,7 +27366,6 @@ GitEngine.prototype.makeOrigin = function(treeString) {
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.setLocalToTrackRemote = function(localBranch, remoteBranch) {
|
GitEngine.prototype.setLocalToTrackRemote = function(localBranch, remoteBranch) {
|
||||||
remoteBranch.addLocalBranchThatTracksThis(localBranch.get('id'));
|
|
||||||
localBranch.setRemoteTrackingBranchID(remoteBranch.get('id'));
|
localBranch.setRemoteTrackingBranchID(remoteBranch.get('id'));
|
||||||
|
|
||||||
if (!this.command) {
|
if (!this.command) {
|
||||||
|
@ -27808,16 +27850,22 @@ GitEngine.prototype.descendSortDepth = function(objects) {
|
||||||
|
|
||||||
GitEngine.prototype.push = function(options) {
|
GitEngine.prototype.push = function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var localBranch = this.getOneBeforeCommit('HEAD');
|
|
||||||
var remoteBranch = this.refs[options.destination];
|
var remoteBranch = this.refs[options.destination];
|
||||||
var branchOnRemote = this.origin.refs[remoteBranch.getBaseID()];
|
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
|
// first check if this is even allowed by checking the sync between
|
||||||
this.checkUpstreamOfSource(
|
this.checkUpstreamOfSource(
|
||||||
this,
|
this,
|
||||||
this.origin,
|
this.origin,
|
||||||
branchOnRemote,
|
branchOnRemote,
|
||||||
localBranch,
|
sourceLocation,
|
||||||
intl.str('git-error-origin-push-no-ff')
|
intl.str('git-error-origin-push-no-ff')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -27825,7 +27873,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
this.origin,
|
this.origin,
|
||||||
this,
|
this,
|
||||||
branchOnRemote,
|
branchOnRemote,
|
||||||
localBranch
|
sourceLocation
|
||||||
);
|
);
|
||||||
|
|
||||||
// now here is the tricky part -- the difference between local master
|
// now here is the tricky part -- the difference between local master
|
||||||
|
@ -27874,7 +27922,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
chain = chain.then(_.bind(function() {
|
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];
|
var remoteCommit = this.origin.refs[localLocationID];
|
||||||
this.origin.setTargetLocation(branchOnRemote, remoteCommit);
|
this.origin.setTargetLocation(branchOnRemote, remoteCommit);
|
||||||
// unhighlight local
|
// unhighlight local
|
||||||
|
@ -27884,7 +27932,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
|
|
||||||
// HAX HAX update master and remote tracking for master
|
// HAX HAX update master and remote tracking for master
|
||||||
chain = chain.then(_.bind(function() {
|
chain = chain.then(_.bind(function() {
|
||||||
var localCommit = this.getCommitFromRef(localBranch);
|
var localCommit = this.getCommitFromRef(sourceLocation);
|
||||||
this.setTargetLocation(remoteBranch, localCommit);
|
this.setTargetLocation(remoteBranch, localCommit);
|
||||||
return this.animationFactory.playRefreshAnimation(this.gitVisuals);
|
return this.animationFactory.playRefreshAnimation(this.gitVisuals);
|
||||||
}, this));
|
}, this));
|
||||||
|
@ -27894,6 +27942,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) {
|
GitEngine.prototype.fetch = function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
@ -29095,7 +29169,7 @@ GitEngine.prototype.isRemoteBranchRef = function(ref) {
|
||||||
return resolved.getIsRemote();
|
return resolved.getIsRemote();
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.deleteBranch = function(name) {
|
GitEngine.prototype.validateAndDeleteBranch = function(name) {
|
||||||
// trying to delete, lets check our refs
|
// trying to delete, lets check our refs
|
||||||
var target = this.resolveID(name);
|
var target = this.resolveID(name);
|
||||||
|
|
||||||
|
@ -29115,7 +29189,10 @@ GitEngine.prototype.deleteBranch = function(name) {
|
||||||
msg: intl.str('git-error-remote-branch')
|
msg: intl.str('git-error-remote-branch')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.deleteBranch(branch);
|
||||||
|
};
|
||||||
|
|
||||||
|
GitEngine.prototype.deleteBranch = function(branch) {
|
||||||
this.branchCollection.remove(branch);
|
this.branchCollection.remove(branch);
|
||||||
this.refs[branch.get('id')] = undefined;
|
this.refs[branch.get('id')] = undefined;
|
||||||
delete this.refs[branch.get('id')];
|
delete this.refs[branch.get('id')];
|
||||||
|
@ -29386,7 +29463,6 @@ var Branch = Ref.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
visBranch: null,
|
visBranch: null,
|
||||||
remoteTrackingBranchID: null,
|
remoteTrackingBranchID: null,
|
||||||
localBranchesThatTrackThis: null,
|
|
||||||
remote: false
|
remote: false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -29413,20 +29489,6 @@ var Branch = Ref.extend({
|
||||||
return this.get('remoteTrackingBranchID');
|
return this.get('remoteTrackingBranchID');
|
||||||
},
|
},
|
||||||
|
|
||||||
addLocalBranchThatTracksThis: function(localBranch) {
|
|
||||||
this.setLocalBranchesThatTrackThis(
|
|
||||||
this.getLocalBranchesThatTrackThis().concat([localBranch])
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
setLocalBranchesThatTrackThis: function(branches) {
|
|
||||||
this.set('localBranchesThatTrackThis', branches);
|
|
||||||
},
|
|
||||||
|
|
||||||
getLocalBranchesThatTrackThis: function() {
|
|
||||||
return this.get('localBranchesThatTrackThis') || [];
|
|
||||||
},
|
|
||||||
|
|
||||||
getPrefixedID: function() {
|
getPrefixedID: function() {
|
||||||
if (this.getIsRemote()) {
|
if (this.getIsRemote()) {
|
||||||
throw new Error('im already remote');
|
throw new Error('im already remote');
|
||||||
|
@ -29932,13 +29994,11 @@ TreeCompare.reduceTreeFields = function(trees) {
|
||||||
var branchSaveFields = [
|
var branchSaveFields = [
|
||||||
'target',
|
'target',
|
||||||
'id',
|
'id',
|
||||||
'remoteTrackingBranchID',
|
'remoteTrackingBranchID'
|
||||||
'localBranchesThatTrackThis'
|
|
||||||
];
|
];
|
||||||
// for backwards compatibility, fill in some fields if missing
|
// for backwards compatibility, fill in some fields if missing
|
||||||
var defaults = {
|
var defaults = {
|
||||||
remoteTrackingBranchID: null,
|
remoteTrackingBranchID: null
|
||||||
localBranchesThatTrackThis: null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// this function saves only the specified fields of a tree
|
// this function saves only the specified fields of a tree
|
||||||
|
|
File diff suppressed because one or more lines are too long
1
build/bundle.min.js
vendored
1
build/bundle.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -445,7 +445,7 @@
|
||||||
For a much easier time perusing the source, see the individual files at:
|
For a much easier time perusing the source, see the individual files at:
|
||||||
https://github.com/pcottle/learnGitBranching
|
https://github.com/pcottle/learnGitBranching
|
||||||
-->
|
-->
|
||||||
<script src="build/bundle.min.63fdd97d.js"></script>
|
<script src="build/bundle.js"></script>
|
||||||
|
|
||||||
<!-- The advantage of github pages: super-easy, simple, slick static hostic.
|
<!-- The advantage of github pages: super-easy, simple, slick static hostic.
|
||||||
The downside? No raw logs to parse for analytics, so I have to include
|
The downside? No raw logs to parse for analytics, so I have to include
|
||||||
|
|
|
@ -123,10 +123,31 @@ describe('Git Remotes', function() {
|
||||||
|
|
||||||
it('also sets tracking when just branching', function() {
|
it('also sets tracking when just branching', function() {
|
||||||
expectTreeAsync(
|
expectTreeAsync(
|
||||||
'git clone; git branch side o/master',
|
'git clone; gb side o/master',
|
||||||
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["master","side"]},"side":{"target":"C1","id":"side","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
|
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["master","side"]},"side":{"target":"C1","id":"side","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can push with colon refspec', function() {
|
||||||
|
expectTreeAsync(
|
||||||
|
'git clone; gc; git checkout -b foo HEAD~1; git push master:master',
|
||||||
|
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"foo","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can delete branches with colon refspec', function() {
|
||||||
|
expectTreeAsync(
|
||||||
|
'git branch foo; git clone; git push :foo',
|
||||||
|
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('but it cant delete master on remote', function() {
|
||||||
|
expectTreeAsync(
|
||||||
|
'git branch foo; git clone; git push :master',
|
||||||
|
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":"o/foo"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,10 @@ var crappyUnescape = function(str) {
|
||||||
return str.replace(/'/g, "'").replace(///g, "/");
|
return str.replace(/'/g, "'").replace(///g, "/");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isColonRefspec(str) {
|
||||||
|
return str.indexOf(':') !== -1 && str.split(':').length === 2;
|
||||||
|
}
|
||||||
|
|
||||||
var assertOriginSpecified = function(generalArgs) {
|
var assertOriginSpecified = function(generalArgs) {
|
||||||
if (generalArgs[0] !== 'origin') {
|
if (generalArgs[0] !== 'origin') {
|
||||||
throw new GitError({
|
throw new GitError({
|
||||||
|
@ -283,7 +287,7 @@ var commandConfig = {
|
||||||
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
|
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
|
||||||
|
|
||||||
_.each(names, function(name) {
|
_.each(names, function(name) {
|
||||||
engine.deleteBranch(name);
|
engine.validateAndDeleteBranch(name);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -557,15 +561,24 @@ var commandConfig = {
|
||||||
assertOriginSpecified(generalArgs);
|
assertOriginSpecified(generalArgs);
|
||||||
|
|
||||||
var tracking;
|
var tracking;
|
||||||
if (generalArgs[1]) {
|
var source;
|
||||||
tracking = assertBranchIsRemoteTracking(engine, generalArgs[1]);
|
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 {
|
} else {
|
||||||
var oneBefore = engine.getOneBeforeCommit('HEAD');
|
var oneBefore = engine.getOneBeforeCommit('HEAD');
|
||||||
tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id'));
|
tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.push({
|
engine.push({
|
||||||
destination: tracking
|
destination: tracking,
|
||||||
|
source: source
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -860,16 +860,22 @@ GitEngine.prototype.descendSortDepth = function(objects) {
|
||||||
|
|
||||||
GitEngine.prototype.push = function(options) {
|
GitEngine.prototype.push = function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var localBranch = this.getOneBeforeCommit('HEAD');
|
|
||||||
var remoteBranch = this.refs[options.destination];
|
var remoteBranch = this.refs[options.destination];
|
||||||
var branchOnRemote = this.origin.refs[remoteBranch.getBaseID()];
|
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
|
// first check if this is even allowed by checking the sync between
|
||||||
this.checkUpstreamOfSource(
|
this.checkUpstreamOfSource(
|
||||||
this,
|
this,
|
||||||
this.origin,
|
this.origin,
|
||||||
branchOnRemote,
|
branchOnRemote,
|
||||||
localBranch,
|
sourceLocation,
|
||||||
intl.str('git-error-origin-push-no-ff')
|
intl.str('git-error-origin-push-no-ff')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -877,7 +883,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
this.origin,
|
this.origin,
|
||||||
this,
|
this,
|
||||||
branchOnRemote,
|
branchOnRemote,
|
||||||
localBranch
|
sourceLocation
|
||||||
);
|
);
|
||||||
|
|
||||||
// now here is the tricky part -- the difference between local master
|
// now here is the tricky part -- the difference between local master
|
||||||
|
@ -926,7 +932,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
chain = chain.then(_.bind(function() {
|
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];
|
var remoteCommit = this.origin.refs[localLocationID];
|
||||||
this.origin.setTargetLocation(branchOnRemote, remoteCommit);
|
this.origin.setTargetLocation(branchOnRemote, remoteCommit);
|
||||||
// unhighlight local
|
// unhighlight local
|
||||||
|
@ -936,7 +942,7 @@ GitEngine.prototype.push = function(options) {
|
||||||
|
|
||||||
// HAX HAX update master and remote tracking for master
|
// HAX HAX update master and remote tracking for master
|
||||||
chain = chain.then(_.bind(function() {
|
chain = chain.then(_.bind(function() {
|
||||||
var localCommit = this.getCommitFromRef(localBranch);
|
var localCommit = this.getCommitFromRef(sourceLocation);
|
||||||
this.setTargetLocation(remoteBranch, localCommit);
|
this.setTargetLocation(remoteBranch, localCommit);
|
||||||
return this.animationFactory.playRefreshAnimation(this.gitVisuals);
|
return this.animationFactory.playRefreshAnimation(this.gitVisuals);
|
||||||
}, this));
|
}, 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) {
|
GitEngine.prototype.fetch = function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
@ -2147,7 +2179,7 @@ GitEngine.prototype.isRemoteBranchRef = function(ref) {
|
||||||
return resolved.getIsRemote();
|
return resolved.getIsRemote();
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.deleteBranch = function(name) {
|
GitEngine.prototype.validateAndDeleteBranch = function(name) {
|
||||||
// trying to delete, lets check our refs
|
// trying to delete, lets check our refs
|
||||||
var target = this.resolveID(name);
|
var target = this.resolveID(name);
|
||||||
|
|
||||||
|
@ -2167,7 +2199,10 @@ GitEngine.prototype.deleteBranch = function(name) {
|
||||||
msg: intl.str('git-error-remote-branch')
|
msg: intl.str('git-error-remote-branch')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.deleteBranch(branch);
|
||||||
|
};
|
||||||
|
|
||||||
|
GitEngine.prototype.deleteBranch = function(branch) {
|
||||||
this.branchCollection.remove(branch);
|
this.branchCollection.remove(branch);
|
||||||
this.refs[branch.get('id')] = undefined;
|
this.refs[branch.get('id')] = undefined;
|
||||||
delete this.refs[branch.get('id')];
|
delete this.refs[branch.get('id')];
|
||||||
|
|
4
todo.txt
4
todo.txt
|
@ -10,8 +10,7 @@ Origin things:
|
||||||
Medium things:
|
Medium things:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
[ ] figure out what to do with instant commands (and parse waterfall and the like)
|
[ ] figure out what to do with instant commands (and parse waterfall and the like)
|
||||||
[ ] disable git commands on hg levels
|
[ ] disable git commands on hg levels (and vice versa)
|
||||||
[ ] EASY -- make colors the same between remote branches and their remote counterparts
|
|
||||||
|
|
||||||
Cases to handle / things to edit
|
Cases to handle / things to edit
|
||||||
=======================
|
=======================
|
||||||
|
@ -31,6 +30,7 @@ Ideas for cleaning
|
||||||
Done things:
|
Done things:
|
||||||
(I only started this on Dec 17th 2012 to get a better sense of what was done)
|
(I only started this on Dec 17th 2012 to get a better sense of what was done)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
[x] EASY -- make colors the same between remote branches and their remote counterparts
|
||||||
[x] fix undo not syncing the remote tracking
|
[x] fix undo not syncing the remote tracking
|
||||||
[x] get clone as a before command working in demonstration views (related to test infra as well)
|
[x] get clone as a before command working in demonstration views (related to test infra as well)
|
||||||
[x] importTreeNow fails if origin isnt updated
|
[x] importTreeNow fails if origin isnt updated
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue