49 votes

Utiliser ediff comme git mergetool

Je voudrais être en mesure d'utiliser ediff avec "git mergetool".

J'ai trouvé quelques patchs qui modifient le code source, je ne veux pas faire. Au lieu de cela, je voudrais ajouter ediff de soutien avec mon .gitconfig.

Je sais que git a la prise en charge intégrée pour émerger, mais je préfère ediff.

J'ai tenté d'ajouter ces lignes dans mon .gitconfig:

[mergetool "ediff"]
    cmd = emacs --eval "(ediff-merge-files-with-ancestor \"$LOCAL\" \"$REMOTE\" \"$BASE\" nil \"$MERGED\")"

Mais lorsque j'essaie d'exécuter cette avec "git mergetool --tool=ediff", j'obtiens ceci:

eval: 1: Syntax error: "(" unexpected

Ce que je fais mal?

30voto

tarsius Points 1427

J'utilise un plus compliqué de commande. Comme je me souviens bien je l'ai eu à partir de ce fil http://kerneltrap.org/mailarchive/git/2007/6/28/250230 (probablement le même que ce que vous faire rêver).

[mergetool.ediff]
    cmd = emacs --eval \"
(progn
  (defun ediff-write-merge-buffer ()
    (let ((file ediff-merge-store-file))
      (set-buffer ediff-buffer-C)
      (write-region (point-min) (point-max) file)
      (message \\\"Merge buffer saved in: %s\\\" file)
      (set-buffer-modified-p nil)
      (sit-for 1)))
  (setq ediff-quit-hook 'kill-emacs
        ediff-quit-merge-hook 'ediff-write-merge-buffer) 
  (ediff-merge-files-with-ancestor \\\"$LOCAL\\\" \\\"$REMOTE\\\"
                                   \\\"$BASE\\\" nil \\\"$MERGED\\\"))\"

Notez que j'ai divisé ce sur plusieurs lignes pour augmenter la lisibilité. Dans la pratique, vous avez l'ensemble de l'argument de l' --eval option sur une seule ligne.

J'ai l'habitude d'utiliser emacsclient pour modifier par exemple des messages de commit. Le ci-dessus mergetool de configuration, malheureusement, ne pas utiliser de emacsclient, et quand j'ai essayé de le faire fonctionner avec emacsclient, j'ai couru dans divers problèmes, notamment le fait que emacsclient retourné immédiatement.

Mais vous venez de me rappelle de ce problème, je vais peut-être travailler sur la façon de résoudre ce problème bientôt. Toutefois, si quelqu'un d'autre est déjà trouvé une solution, ce serait super bien sur ;-)

13voto

u-punkt Points 1094

J'utilise le script suivant que mergetool qui fonctionne très bien.

#!/bin/bash

# test args
if [ ! ${#} -ge 3 ]; then
    echo 1>&2 "Usage: ${0} LOCAL REMOTE MERGED BASE"
    echo 1>&2 "       (LOCAL, REMOTE, MERGED, BASE can be provided by \`git mergetool'.)"
    exit 1
fi

# tools
_EMACSCLIENT=/usr/local/bin/emacsclient
_BASENAME=/bin/basename
_CP=/bin/cp
_EGREP=/bin/egrep
_MKTEMP=/bin/mktemp

# args
_LOCAL=${1}
_REMOTE=${2}
_MERGED=${3}
if [ -r ${4} ] ; then
    _BASE=${4}
    _EDIFF=ediff-merge-files-with-ancestor
    _EVAL="${_EDIFF} \"${_LOCAL}\" \"${_REMOTE}\" \"${_BASE}\" nil \"${_MERGED}\""
else
    _EDIFF=ediff-merge-files
    _EVAL="${_EDIFF} \"${_LOCAL}\" \"${_REMOTE}\" nil \"${_MERGED}\""
fi

# console vs. X
if [ "${TERM}" = "linux" ]; then
    unset DISPLAY
    _EMACSCLIENTOPTS="-t"
else
    _EMACSCLIENTOPTS="-c"
fi

# run emacsclient
${_EMACSCLIENT} ${_EMACSCLIENTOPTS} -a "" -e "(${_EVAL})" 2>&1

# check modified file
if [ ! $(egrep -c '^(<<<<<<<|=======|>>>>>>>|####### Ancestor)' ${_MERGED}) = 0 ]; then
    _MERGEDSAVE=$(${_MKTEMP} --tmpdir `${_BASENAME} ${_MERGED}`.XXXXXXXXXX)
    ${_CP} ${_MERGED} ${_MERGEDSAVE}
    echo 1>&2 "Oops! Conflict markers detected in $_MERGED."
    echo 1>&2 "Saved your changes to ${_MERGEDSAVE}"
    echo 1>&2 "Exiting with code 1."
    exit 1
fi

exit 0

À utiliser avec git mergetool', placez la ligne suivante dans votre git config:

[merge]
        tool = ediff

[mergetool "ediff"]
        cmd = /path/to/ediff-merge-script $LOCAL $REMOTE $MERGED $BASE
        trustExitCode = true

En outre, vous devriez vérifier (dans le script) les chemins des outils utilisés et si le pauvre homme de la console de détection fonctionne pour vous.

Le script en lui-même commence un client emacs (ou emacs suivie par un client emacs, -a "") et est évaluée comme soit ediff-merge-files-with-ancestor ou ediff-merge-files si il n'y a pas de version de base (par exemple, lors de la fusion de deux branches où le même chemin/fichier a été créé de façon indépendante).

Après la emacs client a fini de la fusion de vérification du fichier de marqueurs de conflit. Devraient-elles être trouvé, votre travail sera enregistré à l'écart dans un fichier temporaire, le script se terminera avec le code 1 et git sera de restaurer la pré-mergetool contenu du fichier fusionné.

Lorsqu'il n'existe pas de marqueurs de conflit présent, le script se termine avec le code 0 et git va considérer l'opération comme un succès.

Important: le Réglage de la mergetool option trustExitCode de true ainsi que la post-édition vérifier les marqueurs de conflit ne fonctionnera pas si vous commencez emacsclient avec l' --no-wait option.

8voto

harveyt Points 81

Voici mon installation, qui fonctionne assez bien, en utilisant Emacs 23.3 au moins. L'astuce que j'ai utilisé était l'aide de (récursif-edit) dans un crochet tels que emacsclient ne pas quitter jusqu'à ce qu'un conseillé ediff-fermeture crochet appels (sortie-recursive-edit).

J'ai utilisé un advisted ediff-quit pour assurer la sortie-recursive-édition est la dernière chose à faire.

Il existe également des crochets pour enregistrer l'image actuelle et l'état de la fenêtre et de le restaurer par la suite, et le crochet, fait à l'image actuelle de remplir l'écran. Vous pouvez le modifier, mais je trouve que la fusion complète de l'écran est la meilleure façon.

Je n'ai pas résolu le problème de l'abandon de l'ediff et de faire emacsclient retourner une valeur non nulle.

Mettre dans votre gitconfig:

[mergetool "ediff"]
       cmd = emacsclient --eval \"(git-mergetool-emacsclient-ediff \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$BASE\\\" \\\"$MERGED\\\")\"
       trustExitCode = true
[mergetool]
    prompt = false
[merge]
    tool = ediff

Mettre dans votre .emacs ou l'équivalent:

;;
;; Setup for ediff.
;;
(require 'ediff)

(defvar ediff-after-quit-hooks nil
  "* Hooks to run after ediff or emerge is quit.")

(defadvice ediff-quit (after edit-after-quit-hooks activate)
  (run-hooks 'ediff-after-quit-hooks))

(setq git-mergetool-emacsclient-ediff-active nil)

(defun local-ediff-frame-maximize ()
  (let* ((bounds (display-usable-bounds))
     (x (nth 0 bounds))
     (y (nth 1 bounds))
     (width (/ (nth 2 bounds) (frame-char-width)))
     (height (/ (nth 3 bounds) (frame-char-height))))
    (set-frame-width (selected-frame) width)
    (set-frame-height (selected-frame) height)
    (set-frame-position (selected-frame) x y)))

(setq ediff-window-setup-function 'ediff-setup-windows-plain)
(setq ediff-split-window-function 'split-window-horizontally)

(defun local-ediff-before-setup-hook ()
  (setq local-ediff-saved-frame-configuration (current-frame-configuration))
  (setq local-ediff-saved-window-configuration (current-window-configuration))
  (local-ediff-frame-maximize)
  (if git-mergetool-emacsclient-ediff-active
      (raise-frame)))

(defun local-ediff-quit-hook ()
  (set-frame-configuration local-ediff-saved-frame-configuration)
  (set-window-configuration local-ediff-saved-window-configuration))

(defun local-ediff-suspend-hook ()
  (set-frame-configuration local-ediff-saved-frame-configuration)
  (set-window-configuration local-ediff-saved-window-configuration))

(add-hook 'ediff-before-setup-hook 'local-ediff-before-setup-hook)
(add-hook 'ediff-quit-hook 'local-ediff-quit-hook 'append)
(add-hook 'ediff-suspend-hook 'local-ediff-suspend-hook 'append)

;; Useful for ediff merge from emacsclient.
(defun git-mergetool-emacsclient-ediff (local remote base merged)
  (setq git-mergetool-emacsclient-ediff-active t)
  (if (file-readable-p base)
      (ediff-merge-files-with-ancestor local remote base nil merged)
    (ediff-merge-files local remote nil merged))
  (recursive-edit))

(defun git-mergetool-emacsclient-ediff-after-quit-hook ()
  (exit-recursive-edit))

(add-hook 'ediff-after-quit-hooks 'git-mergetool-emacsclient-ediff-after-quit-hook 'append)

6voto

pajato0 Points 1689

Mis à part le problème git vs bzr que j’ai identifié dans mon commentaire ci-dessus, j’ai pu confirmer que vous deviez vous échapper du parens comme dans

  cmd = emacs --eval "\\(ediff-merge-files-with-ancestor \"$LOCAL\" \"$REMOTE\" \"$BASE\" nil \"$MERGED\"\\)"
 

Notez les doubles barres obliques inverses. Je comprends un peu qu'ils ont besoin (plutôt que d'un seul) de passer à la fois par les mécanismes de citations sh / bash ET les caisses de démarrage d'emacs. Je laisserai cela à quelqu'un avec une meilleure connaissance d'Emacs et un shell citant pour expliquer les détails sanglants.

-pmr

4voto

Nei Points 86

Merci, cela fonctionne également dans xemacs, cependant la citation comme dans la réponse de pmr ne semble pas fonctionner alors que je pense que la citation dans toutes les autres réponses est correcte:

 [mergetool "ediff"]
    cmd = xemacs -eval \"(ediff-merge-files-with-ancestor \\\"$PWD/$LOCAL\\\" \\\"$PWD/$REMOTE\\\" \\\"$PWD/$BASE\\\" nil \\\"$PWD/$MERGED\\\")\"
[merge]
    tool = ediff
 

Je mets ce code ci-dessus dans ~/.gitconfig .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X