From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: =?utf-8?Q?=C3=93scar_Fuentes?= Newsgroups: gmane.emacs.devel Subject: Git conflict VC state detection Date: Sun, 10 Nov 2013 21:30:08 +0100 Message-ID: <87wqkgyp7z.fsf_-_@wanadoo.es> References: <527BCD00.9090105@openmailbox.org> <87d2mcdrgu.fsf@yandex.ru> <877gcia4c5.fsf@web.de> <87fvr61f4d.fsf@wanadoo.es> <877gch1uul.fsf@wanadoo.es> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: ger.gmane.org 1384115435 21107 80.91.229.3 (10 Nov 2013 20:30:35 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 10 Nov 2013 20:30:35 +0000 (UTC) Cc: Dmitry Gutov , emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Nov 10 21:30:35 2013 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1VfbeQ-0002q2-2c for ged-emacs-devel@m.gmane.org; Sun, 10 Nov 2013 21:30:30 +0100 Original-Received: from localhost ([::1]:33635 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VfbeP-0003SD-J1 for ged-emacs-devel@m.gmane.org; Sun, 10 Nov 2013 15:30:29 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:35444) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VfbeG-0003NU-I1 for emacs-devel@gnu.org; Sun, 10 Nov 2013 15:30:26 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VfbeA-0000XV-Lx for emacs-devel@gnu.org; Sun, 10 Nov 2013 15:30:20 -0500 Original-Received: from smtp09.acens.net ([86.109.99.133]:17815 helo=smtp.movistar.es) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VfbeA-0000X6-7u for emacs-devel@gnu.org; Sun, 10 Nov 2013 15:30:14 -0500 X-CTCH-RefID: str=0001.0A0B020A.527FECD1.00C7, ss=1, re=0.100, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 X-CTCH-Spam: Unknown Original-Received: from qcore (83.46.215.247) by smtp.movistar.es (8.6.117.02) (authenticated as 981711563$telefonica.net) id 527E8AD60006D7E8; Sun, 10 Nov 2013 20:30:09 +0000 In-Reply-To: (Stefan Monnier's message of "Sun, 10 Nov 2013 08:24:41 -0500") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 86.109.99.133 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:165125 Archived-At: --=-=-= Content-Type: text/plain Stefan Monnier writes: >>> Is it really all it takes to detect `conflict' state? >> Git conflict state detection worked when I implemented the feature many >> moons ago, although it was not 100% reliable. It doesn't work anymore. >> Maybe something was lost on one of the many merges. > > Could you try and make it work again and submit/install the patch for that? I've revised the initial commit implementing conflict state detection on my private branch and the problem with it was that it didn't detect edited state on a staged file, i.e. a file containing staged (but uncommitted) changes would show as up to date. So I pursued a more precise method. The problem is that the git commands that tells you that a file is unmerged doesn't tell that a file contains changes if those are staged. The solution is to execute two git commands: the first one informs about edited (but unstaged) files plus unmerged files. If that command says that the file is up to date, a second command is executed for detecting staged changes. The problem with this approach is that on some platforms (i.e. Windows) invoking git is slow. The delay is already noticeable when the modeline is updated. Adding yet another call makes things somewhat worse. I CC'ed Dmitry as he implemented the part that my patch touches. I'll like to get the ok from him before installing the patch, if you (Stefan) think that conflict detection is valuable enough to warrant an extra git invocation. --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=vc-git.patch diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 1d67dee..cb500eb 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -204,15 +204,26 @@ matching the resulting Git log output, and KEYWORDS is a list of (?M 'edited) (?A 'added) (?D 'removed) - (?U 'edited) ;; FIXME + (?U 'conflict) (?T 'edited))) ;; FIXME +(defun vc-git--state-letter (file index-p) + (let ((diff (vc-git--run-command-string + file + "diff-index" + ;; How to conditionally add --cached without this kludge? + (if index-p "--cached" "-z") + "--name-status" "--raw" "-z" "HEAD" "--"))) + (and diff + (string-match "^\\([ADMUT]\\)\0" diff) + (match-string 1 diff)))) + (defun vc-git-state (file) "Git-specific version of `vc-state'." - ;; FIXME: This can't set 'ignored or 'conflict yet + ;; FIXME: This can't set 'ignored yet. ;; The 'ignored state could be detected with `git ls-files -i -o - ;; --exclude-standard` It also can't set 'needs-update or - ;; 'needs-merge. The rough equivalent would be that upstream branch + ;; --exclude-standard` It also can't set 'needs-update. + ;; The rough equivalent would be that upstream branch ;; for current branch is in fast-forward state i.e. current branch ;; is direct ancestor of corresponding upstream branch, and the file ;; was modified upstream. But we can't check that without a network @@ -220,21 +231,16 @@ matching the resulting Git log output, and KEYWORDS is a list of ;; This assumes that status is known to be not `unregistered' because ;; we've been successfully dispatched here from `vc-state', that ;; means `vc-git-registered' returned t earlier once. Bug#11757 - (let ((diff (vc-git--run-command-string - file "diff-index" "-p" "--raw" "-z" "HEAD" "--"))) - (if (and diff - (string-match ":[0-7]\\{6\\} [0-7]\\{6\\} [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\([ADMUT]\\)\0[^\0]+\0\\(.*\n.\\)?" - diff)) - (let ((diff-letter (match-string 1 diff))) - (if (not (match-beginning 2)) - ;; Empty diff: file contents is the same as the HEAD - ;; revision, but timestamps are different (eg, file - ;; was "touch"ed). Update timestamp in index: - (prog1 'up-to-date - (vc-git--call nil "add" "--refresh" "--" - (file-relative-name file))) - (vc-git--state-code diff-letter))) - (if (vc-git--empty-db-p) 'added 'up-to-date)))) + (let ((diff-letter (or (vc-git--state-letter file t) + (vc-git--state-letter file nil)))) + (if (not diff-letter) + ;; Empty diff: file contents is the same as the HEAD + ;; revision, but timestamps are different (eg, file + ;; was "touch"ed). Update timestamp in index: + (prog1 'up-to-date + (vc-git--call nil "add" "--refresh" "--" + (file-relative-name file))) + (vc-git--state-code diff-letter)))) (defun vc-git-working-revision (file) "Git-specific version of `vc-working-revision'." --=-=-=--