Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/controllers/git-panel-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
76 changes: 40 additions & 36 deletions lib/controllers/status-bar-tile-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,22 @@ export default class StatusBarTileController {
this.push = this.push.bind(this)
this.pull = this.pull.bind(this)
this.fetch = this.fetch.bind(this)
this.disposables = new CompositeDisposable()
this.branchMenuView = null
this.pushPullMenuView = null
this.branchTooltipDisposable = null
this.pushPullTooltipDisposable = null
this.repositoryObserver = new ModelObserver({
fetchData: this.fetchRepositoryData.bind(this),
didUpdate: () => etch.update(this)
didUpdate: () => {
// Since changing repositories causes the destruction of the DOM
// elements that the tooltips are bound to, we get rid of the old
// disposables & create new tooltips when the disposables are nulled out
this.branchTooltipDisposable && this.branchTooltipDisposable.dispose()
this.pushPullTooltipDisposable && this.pushPullTooltipDisposable.dispose()
this.branchTooltipDisposable = null
this.pushPullTooltipDisposable = null
return etch.update(this)
}
})
this.repositoryObserver.setActiveModel(props.repository)
etch.initialize(this)
Expand All @@ -37,13 +47,6 @@ export default class StatusBarTileController {
render () {
const modelData = this.repositoryObserver.getActiveModelData()

const pushPullView = (
<PushPullView
ref='pushPullView'
{...modelData}
/>
)

if (modelData) {
return (
<div className='git-StatusBarTileController'>
Expand All @@ -52,7 +55,10 @@ export default class StatusBarTileController {
{...modelData}
workspace={this.props.workspace}
checkout={this.checkout} />
{ modelData.remoteName ? pushPullView : <noscript /> }
<PushPullView
ref='pushPullView'
{...modelData}
/>
<ChangedFilesCountView
ref="changedFilesCountView"
{...modelData}
Expand Down Expand Up @@ -83,14 +89,14 @@ export default class StatusBarTileController {
pull: this.pull,
fetch: this.fetch
})
}

this.disposables.add(
atom.tooltips.add(this.refs.pushPullView.element, {
item: this.pushPullMenuView,
class: 'git-StatusBarTileController-tooltipMenu',
trigger: 'click'
})
)
if (!this.pushPullTooltipDisposable) {
this.pushPullTooltipDisposable = atom.tooltips.add(this.refs.pushPullView.element, {
item: this.pushPullMenuView,
class: 'git-StatusBarTileController-tooltipMenu',
trigger: 'click'
})
}
}

Expand All @@ -103,14 +109,14 @@ export default class StatusBarTileController {
workspace: this.props.workspace,
checkout: this.checkout
})
}

this.disposables.add(
atom.tooltips.add(this.refs.branchView.element, {
item: this.branchMenuView,
class: 'git-StatusBarTileController-tooltipMenu',
trigger: 'click'
})
)
if (!this.branchTooltipDisposable) {
this.branchTooltipDisposable = atom.tooltips.add(this.refs.branchView.element, {
item: this.branchMenuView,
class: 'git-StatusBarTileController-tooltipMenu',
trigger: 'click'
})
}
}

Expand All @@ -120,18 +126,16 @@ export default class StatusBarTileController {

async fetchRepositoryData (repository) {
const branchName = await repository.getCurrentBranch()
const remoteName = await repository.getRemote(branchName)
const remoteName = await repository.getRemoteForBranch(branchName)
const changedFilesCount = await this.fetchChangedFilesCount(repository)
const data = {
branchName,
remoteName,
changedFilesCount,
branches: await repository.getBranches()
}
if (remoteName) {
data.aheadCount = await repository.getAheadCount(branchName),
data.behindCount = await repository.getBehindCount(branchName),
data.pullDisabled = changedFilesCount > 0
branches: await repository.getBranches(),
remoteName,
aheadCount: await repository.getAheadCount(branchName),
behindCount: await repository.getBehindCount(branchName),
pullDisabled: changedFilesCount > 0
}
return data
}
Expand All @@ -155,14 +159,13 @@ 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 () {
const {pullDisabled, branchName} = this.repositoryObserver.getActiveModelData()
console.log('status bar pull');
return pullDisabled ? Promise.resolve() : this.getActiveRepository().pull(branchName)
}

Expand All @@ -184,6 +187,7 @@ export default class StatusBarTileController {
}

destroy () {
this.disposables.dispose()
this.branchTooltipDisposable && this.branchTooltipDisposable.dispose()
this.pushPullTooltipDisposable && this.pushPullTooltipDisposable.dispose()
}
}
37 changes: 24 additions & 13 deletions lib/git-shell-out-strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -212,7 +212,7 @@ export default class GitShellOutStrategy {
return this.exec(args)
}

async getRemote (branchName) {
async getRemoteForBranch (branchName) {
try {
const output = await this.exec(['config', `branch.${branchName}.remote`])
return output.trim()
Expand All @@ -223,29 +223,40 @@ export default class GitShellOutStrategy {

async fetch (branchName) {
try {
const remote = await this.getRemote(branchName)
const remote = await this.getRemoteForBranch(branchName)
const output = await this.exec(['fetch', remote, branchName])
return output
} catch (e) {
console.error(e)
}
}

async push (branchName) {
const remote = await this.getRemote(branchName)
return this.exec(['push', remote, branchName])
async push (branchName, options = {}) {
let remote = await this.getRemoteForBranch(branchName)
const args = ['push', remote || 'origin', branchName]
if (options.setUpstream) args.push('--set-upstream')
if (options.force) args.push('--force')
return this.exec(args)
}

async getAheadCount (branchName) {
const remote = await this.getRemote(branchName)
const output = await this.exec(['rev-list', `${remote}/${branchName}..${branchName}`])
return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length
const remote = await this.getRemoteForBranch(branchName)
if (remote) {
const output = await this.exec(['rev-list', `${remote}/${branchName}..${branchName}`])
return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length
} else {
return null
}
}

async getBehindCount (branchName) {
const remote = await this.getRemote(branchName)
const output = await this.exec(['rev-list', `${branchName}..${remote}/${branchName}`])
return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length
const remote = await this.getRemoteForBranch(branchName)
if (remote) {
const output = await this.exec(['rev-list', `${branchName}..${remote}/${branchName}`])
return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length
} else {
return null
}
}

/**
Expand Down
10 changes: 5 additions & 5 deletions lib/models/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -331,7 +331,7 @@ export default class Repository {

async pull (branchName) {
await this.fetch(branchName)
const remote = await this.git.getRemote(branchName)
const remote = await this.git.getRemoteForBranch(branchName)
return this.git.merge(`${remote}/${branchName}`)
}

Expand All @@ -343,8 +343,8 @@ export default class Repository {
return this.git.getBehindCount(branchName)
}

getRemote (branchName) {
return this.git.getRemote(branchName)
getRemoteForBranch (branchName) {
return this.git.getRemoteForBranch(branchName)
}

getCurrentBranch () {
Expand Down
8 changes: 6 additions & 2 deletions lib/views/branch-menu-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/views/branch-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default class BranchView {

render () {
return (
<div className="git-branch inline-block" onclick={this.props.didClick}>
<div className="git-branch inline-block">
<span className="icon icon-git-branch" />
<span className="branch-label">{this.props.branchName}</span>
</div>
Expand Down
37 changes: 31 additions & 6 deletions lib/views/push-pull-menu-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,62 @@ import etch from 'etch'
export default class PushPullMenuView {
constructor (props) {
this.props = props
this.checkRemote()
this.push = this.push.bind(this)
etch.initialize(this)
}

update (props) {
this.props = props
this.props = Object.assign({}, this.props, props)
this.checkRemote()
return etch.update(this)
}

checkRemote () {
if (!this.props.remoteName) {
this.errorMessage = `Note: No remote detected for branch ${this.props.branchName}. Pushing will set up a remote tracking branch on remote repo 'origin'`
} else {
this.errorMessage = ''
}
}

render () {
return (
<div className='git-Panel-item'>
<div className='git-PushPullMenuView '>
<span className='git-PushPullMenuView-item icon icon-mark-github'/>
<button className='git-PushPullMenuView-item btn' onclick={this.props.fetch}>Fetch</button>
<button className='git-PushPullMenuView-item btn' ref='fetchButton' onclick={this.props.fetch} disabled={!this.props.remoteName}>Fetch</button>

<div className='git-PushPullMenuView-item is-flexible btn-group'>
<button ref="pullButton" className='btn' onclick={this.props.pull} disabled={this.props.pullDisabled}>
<button ref='pullButton' className='btn' onclick={this.props.pull} disabled={!this.props.remoteName || this.props.pullDisabled}>
<Tooltip active={this.props.pullDisabled} text='Commit changes before pulling' className='btn-tooltip-wrapper'>
<span className='icon icon-arrow-down'/>
<span ref="behindCount">Pull {this.props.behindCount !== 0 ? `(${this.props.behindCount})` : ''}</span>
<span ref='behindCount'>Pull {this.props.behindCount ? `(${this.props.behindCount})` : ''}</span>
</Tooltip>
</button>
<button className='btn' onclick={this.props.push}>
<button ref='pushButton' className='btn' onclick={this.push}>
<span className='icon icon-arrow-up'/>
<span ref="aheadCount">Push {this.props.aheadCount !== 0 ? `(${this.props.aheadCount})` : ''}</span>
<span ref='aheadCount'>Push {this.props.aheadCount ? `(${this.props.aheadCount})` : ''}</span>
</button>
</div>
</div>
<div className='git-PushPullMenuView-message' ref='message' innerHTML={this.errorMessage}></div>
</div>
)
}

async push (event) {
try {
await this.props.push({force: event.metaKey, setUpstream: !this.props.remoteName})
} 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 {
Expand Down
6 changes: 3 additions & 3 deletions lib/views/push-pull-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ export default class PushPullView {

render () {
return (
<div className="git-PushPull inline-block" onclick={this.props.didClick}>
<div className="git-PushPull inline-block">
<span className="git-PushPull-icon icon icon-arrow-down" />
<span className="git-PushPull-label is-push" ref="behindCount">{this.props.behindCount !== 0 ? `${this.props.behindCount}` : ''}</span>
<span className="git-PushPull-label is-push" ref="behindCount">{this.props.behindCount ? `${this.props.behindCount}` : ''}</span>
<span className="git-PushPull-icon icon icon-arrow-up" />
<span className="git-PushPull-label is-pull" ref="aheadCount">{this.props.aheadCount !== 0 ? `${this.props.aheadCount}` : ''}</span>
<span className="git-PushPull-label is-pull" ref="aheadCount">{this.props.aheadCount ? `${this.props.aheadCount}` : ''}</span>
</div>
)
}
Expand Down
17 changes: 17 additions & 0 deletions styles/push-pull-menu-view.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Loading