gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

cvs-commit-patch-buffer.el 2.0


From: Jim Radford
Subject: cvs-commit-patch-buffer.el 2.0
Date: Tue, 7 Feb 2006 09:21:40 -0800
User-agent: Mutt/1.4.2.1i

The Motivation
==============

Have you ever wanted to commit only some of the changes that you've
made to few files, but not say the debug code that you added to get it
to work?  Still, you'd like to keep that debug code in your working
directory, you just don't want to check it in.

Do you like to check in only independent and related changes in each
commit even though you may be working on more than one thing at once?

Have you wanted to makes a quick change to a file before checking it
in, but still have the old version in your working directory?

If so, then cvs-commit-patch and its emacs interface
cvs-commit-patch-buffer can help make this process as simple and easy
as editing a diff buffer in emacs.

The Program
===========

cvs-commit-patch is an independent shell script that commits a patch
(as generated by diff(1)) to a cvs repository. It

  o handles file additions/deletions,
  o verifies that the patch applies cleanly even
    when the working directory is un-clean,
  o can be reliably interrupted (ctrl-c),
  o patches and updates working directories with distinct
    or overlapping changes.

It requires bash(1) and a few utilities from the patchutils
distribution.

The Emacs Interface
===================

cvs-commit-patch-buffer.el is an emacs interface to cvs-commit-patch.
It allows you to just hit C-c C-c in any patch buffer to apply and
commit only the changes indicated by the patch, regardless of the
changes in your working directory.

One method of working with cvs-commit-patch-buffer is to just M-x
vc-diff a file then kill, split or edit the resulting hunks and to
then hit C-c C-c to commit the patch.  The other is to use PCL cvs
mode to tag many files and then to diff them into a buffer which can
again be edited and committed.

This code has been working reliably for me for over two years.  I'm
sure the emacs community will break it in less than a day.  The lisp
code leaves a lot to be desired.  Suggestions are welcome.

-Jim

  http://blackbean.org/cvs-commit-patch/
#!/bin/bash
# Copyright 2003,2004
#   by Jim Radford <address@hidden> 
#   and David Caldwell <address@hidden>
# This code can be distributed under the terms of the GNU Public License
# Version: 1.1

set -e

eval set -- "`getopt -o m: -- "$@"`"
while true; do
  case "$1" in
         -m) message="$2" ; shift 2 ;;
         --) shift ; break ;;
  esac
done

patch=$1

if [ -z "$patch" -o -n "$2" ]; then
  echo "usage: $0 [-m <message>] <patch>"
  exit 1
fi

IFS='
' \
lsdiff=`lsdiff $patch|sort|uniq`

#[ $? != 0 ] && exit $?;

if [ "address@hidden" = "x" ]; then
        echo "No files in the patch"
        exit 1
fi

if cvs status address@hidden | grep "Status: Needs" 2>/dev/null; then
  echo "The above files need to be updated first!"
  exit 1
fi

function clean () {
  for f in address@hidden; do
    mv -vfb "$f.orig.$$" "$f"
  done
  trap "" INT EXIT
  echo "$0: failed"
  exit 1
}

trap clean INT EXIT

for f in address@hidden; do
  mv -f "$f" "$f.orig.$$"
  clean=("address@hidden" "$f")
done

cvs update -C address@hidden

# coarse timestamps can keep cvs diff from noticing a patch immediately after 
and update
: $(( i=0 )); touch .a$$ .b$$; until [ .a$$ -nt .b$$ ]; do : $(( i++ )); touch 
.a$$; done; rm -f .a$$ .b$$; echo $((i))

patch --dry-run -sp0 < $patch
patch -p0 < $patch

cvs add address@hidden 2>/dev/null || true
cvs rm  address@hidden 2>/dev/null || true

rest=rest.$$.patch

> $rest
for f in address@hidden; do
  diff -u "$f" "$f.orig.$$" >> $rest || [ $? = 1 ]
done

if [ -n "$message" ]; then
  cvs commit -m "$message" address@hidden
else
  cvs commit address@hidden
fi

patch -p0 < $rest

rm $rest

trap "" INT EXIT

for f in address@hidden; do
  rm "$f.orig.$$"
done
;; Copyright 2003,2004
;;   by Jim Radford <address@hidden> 
;;   and David Caldwell <address@hidden>
;; This code can be distributed under the terms of the GNU Public License
;; Version: 2.0

(require 'vc)
(require 'log-edit)

(defun cvs-commit-patch-buffer (buffer directory)
  "Commit the patch found in BUFFER applying it from DIRECTORY."
  (interactive "bBuffer to commit: \nDDirectory: ")
  (let* ((patch-files (with-temp-buffer
                        (let ((lsdiff (current-buffer)))
                          (when (eq 0 (with-current-buffer buffer
                                        (call-process-region (point-min) 
(point-max) 
                                                             "lsdiff" nil 
lsdiff nil)))
                            (split-string (buffer-string)))))) 
         (f patch-files) visiting-buffers)
    (while (car f)
      (let ((buf (find-buffer-visiting (car f))))
        (when buf
          (with-current-buffer buf (vc-buffer-sync))
          (add-to-list 'visiting-buffers buf)))
      (setq f (cdr f)))
    (log-edit
     `(lambda () (interactive)
        (let ((patch (make-temp-file "commit-buffer" nil))
              (comment (buffer-string))
              (output-buffer (window-buffer
                              (display-buffer
                               (get-buffer-create "*cvs-commit-patch*")))))
          (unwind-protect 
              (progn
                (with-current-buffer ,buffer
                  (write-region (point-min) (point-max) patch))
                (with-current-buffer output-buffer
                  (erase-buffer)
                  (let* ((default-directory ,directory) 
                         (status (call-process "cvs-commit-patch" nil
                                               output-buffer 'display
                                               "-m" comment patch)))
                    (if (not (eq status 0))
                        (message "Commit patch failed with a status of '%S' 
(%S)." status patch)
                      (mapc (lambda (buf) (with-current-buffer buf
                                            (vc-resynch-buffer 
(buffer-file-name buf) 'revert 'noquery)
                                            ;; stupid vc-revert-buffer1 doesn't 
call revert-buffer
                                            ;; with preserve-modes which means 
the CVS version doesn't
                                            ;; get updated, so we do it by hand.
                                            (run-hooks 'find-file-hooks)))
                            ',visiting-buffers)
                      (message "Patched and commited %S file(s) and reverted 
%S." 
                               ,(length patch-files) ,(length 
visiting-buffers))))))
            (delete-file patch))))
     nil
     `(lambda () ',patch-files)
     "*cvs-commit*")))

(when (require 'diff-mode)
  (setq diff-default-read-only nil)
  (define-key diff-mode-map "\C-c\C-c" 'cvs-commit-patch-buffer))

(provide 'cvs-commit-patch-buffer)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]