diff --git a/__tests__/remote.spec.js b/__tests__/remote.spec.js index 167ea5cb..47f4b3e3 100644 --- a/__tests__/remote.spec.js +++ b/__tests__/remote.spec.js @@ -156,6 +156,29 @@ describe('Git Remotes', function() { ); }); + it('can delete branches with --delete flag', function() { + expectTreeAsync( + 'git branch foo; git clone; git push origin --delete', + '{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":"o/main"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":"o/foo"},"o/main":{"target":"C1","id":"o/main","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{},"HEAD":{"target":"main","id":"HEAD"},"originTree":{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":null},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{},"HEAD":{"target":"main","id":"HEAD"}}}' + ); + + expectTreeAsync( + 'git branch foo; git clone; git push origin --delete main:foo', + '{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":"o/main"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":"o/foo"},"o/main":{"target":"C1","id":"o/main","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{},"HEAD":{"target":"main","id":"HEAD"},"originTree":{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":null},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{},"HEAD":{"target":"main","id":"HEAD"}}}' + ); + + expectTreeAsync( + 'git branch foo; git clone; git push --delete origin foo', + '{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":"o/main"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null},"o/main":{"target":"C1","id":"o/main","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"main","id":"HEAD"},"originTree":{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"main","id":"HEAD"}}}' + ); + + return expectTreeAsync( + 'git branch foo; git clone; git push origin --delete foo', + '{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":"o/main"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null},"o/main":{"target":"C1","id":"o/main","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"main","id":"HEAD"},"originTree":{"branches":{"main":{"target":"C1","id":"main","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"main","id":"HEAD"}}}' + ); + }); + + it('pushes new branch onto server', function() { return expectTreeAsync( 'git clone; git commit; git push origin main:foo', diff --git a/src/js/git/commands.js b/src/js/git/commands.js index 49e3675c..7508f3e2 100644 --- a/src/js/git/commands.js +++ b/src/js/git/commands.js @@ -744,7 +744,9 @@ var commandConfig = { push: { regex: /^git +push($|\s)/, options: [ - '--force' + '--force', + '--delete', + '-d' ], execute: function(engine, command) { if (!engine.hasOrigin()) { @@ -758,14 +760,46 @@ var commandConfig = { var source; var sourceObj; var commandOptions = command.getOptionsMap(); + var isDelete = commandOptions['-d'] || commandOptions['--delete']; // git push is pretty complex in terms of // the arguments it wants as well... get ready! var generalArgs = command.getGeneralArgs(); + + // put the commandOption of delete back in the generalArgs + // as it is a flag option + if(isDelete) { + let option = commandOptions['-d'] || commandOptions['--delete']; + generalArgs = option[0] === 'origin' + ? option.concat(generalArgs) + : generalArgs.concat(option); + } + command.twoArgsForOrigin(generalArgs); assertOriginSpecified(generalArgs); - var firstArg = generalArgs[1]; + + if(isDelete) { + if(!firstArg) { + throw new GitError({ + msg: intl.todo( + '--delete doesn\'t make sense without any refs' + ) + }); + } + + if(isColonRefspec(firstArg)) { + throw new GitError({ + msg: intl.todo( + '--delete only accepts plain target ref names' + ) + }); + } + + // transform delete target ref to delete colon refspec + firstArg = ":"+firstArg; + } + if (firstArg && isColonRefspec(firstArg)) { var refspecParts = firstArg.split(':'); source = refspecParts[0]; @@ -773,7 +807,7 @@ var commandConfig = { if (source === "" && !engine.origin.resolveID(destination)) { throw new GitError({ msg: intl.todo( - 'cannot delete branch ' + options.destination + ' which doesnt exist' + 'cannot delete branch ' + options.destination + ' which doesn\'t exist' ) }); } diff --git a/yarn.lock b/yarn.lock index 08c7d2c9..ca3a77ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3379,12 +3379,12 @@ semver-greatest-satisfied-range@^1.1.0: sver-compat "^1.5.0" "semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" set-blocking@^2.0.0: version "2.0.0"