From 406cf49b8daa5b583aa83c61c6438e04861e3dec Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 25 Oct 2016 14:09:36 -0700 Subject: [PATCH 1/7] Fix :bug: in PushPullMenuView --- lib/views/push-pull-menu-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/push-pull-menu-view.js b/lib/views/push-pull-menu-view.js index 6999055cb8..5f4560df60 100644 --- a/lib/views/push-pull-menu-view.js +++ b/lib/views/push-pull-menu-view.js @@ -10,7 +10,7 @@ export default class PushPullMenuView { } update (props) { - this.props = props + this.props = Object.assign({}, this.props, props) return etch.update(this) } From 44da5929fc874afd7164549aea2365bc410953af Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 25 Oct 2016 14:17:55 -0700 Subject: [PATCH 2/7] :fire: console.log --- lib/controllers/status-bar-tile-controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/controllers/status-bar-tile-controller.js b/lib/controllers/status-bar-tile-controller.js index 545540b86b..6d8f5aa28c 100644 --- a/lib/controllers/status-bar-tile-controller.js +++ b/lib/controllers/status-bar-tile-controller.js @@ -162,7 +162,6 @@ export default class StatusBarTileController { pull () { const {pullDisabled, branchName} = this.repositoryObserver.getActiveModelData() - console.log('status bar pull'); return pullDisabled ? Promise.resolve() : this.getActiveRepository().pull(branchName) } From ab23b9cfda26f5aee1d236489296484265ee1395 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 25 Oct 2016 17:20:04 -0700 Subject: [PATCH 3/7] Enable force pushing by holding down meta key when clicking "Push" button --- lib/controllers/status-bar-tile-controller.js | 4 +-- lib/git-shell-out-strategy.js | 10 ++++--- lib/models/repository.js | 4 +-- lib/views/push-pull-menu-view.js | 18 ++++++++++++- styles/push-pull-menu-view.less | 17 ++++++++++++ .../status-bar-tile-controller.test.js | 27 +++++++++++++++++++ 6 files changed, 71 insertions(+), 9 deletions(-) diff --git a/lib/controllers/status-bar-tile-controller.js b/lib/controllers/status-bar-tile-controller.js index 6d8f5aa28c..c466c8eb8f 100644 --- a/lib/controllers/status-bar-tile-controller.js +++ b/lib/controllers/status-bar-tile-controller.js @@ -155,9 +155,9 @@ export default class StatusBarTileController { return this.getActiveRepository().checkout(branchName, options) } - push () { + push (options) { const {branchName} = this.repositoryObserver.getActiveModelData() - return this.getActiveRepository().push(branchName) + return this.getActiveRepository().push(branchName, options) } pull () { diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 7b0727eec2..224b4d4864 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -91,7 +91,7 @@ export default class GitShellOutStrategy { * File Status and Diffs */ async diffFileStatus (options = {}) { - let args = ['diff', '--name-status', '--no-renames'] + const args = ['diff', '--name-status', '--no-renames'] if (options.staged) args.push('--staged') if (options.target) args.push(options.target) if (options.diffFilter === 'unmerged') args.push('--diff-filter=U') @@ -121,7 +121,7 @@ export default class GitShellOutStrategy { } async diff (options = {}) { - let args = ['diff', '--no-prefix', '--no-renames', '--diff-filter=u'] + const args = ['diff', '--no-prefix', '--no-renames', '--diff-filter=u'] if (options.staged) args.push('--staged') if (options.baseCommit) args.push(options.baseCommit) let output = await this.exec(args) @@ -231,9 +231,11 @@ export default class GitShellOutStrategy { } } - async push (branchName) { + async push (branchName, options = {}) { const remote = await this.getRemote(branchName) - return this.exec(['push', remote, branchName]) + const args = ['push', remote, branchName] + if (options.force) args.push('--force') + return this.exec(args) } async getAheadCount (branchName) { diff --git a/lib/models/repository.js b/lib/models/repository.js index b5b7b2977b..7c7fb8f1f7 100644 --- a/lib/models/repository.js +++ b/lib/models/repository.js @@ -321,8 +321,8 @@ export default class Repository { return this.git.readFileFromIndex(path) } - push (branchName) { - return this.git.push(branchName) + push (branchName, options) { + return this.git.push(branchName, options) } fetch (branchName) { diff --git a/lib/views/push-pull-menu-view.js b/lib/views/push-pull-menu-view.js index 5f4560df60..b68a628302 100644 --- a/lib/views/push-pull-menu-view.js +++ b/lib/views/push-pull-menu-view.js @@ -6,11 +6,13 @@ import etch from 'etch' export default class PushPullMenuView { constructor (props) { this.props = props + this.push = this.push.bind(this) etch.initialize(this) } update (props) { this.props = Object.assign({}, this.props, props) + this.errorMessage = '' return etch.update(this) } @@ -28,15 +30,29 @@ export default class PushPullMenuView { Pull {this.props.behindCount !== 0 ? `(${this.props.behindCount})` : ''} - +
) } + + async push (event) { + try { + await this.props.push({force: event.metaKey}) + } catch (error) { + if (error.stdErr.match(/rejected[\s\S]*failed to push/)) { + this.errorMessage = 'Push rejected.\nTry pulling before pushing again. Or to force push hold `cmd` while clicking' + } else { + this.errorMessage = error.stdErr + } + return etch.update(this) + } + } } class Tooltip { diff --git a/styles/push-pull-menu-view.less b/styles/push-pull-menu-view.less index b8e96c2475..7a7ba9a3c6 100644 --- a/styles/push-pull-menu-view.less +++ b/styles/push-pull-menu-view.less @@ -31,4 +31,21 @@ .btn-tooltip-wrapper .icon { pointer-events: none; } + + &-message { + max-height: 4.8em; + margin-top: @component-padding; + padding: @component-padding / 2; + line-height: 1.4; + white-space: normal; + text-align: left; + overflow-y: auto; + border: 1px solid @base-border-color; + border-radius: @component-border-radius; + background-color: @inset-panel-background-color; + + &:empty { + display: none; + } + } } diff --git a/test/controllers/status-bar-tile-controller.test.js b/test/controllers/status-bar-tile-controller.test.js index 55f2a3db55..564ea138e1 100644 --- a/test/controllers/status-bar-tile-controller.test.js +++ b/test/controllers/status-bar-tile-controller.test.js @@ -234,6 +234,33 @@ describe('StatusBarTileController', () => { await controller.getLastModelDataRefreshPromise() assert.isFalse(pullButton.disabled) }) + + it('displays an error message if push fails and allows force pushing if meta key is pressed', async () => { + const {localRepoPath} = await setUpLocalAndRemoteRepositories() + const repository = await buildRepository(localRepoPath) + await repository.git.exec(['reset', '--hard', 'head~2']) + await repository.git.commit('another commit', {allowEmpty: true}) + + const controller = new StatusBarTileController({workspace, repository}) + await controller.getLastModelDataRefreshPromise() + + const pushPullMenuView = controller.pushPullMenuView + const {pushButton, pullButton, message} = pushPullMenuView.refs + + assert.equal(pushButton.textContent, 'Push (1)') + assert.equal(pullButton.textContent, 'Pull (2)') + + pushButton.dispatchEvent(new MouseEvent('click')) + await etch.getScheduler().getNextUpdatePromise() + assert.match(message.innerHTML, /Push rejected/) + + pushButton.dispatchEvent(new MouseEvent('click', {metaKey: true})) + await repository.refresh() + await controller.getLastModelDataRefreshPromise() + + assert.equal(pushButton.textContent, 'Push ') + assert.equal(pullButton.textContent, 'Pull ') + }) }) }) From c62374ad5aacbeb792c268c2d37ac71951a11f4a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 25 Oct 2016 17:44:20 -0700 Subject: [PATCH 4/7] Display error message when creating branch fails due to merge conflicts --- lib/views/branch-menu-view.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/views/branch-menu-view.js b/lib/views/branch-menu-view.js index 12032adf06..d9fac13a46 100644 --- a/lib/views/branch-menu-view.js +++ b/lib/views/branch-menu-view.js @@ -65,9 +65,13 @@ export default class BranchMenuView { } catch (e) { if (e.stdErr.match(/branch.*already exists/)) { this.errorMessage = `Cannot create branch "${branchName}" as it already exists` - this.createNew = false - return etch.update(this) + } else if (e.stdErr.match(/error: you need to resolve your current index first/)) { + this.errorMessage = 'You must resolve merge conflicts before creating a new branch' + } else { + this.errorMessage = e.stdErr } + this.createNew = false + return etch.update(this) } } else { this.createNew = true From 0af5e7a6e653d797831fd08be877c97050105cee Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 26 Oct 2016 09:59:45 -0700 Subject: [PATCH 5/7] Allow pushing branches that have no remote tracking branch Disable fetch/pull buttons when there is no remote trackign branch and display informative message about setting up remote tracking branch by pushing Also, rename getRemote -> getRemoteForBranch --- lib/controllers/git-panel-controller.js | 2 +- lib/controllers/status-bar-tile-controller.js | 26 +++++++---------- lib/git-shell-out-strategy.js | 29 ++++++++++++------- lib/models/repository.js | 6 ++-- lib/views/push-pull-menu-view.js | 23 ++++++++++----- lib/views/push-pull-view.js | 4 +-- .../status-bar-tile-controller.test.js | 24 +++++++++++++++ test/git-shell-out-strategy.test.js | 8 ++--- test/models/repository.test.js | 8 ++--- 9 files changed, 83 insertions(+), 47 deletions(-) diff --git a/lib/controllers/git-panel-controller.js b/lib/controllers/git-panel-controller.js index b8982d38f4..af06bccd24 100644 --- a/lib/controllers/git-panel-controller.js +++ b/lib/controllers/git-panel-controller.js @@ -93,7 +93,7 @@ export default class GitPanelController { branches: await repository.getBranches(), aheadCount: null, behindCount: null, - remoteName: await repository.getRemote(this.branchName) + remoteName: await repository.getRemoteForBranch(this.branchName) } if (data.remoteName) { diff --git a/lib/controllers/status-bar-tile-controller.js b/lib/controllers/status-bar-tile-controller.js index c466c8eb8f..b54563a545 100644 --- a/lib/controllers/status-bar-tile-controller.js +++ b/lib/controllers/status-bar-tile-controller.js @@ -37,13 +37,6 @@ export default class StatusBarTileController { render () { const modelData = this.repositoryObserver.getActiveModelData() - const pushPullView = ( - - ) - if (modelData) { return (
@@ -52,7 +45,10 @@ export default class StatusBarTileController { {...modelData} workspace={this.props.workspace} checkout={this.checkout} /> - { modelData.remoteName ? pushPullView :