diff --git a/spec/remote.spec.js b/spec/remote.spec.js index 9b5a0b1a..ab1cc5c0 100644 --- a/spec/remote.spec.js +++ b/spec/remote.spec.js @@ -263,8 +263,8 @@ describe('Git Remotes', function() { it('doesnt fetch if out of sync, but will update explicit dest if specified', function() { expectTreeAsync( - 'git clone; git fakeTeamwork; git fetch origin master:master;gc;git fakeTeamwork;git fetch origin master:master', - '{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C2"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"}}}' + 'git clone; git fakeTeamwork; go HEAD~1; git fetch origin master:master;go master; gc; go HEAD~1; git fakeTeamwork;git fetch origin master:master', + '{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"HEAD":{"target":"C2","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C2"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"}}}' ); }); diff --git a/src/js/git/commands.js b/src/js/git/commands.js index e72bd549..471c1492 100644 --- a/src/js/git/commands.js +++ b/src/js/git/commands.js @@ -7,6 +7,8 @@ var GitError = Errors.GitError; var Warning = Errors.Warning; var CommandResult = Errors.CommandResult; +var ORIGIN_PREFIX = 'o/'; + var crappyUnescape = function(str) { return str.replace(/'/g, "'").replace(///g, "/"); }; @@ -30,6 +32,19 @@ var validateBranchNameIfNeeded = function(engine, name) { return validateBranchName(engine, name); }; +var assertNotCheckedOut = function(engine, ref) { + if (!engine.refs[ref]) { + return; + } + if (engine.HEAD.get('target') === engine.refs[ref]) { + throw new GitError({ + msg: intl.todo( + 'cannot fetch to ' + ref + ' when checked out on ' + ref + ) + }); + } +}; + var assertIsBranch = function(engine, ref) { assertIsRef(engine, ref); var obj = engine.refs[ref]; @@ -191,6 +206,10 @@ var commandConfig = { }); } + var commandOptions = command.getOptionsMap(); + var generalArgs = command.getGeneralArgs(); + command.twoArgsImpliedOrigin(generalArgs); + assertOriginSpecified(generalArgs); // here is the deal -- git pull is pretty complex with // the arguments it wants. You can // A) specify the remote branch you want to @@ -201,17 +220,27 @@ var commandConfig = { // the branch to fetch from the remote tracking // and merges those in, or // - // C) specify the colon refspec like fetch (where it - // so lets switch on A/B here + // C) specify the colon refspec like fetch, where it does + // the fetch and then just merges the dest - var commandOptions = command.getOptionsMap(); - var generalArgs = command.getGeneralArgs(); - command.twoArgsImpliedOrigin(generalArgs); - assertOriginSpecified(generalArgs); - - var tracking; - if (generalArgs[1]) { + var source; + var destination; + var firstArg = generalArgs[1]; + // COPY PASTA validation code from fetch. maybe fix this? + if (firstArg && isColonRefspec(firstArg)) { tracking = assertBranchIsRemoteTracking(engine, generalArgs[1]); + var refspecParts = firstArg.split(':'); + source = refspecParts[0]; + destination = validateBranchNameIfNeeded( + engine, + crappyUnescape(refspecParts[1]) + ); + assertNotCheckedOut(engine, destination); + } else if (firstArg) { + source = firstArg; + assertIsBranch(engine.origin, source); + // get o/master locally if master is specified + destination = engine.origin.refs[source].getPrefixedID(); } else { // cant be detached if (engine.getDetachedHead()) { @@ -219,12 +248,18 @@ var commandConfig = { msg: intl.todo('Git pull can not be executed in detached HEAD mode if no remote branch specified!') }); } - var oneBefore = engine.getOneBeforeCommit('HEAD'); - tracking = assertBranchIsRemoteTracking(engine, oneBefore.get('id')); + // ok we need to get our currently checked out branch + // and then specify source and dest + var branch = engine.getOneBeforeCommit('HEAD'); + var branchName = branch.get('id'); + assertBranchIsRemoteTracking(engine, branchName); + destination = branch.getRemoteTrackingBranchID(); + source = destination.replace(ORIGIN_PREFIX, ''); } engine.pull({ - source: tracking, + source: source, + destination: destination, isRebase: commandOptions['--rebase'] }); } @@ -308,6 +343,7 @@ var commandConfig = { engine, crappyUnescape(refspecParts[1]) ); + assertNotCheckedOut(engine, destination); } else if (firstArg) { // here is the deal -- its JUST like git push. the first arg // is used as both the destination and the source, so we need diff --git a/src/js/git/index.js b/src/js/git/index.js index aec553f4..4ea543cf 100644 --- a/src/js/git/index.js +++ b/src/js/git/index.js @@ -1214,18 +1214,21 @@ GitEngine.prototype.fetchCore = function(sourceDestPairs, options) { GitEngine.prototype.pull = function(options) { options = options || {}; var localBranch = this.getOneBeforeCommit('HEAD'); - var remoteBranch = this.refs[options.source]; // no matter what fetch var pendingFetch = this.fetch({ dontResolvePromise: true, - dontThrowOnNoFetch: true + dontThrowOnNoFetch: true, + source: options.source, + destination: options.destination }); + + var destBranch = this.refs[options.destination]; // then either rebase or merge if (options.isRebase) { - this.pullFinishWithRebase(pendingFetch, localBranch, remoteBranch); + this.pullFinishWithRebase(pendingFetch, localBranch, destBranch); } else { - this.pullFinishWithMerge(pendingFetch, localBranch, remoteBranch); + this.pullFinishWithMerge(pendingFetch, localBranch, destBranch); } };