diff --git a/spec/base.js b/spec/base.js index 86dc94d1..11e15a11 100644 --- a/spec/base.js +++ b/spec/base.js @@ -52,7 +52,7 @@ var expectTreeAsync = function(command, expectedJSON) { }); waitsFor(function() { var diff = (Date.now() - start); - if (diff > TIME - 50 && !haveReported) { + if (diff > TIME - 20 && !haveReported) { haveReported = true; console.log('not going to match', command); console.log('expected\n>>>>>>>>\n', loadTree(expectedJSON)); diff --git a/spec/create.js b/spec/create.js index f934d743..827af467 100644 --- a/spec/create.js +++ b/spec/create.js @@ -9,7 +9,10 @@ prompt.get(['command'], function(err, result) { var headless = new HeadlessGit(); headless.sendCommand(result.command); setTimeout(function() { - console.log(headless.gitEngine.printTree()); + console.log('expectTreeAsync('); + console.log(" \t'" + result.command + "',"); + console.log(" \t'" + headless.gitEngine.printTree() + "'"); + console.log(');'); }, 100); }); diff --git a/spec/remote.spec.js b/spec/remote.spec.js index a68f71c0..b4e01ac0 100644 --- a/spec/remote.spec.js +++ b/spec/remote.spec.js @@ -109,7 +109,7 @@ describe('Git Remotes', function() { it('pushes to another remote', function() { expectTreeAsync( - 'git branch side; git clone;git commit; git push origin side', + 'git branch side; git clone;git commit; git push origin HEAD:side', '{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"side":{"target":"C1","id":"side","remoteTrackingBranchID":"o/side"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["master"]},"o/side":{"target":"C2","id":"o/side","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["side"]}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"side":{"target":"C2","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}' ); }); @@ -117,7 +117,7 @@ describe('Git Remotes', function() { it('pushes to tracking remote', function() { expectTreeAsync( 'git branch side; git clone;git commit;git push; go side; git commit; git push', - '{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"side":{"target":"C3","id":"side","remoteTrackingBranchID":"o/side"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["master"]},"o/side":{"target":"C3","id":"o/side","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["side"]}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"side","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"side":{"target":"C3","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"master","id":"HEAD"}}}' + '{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"side":{"target":"C3","id":"side","remoteTrackingBranchID":"o/side"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"o/side":{"target":"C3","id":"o/side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"side","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"side":{"target":"C3","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"master","id":"HEAD"}}}' ); }); @@ -151,7 +151,7 @@ describe('Git Remotes', function() { it('pushes new branch onto server', function() { expectTreeAsync( - 'git clone; git commit; git push origin foo', + 'git clone; git commit; git push origin master:foo', '{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C2","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}' ); }); @@ -184,5 +184,26 @@ describe('Git Remotes', function() { ); }); + it('will not push to a remote if the local ref does not exist', function() { + expectTreeAsync( + 'git clone; git push origin foo', + '{"branches":{"master":{"target":"C1","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"}},"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('will push to the remote branch IF IT has tracking', function() { + expectTreeAsync( + 'git clone; git checkout -b foo o/master; git commit; git push', + '{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":"o/master"}},"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('will push to a new remote branch if no tracking is set up', function() { + expectTreeAsync( + 'git clone; git checkout -b foo; git commit; git push', + '{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":"o/foo"},"o/foo":{"target":"C2","id":"o/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":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}' + ); + }); + }); diff --git a/src/js/git/commands.js b/src/js/git/commands.js index ba95abe7..9be6916c 100644 --- a/src/js/git/commands.js +++ b/src/js/git/commands.js @@ -19,7 +19,7 @@ var assertIsRef = function(engine, ref) { engine.resolveID(ref); // will throw giterror if cant resolve }; -var validateAndAssertBranchName = function(engine, name) { +var validateBranchName = function(engine, name) { return engine.validateBranchName(name); }; @@ -576,19 +576,29 @@ var commandConfig = { if (isColonRefspec(firstArg)) { var refspecParts = firstArg.split(':'); source = refspecParts[0]; - destination = validateAndAssertBranchName(engine, refspecParts[1]); + destination = validateBranchName(engine, refspecParts[1]); } else { - // we are using this arg as destination -- source is one before head - destination = firstArg; - source = engine.getOneBeforeCommit('HEAD').get('id'); + // we are using this arg as destination AND source. the dest branch + // can be created on demand but we at least need this to be a source + // locally otherwise we will fail + source = destination = firstArg; } } else { // since they have not specified a source or destination, then - // we source from the branch we are on (or HEAD) and push to - // the branch we are on - source = engine.getOneBeforeCommit('HEAD').get('id'); - destination = source; - assertBranchIsRemoteTracking(engine, source); + // we source from the branch we are on (or HEAD) + var sourceObj = engine.getOneBeforeCommit('HEAD'); + source = sourceObj.get('id'); + + // HOWEVER we push to either the remote tracking branch we have + // OR a new named branch if we aren't tracking anything + if (sourceObj.getRemoteTrackingBranchID && + sourceObj.getRemoteTrackingBranchID()) { + assertBranchIsRemoteTracking(engine, source); + var remoteBranch = sourceObj.getRemoteTrackingBranchID(); + destination = engine.refs[remoteBranch].getBaseID(); + } else { + destination = validateBranchName(engine, source); + } } if (source) { assertIsRef(engine, source);