From 121cd1ddca25188fb422bcda70fd3394471f1340 Mon Sep 17 00:00:00 2001
From: Stefan Liebl <S.Liebl@gmx.de>
Date: Tue, 10 Feb 2015 16:20:04 +0100
Subject: [PATCH] + merginal

---
 vimfiles/GetLatest/GetLatestVimScripts.dat |    1 +
 vimfiles/autoload/merginal.vim             | 1052 ++++++++++++++++++++
 vimfiles/doc/merginal.txt                  |  142 +++
 vimfiles/doc/tags                          |    9 +
 vimfiles/plugin/merginal.vim               |   51 +
 5 files changed, 1255 insertions(+)
 create mode 100755 vimfiles/autoload/merginal.vim
 create mode 100755 vimfiles/doc/merginal.txt
 create mode 100755 vimfiles/plugin/merginal.vim

diff --git a/vimfiles/GetLatest/GetLatestVimScripts.dat b/vimfiles/GetLatest/GetLatestVimScripts.dat
index a863f5b..29cc84b 100644
--- a/vimfiles/GetLatest/GetLatestVimScripts.dat
+++ b/vimfiles/GetLatest/GetLatestVimScripts.dat
@@ -39,3 +39,4 @@ ScriptID SourceID Filename
 2830 22798 csv.vim
 3849 22637 git-time-lapse
 4932 22787 diffchar.vim
+4955 22442 Merginal
diff --git a/vimfiles/autoload/merginal.vim b/vimfiles/autoload/merginal.vim
new file mode 100755
index 0000000..1ebc5c0
--- /dev/null
+++ b/vimfiles/autoload/merginal.vim
@@ -0,0 +1,1052 @@
+"Use vimproc if available under windows to prevent opening a console window
+function! merginal#system(command,...)
+    if has('win32') && exists(':VimProcBang') "We don't need vimproc when we use linux
+        if empty(a:000)
+            return vimproc#system(a:command)
+        else
+            return vimproc#system(a:command,a:000[0])
+        endif
+    else
+        if empty(a:000)
+            return system(a:command)
+        else
+            return system(a:command,a:000[0])
+        endif
+    endif
+endfunction
+
+"Opens a file that belongs to a repo in a window that already belongs to that
+"repo. Creates a new window if can't find suitable window.
+function! merginal#openFileDecidedWindow(repo,fileName)
+    "We have to check with bufexists, because bufnr also match prefixes of the
+    "file name
+    let l:fileBuffer=-1
+    if bufexists(a:fileName)
+        let l:fileBuffer=bufnr(a:fileName)
+    endif
+
+    "We have to check with bufloaded, because bufwinnr also matches closed
+    "windows...
+    let l:windowToOpenIn=-1
+    if bufloaded(l:fileBuffer)
+        let l:windowToOpenIn=bufwinnr(l:fileBuffer)
+    endif
+
+    "If we found an open window with the correct file, we jump to it
+    if -1<l:windowToOpenIn
+        execute l:windowToOpenIn.'wincmd w'
+    else
+        "Check if the previous window can be used
+        let l:previousWindow=winnr('#')
+        if s:isWindowADisposableWindowOfRepo(l:previousWindow,a:repo)
+            execute winnr('#').'wincmd w'
+        else
+            "If the previous window can't be used, check if any open
+            "window can be used
+            let l:windowsToOpenTheFileIn=merginal#getListOfDisposableWindowsOfRepo(a:repo)
+            if empty(l:windowsToOpenTheFileIn)
+                "If no open window can be used, open a new Vim window
+                new
+            else
+                execute l:windowsToOpenTheFileIn[0].'wincmd w'
+            endif
+        endif
+        if -1<l:fileBuffer
+            "If the buffer is already open, jump to it
+            execute 'buffer '.l:fileBuffer
+        else
+            "Otherwise, load it
+            execute 'edit '.fnameescape(a:fileName)
+        endif
+    endif
+    diffoff "Just in case...
+endfunction
+
+"Check if the current window is modifiable, saved, and belongs to the repo
+function! s:isCurrentWindowADisposableWindowOfRepo(repo)
+    if !&modifiable
+        return 0
+    endif
+    if &modified
+        return 0
+    endif
+    try
+        return a:repo==fugitive#repo()
+    catch
+        return 0
+    endtry
+endfunction
+
+"Calls s:isCurrentWindowADisposableWindowOfRepo with a window number
+function! s:isWindowADisposableWindowOfRepo(winnr,repo)
+    let l:currentWindow=winnr()
+    try
+        execute a:winnr.'wincmd w'
+        return s:isCurrentWindowADisposableWindowOfRepo(a:repo)
+    finally
+        execute l:currentWindow.'wincmd w'
+    endtry
+endfunction
+
+"Get a list of windows that yield true with s:isWindowADisposableWindowOfRepo
+function! merginal#getListOfDisposableWindowsOfRepo(repo)
+    let l:result=[]
+    let l:currentWindow=winnr()
+    windo if s:isCurrentWindowADisposableWindowOfRepo(a:repo) | call add(l:result,winnr()) |  endif
+    execute l:currentWindow.'wincmd w'
+    return l:result
+endfunction
+
+"Get the repository that belongs to a window
+function! s:getRepoOfWindow(winnr)
+    "Ignore bad window numbers
+    if a:winnr<=0
+        return {}
+    endif
+    let l:currentWindow=winnr()
+    try
+        execute a:winnr.'wincmd w'
+        return fugitive#repo()
+    catch
+        return {}
+    finally
+        execute l:currentWindow.'wincmd w'
+    endtry
+endfunction
+
+"Reload the buffers
+function! merginal#reloadBuffers()
+    let l:currentWindow=winnr()
+    try
+        silent windo if ''==&buftype
+                    \| edit
+                    \| endif
+    catch
+        "do nothing
+    endtry
+    execute l:currentWindow.'wincmd w'
+endfunction
+
+"Exactly what it says on tin
+function! merginal#runGitCommandInTreeReturnResult(repo,command)
+    let l:dir=getcwd()
+    execute 'cd '.fnameescape(a:repo.tree())
+    try
+        return merginal#system(a:repo.git_command().' '.a:command)
+    finally
+        execute 'cd '.fnameescape(l:dir)
+    endtry
+endfunction
+
+"Like merginal#runGitCommandInTreeReturnResult but split result to lines
+function! merginal#runGitCommandInTreeReturnResultLines(repo,command)
+    let l:dir=getcwd()
+    execute 'cd '.fnameescape(a:repo.tree())
+    try
+        return split(merginal#system(a:repo.git_command().' '.a:command),'\r\n\|\n\|\r')
+    finally
+        execute 'cd '.fnameescape(l:dir)
+    endtry
+endfunction
+
+"Returns 1 if there was a merginal bufffer to close
+function! merginal#closeMerginalBuffer()
+    let l:merginalWindowNumber=bufwinnr('Merginal:')
+    if 0<=l:merginalWindowNumber
+        let l:currentWindow=winnr()
+        try
+            execute l:merginalWindowNumber.'wincmd w'
+            wincmd q
+            "If the current window is after the merginal window, closing the
+            "merginal window will decrease the current window's nubmer.
+            if l:merginalWindowNumber<l:currentWindow
+                let l:currentWindow=l:currentWindow-1
+            endif
+            return 1
+        finally
+            execute l:currentWindow.'wincmd w'
+        endtry
+    end
+    return 0
+endfunction
+
+"Returns 1 if a new buffer was opened, 0 if it already existed
+function! merginal#openTuiBuffer(bufferName,inWindow)
+    let l:repo=fugitive#repo()
+
+    let l:tuiBufferWindow=bufwinnr(bufnr(a:bufferName))
+
+    if -1<l:tuiBufferWindow "Jump to the already open buffer
+        execute l:tuiBufferWindow.'wincmd w'
+    else "Open a new buffer
+        if merginal#isMerginalWindow(a:inWindow)
+            execute a:inWindow.'wincmd w'
+            enew
+        else
+            40vnew
+        endif
+        setlocal buftype=nofile
+        setlocal bufhidden=wipe
+        setlocal nomodifiable
+        setlocal winfixwidth
+        setlocal winfixheight
+        setlocal nonumber
+        setlocal norelativenumber
+        execute 'silent file '.a:bufferName
+        call fugitive#detect(l:repo.dir())
+    endif
+
+    "At any rate, reassign the active repository
+    let b:merginal_repo=l:repo
+    let b:headerLinesCount=0
+
+    "Check and return if a new buffer was created
+    return -1==l:tuiBufferWindow
+endfunction
+
+
+"Check if a window belongs to Merginal
+function! merginal#isMerginalWindow(winnr)
+    if a:winnr<=0
+        return 0
+    endif
+    let l:buffer=winbufnr(a:winnr)
+    if l:buffer<=0
+        return 0
+    endif
+    "check for the merginal repo buffer variable
+    return !empty(getbufvar(l:buffer,'merginal_repo'))
+endfunction
+
+
+"For the branch in the specified line, retrieve:
+" - type: 'local', 'remote' or 'detached'
+" - isCurrent, isLocal, isRemote, isDetached
+" - remote: the name of the remote or '' for local branches
+" - name: the name of the branch, without the remote
+" - handle: the named used for referring the branch in git commands
+function! merginal#branchDetails(lineNumber)
+    if !exists('b:merginal_repo')
+        throw 'Unable to get branch details outside the merginal window'
+    endif
+    if line(a:lineNumber)<=b:headerLinesCount
+        throw 'Unable to get branch details for the header of the merginal window'
+    endif
+    let l:line=getline(a:lineNumber)
+    let l:result={}
+
+
+    "Check if this branch is the currently selected one
+    let l:result.isCurrent=('*'==l:line[0])
+    let l:line=l:line[2:]
+
+    let l:detachedMatch=matchlist(l:line,'\v^\(detached from ([^/]+)%(/(.*))?\)$')
+    if !empty(l:detachedMatch)
+        let l:result.type='detached'
+        let l:result.isLocal=0
+        let l:result.isRemote=0
+        let l:result.isDetached=1
+        let l:result.remote=l:detachedMatch[1]
+        let l:result.name=l:detachedMatch[2]
+        if empty(l:detachedMatch[2])
+            let l:result.handle=l:detachedMatch[1]
+        else
+            let l:result.handle=l:detachedMatch[1].'/'.l:detachedMatch[2]
+        endif
+        return l:result
+    endif
+
+    let l:remoteMatch=matchlist(l:line,'\v^remotes/([^/]+)%(/(\S*))%( \-\> (\S+))?$')
+    if !empty(l:remoteMatch)
+        let l:result.type='remote'
+        let l:result.isLocal=0
+        let l:result.isRemote=1
+        let l:result.isDetached=0
+        let l:result.remote=l:remoteMatch[1]
+        let l:result.name=l:remoteMatch[2]
+        if empty(l:remoteMatch[2])
+            let l:result.handle=l:remoteMatch[1]
+        else
+            let l:result.handle=l:remoteMatch[1].'/'.l:remoteMatch[2]
+        endif
+        return l:result
+    endif
+
+    let l:result.type='local'
+    let l:result.isLocal=1
+    let l:result.isRemote=0
+    let l:result.isDetached=0
+    let l:result.remote=''
+    let l:result.name=l:line
+    let l:result.handle=l:line
+
+    return l:result
+endfunction
+
+"For the file in the specified line, retrieve:
+" - name: the name of the file
+function! merginal#fileDetails(lineNumber)
+    if !exists('b:merginal_repo')
+        throw 'Unable to get file details outside the merginal window'
+    endif
+    if line(a:lineNumber)<=b:headerLinesCount
+        throw 'Unable to get branch details for the header of the merginal window'
+    endif
+    let l:line=getline(a:lineNumber)
+    let l:result={}
+
+    let l:result.name=l:line
+
+    return l:result
+endfunction
+
+function! merginal#getLocalBranchNamesThatTrackARemoteBranch(remoteBranchName)
+    "Get verbose list of branches
+    let l:branchList=split(merginal#system(b:merginal_repo.git_command('branch','-vv')),'\r\n\|\n\|\r')
+
+    "Filter for branches that track our remote
+    let l:checkIfTrackingRegex='\V['.escape(a:remoteBranchName,'\').'\[\]:]'
+    let l:branchList=filter(l:branchList,'v:val=~l:checkIfTrackingRegex')
+
+    "Extract the branch name from the matching lines
+    "let l:extractBranchNameRegex='\v^\*?\s*(\S+)'
+    "let l:branchList=map(l:branchList,'matchlist(v:val,l:extractBranchNameRegex)[1]')
+    let l:extractBranchNameRegex='\v^\*?\s*\zs\S+'
+    let l:branchList=map(l:branchList,'matchstr(v:val,l:extractBranchNameRegex)')
+
+    return l:branchList
+endfunction
+
+function! merginal#getRemoteBranchTrackedByLocalBranch(localBranchName)
+    let l:result=merginal#system(b:merginal_repo.git_command('branch','--list',a:localBranchName,'-vv'))
+    echo l:result
+    return matchstr(l:result,'\v\[\zs[^\[\]:]*\ze[\]:]')
+endfunction
+
+
+"Check if the current buffer's repo is in rebase mode
+function! merginal#isRebaseMode()
+    return isdirectory(fugitive#repo().dir('rebase-apply'))
+endfunction
+
+"Check if the current buffer's repo is in rebase amend mode
+function! merginal#isRebaseAmendMode()
+    return isdirectory(fugitive#repo().dir('rebase-merge'))
+endfunction
+
+"Check if the current buffer's repo is in merge mode
+function! merginal#isMergeMode()
+    "Use glob() to check for file existence
+    return !empty(glob(fugitive#repo().dir('MERGE_MODE')))
+endfunction
+
+"Open the branch list buffer for controlling buffers
+function! merginal#openBranchListBuffer(...)
+    if merginal#openTuiBuffer('Merginal:Branches',get(a:000,1,bufwinnr('Merginal:')))
+        doautocmd User Merginal_BranchList
+    endif
+
+    "At any rate, refresh the buffer:
+    call merginal#tryRefreshBranchListBuffer(1)
+endfunction
+
+augroup merginal
+    autocmd User Merginal_BranchList nnoremap <buffer> R :call merginal#tryRefreshBranchListBuffer(0)<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> C :call <SID>checkoutBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> cc :call <SID>checkoutBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> ct :call <SID>trackBranchUnderCursor(0)<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> cT :call <SID>trackBranchUnderCursor(1)<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> A :call <SID>promptToCreateNewBranch()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> aa :call <SID>promptToCreateNewBranch()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> D :call <SID>deleteBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> dd :call <SID>deleteBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> M :call <SID>mergeBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> mm :call <SID>mergeBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> mf :call <SID>mergeBranchUnderCursorUsingFugitive()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> rb :call <SID>rebaseBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> ps :call <SID>remoteActionForBranchUnderCursor('push',0)<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> pS :call <SID>remoteActionForBranchUnderCursor('push',1)<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> pl :call <SID>remoteActionForBranchUnderCursor('pull',0)<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> pf :call <SID>remoteActionForBranchUnderCursor('fetch',0)<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> gd :call <SID>diffWithBranchUnderCursor()<Cr>
+    autocmd User Merginal_BranchList nnoremap <buffer> rn :call <SID>renameBranchUnderCursor()<Cr>
+augroup END
+
+"If the current buffer is a branch list buffer - refresh it!
+function! merginal#tryRefreshBranchListBuffer(jumpToCurrentBranch)
+    if 'Merginal:Branches'==bufname('')
+        let l:branchList=split(merginal#system(b:merginal_repo.git_command('branch','--all')),'\r\n\|\n\|\r')
+        let l:currentLine=line('.')
+
+        setlocal modifiable
+        "Clear the buffer:
+        normal ggdG
+        "Write the branch list:
+        call setline(1,l:branchList)
+        setlocal nomodifiable
+
+
+        if a:jumpToCurrentBranch
+            "Find the current branch's index
+            let l:currentBranchIndex=-1
+            for i in range(len(l:branchList))
+                if '*'==l:branchList[i][0]
+                    let l:currentBranchIndex=i
+                    break
+                endif
+            endfor
+            if -1<l:currentBranchIndex
+                "Jump to the current branch's line
+                execute l:currentBranchIndex+1
+            endif
+        else
+            execute l:currentLine
+        endif
+    endif
+endfunction
+
+"Exactly what it says on tin
+function! s:checkoutBranchUnderCursor()
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout '.shellescape(l:branch.handle))
+        call merginal#reloadBuffers()
+        call merginal#tryRefreshBranchListBuffer(0)
+    endif
+endfunction
+
+"Track what it says on tin
+function! s:trackBranchUnderCursor(promptForName)
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        if !l:branch.isRemote
+            throw 'Can not track - branch is not remote'
+        endif
+        let l:newBranchName=l:branch.name
+        if a:promptForName
+            let l:newBranchName=input('Track `'.l:branch.handle.'` as: ',l:newBranchName)
+            if empty(l:newBranchName)
+                echo ' '
+                echo 'Branch tracking canceled by the user'
+                return
+            endif
+        endif
+        echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout -b '.shellescape(l:newBranchName).' --track '.shellescape(l:branch.handle))
+        call merginal#reloadBuffers()
+        call merginal#tryRefreshBranchListBuffer(0)
+    endif
+endfunction
+
+"Uses the current branch as the source
+function! s:promptToCreateNewBranch()
+    if 'Merginal:Branches'==bufname('')
+        let l:newBranchName=input('Branch `'.b:merginal_repo.head().'` to: ')
+            if empty(l:newBranchName)
+                echo ' '
+                echo 'Branch creation canceled by the user'
+                return
+            endif
+        echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout -b '.shellescape(l:newBranchName))
+        call merginal#reloadBuffers()
+        call merginal#tryRefreshBranchListBuffer(1)
+    endif
+endfunction
+
+"Verifies the decision
+function! s:deleteBranchUnderCursor()
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        let l:answer=0
+        if l:branch.isLocal
+            let l:answer='yes'==input('Delete branch `'.l:branch.handle.'`?(type "yes" to confirm) ')
+        elseif l:branch.isRemote
+            "Deleting remote branches needs a special warning
+            let l:answer='yes-remote'==input('Delete remote(!) branch `'.l:branch.handle.'`?(type "yes-remote" to confirm) ')
+        endif
+        if l:answer
+            if l:branch.isLocal
+                echo ' '
+                echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager branch -D '.shellescape(l:branch.handle))
+            else
+                execute '!'.b:merginal_repo.git_command('push').' '.shellescape(l:branch.remote).' --delete '.shellescape(l:branch.name)
+            endif
+            call merginal#reloadBuffers()
+            call merginal#tryRefreshBranchListBuffer(0)
+        else
+            echo ' '
+            echo 'Branch deletion canceled by the user'
+        endif
+    endif
+endfunction
+
+"If there are merge conflicts, opens the merge conflicts buffer
+function! s:mergeBranchUnderCursor()
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        echo ' '
+        echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'merge --no-commit '.shellescape(l:branch.handle))
+        call merginal#reloadBuffers()
+        if v:shell_error
+            call merginal#openMergeConflictsBuffer(winnr())
+        elseif merginal#isMergeMode()
+            "If we are in merge mode without a shell error, that means there
+            "are not conflicts and the user can be prompted to enter a merge
+            "message.
+            Gstatus
+            call merginal#closeMerginalBuffer()
+        endif
+    endif
+endfunction
+
+"Use Fugitive's :Gmerge. It was added to Fugitive after I implemented
+"Merginal's merge, and I don't want to remove it since it can still more
+"comfortable for some.
+function! s:mergeBranchUnderCursorUsingFugitive()
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        execute ':Gmerge '.l:branchName.handle
+    endif
+endfunction
+
+"If there are rebase conflicts, opens the rebase conflicts buffer
+function! s:rebaseBranchUnderCursor()
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        echo ' '
+        echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'rebase '.shellescape(l:branch.handle))
+        call merginal#reloadBuffers()
+        if v:shell_error
+            call merginal#openRebaseConflictsBuffer(winnr())
+        endif
+    endif
+endfunction
+
+"Run various remote actions
+function! s:remoteActionForBranchUnderCursor(remoteAction,force)
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        if l:branch.isLocal
+            let l:remotes=merginal#runGitCommandInTreeReturnResultLines(b:merginal_repo,'remote')
+            if empty(l:remotes)
+                throw 'Can not '.a:remoteAction.' - no remotes defined'
+            endif
+
+            let l:chosenRemoteIndex=0
+            if 1<len(l:remotes)
+                let l:listForInputlist=map(copy(l:remotes),'v:key+1.") ".v:val')
+                "Choose the correct text accoring to the action:
+                if 'push'==a:remoteAction
+                    call insert(l:listForInputlist,'Choose remote to '.a:remoteAction.' `'.l:branch.handle.'` to:')
+                else
+                    call insert(l:listForInputlist,'Choose remote to '.a:remoteAction.' `'.l:branch.handle.'` from:')
+                endif
+                let l:chosenRemoteIndex=inputlist(l:listForInputlist)
+
+                "Check that the chosen index is in range
+                if l:chosenRemoteIndex<=0 || len(l:remotes)<l:chosenRemoteIndex
+                    return
+                endif
+
+                let l:chosenRemoteIndex=l:chosenRemoteIndex-1
+            endif
+
+            let l:localBranchName=l:branch.name
+            let l:chosenRemote=l:remotes[l:chosenRemoteIndex]
+
+            let l:remoteBranchNameCanadidate=merginal#getRemoteBranchTrackedByLocalBranch(l:branch.name)
+            echo ' '
+            if !empty(l:remoteBranchNameCanadidate)
+                "Check that this is the same remote:
+                if l:remoteBranchNameCanadidate=~'\V\^'.escape(l:chosenRemote,'\').'/'
+                    "Remote the remote repository name
+                    let l:remoteBranchName=l:remoteBranchNameCanadidate[len(l:chosenRemote)+1:(-1)]
+                endif
+            endif
+        elseif l:branch.isRemote
+            let l:chosenRemote=l:branch.remote
+            if 'push'==a:remoteAction
+                "For push, we want to specify the remote branch name
+                let l:remoteBranchName=l:branch.name
+
+                let l:locals=merginal#getLocalBranchNamesThatTrackARemoteBranch(l:branch.handle)
+                if empty(l:locals)
+                    let l:localBranchName=l:branch.name
+                elseif 1==len(l:locals)
+                    let l:localBranchName=l:locals[0]
+                else
+                    let l:listForInputlist=map(copy(l:locals),'v:key+1.") ".v:val')
+                    call insert(l:listForInputlist,'Choose local branch to push `'.l:branch.handle.'` from:')
+                    let l:chosenLocalIndex=inputlist(l:listForInputlist)
+
+                    "Check that the chosen index is in range
+                    if l:chosenLocalIndex<=0 || len(l:locals)<l:chosenLocalIndex
+                        return
+                    endif
+
+                    let l:localBranchName=l:locals[l:chosenLocalIndex-1]
+                endif
+            else
+                "For pull and fetch, git automatically resolves the tracking
+                "branch based on the remote branch.
+                let l:localBranchName=l:branch.name
+            endif
+        endif
+
+        if exists('l:remoteBranchName') && empty(l:remoteBranchName)
+            unlet l:remoteBranchName
+        endif
+
+        let l:gitCommandWithArgs=[a:remoteAction]
+        if a:force
+            call add(l:gitCommandWithArgs,'--force')
+        endif
+
+        let l:reloadBuffers=0
+
+        "Pulling requires the --no-commit flag
+        if 'pull'==a:remoteAction
+            if exists('l:remoteBranchName')
+                let l:remoteBranchNameAsPrefix=shellescape(l:remoteBranchName).':'
+            else
+                let l:remoteBranchNameAsPrefix=''
+            endif
+            let l:remoteBranchEscapedName=l:remoteBranchNameAsPrefix.shellescape(l:localBranchName)
+            call add(l:gitCommandWithArgs,'--no-commit')
+            let l:reloadBuffers=1
+
+        elseif 'push'==a:remoteAction
+            if exists('l:remoteBranchName')
+                let l:remoteBranchNameAsSuffix=':'.shellescape(l:remoteBranchName)
+            else
+                let l:remoteBranchNameAsSuffix=''
+            endif
+            let l:remoteBranchEscapedName=shellescape(l:localBranchName).l:remoteBranchNameAsSuffix
+
+        elseif 'fetch'==a:remoteAction
+            if exists('l:remoteBranchName')
+                let l:targetBranchName=l:remoteBranchName
+            else
+                let l:targetBranchName=l:localBranchName
+            endif
+            let l:remoteBranchEscapedName=shellescape(l:targetBranchName)
+            execute '!'.b:merginal_repo.git_command(a:remoteAction).' '.shellescape(l:chosenRemote).' '.shellescape(l:targetBranchName)
+        endif
+        execute '!'.call(b:merginal_repo.git_command,l:gitCommandWithArgs,b:merginal_repo).' '.shellescape(l:chosenRemote).' '.l:remoteBranchEscapedName
+        if l:reloadBuffers
+            call merginal#reloadBuffers()
+        endif
+        call merginal#tryRefreshBranchListBuffer(0)
+    endif
+endfunction
+
+
+"Opens the diff files buffer
+function! s:diffWithBranchUnderCursor()
+    if 'Merginal:Branches'==bufname('')
+                \|| 'Merginal:RebaseAmend'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        if l:branch.isCurrent
+            throw 'Can not diff against the current branch'
+        endif
+        call merginal#openDiffFilesBuffer(l:branch)
+    endif
+endfunction
+
+
+"Prompts for a new name to the branch and renames it
+function! s:renameBranchUnderCursor()
+    if 'Merginal:Branches'==bufname('')
+        let l:branch=merginal#branchDetails('.')
+        if !l:branch.isLocal
+            throw 'Can not rename - not a local branch'
+        endif
+        let l:newName=input('Rename `'.l:branch.handle.'` to: ',l:branch.name)
+        echo ' '
+        if empty(l:newName)
+            echo 'Branch rename canceled by the user'
+            return
+        elseif l:newName==l:branch.name
+            echo 'Branch name was not modified'
+            return
+        endif
+
+        let l:gitCommand=b:merginal_repo.git_command('branch','-m',l:branch.name,l:newName)
+        let l:result=merginal#system(l:gitCommand)
+        echo l:result
+        call merginal#tryRefreshBranchListBuffer(0)
+    endif
+endfunction
+
+
+
+"Open the merge conflicts buffer for resolving merge conflicts
+function! merginal#openMergeConflictsBuffer(...)
+    let l:currentFile=expand('%:~:.')
+    if merginal#openTuiBuffer('Merginal:Conflicts',get(a:000,1,bufwinnr('Merginal:')))
+        doautocmd User Merginal_MergeConflicts
+    endif
+
+    "At any rate, refresh the buffer:
+    call merginal#tryRefreshMergeConflictsBuffer(l:currentFile)
+endfunction
+
+augroup merginal
+    autocmd User Merginal_MergeConflicts nnoremap <buffer> R :call merginal#tryRefreshMergeConflictsBuffer(0)<Cr>
+    autocmd User Merginal_MergeConflicts nnoremap <buffer> <Cr> :call <SID>openMergeConflictUnderCursor()<Cr>
+    autocmd User Merginal_MergeConflicts nnoremap <buffer> A :call <SID>addConflictedFileToStagingArea()<Cr>
+    autocmd User Merginal_MergeConflicts nnoremap <buffer> aa :call <SID>addConflictedFileToStagingArea()<Cr>
+augroup END
+
+"Returns 1 if all merges are done
+function! s:refreshConflictsBuffer(fileToJumpTo,headerLines)
+    "Get the list of unmerged files:
+    let l:conflicts=split(merginal#system(b:merginal_repo.git_command('ls-files','--unmerged')),'\r\n\|\n\|\r')
+    "Split by tab - the first part is info, the second is the file name
+    let l:conflicts=map(l:conflicts,'split(v:val,"\t")')
+    "Only take the stage 1 files - stage 2 and 3 are the same files with
+    "different hash, and we don't care about the hash here
+    let l:conflicts=filter(l:conflicts,'v:val[0] =~ "\\v 1$"')
+    "Take the file name - we no longer care about the info
+    let l:conflicts=map(l:conflicts,'v:val[1]')
+    "If the working copy is not the current dir, we can get wrong paths.
+    "We need to resulve that:
+    let l:conflicts=map(l:conflicts,'b:merginal_repo.tree(v:val)')
+    "Make the paths as short as possible:
+    let l:conflicts=map(l:conflicts,'fnamemodify(v:val,":~:.")')
+
+
+    let l:currentLine=line('.')-b:headerLinesCount
+
+    setlocal modifiable
+    "Clear the buffer:
+    normal ggdG
+    "Write the branch list:
+    call setline(1,a:headerLines+l:conflicts)
+    let b:headerLinesCount=len(a:headerLines)
+    let l:currentLine=l:currentLine+b:headerLinesCount
+    setlocal nomodifiable
+    if empty(l:conflicts)
+        return 1
+    endif
+
+    if empty(a:fileToJumpTo)
+        if 0<l:currentLine
+            execute l:currentLine
+        endif
+    else
+        let l:lineNumber=search('\V\^'+escape(a:fileToJumpTo,'\')+'\$','cnw')
+        if 0<l:lineNumber
+            execute l:lineNumber
+        else
+            execute l:currentLine
+        endif
+    endif
+    return 0
+endfunction
+
+"Returns 1 if all merges are done
+function! merginal#tryRefreshMergeConflictsBuffer(fileToJumpTo)
+    if 'Merginal:Conflicts'==bufname('')
+        return s:refreshConflictsBuffer(a:fileToJumpTo,[])
+    endif
+    return 0
+endfunction
+
+"Exactly what it says on tin
+function! s:openMergeConflictUnderCursor()
+    if 'Merginal:Conflicts'==bufname('')
+                \|| 'Merginal:Rebase'==bufname('')
+        let l:file=merginal#fileDetails('.')
+        if empty(l:file.name)
+            return
+        endif
+        call merginal#openFileDecidedWindow(b:merginal_repo,l:file.name)
+    endif
+endfunction
+
+"If that was the last merge conflict, automatically opens Fugitive's status
+"buffer
+function! s:addConflictedFileToStagingArea()
+    if 'Merginal:Conflicts'==bufname('')
+                \|| 'Merginal:Rebase'==bufname('')
+        let l:file=merginal#fileDetails('.')
+        if empty(l:file.name)
+            return
+        endif
+        echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager add '.shellescape(fnamemodify(l:file.name,':p')))
+
+        if 'Merginal:Conflicts'==bufname('')
+            if merginal#tryRefreshMergeConflictsBuffer(0)
+                "If this returns 1, that means this is the last branch, and we
+                "should open gufitive's status window
+                let l:mergeConflictsBuffer=bufnr('')
+                Gstatus
+                let l:gitStatusBuffer=bufnr('')
+                execute bufwinnr(l:mergeConflictsBuffer).'wincmd w'
+                wincmd q
+                execute bufwinnr(l:gitStatusBuffer).'wincmd w'
+            endif
+        else
+            if merginal#tryRefreshRebaseConflictsBuffer(0)
+                echo 'Added the last file of this patch.'
+                echo 'Continue to the next patch(y/n)?'
+                let l:answer=getchar()
+                if char2nr('y')==l:answer || char2nr('Y')==l:answer
+                    call s:rebaseAction('continue')
+                endif
+            endif
+        endif
+    endif
+endfunction
+
+
+"Open the diff files buffer for diffing agains another branch
+function! merginal#openDiffFilesBuffer(diffBranch,...)
+    if merginal#openTuiBuffer('Merginal:Diff',get(a:000,1,bufwinnr('Merginal:')))
+        doautocmd User Merginal_DiffFiles
+    endif
+
+    let b:merginal_diffBranch=a:diffBranch
+
+    "At any rate, refresh the buffer:
+    call merginal#tryRefreshDiffFilesBuffer()
+endfunction
+
+augroup merginal
+    autocmd User Merginal_DiffFiles nnoremap <buffer> R :call merginal#tryRefreshDiffFilesBuffer()<Cr>
+    autocmd User Merginal_DiffFiles nnoremap <buffer> <Cr> :call <SID>openDiffFileUnderCursor()<Cr>
+    autocmd User Merginal_DiffFiles nnoremap <buffer> ds :call <SID>openDiffFileUnderCursorAndDiff('s')<Cr>
+    autocmd User Merginal_DiffFiles nnoremap <buffer> dv :call <SID>openDiffFileUnderCursorAndDiff('v')<Cr>
+    autocmd User Merginal_DiffFiles nnoremap <buffer> co :call <SID>checkoutDiffFileUnderCursor()<Cr>
+augroup END
+
+
+"For the diff file in the specified line, retrieve:
+" - type: 'added', 'deleted' or 'modified'
+" - isAdded, isDeleted, isModified
+" - fileInTree: the path of the file relative to the repo
+" - fileFullPath: the full path to the file
+function! merginal#diffFileDetails(lineNumber)
+    if !exists('b:merginal_repo')
+        throw 'Unable to get diff file details outside the merginal window'
+    endif
+    let l:line=getline(a:lineNumber)
+    let l:result={}
+
+    let l:matches=matchlist(l:line,'\v([ADM])\t(.*)$')
+
+    if empty(l:matches)
+        throw 'Unable to get diff files details for `'.l:line.'`'
+    endif
+
+    let l:result.isAdded=0
+    let l:result.isDeleted=0
+    let l:result.isModified=0
+    if 'A'==l:matches[1]
+        let l:result.type='added'
+        let l:result.isAdded=1
+    elseif 'D'==l:matches[1]
+        let l:result.type='deleted'
+        let l:result.isDeleted=1
+    else
+        let l:result.type='modified'
+        let l:result.isModified=1
+    endif
+
+    let l:result.fileInTree=l:matches[2]
+    let l:result.fileFullPath=b:merginal_repo.tree(l:matches[2])
+
+    return l:result
+endfunction
+
+"If the current buffer is a branch list buffer - refresh it!
+function! merginal#tryRefreshDiffFilesBuffer()
+    if 'Merginal:Diff'==bufname('')
+        let l:diffBranch=b:merginal_diffBranch
+        let l:diffFiles=merginal#runGitCommandInTreeReturnResultLines(b:merginal_repo,'diff --name-status '.shellescape(l:diffBranch.handle))
+        let l:currentLine=line('.')
+
+        setlocal modifiable
+        "Clear the buffer:
+        normal ggdG
+        "Write the diff files list:
+        call setline(1,l:diffFiles)
+        setlocal nomodifiable
+
+        execute l:currentLine
+    endif
+endfunction
+
+"Exactly what it says on tin
+function! s:openDiffFileUnderCursor()
+    if 'Merginal:Diff'==bufname('')
+        let l:diffFile=merginal#diffFileDetails('.')
+
+        if l:diffFile.isDeleted
+            throw 'File does not exist in current buffer'
+        endif
+
+        call merginal#openFileDecidedWindow(b:merginal_repo,l:diffFile.fileFullPath)
+    endif
+endfunction
+
+"Exactly what it says on tin
+function! s:openDiffFileUnderCursorAndDiff(diffType)
+    if a:diffType!='s' && a:diffType!='v'
+        throw 'Bad diff type'
+    endif
+    if 'Merginal:Diff'==bufname('')
+        let l:diffFile=merginal#diffFileDetails('.')
+
+        if l:diffFile.isAdded
+            throw 'File does not exist in other buffer'
+        endif
+
+        let l:repo=b:merginal_repo
+        let l:diffBranch=b:merginal_diffBranch
+
+        "Close currently open git diffs
+        let l:currentWindowBuffer=winbufnr('.')
+        try
+            windo if 'blob'==get(b:,'fugitive_type','') && exists('w:fugitive_diff_restore')
+                        \| bdelete
+                        \| endif
+        catch
+            "do nothing
+        finally
+            execute bufwinnr(l:currentWindowBuffer).'wincmd w'
+        endtry
+
+        call merginal#openFileDecidedWindow(l:repo,l:diffFile.fileFullPath)
+
+        execute ':G'.a:diffType.'diff '.fnameescape(l:diffBranch.handle)
+    endif
+endfunction
+
+"Checks out the file from the other branch to the current branch
+function! s:checkoutDiffFileUnderCursor()
+    if 'Merginal:Diff'==bufname('')
+        let l:diffFile=merginal#diffFileDetails('.')
+
+        if l:diffFile.isAdded
+            throw 'File does not exist in diffed buffer'
+        endif
+
+        let l:answer=1
+        if !empty(glob(l:diffFile.fileFullPath))
+            let l:answer='yes'==input('Override `'.l:diffFile.fileInTree.'`?(type "yes" to confirm) ')
+        endif
+        if l:answer
+            echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout '.shellescape(b:merginal_diffBranch.handle)
+                        \.' -- '.shellescape(l:diffFile.fileFullPath))
+            call merginal#reloadBuffers()
+            call merginal#tryRefreshDiffFilesBuffer()
+        else
+            echo ' '
+            echo 'File checkout canceled by the user'
+        endif
+    endif
+endfunction
+
+
+"Open the rebase conflicts buffer for resolving rebase conflicts
+function! merginal#openRebaseConflictsBuffer(...)
+    let l:currentFile=expand('%:~:.')
+    if merginal#openTuiBuffer('Merginal:Rebase',get(a:000,1,bufwinnr('Merginal:')))
+        doautocmd User Merginal_RebaseConflicts
+    endif
+
+    "At any rate, refresh the buffer:
+    call merginal#tryRefreshRebaseConflictsBuffer(l:currentFile)
+endfunction
+
+augroup merginal
+    autocmd User Merginal_RebaseConflicts nnoremap <buffer> R :call merginal#tryRefreshRebaseConflictsBuffer(0)<Cr>
+    autocmd User Merginal_RebaseConflicts nnoremap <buffer> <Cr> :call <SID>openMergeConflictUnderCursor()<Cr>
+    autocmd User Merginal_RebaseConflicts nnoremap <buffer> A :call <SID>addConflictedFileToStagingArea()<Cr>
+    autocmd User Merginal_RebaseConflicts nnoremap <buffer> aa :call <SID>addConflictedFileToStagingArea()<Cr>
+    autocmd User Merginal_RebaseConflicts nnoremap <buffer> ra :call <SID>rebaseAction('abort')<Cr>
+    autocmd User Merginal_RebaseConflicts nnoremap <buffer> rs :call <SID>rebaseAction('skip')<Cr>
+    autocmd User Merginal_RebaseConflicts nnoremap <buffer> rc :call <SID>rebaseAction('continue')<Cr>
+augroup END
+
+"Returns 1 if all rebase conflicts are done
+function! merginal#tryRefreshRebaseConflictsBuffer(fileToJumpTo)
+    if 'Merginal:Rebase'==bufname('')
+        let l:currentCommitMessageLines=readfile(b:merginal_repo.dir('rebase-apply','msg-clean'))
+        call insert(l:currentCommitMessageLines,'=== Reapplying: ===')
+        call add(l:currentCommitMessageLines,'===================')
+        call add(l:currentCommitMessageLines,'')
+        return s:refreshConflictsBuffer(a:fileToJumpTo,l:currentCommitMessageLines)
+    endif
+    return 0
+endfunction
+
+"Run various rebase actions
+function! s:rebaseAction(remoteAction)
+    if 'Merginal:Rebase'==bufname('')
+                \|| 'Merginal:RebaseAmend'==bufname('')
+        echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager rebase --'.a:remoteAction)
+        call merginal#reloadBuffers()
+        if merginal#isRebaseMode()
+            call merginal#tryRefreshRebaseConflictsBuffer(0)
+        elseif merginal#isRebaseAmendMode()
+            call merginal#tryRefreshRebaseAmendBuffer()
+        else
+            "If we finished rebasing - close the rebase conflicts buffer
+            wincmd q
+        endif
+    endif
+endfunction
+
+
+
+"Open the rebase amend buffer
+function! merginal#openRebaseAmendBuffer(...)
+    let l:currentFile=expand('%:~:.')
+    if merginal#openTuiBuffer('Merginal:RebaseAmend',get(a:000,1,bufwinnr('Merginal:')))
+        doautocmd User Merginal_RebaseAmend
+    endif
+
+    "At any rate, refresh the buffer:
+    call merginal#tryRefreshRebaseAmendBuffer()
+endfunction
+
+autocmd User Merginal_RebaseAmend nnoremap <buffer> R :call merginal#tryRefreshRebaseAmendBuffer()<Cr>
+autocmd User Merginal_RebaseAmend nnoremap <buffer> ra :call <SID>rebaseAction('abort')<Cr>
+autocmd User Merginal_RebaseAmend nnoremap <buffer> rs :call <SID>rebaseAction('skip')<Cr>
+autocmd User Merginal_RebaseAmend nnoremap <buffer> rc :call <SID>rebaseAction('continue')<Cr>
+autocmd User Merginal_RebaseAmend nnoremap <buffer> gd :call <SID>diffWithBranchUnderCursor()<Cr>
+
+function! merginal#tryRefreshRebaseAmendBuffer()
+    if 'Merginal:RebaseAmend'==bufname('')
+        "let l:gitStatusOutput=split(merginal#system(b:merginal_repo.git_command('status','--all')),'\r\n\|\n\|\r')
+        let l:currentLine=line('.')
+        let l:newBufferLines=[]
+        let l:amendedCommit=readfile(b:merginal_repo.dir('rebase-merge','amend'))
+        let l:amendedCommitShort=merginal#system(b:merginal_repo.git_command('rev-parse','--short',l:amendedCommit[0]))
+        let l:amendedCommitShort=substitute(l:amendedCommitShort,'\v[\r\n]','','g')
+        let l:amendedCommitMessage=readfile(b:merginal_repo.dir('rebase-merge','message'))
+        call add(l:newBufferLines,'=== Amending '.l:amendedCommitShort.' ===')
+        let l:newBufferLines+=l:amendedCommitMessage
+        call add(l:newBufferLines,repeat('=',len(l:newBufferLines[0])))
+        call add(l:newBufferLines,'')
+
+        let b:headerLinesCount=len(l:newBufferLines)+1
+
+        let l:branchList=split(merginal#system(b:merginal_repo.git_command('branch','--all')),'\r\n\|\n\|\r')
+        "The first line is a reminder that we are rebasing
+        "call remove(l:branchList,0)
+        let l:newBufferLines+=l:branchList
+
+
+        setlocal modifiable
+        "Clear the buffer:
+        normal ggdG
+        "Write the new buffer lines:
+        call setline(1,l:newBufferLines)
+        "call setline(1,l:branchList)
+        setlocal nomodifiable
+    endif
+    return 0
+endfunction
diff --git a/vimfiles/doc/merginal.txt b/vimfiles/doc/merginal.txt
new file mode 100755
index 0000000..124d252
--- /dev/null
+++ b/vimfiles/doc/merginal.txt
@@ -0,0 +1,142 @@
+*merginal.txt*
+
+
+Author:  Idan Arye <https://github.com/idanarye/>
+License: Same terms as Vim itself (see |license|)
+
+Version: 1.4.0
+
+INTRODUCTION                                                      *merginal*
+
+Merginal aims provide a nice inteface for dealing with Git branches.  It
+offers interactive TUI for:
+
+* Viewing the list of branches
+* Checking out branches from that list
+* Creating new branches
+* Deleting branches
+* Merging branches
+* Rebasing branches
+* Solving merge conflicts
+* Renaming branches
+
+
+REQUIREMENTS                                         *merginal-requirements*
+
+Merginal is based on Fugitive, so it requires Fugitive. If you don't have it
+already you can get it from https://github.com/tpope/vim-fugitive
+
+It should go without saying that you need Git.
+
+Under Windows, vimproc is an optional requirement. Merginal will work without
+it, but it'll pop an ugly console window every time it needs to run a Git
+command. You can get vimproc from https://github.com/Shougo/vimproc.vim
+
+
+USAGE                                                       *merginal-usage*
+
+To use Merginal you need to know but one command: *:Merginal*. It'll open the
+|merginal-branch-list| buffer, unless the repository is in merge mode then
+it'll open the |merginal-merge-conflicts| buffer.
+
+Like Fugitive's commands, |:Merginal| is native to the buffer, and will only
+work in buffers that are parts of Git repositories.
+
+You can also toggle the buffer with |:MerginalToggle| or close it with
+|:MerginalClose|.
+
+
+THE BRANCH LIST                                       *merginal-branch-list*
+
+The branch list shows a list of branches. While in that list, you can use the
+following keymaps to interact with the branches:
+
+R      Refresh the buffer list.
+cc     Checkout the branch under the cursor.
+ct     Track the remote branch under the cursor.
+cT     Track the remote branch under the cursor, prompting for a name.
+C      Same as cc.
+aa     Create a new branch from the currently checked out branch. You'll be
+       prompted to enter a name for the new branch.
+A      Same as aa.
+dd     Delete the branch under the cursor.
+D      Same as dd.
+mm     Merge the branch under the cursor into the currently checked out
+       branch. If there are merge conflicts, the |merginal-merge-conflicts|
+       buffer will open in place of the branch list buffer.
+M      Same as mm.
+mf     Merge the branch under the cursor into the currently checked out branch
+       using Fugitive's |:Gmerge| command.
+rb     Rebase the currently checked out branch against the branch under the
+       cursor. If there are rebase conflicts, the |merginal-rebase-conflicts|
+       buffer will open in place of
+       the branch list buffer.
+ps     Prompt to choose a remote to push the branch under the cursor.
+pS     Prompt to choose a remote to force push the branch under the cursor.
+pl     Prompt to choose a remote to pull the branch under the cursor.
+pf     Prompt to choose a remote to fetch the branch under the cursor.
+gd     Open |merginal-diff-files| buffer to diff against the branch under the
+       cursor.
+rn     Prompt to rename the branch under the cursor.
+
+
+MERGE CONFLICTS                                   *merginal-merge-conflicts*
+
+The merge conflicts buffer is used to solve merge conflicts. It shows all the
+files that have merge conflicts and offers the following keymaps:
+
+R      Refresh the merge conflicts list.
+<Cr>   Open the conflicted file under the cursor.
+aa     Add the conflicted file under the cursor to the staging area. If that
+       was the last conflicted file, the merge conflicts buffer will close and
+       |fugitive-:Gstatus| will open.
+A      Same as aa.
+
+
+REBASE CONFLICTS                                 *merginal-rebase-conflicts*
+
+The rebase conflicts buffer is used to solve rebase conflicts. It shows the
+currently applied commit message and all the files that have rebase conflicts,
+and offers the following keymaps:
+
+R      Refresh the rebase conflicts list.
+<Cr>   Open the conflicted file under the cursor.
+aa     Add the conflicted file under the cursor to the staging area. If that
+       was the last conflicted file, prompt the user to continue to the next
+       patch.
+A      Same as aa.
+ra     Abort the rebase
+rc     Continue to the next patch.
+rs     Skip the current patch
+
+
+REBASE AMEND                                         *merginal-rebase-amend*
+
+The rebase amend buffer is shown when you amend a patch during a rebase. It
+shows the amended commit's shortened hash and commit message. Additionally, it
+shows all the branches so you can diff against them while the patch. If offers
+the folloing keymaps:
+
+R      Refresh the rebase amend buffer.
+gd     Open |merginal-diff-files| buffer to diff against the branch under the
+       cursor.
+ra     Abort the rebase
+rc     Continue to the next patch.
+rs     Skip the current patch
+
+
+DIFF FILES                                             *merginal-diff-files*
+
+The diff files buffer is used to diff against another branch. It displays all
+the differences between the currently checked out branch and the branch it was
+opened against, and offerts the following keymaps:
+
+R      Refresh the diff files list.
+<Cr>   Open the file under the cursor(if it exists in the currently checked
+       out branch).
+ds     Split-diff against the file under the cursor(if it exists in the other
+       branch)
+ds     VSplit-diff against the file under the cursor(if it exists in the other
+       branch)
+co     Check out the file under the cursor(if it exists in the other branch)
+       into the current branch.
diff --git a/vimfiles/doc/tags b/vimfiles/doc/tags
index 90177b7..6b7fb68 100644
--- a/vimfiles/doc/tags
+++ b/vimfiles/doc/tags
@@ -1940,6 +1940,15 @@ matchit-troubleshoot	matchit.txt	/*matchit-troubleshoot*
 matchit-v_%	matchit.txt	/*matchit-v_%*
 matchit.txt	matchit.txt	/*matchit.txt*
 matchit.vim	matchit.txt	/*matchit.vim*
+merginal	merginal.txt	/*merginal*
+merginal-branch-list	merginal.txt	/*merginal-branch-list*
+merginal-diff-files	merginal.txt	/*merginal-diff-files*
+merginal-merge-conflicts	merginal.txt	/*merginal-merge-conflicts*
+merginal-rebase-amend	merginal.txt	/*merginal-rebase-amend*
+merginal-rebase-conflicts	merginal.txt	/*merginal-rebase-conflicts*
+merginal-requirements	merginal.txt	/*merginal-requirements*
+merginal-usage	merginal.txt	/*merginal-usage*
+merginal.txt	merginal.txt	/*merginal.txt*
 n_<Plug>TComment-Comment	tcomment.txt	/*n_<Plug>TComment-Comment*
 n_<Plug>TComment-Commentb	tcomment.txt	/*n_<Plug>TComment-Commentb*
 n_<Plug>TComment-Commentc	tcomment.txt	/*n_<Plug>TComment-Commentc*
diff --git a/vimfiles/plugin/merginal.vim b/vimfiles/plugin/merginal.vim
new file mode 100755
index 0000000..1cda509
--- /dev/null
+++ b/vimfiles/plugin/merginal.vim
@@ -0,0 +1,51 @@
+function! s:openBasedOnMergeMode() abort
+    if merginal#isRebaseMode()
+        call merginal#openRebaseConflictsBuffer()
+    elseif merginal#isRebaseAmendMode()
+        call merginal#openRebaseAmendBuffer()
+    elseif merginal#isMergeMode()
+        call merginal#openMergeConflictsBuffer()
+    else
+        call merginal#openBranchListBuffer()
+    endif
+endfunction
+
+function! s:toggleBasedOnMergeMode() abort
+    let l:repo=fugitive#repo()
+    let l:merginalWindowNumber=bufwinnr('Merginal:')
+    if 0<=l:merginalWindowNumber
+        let l:merginalBufferNumber=winbufnr(l:merginalWindowNumber)
+        let l:merginalBufferName=bufname(l:merginalBufferNumber)
+
+        "If we are not on the same dir we need to reload the merginal buffer
+        "anyways:
+        if getbufvar(l:merginalBufferNumber,'merginal_repo').dir()==l:repo.dir()
+            if merginal#isRebaseMode()
+                if 'Merginal:Rebase'==l:merginalBufferName
+                    call merginal#closeMerginalBuffer()
+                    return
+                endif
+            elseif merginal#isRebaseAmendMode()
+                if 'Merginal:RebaseAmend'==l:merginalBufferName
+                    call merginal#closeMerginalBuffer()
+                    return
+                endif
+            elseif merginal#isMergeMode()
+                if 'Merginal:Conflicts'==l:merginalBufferName
+                    call merginal#closeMerginalBuffer()
+                    return
+                endif
+            else
+                if 'Merginal:Branches'==l:merginalBufferName
+                    call merginal#closeMerginalBuffer()
+                    return
+                endif
+            end
+        endif
+    endif
+    call s:openBasedOnMergeMode()
+endfunction
+
+autocmd User Fugitive command! -buffer -nargs=0 Merginal call s:openBasedOnMergeMode()
+autocmd User Fugitive command! -buffer -nargs=0 MerginalToggle call s:toggleBasedOnMergeMode()
+autocmd User Fugitive command! -buffer -nargs=0 MerginalClose call merginal#closeMerginalBuffer()