1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-11-18 06:54:55 +01:00

Merge branch 'master' into next

* master:
  AsciiDoc fix for tutorial
  git.el: Added customize support for all parameters.
  git.el: Added support for Signed-off-by.
  git.el: Automatically update .gitignore status.
  git.el: Set default directory before running the status mode setup hooks.
  git.el: Portability fixes for XEmacs and Emacs CVS.
  contrib/emacs: Add an Emacs VC backend.
This commit is contained in:
Junio C Hamano 2006-03-04 13:53:27 -08:00
commit b463ceb885
3 changed files with 217 additions and 41 deletions

View file

@ -309,7 +309,7 @@ git diff HEAD^^ HEAD^
------------------------------------- -------------------------------------
shows the difference between that previous state and the state two shows the difference between that previous state and the state two
commits ago. Also, HEAD~5 can be used as a shorthand for HEAD^^^^^, commits ago. Also, HEAD~5 can be used as a shorthand for HEAD{caret}{caret}{caret}{caret}{caret},
and more generally HEAD~n can refer to the nth previous commit. and more generally HEAD~n can refer to the nth previous commit.
Commits representing merges have more than one parent, and you can Commits representing merges have more than one parent, and you can
specify which parent to follow in that case; see specify which parent to follow in that case; see

View file

@ -39,13 +39,11 @@
;; - hook into file save (after-save-hook) ;; - hook into file save (after-save-hook)
;; - diff against other branch ;; - diff against other branch
;; - renaming files from the status buffer ;; - renaming files from the status buffer
;; - support for appending signed-off-by
;; - creating tags ;; - creating tags
;; - fetch/pull ;; - fetch/pull
;; - switching branches ;; - switching branches
;; - revlist browser ;; - revlist browser
;; - git-show-branch browser ;; - git-show-branch browser
;; - customize support
;; - menus ;; - menus
;; ;;
@ -53,65 +51,92 @@
(require 'ewoc) (require 'ewoc)
;;;; Faces ;;;; Customizations
;;;; ------------------------------------------------------------ ;;;; ------------------------------------------------------------
(defgroup git nil
"Git user interface")
(defcustom git-committer-name nil
"User name to use for commits.
The default is to fall back to `add-log-full-name' and then `user-full-name'."
:group 'git
:type '(choice (const :tag "Default" nil)
(string :tag "Name")))
(defcustom git-committer-email nil
"Email address to use for commits.
The default is to fall back to `add-log-mailing-address' and then `user-mail-address'."
:group 'git
:type '(choice (const :tag "Default" nil)
(string :tag "Email")))
(defcustom git-commits-coding-system 'utf-8
"Default coding system for the log message of git commits."
:group 'git
:type 'coding-system)
(defcustom git-append-signed-off-by nil
"Whether to append a Signed-off-by line to the commit message before editing."
:group 'git
:type 'boolean)
(defcustom git-per-dir-ignore-file ".gitignore"
"Name of the per-directory ignore file."
:group 'git
:type 'string)
(defface git-status-face (defface git-status-face
'((((class color) (background light)) (:foreground "purple"))) '((((class color) (background light)) (:foreground "purple")))
"Git mode face used to highlight added and modified files.") "Git mode face used to highlight added and modified files."
:group 'git)
(defface git-unmerged-face (defface git-unmerged-face
'((((class color) (background light)) (:foreground "red" :bold t))) '((((class color) (background light)) (:foreground "red" :bold t)))
"Git mode face used to highlight unmerged files.") "Git mode face used to highlight unmerged files."
:group 'git)
(defface git-unknown-face (defface git-unknown-face
'((((class color) (background light)) (:foreground "goldenrod" :bold t))) '((((class color) (background light)) (:foreground "goldenrod" :bold t)))
"Git mode face used to highlight unknown files.") "Git mode face used to highlight unknown files."
:group 'git)
(defface git-uptodate-face (defface git-uptodate-face
'((((class color) (background light)) (:foreground "grey60"))) '((((class color) (background light)) (:foreground "grey60")))
"Git mode face used to highlight up-to-date files.") "Git mode face used to highlight up-to-date files."
:group 'git)
(defface git-ignored-face (defface git-ignored-face
'((((class color) (background light)) (:foreground "grey60"))) '((((class color) (background light)) (:foreground "grey60")))
"Git mode face used to highlight ignored files.") "Git mode face used to highlight ignored files."
:group 'git)
(defface git-mark-face (defface git-mark-face
'((((class color) (background light)) (:foreground "red" :bold t))) '((((class color) (background light)) (:foreground "red" :bold t)))
"Git mode face used for the file marks.") "Git mode face used for the file marks."
:group 'git)
(defface git-header-face (defface git-header-face
'((((class color) (background light)) (:foreground "blue"))) '((((class color) (background light)) (:foreground "blue")))
"Git mode face used for commit headers.") "Git mode face used for commit headers."
:group 'git)
(defface git-separator-face (defface git-separator-face
'((((class color) (background light)) (:foreground "brown"))) '((((class color) (background light)) (:foreground "brown")))
"Git mode face used for commit separator.") "Git mode face used for commit separator."
:group 'git)
(defface git-permission-face (defface git-permission-face
'((((class color) (background light)) (:foreground "green" :bold t))) '((((class color) (background light)) (:foreground "green" :bold t)))
"Git mode face used for permission changes.") "Git mode face used for permission changes."
:group 'git)
(defvar git-committer-name nil
"*User name to use for commits.
If not set, fall back to `add-log-full-name' and then `user-full-name'.")
(defvar git-committer-email nil
"*Email address to use for commits.
If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.")
(defvar git-commits-coding-system 'utf-8
"Default coding system for git commits.")
(defconst git-log-msg-separator "--- log message follows this line ---")
(defconst git-per-dir-ignore-file ".gitignore"
"Name of the per-directory ignore file.")
;;;; Utilities ;;;; Utilities
;;;; ------------------------------------------------------------ ;;;; ------------------------------------------------------------
(defconst git-log-msg-separator "--- log message follows this line ---")
(defun git-get-env-strings (env) (defun git-get-env-strings (env)
"Build a list of NAME=VALUE strings from a list of environment strings." "Build a list of NAME=VALUE strings from a list of environment strings."
(mapcar (lambda (entry) (concat (car entry) "=" (cdr entry))) env)) (mapcar (lambda (entry) (concat (car entry) "=" (cdr entry))) env))
@ -213,14 +238,19 @@ If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.
"Add a file name to the ignore file in its directory." "Add a file name to the ignore file in its directory."
(let* ((fullname (expand-file-name file)) (let* ((fullname (expand-file-name file))
(dir (file-name-directory fullname)) (dir (file-name-directory fullname))
(name (file-name-nondirectory fullname))) (name (file-name-nondirectory fullname))
(ignore-name (expand-file-name git-per-dir-ignore-file dir))
(created (not (file-exists-p ignore-name))))
(save-window-excursion (save-window-excursion
(set-buffer (find-file-noselect (expand-file-name git-per-dir-ignore-file dir))) (set-buffer (find-file-noselect ignore-name))
(goto-char (point-max)) (goto-char (point-max))
(unless (zerop (current-column)) (insert "\n")) (unless (zerop (current-column)) (insert "\n"))
(insert name "\n") (insert name "\n")
(sort-lines nil (point-min) (point-max)) (sort-lines nil (point-min) (point-max))
(save-buffer)))) (save-buffer))
(when created
(git-run-command nil nil "update-index" "--info-only" "--add" "--" (file-relative-name ignore-name)))
(git-add-status-file (if created 'added 'modified) (file-relative-name ignore-name))))
;;;; Wrappers for basic git commands ;;;; Wrappers for basic git commands
@ -272,7 +302,7 @@ If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.
(with-current-buffer buffer (with-current-buffer buffer
(goto-char (point-min)) (goto-char (point-min))
(if (if
(setq log-start (re-search-forward (concat "^" git-log-msg-separator "\n") nil t)) (setq log-start (re-search-forward (concat "^" (regexp-quote git-log-msg-separator) "\n") nil t))
(save-restriction (save-restriction
(narrow-to-region (point-min) log-start) (narrow-to-region (point-min) log-start)
(goto-char (point-min)) (goto-char (point-min))
@ -388,9 +418,9 @@ If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.
(propertize (propertize
(if (or (not old-perm) (if (or (not old-perm)
(not new-perm) (not new-perm)
(eq 0 (logand #O111 (logxor old-perm new-perm)))) (eq 0 (logand ?\111 (logxor old-perm new-perm))))
" " " "
(if (eq 0 (logand #O111 old-perm)) "+x" "-x")) (if (eq 0 (logand ?\111 old-perm)) "+x" "-x"))
'face 'git-permission-face)) 'face 'git-permission-face))
(defun git-fileinfo-prettyprint (info) (defun git-fileinfo-prettyprint (info)
@ -787,7 +817,8 @@ If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.
(unless git-status (error "Not in git-status buffer.")) (unless git-status (error "Not in git-status buffer."))
(let ((buffer (get-buffer-create "*git-commit*")) (let ((buffer (get-buffer-create "*git-commit*"))
(merge-heads (git-get-merge-heads)) (merge-heads (git-get-merge-heads))
(dir default-directory)) (dir default-directory)
(sign-off git-append-signed-off-by))
(with-current-buffer buffer (with-current-buffer buffer
(when (eq 0 (buffer-size)) (when (eq 0 (buffer-size))
(cd dir) (cd dir)
@ -804,9 +835,18 @@ If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.
'face 'git-header-face) 'face 'git-header-face)
(propertize git-log-msg-separator 'face 'git-separator-face) (propertize git-log-msg-separator 'face 'git-separator-face)
"\n") "\n")
(when (and merge-heads (file-readable-p ".git/MERGE_MSG")) (cond ((and merge-heads (file-readable-p ".git/MERGE_MSG"))
(insert-file-contents ".git/MERGE_MSG")))) (insert-file-contents ".git/MERGE_MSG"))
(log-edit #'git-do-commit nil #'git-log-edit-files buffer))) (sign-off
(insert (format "\n\nSigned-off-by: %s <%s>\n"
(git-get-committer-name) (git-get-committer-email)))))))
(let ((log-edit-font-lock-keywords
`(("^\\(Author:\\|Date:\\|Parent:\\|Signed-off-by:\\)\\(.*\\)"
(1 font-lock-keyword-face)
(2 font-lock-function-name-face))
(,(concat "^\\(" (regexp-quote git-log-msg-separator) "\\)$")
(1 font-lock-comment-face)))))
(log-edit #'git-do-commit nil #'git-log-edit-files buffer))))
(defun git-find-file () (defun git-find-file ()
"Visit the current file in its own buffer." "Visit the current file in its own buffer."
@ -891,7 +931,7 @@ If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.
(define-key map "d" diff-map) (define-key map "d" diff-map)
(define-key map "=" 'git-diff-file) (define-key map "=" 'git-diff-file)
(define-key map "f" 'git-find-file) (define-key map "f" 'git-find-file)
(define-key map [RET] 'git-find-file) (define-key map "\r" 'git-find-file)
(define-key map "g" 'git-refresh-status) (define-key map "g" 'git-refresh-status)
(define-key map "i" 'git-ignore-file) (define-key map "i" 'git-ignore-file)
(define-key map "l" 'git-log-file) (define-key map "l" 'git-log-file)
@ -937,6 +977,7 @@ Commands:
(erase-buffer) (erase-buffer)
(let ((status (ewoc-create 'git-fileinfo-prettyprint "" ""))) (let ((status (ewoc-create 'git-fileinfo-prettyprint "" "")))
(set (make-local-variable 'git-status) status)) (set (make-local-variable 'git-status) status))
(set (make-local-variable 'list-buffers-directory) default-directory)
(run-hooks 'git-status-mode-hook))) (run-hooks 'git-status-mode-hook)))
(defun git-status (dir) (defun git-status (dir)
@ -946,8 +987,8 @@ Commands:
(if (file-directory-p (concat (file-name-as-directory dir) ".git")) (if (file-directory-p (concat (file-name-as-directory dir) ".git"))
(let ((buffer (create-file-buffer (expand-file-name "*git-status*" dir)))) (let ((buffer (create-file-buffer (expand-file-name "*git-status*" dir))))
(switch-to-buffer buffer) (switch-to-buffer buffer)
(git-status-mode)
(cd dir) (cd dir)
(git-status-mode)
(git-refresh-status) (git-refresh-status)
(goto-char (point-min))) (goto-char (point-min)))
(message "%s is not a git working tree." dir))) (message "%s is not a git working tree." dir)))

135
contrib/emacs/vc-git.el Normal file
View file

@ -0,0 +1,135 @@
;;; vc-git.el --- VC backend for the git version control system
;; Copyright (C) 2006 Alexandre Julliard
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2 of
;; the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be
;; useful, but WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE. See the GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public
;; License along with this program; if not, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA
;;; Commentary:
;; This file contains a VC backend for the git version control
;; system.
;;
;; To install: put this file on the load-path and add GIT to the list
;; of supported backends in `vc-handled-backends'.
;;
;; TODO
;; - changelog generation
;; - working with revisions other than HEAD
;;
(defvar git-commits-coding-system 'utf-8
"Default coding system for git commits.")
(defun vc-git--run-command-string (file &rest args)
"Run a git command on FILE and return its output as string."
(let* ((ok t)
(str (with-output-to-string
(with-current-buffer standard-output
(unless (eq 0 (apply #'call-process "git" nil '(t nil) nil
(append args (list (file-relative-name file)))))
(setq ok nil))))))
(and ok str)))
(defun vc-git--run-command (file &rest args)
"Run a git command on FILE, discarding any output."
(let ((name (file-relative-name file)))
(eq 0 (apply #'call-process "git" nil (get-buffer "*Messages") nil (append args (list name))))))
(defun vc-git-registered (file)
"Check whether FILE is registered with git."
(with-temp-buffer
(let* ((dir (file-name-directory file))
(name (file-relative-name file dir)))
(when dir (cd dir))
(and (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name))
(let ((str (buffer-string)))
(and (> (length str) (length name))
(string= (substring str 0 (1+ (length name))) (concat name "\0"))))))))
(defun vc-git-state (file)
"git-specific version of `vc-state'."
(let ((diff (vc-git--run-command-string file "diff-index" "-z" "HEAD" "--")))
(if (and diff (string-match ":[0-7]\\{6\\} [0-7]\\{6\\} [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} [ADMU]\0[^\0]+\0" diff))
'edited
'up-to-date)))
(defun vc-git-workfile-version (file)
"git-specific version of `vc-workfile-version'."
(let ((str (with-output-to-string
(with-current-buffer standard-output
(call-process "git" nil '(t nil) nil "symbolic-ref" "HEAD")))))
(if (string-match "^\\(refs/heads/\\)?\\(.+\\)$" str)
(match-string 2 str)
str)))
(defun vc-git-revert (file &optional contents-done)
"Revert FILE to the version stored in the git repository."
(if contents-done
(vc-git--run-command file "update-index" "--")
(vc-git--run-command file "checkout" "HEAD")))
(defun vc-git-checkout-model (file)
'implicit)
(defun vc-git-workfile-unchanged-p (file)
(let ((sha1 (vc-git--run-command-string file "hash-object" "--"))
(head (vc-git--run-command-string file "ls-tree" "-z" "HEAD" "--")))
(and head
(string-match "[0-7]\\{6\\} blob \\([0-9a-f]\\{40\\}\\)\t[^\0]+\0" head)
(string= (car (split-string sha1 "\n")) (match-string 1 head)))))
(defun vc-git-register (file &optional rev comment)
"Register FILE into the git version-control system."
(vc-git--run-command file "update-index" "--add" "--"))
(defun vc-git-print-log (file)
(let ((name (file-relative-name file))
(coding-system-for-read git-commits-coding-system))
(vc-do-command nil 'async "git" name "rev-list" "--pretty" "HEAD" "--")))
(defun vc-git-diff (file &optional rev1 rev2)
(let ((name (file-relative-name file)))
(if (and rev1 rev2)
(vc-do-command "*vc-diff*" 0 "git" name "diff-tree" "-p" rev1 rev2 "--")
(vc-do-command "*vc-diff*" 0 "git" name "diff-index" "-p" (or rev1 "HEAD") "--"))
; git-diff-index doesn't set exit status like diff does
(if (vc-git-workfile-unchanged-p file) 0 1)))
(defun vc-git-checkin (file rev comment)
(let ((coding-system-for-write git-commits-coding-system))
(vc-git--run-command file "commit" "-m" comment "--only" "--")))
(defun vc-git-checkout (file &optional editable rev destfile)
(vc-git--run-command file "checkout" (or rev "HEAD")))
(defun vc-git-annotate-command (file buf &optional rev)
; FIXME: rev is ignored
(let ((name (file-relative-name file)))
(call-process "git" nil buf nil "annotate" name)))
(defun vc-git-annotate-time ()
(and (re-search-forward "[0-9a-f]+\t(.*\t\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\) \\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\) \\([-+0-9]+\\)\t[0-9]+)" nil t)
(vc-annotate-convert-time
(apply #'encode-time (mapcar (lambda (match) (string-to-number (match-string match))) '(6 5 4 3 2 1 7))))))
;; Not really useful since we can't do anything with the revision yet
;;(defun vc-annotate-extract-revision-at-line ()
;; (save-excursion
;; (move-beginning-of-line 1)
;; (and (looking-at "[0-9a-f]+")
;; (buffer-substring (match-beginning 0) (match-end 0)))))
(provide 'vc-git)