From 220fe9c9ff9b5ca0c6acfee7db3bfa953a992c36 Mon Sep 17 00:00:00 2001 From: nikewall Date: Sun, 21 Jun 2020 02:37:44 -0400 Subject: [PATCH 1/3] Implemented Branch Checkout (#141) There are three bindings: , , and . is the equivalent of 'git checkout -b'; is the equivalent of 'git checkout -B', and 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 /, 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. --- autoload/magit/git.vim | 6 ++ autoload/magit/mapping.vim | 18 +++++ common/magit_common.vim | 3 +- doc/vimagit.txt | 34 +++++++++- plugin/magit.vim | 132 ++++++++++++++++++++++++++++++++++++- 5 files changed, 190 insertions(+), 3 deletions(-) diff --git a/autoload/magit/git.vim b/autoload/magit/git.vim index 27cd507..cfc581d 100644 --- a/autoload/magit/git.vim +++ b/autoload/magit/git.vim @@ -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 + diff --git a/autoload/magit/mapping.vim b/autoload/magit/mapping.vim index 6bffbf8..50fbcfe 100644 --- a/autoload/magit/mapping.vim +++ b/autoload/magit/mapping.vim @@ -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', '') let g:magit_jump_prev_hunk = get(g:, 'magit_jump_prev_hunk', '') @@ -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 '' in a mapping command without being interpreted let func_arg = ( mapping ==? "" ) ? '+' : mapping @@ -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 diff --git a/common/magit_common.vim b/common/magit_common.vim index f1f8123..e0bb6ae 100644 --- a/common/magit_common.vim +++ b/common/magit_common.vim @@ -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 = { diff --git a/doc/vimagit.txt b/doc/vimagit.txt index e0ef71e..0c87a00 100644 --- a/doc/vimagit.txt +++ b/doc/vimagit.txt @@ -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 @@ -218,6 +229,27 @@ section only. + *vimagit-CBB* *magit#checkout_branch('B')* + *vimagit-g:magit_checkout_mapping* + 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 [remote]` + + *vimagit-CBF* *magit#checkout_branch('F')* + *vimagit-g:magit_checkout_force_mapping* + From `stage mode` or `branch mode`, set branching to `force` mode, + and checkout any new or existing branches with while the cursor + is on the line of the desired branch. This is equivalent to + `git checkout -B [remote]`. + + *vimagit-CB-* *magit#checkout_branch('-')* + *vimagit-g:magit_checkout_last_mapping* + From `stage mode`, instantly checkout the previous branch. Any + changes are carried along the checkout. This is equivalent to + `git checkout -`. + + *vimagit-* *magit#jump_hunk()* *vimagit-* *vimagit-g:magit_jump_next_hunk* diff --git a/plugin/magit.vim b/plugin/magit.vim index 1455382..b6d5cf9 100644 --- a/plugin/magit.vim +++ b/plugin/magit.vim @@ -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) @@ -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: @@ -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 @@ -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']}, @@ -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 @@ -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 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 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 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() @@ -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 From 159bb12446cb8c2aed60da629f1e6499dfcc8d04 Mon Sep 17 00:00:00 2001 From: nikewall Date: Sun, 21 Jun 2020 02:37:44 -0400 Subject: [PATCH 2/3] Implemented Branch Checkout (#141) There are three bindings: , , and . is the equivalent of 'git checkout -b'; is the equivalent of 'git checkout -B', and 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 /, 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. --- plugin/magit.vim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugin/magit.vim b/plugin/magit.vim index b6d5cf9..5f6d43f 100644 --- a/plugin/magit.vim +++ b/plugin/magit.vim @@ -249,8 +249,13 @@ function! s:mg_get_commit_section() endif endfunction +<<<<<<< HEAD " 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 +======= +" s:mg_get_branches_section: this function writes in current buffer the branch +" section. +>>>>>>> 39003c0... Implemented Branch Checkout (#141) " WARNING: this function writes in file, it should only be called through " protected functions like magit#update_buffer " param[in] b:magit_show_branches: From ec84811bac2d1572f24ae1fb4247d0448751abfe Mon Sep 17 00:00:00 2001 From: nikewall Date: Sun, 21 Jun 2020 02:56:35 -0400 Subject: [PATCH 3/3] Fix amend blunder. --- plugin/magit.vim | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugin/magit.vim b/plugin/magit.vim index 5f6d43f..2f54652 100644 --- a/plugin/magit.vim +++ b/plugin/magit.vim @@ -249,13 +249,8 @@ function! s:mg_get_commit_section() endif endfunction -<<<<<<< HEAD -" 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 -======= " s:mg_get_branches_section: this function writes in current buffer the branch " section. ->>>>>>> 39003c0... Implemented Branch Checkout (#141) " WARNING: this function writes in file, it should only be called through " protected functions like magit#update_buffer " param[in] b:magit_show_branches: