Download
(eval-when-compile (require 'cl))
(defgroup git-dwim nil
"git-dwim"
:group 'vc)
(defun gd-shell-command (command)
(shell-command command " *git-dwim*"))
(defun git-current-branch ()
(substring (shell-command-to-string "git branch | grep '\*'") 2 -1))
(defun git-get-branches ()
(split-string (shell-command-to-string "git branch | cut -b3-") "\n" t))
(defun git-unmerged-p ()
(string-match "^# Unmerged paths:" (shell-command-to-string "git status")))
(defun gd-display-string (output buffer)
(with-current-buffer (get-buffer-create buffer)
(buffer-disable-undo)
(insert output "\n===========================================================\n")
(display-buffer (current-buffer))))
(defun gd-menu-select (menu-alist &optional caption)
"Menu selection. MENU-ALIST is a list of (KEY DISPLAY FUNCTION).
KEY is a character such as ?a.
DISPLAY is display string.
FUNCTION has no argument and is called when the KEY is pressed.
Example:
(gd-menu-select '((?a \"A\" (lambda () (message \"[a]\")))
(?b \"B\" (lambda () (error \"err\")))))
"
(condition-case err
(funcall
(caddr
(assq (read-event
(concat (if caption (concat caption " ") "")
(mapconcat 'identity (mapcar 'cadr menu-alist) " ")))
menu-alist)))
(void-function (error "invalid key"))))
(defun gd-menu-select-with-current-branch (menu-alist)
(gd-menu-select menu-alist (propertize (git-current-branch) 'face 'highlight)))
(defun git-branch-next-action ()
"Do appropriate action for branch.
* If current branch is master: switch to other or new branch.
* If current branch is not master: switch to other branch or merge this branch to master.
* If merge is failed: continue merging (You have to resolve conflict merker)
"
(interactive)
(cond ((equal (git-current-branch) "master")
(gd-menu-select-with-current-branch
'((?s "[s]witch-to-other-branch" git-switch-to-other-branch)
(?c "[c]reate-new-branch" git-create-new-branch))))
((git-unmerged-p)
(git-merge-to "master" t))
(t
(gd-menu-select-with-current-branch
'((?s "[s]witch-to-other-branch" git-switch-to-other-branch)
(?m "[m]erge-to-master" git-merge-to)
(?f "merge-[f]rom-master" git-merge-from-master))))))
(defun git-create-new-branch (&optional branch)
"Create new BRANCH and switch to it."
(interactive)
(setq branch (or branch (read-string "Create and switch to new branch: ")))
(gd-shell-command (format "git checkout -b %s" branch)))
(defun git-switch-to-other-branch (&optional branch)
"Switch to existing BRANCH."
(interactive)
(setq branch (or branch (completing-read "Switch to new branch: "
(git-get-branches) nil t)))
(gd-shell-command (format "git checkout %s" branch)))
(defun git-merge-to (&optional branch continue)
"Merge this branch to master."
(interactive)
(setq branch (or branch "master"))
(when continue
(gd-shell-command (format "git add %s" (shell-quote-argument buffer-file-name))))
(let ((output (shell-command-to-string
(format "git rebase %s %s" (if continue "--continue" "") branch))))
(if (string-match "^CONFLICT\\|^You must edit all merge conflicts" output)
(gd-display-string output "*git rebase conflict*")
(let ((cur (git-current-branch)))
(ignore-errors (kill-buffer "*git rebase conflict*"))
(gd-shell-command (format "git checkout %s; git merge %s; git branch -d %s"
branch cur cur))))))
(defun git-merge-from-master ()
(gd-shell-command "git rebase " ))
(provide 'git-dwim)