Use ediff interactive merge to help conflict resolution.

Idea from smerge code, adapted to git, new key binding on "e"
This commit is contained in:
Rémi Vanicat 2009-02-25 14:55:52 +01:00
parent 5cd62fa9ac
commit 1eac6b70c6
2 changed files with 73 additions and 17 deletions

View file

@ -105,7 +105,7 @@ Setting this to nil will make it do nothing, setting it to t will arrange things
"Require acknowledgement before cancelling the log edit buffer." "Require acknowledgement before cancelling the log edit buffer."
:group 'magit :group 'magit
:type 'boolean) :type 'boolean)
(defface magit-header (defface magit-header
'((t)) '((t))
"Face for generic header lines. "Face for generic header lines.
@ -415,7 +415,7 @@ Many Magit faces inherit from this one by default."
(if (stringp range) (if (stringp range)
(format "%s in %s" things range) (format "%s in %s" things range)
(if (cdr range) (if (cdr range)
(format "%s from %s to %s" things (format "%s from %s to %s" things
(magit-rev-describe (car range)) (magit-rev-describe (car range))
(magit-rev-describe (cdr range))) (magit-rev-describe (cdr range)))
(format "%s at %s" things (magit-rev-describe (car range)))))) (format "%s at %s" things (magit-rev-describe (car range))))))
@ -605,7 +605,7 @@ Many Magit faces inherit from this one by default."
(magit-section-children (magit-section-children
section))) section)))
(magit-next-section section)))) (magit-next-section section))))
(if next (if next
(progn (progn
(goto-char (magit-section-beginning next)) (goto-char (magit-section-beginning next))
@ -1001,7 +1001,7 @@ Many Magit faces inherit from this one by default."
(defun magit-run-git (&rest args) (defun magit-run-git (&rest args)
(magit-with-refresh (magit-with-refresh
(magit-run* (append (cons magit-git-executable (magit-run* (append (cons magit-git-executable
magit-git-standard-options) magit-git-standard-options)
args)))) args))))
@ -1011,7 +1011,7 @@ Many Magit faces inherit from this one by default."
(defun magit-run-git-with-input (input &rest args) (defun magit-run-git-with-input (input &rest args)
(magit-with-refresh (magit-with-refresh
(magit-run* (append (cons magit-git-executable (magit-run* (append (cons magit-git-executable
magit-git-standard-options) magit-git-standard-options)
args) args)
nil nil nil nil input))) nil nil nil nil input)))
@ -1023,7 +1023,7 @@ Many Magit faces inherit from this one by default."
cmd)))) cmd))))
(defun magit-run-git-async (&rest args) (defun magit-run-git-async (&rest args)
(magit-run* (append (cons magit-git-executable (magit-run* (append (cons magit-git-executable
magit-git-standard-options) magit-git-standard-options)
args) args)
nil nil nil t)) nil nil nil t))
@ -1104,6 +1104,7 @@ Many Magit faces inherit from this one by default."
(define-key map (kbd "B") 'magit-create-branch) (define-key map (kbd "B") 'magit-create-branch)
(define-key map (kbd "m") 'magit-manual-merge) (define-key map (kbd "m") 'magit-manual-merge)
(define-key map (kbd "M") 'magit-automatic-merge) (define-key map (kbd "M") 'magit-automatic-merge)
(define-key map (kbd "e") 'magit-interactive-resolve-item)
(define-key map (kbd "N r") 'magit-svn-rebase) (define-key map (kbd "N r") 'magit-svn-rebase)
(define-key map (kbd "N c") 'magit-svn-dcommit) (define-key map (kbd "N c") 'magit-svn-dcommit)
(define-key map (kbd "R") 'magit-rebase-step) (define-key map (kbd "R") 'magit-rebase-step)
@ -1167,6 +1168,7 @@ Many Magit faces inherit from this one by default."
["Create branch" magit-create-branch t] ["Create branch" magit-create-branch t]
["Merge" magit-automatic-merge t] ["Merge" magit-automatic-merge t]
["Merge (no commit)" magit-manual-merge t] ["Merge (no commit)" magit-manual-merge t]
["Interactive resolve" magit-interactive-resolve-item t]
["Rebase" magit-rebase-step t] ["Rebase" magit-rebase-step t]
("Git SVN" ("Git SVN"
["Rebase" magit-svn-rebase (magit-svn-enabled)] ["Rebase" magit-svn-rebase (magit-svn-enabled)]
@ -1519,7 +1521,7 @@ Please see the manual for a complete description of Magit.
diff)) diff))
(defun magit-diff-item-insert-header (diff buf) (defun magit-diff-item-insert-header (diff buf)
(let ((beg (save-excursion (let ((beg (save-excursion
(goto-char (magit-section-beginning diff)) (goto-char (magit-section-beginning diff))
(forward-line) (forward-line)
(point))) (point)))
@ -1529,7 +1531,7 @@ Please see the manual for a complete description of Magit.
(magit-insert-region beg end buf))) (magit-insert-region beg end buf)))
(defun magit-insert-diff-item-patch (diff buf) (defun magit-insert-diff-item-patch (diff buf)
(let ((beg (save-excursion (let ((beg (save-excursion
(goto-char (magit-section-beginning diff)) (goto-char (magit-section-beginning diff))
(forward-line) (forward-line)
(point))) (point)))
@ -2314,7 +2316,7 @@ Prefix arg means justify as well."
(defun magit-log-edit-cancel-log-message () (defun magit-log-edit-cancel-log-message ()
(interactive) (interactive)
(when (or (not magit-log-edit-confirm-cancellation) (when (or (not magit-log-edit-confirm-cancellation)
(yes-or-no-p (yes-or-no-p
"Really cancel editing the log (any changes will be lost)?")) "Really cancel editing the log (any changes will be lost)?"))
(erase-buffer) (erase-buffer)
(bury-buffer) (bury-buffer)
@ -2510,7 +2512,7 @@ Prefix arg means justify as well."
(t (t
(magit-log-edit-append (magit-log-edit-append
(magit-format-commit commit "%s%n%n%b")) (magit-format-commit commit "%s%n%n%b"))
(magit-log-edit-set-field (magit-log-edit-set-field
'author 'author
(magit-format-commit commit "%an <%ae>, %ai"))))) (magit-format-commit commit "%an <%ae>, %ai")))))
success)) success))
@ -2625,7 +2627,7 @@ Prefix arg means justify as well."
(let* ((topdir (magit-get-top-dir default-directory)) (let* ((topdir (magit-get-top-dir default-directory))
(args (magit-rev-to-git head))) (args (magit-rev-to-git head)))
(switch-to-buffer "*magit-reflog*") (switch-to-buffer "*magit-reflog*")
(magit-mode-init topdir 'reflog (magit-mode-init topdir 'reflog
#'magit-refresh-reflog-buffer head args)))) #'magit-refresh-reflog-buffer head args))))
(defun magit-reflog-head () (defun magit-reflog-head ()
@ -2681,7 +2683,7 @@ Prefix arg means justify as well."
head b)) head b))
(section (section
(let ((magit-section-hidden-default t)) (let ((magit-section-hidden-default t))
(magit-git-section (magit-git-section
(cons b 'wazzup) (cons b 'wazzup)
(format "%s unmerged commits in %s" (format "%s unmerged commits in %s"
n b) n b)
@ -2697,7 +2699,7 @@ Prefix arg means justify as well."
(interactive) (interactive)
(let* ((topdir (magit-get-top-dir default-directory))) (let* ((topdir (magit-get-top-dir default-directory)))
(switch-to-buffer "*magit-wazzup*") (switch-to-buffer "*magit-wazzup*")
(magit-mode-init topdir 'wazzup (magit-mode-init topdir 'wazzup
#'magit-refresh-wazzup-buffer #'magit-refresh-wazzup-buffer
(magit-get-current-branch)))) (magit-get-current-branch))))
@ -2865,4 +2867,58 @@ Prefix arg means justify as well."
(erase-buffer) (erase-buffer)
(shell-command (concat magit-git-executable " branch -va") t t))) (shell-command (concat magit-git-executable " branch -va") t t)))
(defvar magit-ediff-file)
(defvar magit-ediff-windows)
(defun magit-interactive-resolve (file)
(let ((merge-status (magit-git-string "ls-files -u -- %s" file))
(base-buffer (generate-new-buffer (concat file ".base")))
(our-buffer (generate-new-buffer (concat file ".ours")))
(their-buffer (generate-new-buffer (concat file ".theirs")))
(windows (current-window-configuration)))
(if (null merge-status)
(error "Cannot resolge %s" file))
(with-current-buffer base-buffer
(if (string-match "^[0-9]+ [0-9a-f]+ 1" merge-status)
(insert (magit-git-string "cat-file blob :1:%s" file))))
(with-current-buffer our-buffer
(if (string-match "^[0-9]+ [0-9a-f]+ 2" merge-status)
(insert (magit-git-string "cat-file blob :2:%s" file))))
(with-current-buffer their-buffer
(if (string-match "^[0-9]+ [0-9a-f]+ 3" merge-status)
(insert (magit-git-string "cat-file blob :3:%s" file))))
;; We have now created the 3 buffer with ours, theirs and the ancestor files
(with-current-buffer (ediff-merge-buffers-with-ancestor our-buffer their-buffer base-buffer)
(make-local-variable 'magit-ediff-file)
(setq magit-ediff-file file)
(make-local-variable 'magit-ediff-windows)
(setq magit-ediff-windows windows)
(make-local-variable 'ediff-quit-hook)
(add-hook 'ediff-quit-hook
(lambda ()
(let ((buffer-A ediff-buffer-A)
(buffer-B ediff-buffer-B)
(buffer-C ediff-buffer-C)
(buffer-Ancestor ediff-ancestor-buffer)
(file magit-ediff-file)
(windows magit-ediff-windows))
(ediff-cleanup-mess)
(find-file file)
(erase-buffer)
(insert-buffer-substring buffer-C)
(kill-buffer buffer-A)
(kill-buffer buffer-B)
(kill-buffer buffer-C)
(when (bufferp buffer-Ancestor) (kill-buffer buffer-Ancestor))
(set-window-configuration windows)
(message "Conflict resolution finished; you may save the buffer")))))))
(defun magit-interactive-resolve-item ()
(interactive)
(magit-section-action (item info "resolv")
((diff)
(magit-interactive-resolve (cadr info)))))
(provide 'magit) (provide 'magit)

View file

@ -452,10 +452,10 @@ one parent). If you want to abort a manual merge, just do a hard
reset to HEAD with @kbd{X}. reset to HEAD with @kbd{X}.
Merges can fail if the two branches you merge want to introduce Merges can fail if the two branches you merge want to introduce
conflicting changes. In that case, the automatic merge stops before conflicting changes. In that case, the automatic merge stops before the
the commit, essentially falling back to a manual merge. You need to commit, essentially falling back to a manual merge. You need to resolve
resolve the conflicts and stage the resolved files, for example with the conflicts for example with @kbd{e} and stage the resolved files, for
@kbd{S}. example with @kbd{S}.
You can not stage individual hunks one by one as you resolve them, you You can not stage individual hunks one by one as you resolve them, you
can only stage whole files once all conflicts in them have been can only stage whole files once all conflicts in them have been