Skip to content

Commit

Permalink
Implemented Branch Checkout (jreybert#141)
Browse files Browse the repository at this point in the history
There are three bindings: <CBB>, <CBF>, and <CB->. <CBB> is the
equivalent of 'git checkout -b'; <CBF> is the equivalent of 'git
checkout -B', and <CB-> is the equivalent of 'git checkout -'.

I adapted the UI based off of the proposed UI in the issue by changing
from autocompletion(?) of typed branch names to listed branches (remote
and local alike) which can be selected with <CBB>/<CBF>, along with the
option to Close the section as well as create a new local branch.

Inline help and vimagit.txt are updated with details.
  • Loading branch information
nikewall committed Jun 21, 2020
1 parent 94762b1 commit 220fe9c
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 3 deletions.
6 changes: 6 additions & 0 deletions autoload/magit/git.vim
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,9 @@ function! magit#git#get_remote_branch(ref, type)
return "none"
endtry
endfunction


function! magit#git#get_branches()
return magit#sys#system(g:magit_git_cmd . " branch -a")
endfunction

18 changes: 18 additions & 0 deletions autoload/magit/mapping.vim
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ let g:magit_commit_fixup_mapping = get(g:, 'magit_commit_fixup_mapping',
let g:magit_close_commit_mapping = get(g:, 'magit_close_commit_mapping', 'CU' )
let g:magit_reload_mapping = get(g:, 'magit_reload_mapping', 'R' )
let g:magit_edit_mapping = get(g:, 'magit_edit_mapping', 'E' )
let g:magit_checkout_mapping = get(g:, 'magit_checkout_mapping', 'CBB')
let g:magit_checkout_last_mapping = get(g:, 'magit_checkout_last_mapping', 'CB-')
let g:magit_checkout_force_mapping = get(g:, 'magit_checkout_force_mapping', 'CBF')

let g:magit_jump_next_hunk = get(g:, 'magit_jump_next_hunk', '<C-N>')
let g:magit_jump_prev_hunk = get(g:, 'magit_jump_prev_hunk', '<C-P>')
Expand Down Expand Up @@ -157,6 +160,13 @@ function! magit#mapping#set_default()
call s:mg_set_mapping('n', g:magit_jump_prev_hunk,
\ "magit#jump_hunk('P')")

call s:mg_set_mapping('n', g:magit_checkout_mapping,
\ "magit#checkout_branch('B')")
call s:mg_set_mapping('n', g:magit_checkout_last_mapping,
\ "magit#checkout_branch('-')")
call s:mg_set_mapping('n', g:magit_checkout_force_mapping,
\ "magit#checkout_branch('F')")

for mapping in g:magit_folding_toggle_mapping
" trick to pass '<cr>' in a mapping command without being interpreted
let func_arg = ( mapping ==? "<cr>" ) ? '+' : mapping
Expand Down Expand Up @@ -227,6 +237,14 @@ function! magit#mapping#set_default()
\' modifying the previous commit message',
\g:magit_close_commit_mapping
\. ' commit undo, cancel and close current commit message',
\g:magit_checkout_mapping
\. ' From stage mode: set branch mode in normal flavor',
\' From branch mode: checkout branch on line cursor is on.',
\g:magit_checkout_force_mapping
\. ' From stage mode: set branch mode in force flavor',
\' From branch mode: checkout/reset branch on line cursor is on.',
\g:magit_checkout_last_mapping
\. ' From stage mode: checkout previous branch.',
\g:magit_reload_mapping
\.' refresh magit buffer',
\g:magit_diff_shrink.','.g:magit_diff_enlarge.','.g:magit_diff_reset
Expand Down
3 changes: 2 additions & 1 deletion common/magit_common.vim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ let g:magit_sections = {
\ 'staged': 'Staged changes',
\ 'unstaged': 'Unstaged changes',
\ 'commit': 'Commit message',
\ 'stash': 'Stash list'
\ 'stash': 'Stash list',
\ 'branches': 'Branch list'
\ }

let g:magit_section_info = {
Expand Down
34 changes: 33 additions & 1 deletion doc/vimagit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,26 @@ Commit mode has two flavors.

By the way, you can also perform all stage mode actions in commit mode.

BRANCH MODE *vimagit-branch-mode*

In this mode, the `Branch list` section is open, where you can choose any
existing local or remote branch as well as create a new local branch.
There are two flavors to Branch mode:

* `normal`: selected branch will be created/checked out normally.
* `force`: selected branch will be created if nonexistant, or reset if existant.

SECTIONS *vimagit-sections*

IMPORTANT: mappings can have different meanings regarding the cursor position.

There are 5 sections:
There are 6 sections:
* Info: this section display some information about the git repository, like
the current branch and the HEAD commit.
* Commit message: this section appears in commit mode (see below). It contains
the message to be committed.
* Branch list: this section contains all of the current local and remote
brances.
* Staged changes: this sections contains all staged files/hunks, ready to
commit.
* Unstaged changes: this section contains all unstaged and untracked
Expand Down Expand Up @@ -218,6 +229,27 @@ section only.



*vimagit-CBB* *magit#checkout_branch('B')*
*vimagit-g:magit_checkout_mapping*
<CBB> From `stage mode`, set branch mode in `normal` flavor and show
"Branches" section. When used in `branch mode`, the branch name on
the line the cursor is on will be checked out. Created locally if
needed. This is equivalent to `git checkout -b <branch> [remote]`

*vimagit-CBF* *magit#checkout_branch('F')*
*vimagit-g:magit_checkout_force_mapping*
<CBF> From `stage mode` or `branch mode`, set branching to `force` mode,
and checkout any new or existing branches with <CBF> while the cursor
is on the line of the desired branch. This is equivalent to
`git checkout -B <branch> [remote]`.

*vimagit-CB-* *magit#checkout_branch('-')*
*vimagit-g:magit_checkout_last_mapping*
<CB-> From `stage mode`, instantly checkout the previous branch. Any
changes are carried along the checkout. This is equivalent to
`git checkout -`.


*vimagit-<C-n>* *magit#jump_hunk()*
*vimagit-<C-p>*
*vimagit-g:magit_jump_next_hunk*
Expand Down
132 changes: 131 additions & 1 deletion plugin/magit.vim
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ let g:magit_default_show_all_files = get(g:, 'magit_default_show_all_files',
let g:magit_default_fold_level = get(g:, 'magit_default_fold_level', 1)
let g:magit_auto_close = get(g:, 'magit_auto_close', 0)
let g:magit_auto_foldopen = get(g:, 'magit_auto_foldopen', 1)
let g:magit_default_sections = get(g:, 'magit_default_sections', ['info', 'global_help', 'commit', 'staged', 'unstaged'])
let g:magit_default_sections = get(g:, 'magit_default_sections', ['info', 'global_help', 'branch', 'commit', 'staged', 'unstaged'])
let g:magit_discard_untracked_do_delete = get(g:, 'magit_discard_untracked_do_delete', 0)

let g:magit_refresh_gutter = get(g:, 'magit_refresh_gutter' , 1)
Expand Down Expand Up @@ -249,6 +249,25 @@ function! s:mg_get_commit_section()
endif
endfunction

" s:mg_get_branches_section: this function writes in current buffer the commit
" section. It is a commit message, depending on b:magit_current_commit_mode
" WARNING: this function writes in file, it should only be called through
" protected functions like magit#update_buffer
" param[in] b:magit_show_branches:
function! s:mg_get_branches_section()
if ( b:magit_show_branches == 1 )
silent put =g:magit_sections.branches
silent put =magit#utils#underline(g:magit_sections.branches)

let branch_list = magit#git#get_branches()
silent put ='*Close*'
silent put ='New Branch:'
silent put =branch_list
silent put =''
silent put =''
endif
endfunction

" s:mg_search_block: helper function, to get start and end line of a block,
" giving a start and multiple end pattern
" a "pattern parameter" is a List:
Expand Down Expand Up @@ -390,6 +409,42 @@ function! s:mg_git_commit(mode) abort
let b:magit_just_commited = 1
endfunction

" s:mg_git_checkout_branch: checks out a branch (local or remote)
" param[in]: branch_name specifies the name of the branch
" remote specifies the name of the remote
" = '' specifies a local branch
" return none
function! s:mg_git_checkout_branch(branch_name, remote)
" Update the name of the remote branch (format: 'origin/master')
if ( a:remote != '' )
let remote_name = " " . a:remote . "/" . a:branch_name
endif

if ( b:magit_current_checkout_flag == 'B' && a:remote != '' )
let checkout_cmd = g:magit_git_cmd . " checkout -b " .
\ a:branch_name . " " . remote_name
elseif ( b:magit_current_checkout_flag == 'B' && b:magit_creating_new_branch == 1)
let checkout_cmd = g:magit_git_cmd . " checkout -b " .
\ a:branch_name
elseif ( b:magit_current_checkout_flag == 'B' || b:magit_current_checkout_flag == '-' )
let checkout_cmd = g:magit_git_cmd . " checkout " .
\ a:branch_name
elseif ( b:magit_current_checkout_flag == 'F' && a:remote != '' && b:magit_creating_new_branch == 0 )
let checkout_cmd = g:magit_git_cmd . " checkout -B " .
\ a:branch_name . remote_name
elseif ( b:magit_current_checkout_flag == 'F' && b:magit_creating_new_branch == 1 )
let checkout_cmd = g:magit_git_cmd . " checkout -B " .
\ a:branch_name
endif

try
silent! let git_result = magit#sys#system(checkout_cmd)
catch 'shell error'
call magit#sys#print_shell_error()
echoerr "Could not checkout branch ''" . a:branch_name . "'"
endtry
endfunction

" s:mg_select_file_block: select the whole diff file, relative to the current
" cursor position
" nota: if the cursor is not in a diff file when the function is called, this
Expand Down Expand Up @@ -531,6 +586,7 @@ let g:magit_last_updated_buffer = ''
let s:mg_display_functions = {
\ 'info': { 'fn': function("s:mg_get_info"), 'arg': []},
\ 'global_help': { 'fn': function("magit#mapping#get_section_help"), 'arg': ['global']},
\ 'branch': { 'fn': function("s:mg_get_branches_section"), 'arg': []},
\ 'commit': { 'fn': function("s:mg_get_commit_section"), 'arg': []},
\ 'staged': { 'fn': function("s:mg_get_staged_section"), 'arg': ['staged']},
\ 'unstaged': { 'fn': function("s:mg_get_staged_section"), 'arg': ['unstaged']},
Expand Down Expand Up @@ -851,6 +907,9 @@ function! magit#show_magit(display, ...)
let b:magit_current_commit_mode=''
let b:magit_commit_newly_open=0

let b:magit_show_branches=0
let b:magit_current_branch_mode=''

let b:magit_diff_context=3

let b:magit_just_commited = 0
Expand Down Expand Up @@ -1273,6 +1332,73 @@ function! magit#jump_hunk(dir)
endif
endfunction

" magit#checkout_branch: entry function for branch checkout
" param[in]: opt specifies the option for checkout
" 'B' is for '-b'
" 'F' is for '-B'
" '-' is to checkout previous branch
function! magit#checkout_branch(opt)
let b:magit_current_checkout_flag = a:opt
if ( b:magit_show_branches == 0 && a:opt != '-' )
let b:magit_show_branches = 1
else
call magit#select_branch()
endif

if ( a:opt == '-' )
call <SID>mg_git_checkout_branch('-', '')
endif

call magit#update_buffer()
endfunction

" magit#select_branch: handles the parsing and passing of the selected branch
" return no
function! magit#select_branch()
let line = trim(getline("."))

" cannot checkout HEAD
if ( match(line, "HEAD") != -1 )
let b:magit_show_branches = 0
call magit#update_buffer()
return
endif

" close buffer if requested
if ( match(line, "*Close*") != -1 )
let b:magit_show_branches = 0
call magit#update_buffer()
return
endif

" check whether attempting to checkout remote branch
" and pass to s:mg_git_checkout_branch() with correct + clean options
let is_remote = match(line, "remotes")
if ( is_remote != -1 )
let line = substitute(line, "^remotes/", "", "")
let remote = matchstr(line, "[^/]*")
let branch = matchstr(line, ".*", len(remote)+1)
call <SID>mg_git_checkout_branch(branch, remote)
else
" disregard if attempting to checkout current branch
if ( match(line, "*") != -1 )
echo "You are already checked out on this branch..."
return
else
" handle custom input for new branch
if ( match(line, "^New Branch:") != -1 )
let anti_line = matchstr(line, "[^:]*")
let line = trim(matchstr(line, ".*", len(anti_line)+1))
let b:magit_creating_new_branch = 1
else
let b:magit_creating_new_branch = 0
endif

call <SID>mg_git_checkout_branch(line, '')
endif
endif
endfunction

" magit#get_staged_files: function returning an array with staged files names
" return: an array with staged files names
function! magit#get_staged_files()
Expand Down Expand Up @@ -1348,6 +1474,10 @@ function! magit#get_current_mode()
return "COMMIT"
elseif ( b:magit_current_commit_mode == 'CA' )
return "AMEND"
elseif ( b:magit_current_checkout_flag == 'B' )
return "BRANCH"
elseif ( b:magit_current_checkout_flag == 'F' )
return "FORCE"
endif
endfunction

Expand Down

0 comments on commit 220fe9c

Please sign in to comment.