From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Thien-Thi Nguyen Newsgroups: gmane.emacs.devel Subject: Re: git apologia Date: Tue, 18 Nov 2014 09:58:25 +0100 Message-ID: <87a93onavi.fsf@zigzag.favinet> References: <20141114183737.GB3168@acm.acm> <5466517B.50705@porkrind.org> <20141114215404.GD3168@acm.acm> <838ujchods.fsf@gnu.org> <8761egx1k2.fsf@uwakimon.sk.tsukuba.ac.jp> <83sihkg2ds.fsf@gnu.org> <87vbmgv3b9.fsf@uwakimon.sk.tsukuba.ac.jp> <83389jdtae.fsf@gnu.org> <87k32uvg2x.fsf@uwakimon.sk.tsukuba.ac.jp> <83ioidbwz5.fsf@gnu.org> Reply-To: emacs-devel@gnu.org NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha1; protocol="application/pgp-signature" X-Trace: ger.gmane.org 1416300889 21763 80.91.229.3 (18 Nov 2014 08:54:49 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 18 Nov 2014 08:54:49 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Nov 18 09:54:42 2014 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 1XqeYa-0004mM-Ux for ged-emacs-devel@m.gmane.org; Tue, 18 Nov 2014 09:54:41 +0100 Original-Received: from localhost ([::1]:51900 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XqeYa-0001tT-Bd for ged-emacs-devel@m.gmane.org; Tue, 18 Nov 2014 03:54:40 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:37739) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XqeYR-0001tK-9A for emacs-devel@gnu.org; Tue, 18 Nov 2014 03:54:37 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XqeYI-0004vm-0n for emacs-devel@gnu.org; Tue, 18 Nov 2014 03:54:31 -0500 Original-Received: from smtp208.alice.it ([82.57.200.104]:28145) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XqeYH-0004ui-Dz for emacs-devel@gnu.org; Tue, 18 Nov 2014 03:54:21 -0500 Original-Received: from zigzag.favinet (95.245.75.199) by smtp208.alice.it (8.6.060.28) id 5463813700FA584C for emacs-devel@gnu.org; Tue, 18 Nov 2014 09:54:20 +0100 Original-Received: from ttn by zigzag.favinet with local (Exim 4.80) (envelope-from ) id 1XqecM-0002gt-PB for emacs-devel@gnu.org; Tue, 18 Nov 2014 09:58:34 +0100 Mail-Followup-To: emacs-devel@gnu.org In-Reply-To: <83ioidbwz5.fsf@gnu.org> (Eli Zaretskii's message of "Mon, 17 Nov 2014 18:41:50 +0200") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 82.57.200.104 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:177530 Archived-At: --==-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable () Eli Zaretskii () Mon, 17 Nov 2014 18:41:50 +0200 What's more natural than asking for the Nth previous commit? Personally, i use =E2=80=98git-show-branch=E2=80=99 and =E2=80=98more-vc-gi= t-show=E2=80=99 (sample output and definitions attached) and additionally bind =E2=80=98C-c C-s=E2=80=99 to the latter in compilation mode buffers. --=-=-= Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Description: buffer w/ =?utf-8?Q?=E2=80=98git-show-branch=E2=80=99?= output Directory: ~/build/GNU/guile-sdl/ ! [ack] Release: 0.5.1 ! [p] Fix typo: Spell "compatib..." correctly! ! [q] Fix typo: Spell "compatib..." correctly! * [q-fix-k2c] also pass =E2=80=98DEFS=E2=80=99 and =E2=80=98SDL_CFLAGS= =E2=80=99 to k2c, via new var =E2=80=98cppopts=E2=80=99 ! [z-gfx-font] Add =E2=80=98set-font!=E2=80=99 and =E2=80=98builtin-fon= t=E2=80=99. =2D---- * [q-fix-k2c] also pass =E2=80=98DEFS=E2=80=99 and =E2=80=98SDL_CFLAGS= =E2=80=99 to k2c, via new var =E2=80=98cppopts=E2=80=99 * [q-fix-k2c^] make k2c handle command-line =E2=80=98-- CFLAGS=E2=80=99 * [q-fix-k2c~2] bootstrap w/ Guile-BAUX module =E2=80=98minus-i-dirs=E2= =80=99 ++* [p] Fix typo: Spell "compatib..." correctly! + [z-gfx-font] Add =E2=80=98set-font!=E2=80=99 and =E2=80=98builtin-fon= t=E2=80=99. +++*+ [ack] Release: 0.5.1 --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=git-show-branch.el Content-Transfer-Encoding: quoted-printable ;;; git-show-branch.el ;;; ;;; Copyright (C) 2011 Thien-Thi Nguyen ;;; ;;; This file is part of ttn's personal elisp library, released under ;;; the terms of the GNU General Public License as published by the ;;; Free Software Foundation; either version 3, or (at your option) any ;;; later version. There is NO WARRANTY. See file COPYING for details. ;;; ;;; Description: Show "git show-branch" output in a buffer. (require 'view) (require 'vc-git) (require 'set-keys) (require 'compile) (require 'file-contents-to-sexp) (defvar git-show-branch-map (copy-keymap view-mode-map) "Keymap for buffer prepared by `git-show-branch'.") (defvar git-show-branch-all nil) ;;;###autoload (defun git-show-branch-all () "Toggle variable `git-show-branch-all'. If the current buffer is named \"*gb* ...\", that is, presumed to be created by `git-show-branch', revert it." (interactive) (message "git-show-branch-all: %S" (setq git-show-branch-all (not git-show-branch-all))) (when (string-match "^\\*gb\\* " (or (buffer-name) "")) (revert-buffer t t))) (defun git-show-branch-read-remote-name () (let ((all (split-string (shell-command-to-string "git remote")))) (unless all (error "No remote repos found")) (if (cdr all) ;; many (completing-read "Remote: " all) ;; just one (car all)))) (defun git-show-branch-fetch (remote) "Do \"git fetch REMOTE\" in a *gb DIR* buffer. If `git-show-branch-all' is set, revert the buffer also." (interactive (list (git-show-branch-read-remote-name))) (let* ((orig (current-buffer)) (cmd (format "git fetch %s" remote)) (compilation-buffer-name-function `(lambda (&rest ignored) ,(format "*%s*" cmd)))) (with-current-buffer ;; kick it! (compilation-start cmd) (set (make-local-variable 'compilation-finish-functions) (list `(lambda (buffer status) (when (buffer-live-p ,orig) (with-current-buffer ,orig (when git-show-branch-all (message "Refreshing %s" (current-buffer)) (revert-buffer-t-t)))))))))) ;;;###autoload (defun git-show-branch (dir) "Display \"git show-branch\" output for DIR in a buffer. Actually, use its top directory, the one returned by `vc-git-root'. Interactively, try `default-directory' first, and query if no top directory is found. You can use commands from keymap `git-show-branch-map' in that buffer. If file \".git/.gsb/specifically\" exists, its contents specify branches to show, instead of all of them. The file format is `read' as a series of Lisp expressions (all atoms are symbols): SPEC ... where each SPEC is the name of a branch, or a list of the form: (REMOTE BRANCH...) where REMOTE names a remote and BRANCH... the desired branches. As a special case if BRANCH is =E2=80=98*=E2=80=99, that means all the bran= ches of that REMOTE, and the branches will be displayed with the prefix \"refs/remotes/\"." (interactive (list (or (vc-git-root default-directory) (read-directory-name "Directory: ")))) (setq dir (file-name-as-directory dir)) (switch-to-buffer (get-buffer-create (format "*gb* %s" dir))) (setq default-directory dir) (buffer-disable-undo) (set (make-local-variable 'revert-buffer-function) (lambda (ignore-auto noconfirm) (git-show-branch default-directory))) (let* ((filename ".git/.gsb/specifically") (specifically (when (file-exists-p filename) (file-contents-to-sexp filename t)))) (flet ((rem (x) (if git-show-branch-all (let ((remote (symbol-name (car x)))) (mapconcat (lambda (b) (concat remote "/" b)) (mapcar 'symbol-name (cdr x)) " ")) "")) (exp (x) (funcall (if (symbolp x) 'symbol-name 'rem) x))) (shell-command (format "git show-branch %s" (cond (specifically (mapconcat 'exp specifically " ")) (git-show-branch-all "-a") (t ""))) (current-buffer)))) (insert "Directory: " dir "\n\n") (view-mode 1) (use-local-map git-show-branch-map)) ;;;------------------------------------------------------------------------= --- ;;; load-time actions (define-keys git-show-branch-map "\C-c\C-a" 'git-show-branch-all "\C-c\C-f" 'git-show-branch-fetch [remap View-quit] 'bury-buffer) ;;;------------------------------------------------------------------------= --- ;;; that's it! (provide 'git-show-branch) ;;; git-show-branch.el ends here --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=more-vc.el Content-Transfer-Encoding: quoted-printable ;;; more-vc.el ;;; ;;; Copyright (C) 2007, 2008 Thien-Thi Nguyen ;;; ;;; This file is part of ttn's personal elisp library, released under ;;; the terms of the GNU General Public License as published by the ;;; Free Software Foundation; either version 3, or (at your option) any ;;; later version. There is NO WARRANTY. See file COPYING for details. ;;; ;;; Description: Additional version-control functionality. ;;; Plug holes. (require 'scheme) (eval-when-compile (require 'cl)) (require 'vc) (eval-when-compile (require 'vc-git)) (eval-when-compile (require 'log-view)) (eval-when-compile (require 'diff-mode)) ;;;###autoload (defun ttn-vc-toggle-read-only () (interactive) (if (or (and (boundp 'vc-dired-mode) vc-dired-mode) ;; use boundp because vc.el might not be loaded (vc-backend buffer-file-name)) (vc-next-action nil) (toggle-read-only))) ;;; New functionality. ;;;###autoload (defun more-vc-set-state (files state) "Set \"file state\" to STATE for each file in FILES. Revert any buffers visiting those files and return them in a list. The backend to use is determined by the first element in FILES." (let* ((backend (or (vc-backend (expand-file-name (car files))) (error "Not under version control: %s" (car files)))) (commands (or (get backend 'more-vc-set-state-commands) (error "No %s commands to set state" backend))) (ls (mapconcat (lambda (name) (shell-quote-argument name)) files " ")) (bufs (delq nil (mapcar 'find-buffer-visiting files)))) ;; Each element in COMMANDS has the form (SHELL-COMMAND ARGS...). ;; SHELL-COMMAND is a string, and ARGS... are zero or more symbols, one ;; of `ls', which stands for the list FILES, shell-quoted and space- ;; separated, as a single string; or `state', which stands for STATE. (with-temp-buffer (dolist (command commands) (shell-command (eval (cons 'format command)) t))) (dolist (buf bufs) (with-current-buffer buf (revert-buffer t t))) bufs)) (put 'RCS 'more-vc-set-state-commands '(("co -l %s" ls) ("ci -u -s%S -m'State now %s.' %s" state state ls))) (put 'CVS 'more-vc-set-state-commands '(("cvs commit -f -m'State now %s.' %s" state ls) ("cvs admin -s%S %s" state ls) ("rm -f %s" ls) ("cvs update %s" ls))) ;;;###autoload (defun more-vc-make-sure-writeable () "Make sure current buffer is writeable. Do `vc-toggle-read-only' (perhaps twice!) if not. Make sure underlying file is writeable, as well. But all of this is done iff `this-command' is either `add-change-log-entry' or `add-change-log-entry-other-window'." (when (memq this-command '(add-change-log-entry add-change-log-entry-other-window)) (flet ((try () (when buffer-read-only (ttn-vc-toggle-read-only)))) ;; twice in case vc-update intervened (try) (try)) ;; vc was horribly crippled ca emacs 23 (when buffer-read-only (toggle-read-only)) (when (and (not buffer-read-only) buffer-file-name) (let ((mode (file-modes buffer-file-name))) (when (and mode (zerop (logand #o200 mode))) (set-file-modes buffer-file-name (logior #o200 mode))))))) (defun more-vc-backend-get (property &optional filename) (let ((backend (vc-backend (or filename buffer-file-name (buffer-file-name vc-parent-buffer))))) (when backend (get backend property)))) ;;;###autoload (defun more-vc-pretty-up-log () (buffer-disable-undo) (vc-exec-after (more-vc-backend-get 'more-vc-pretty-up-log-code))) (put 'RCS 'more-vc-pretty-up-log-code '(let ((re (concat "\\(revision \\)\\S-+" "\\(.*\ndate: \\)[^;]+" "\\(;.+author: \\)[^;]+" "\\(;.+state: \\)[^;]+" "\\(\\(;.+lines: \\)[^;\n]+\\)*" "\\(;.*\\)")) buffer-read-only) (flet ((mprop (n p v) (put-text-property (match-beginning n) (match-end n) p v))) (save-excursion (goto-char (point-min)) (while (re-search-forward "^-+\n" nil t) (mprop 0 'display "\n\n") (looking-at re) (dolist (ent '((0 font-lock-face match) (1 nil " ") (2) (3) (4) (6) (7 nil "\n"))) (let ((n (pop ent)) (p (or (pop ent) 'display)) (v (or (pop ent) " "))) (when (match-end n) (mprop n p v))))))) (when (get-buffer-window (current-buffer)) (recenter 0)))) (put 'CVS 'more-vc-pretty-up-log-code (get 'RCS 'more-vc-pretty-up-log-code)) (put 'Git 'more-vc-pretty-up-log-code '(let ((re (concat "\\(commit .*\n\\(Merge:.*\n\\)*Author:.*<\\)[^@]+" "\\(@.*\nDate: +\\).*\n")) buffer-read-only) (flet ((mprop (n p v) (put-text-property (match-beginning n) (match-end n) p v))) (save-excursion (goto-char (point-min)) (while (re-search-forward re nil t) (mprop 0 'font-lock-face 'match) (mprop 1 'display " ") (mprop 3 'display " ")))) (when (get-buffer-window (current-buffer)) (recenter 0)))) ;;;###autoload (defun more-vc-log-view-copy-id-as-kill () "Copy the current log entry's \"id\" onto the `kill-ring'. If point is not `looking-at' the `log-view-message-re', do nothing. Otherwise, take the match's first group to be the entry's id, copy this string onto the `kill-ring' (with `kill-new') and lastly, display it in the echo area." (interactive) (when (looking-at log-view-message-re) (kill-new (buffer-substring-no-properties (match-beginning 1) (match-end 1))) (message "%s" (car kill-ring)))) ;;;###autoload (defun more-vc-likewise () "Edit the current like to be \"\\t(TEXT): Likewise.\". Leave point at eol. When called, the line may have one of the forms: TEXT \\tTEXT (TEXT) \\t(TEXT) \\t* FILENAME (TEXT) Here, \"\\t\" stands for the TAB character. As a special case, if unparenthesized TEXT (i.e., the first two cases) ends with comma and any whitespace, that part is deleted. This command is intended for use in Change Log mode." (interactive) (beginning-of-line) (delete-horizontal-space) (insert "\t") (unless (memq (char-after) '(?\( ?\*)) (insert "(") (end-of-line) (delete-horizontal-space) (insert ")")) (end-of-line) (delete-horizontal-space) (when (=3D ?, (char-before)) (delete-char -1) (insert ")")) (insert ": Likewise.")) ;;;###autoload (defun more-vc-diff-NEW () "Diff current buffer's file with its \".NEW\" file. For instance, if the current buffer is visiting \"foo\", this command diffs \"foo\" and \"foo.NEW\"." (interactive) (let ((same-window-buffer-names (cons "*Diff*" same-window-buffer-names)) (diff-default-read-only t) (short (file-name-nondirectory (buffer-file-name)))) (diff short (concat short ".NEW") nil t))) ;;;###autoload (defun more-vc-toggle-git-post-commit-hook () "In .../.git/hooks/, toggle filename of post-commit hook. Set to \"post-commit\" for enabled, \"post-commit.OFF\" for disabled." (interactive) (let (dir fn off) (if (not (setq dir (vc-git-root default-directory))) (message "Not under Git: %s" (directory-file-name default-directory= )) (setq fn (expand-file-name ".git/hooks/post-commit" dir) off (concat fn ".OFF")) (cond ((file-exists-p fn) (rename-file fn off) (message "%s DISABLED" fn)) (t (rename-file off fn) (message "%s ENABLED" fn)))))) (defun more-vc-ref-at-point () "Return the reference at point as a string. This is essentially the symbol at point under Emacs Lisp syntax. As a special case, if after the symbol there is \"@{...}\", (i.e., at-sign, open-curly-brace, ..., close-curly-brace), then that is also included in the returned value. See gitrevisions(7)." (save-excursion (with-syntax-table scheme-mode-syntax-table (forward-symbol 1) (let ((end (point))) (when (looking-at "@{[^{}]+}") (setq end (match-end 0))) (forward-symbol -1) (buffer-substring-no-properties (point) end))))) ;;;###autoload (defun more-vc-copy-ref-as-kill () "Copy the ref (see `more-vc-ref-at-point') to the kill ring." (interactive) (kill-new (more-vc-ref-at-point))) ;;;###autoload (defun more-vc-git-rebase () "Arrange to invoke `compile' interactively with a \"git rebase\" command. The full command uses the REF (from `more-vc-ref-at-point') like so: git rebase -i REF^ Note the ^ (hat). You can modify the command further prior to dispatch." (interactive) (let ((compile-command (format "git rebase -i --autosquash %s^" (more-vc-ref-at-point)))) (call-interactively 'compile))) ;;;###autoload (defun more-vc-git-show (&optional explicit-ref) "Do \"git show --stat -p REF\" (from `more-vc-ref-at-point'). Display output in a read-only buffer in Diff mode, with Diff Auto-Refine mode enabled." (interactive "P") (let* ((ref (if explicit-ref (read-string "Ref: ") (more-vc-ref-at-point))) (cmd (format "git show --stat -p %s" ref)) (buf (get-buffer-create (format "*(%s) %s*" (file-name-nondirectory (directory-file-name (vc-git-root default-directory))) ref))) (resize-mini-windows nil) (pop-up-windows nil)) (shell-command cmd buf) (with-current-buffer buf (diff-mode) (ignore-errors (diff-auto-refine-mode 1)) (setq buffer-read-only t)) (switch-to-buffer buf))) (provide 'more-vc) ;;; more-vc.el ends here --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable This way i don't need to count anything and stuff before the earliest branch (in the example, =E2=80=98ack=E2=80=99) is never shown to begin w/; instead, i move point to a ref (e.g., branch name in square braces, or SHA1) and type =E2=80=98C-c C-s=E2=80=99. That's most natural to me. The compilation mode support is to be able to likewise type =E2=80=98C-s C-s=E2=80=99 in *compilation* on arbitrary shell command output (e.g., "git stash list" or "git log --oneline -42"). The crux is func =E2=80=98more-vc-ref-at-point=E2=80=99, which could stand to be improved, surely... Anyway, i find "git log" to be only marginally useful (see my previous grumblings re ChangeLog grepping) but that will probably change, seeing where things are headed. Nonetheless, i don't think manually counting commits will ever be part of my workflow. =2D-=20 Thien-Thi Nguyen GPG key: 4C807502 (if you're human and you know it) read my lisp: (responsep (questions 'technical) (not (via 'mailing-list))) =3D> nil --=-=-=-- --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iEYEARECAAYFAlRrCjQACgkQZwMiJEyAdQIS/gCZAdO2QTl0CwOnBt5QSwctmcAP /WYAoI8iqiF1AwU8+GU3qMukM37p4SB7 =3j6x -----END PGP SIGNATURE----- --==-=-=--