diff options
| author | Eric S. Raymond | 2014-12-01 11:41:45 -0500 |
|---|---|---|
| committer | Eric S. Raymond | 2014-12-01 11:43:10 -0500 |
| commit | d17bae9039021b600ceaec93f2f0e888b12e523d (patch) | |
| tree | f6ea0b50386d04f4c584415bed7c5221b872d4de | |
| parent | dce46a7484d9898cc161a8333ec71db3480b110b (diff) | |
| download | emacs-d17bae9039021b600ceaec93f2f0e888b12e523d.tar.gz emacs-d17bae9039021b600ceaec93f2f0e888b12e523d.zip | |
Refactor VC merging to fix a layer violation.
* vc/vc.el, vc/vc-cvs.el, vc/vc-rcs.el, vc/vc-svn.el: The 'merge'
backend method of RCS/CVS/SVN is now 'merge-file', to contrast with
'merge-branch'. Prompting for merge revisions is pushed down to the
back ends; this fixes a layering violation that caused bad behavior
with SVN.
| -rw-r--r-- | lisp/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/vc/vc-cvs.el | 29 | ||||
| -rw-r--r-- | lisp/vc/vc-rcs.el | 25 | ||||
| -rw-r--r-- | lisp/vc/vc-svn.el | 23 | ||||
| -rw-r--r-- | lisp/vc/vc.el | 41 |
5 files changed, 94 insertions, 30 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index b736b2d5617..e75cc89e3e9 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -5,6 +5,12 @@ | |||
| 5 | 5 | ||
| 6 | 2014-12-01 Eric S. Raymond <esr@snark.thyrsus.com> | 6 | 2014-12-01 Eric S. Raymond <esr@snark.thyrsus.com> |
| 7 | 7 | ||
| 8 | * vc/vc.el, vc/vc-cvs.el, vc/vc-rcs.el, vc/vc-svn.el: The 'merge' | ||
| 9 | backend method of RCS/CVS/SVN is now 'merge-file', to contrast with | ||
| 10 | 'merge-branch'. Prompting for merge revisions is pushed down to | ||
| 11 | the back ends; this fixes a layering violation that caused bad | ||
| 12 | behavior with SVN. | ||
| 13 | |||
| 8 | * vc/vc.el, vc-hooks.el, and all backends: API simplification; | 14 | * vc/vc.el, vc-hooks.el, and all backends: API simplification; |
| 9 | vc-stay-local-p and repository-hostname are no longer public | 15 | vc-stay-local-p and repository-hostname are no longer public |
| 10 | methods. Only the CVS and SVN backends used these, and the SVN | 16 | methods. Only the CVS and SVN backends used these, and the SVN |
diff --git a/lisp/vc/vc-cvs.el b/lisp/vc/vc-cvs.el index a09909a8353..fc1e8572578 100644 --- a/lisp/vc/vc-cvs.el +++ b/lisp/vc/vc-cvs.el | |||
| @@ -440,6 +440,35 @@ REV is the revision to check out." | |||
| 440 | ;; Make the file read-only by switching off all w-bits | 440 | ;; Make the file read-only by switching off all w-bits |
| 441 | (set-file-modes file (logand (file-modes file) 3950))))) | 441 | (set-file-modes file (logand (file-modes file) 3950))))) |
| 442 | 442 | ||
| 443 | (defun vc-cvs-merge-file (file) | ||
| 444 | "Accept a file merge request, prompting for revisions." | ||
| 445 | (let* ((first-revision | ||
| 446 | (vc-read-revision | ||
| 447 | (concat "Merge " file | ||
| 448 | " from branch or revision " | ||
| 449 | "(default news on current branch): ") | ||
| 450 | (list file) | ||
| 451 | 'CVS)) | ||
| 452 | second-revision | ||
| 453 | status) | ||
| 454 | (cond | ||
| 455 | ((string= first-revision "") | ||
| 456 | (setq status (vc-cvs-merge-news file))) | ||
| 457 | (t | ||
| 458 | (if (not (vc-branch-p first-revision)) | ||
| 459 | (setq second-revision | ||
| 460 | (vc-read-revision | ||
| 461 | "Second revision: " | ||
| 462 | (list file) 'CVS nil | ||
| 463 | (concat (vc-branch-part first-revision) "."))) | ||
| 464 | ;; We want to merge an entire branch. Set revisions | ||
| 465 | ;; accordingly, so that vc-cvs-merge understands us. | ||
| 466 | (setq second-revision first-revision) | ||
| 467 | ;; first-revision must be the starting point of the branch | ||
| 468 | (setq first-revision (vc-branch-part first-revision))) | ||
| 469 | (setq status (vc-cvs-merge file first-revision second-revision)))) | ||
| 470 | status)) | ||
| 471 | |||
| 443 | (defun vc-cvs-merge (file first-revision &optional second-revision) | 472 | (defun vc-cvs-merge (file first-revision &optional second-revision) |
| 444 | "Merge changes into current working copy of FILE. | 473 | "Merge changes into current working copy of FILE. |
| 445 | The changes are between FIRST-REVISION and SECOND-REVISION." | 474 | The changes are between FIRST-REVISION and SECOND-REVISION." |
diff --git a/lisp/vc/vc-rcs.el b/lisp/vc/vc-rcs.el index 96ae5836f42..940d967d68b 100644 --- a/lisp/vc/vc-rcs.el +++ b/lisp/vc/vc-rcs.el | |||
| @@ -486,6 +486,31 @@ revert all registered files beneath it." | |||
| 486 | (concat (if (eq (vc-state file) 'edited) "-u" "-r") | 486 | (concat (if (eq (vc-state file) 'edited) "-u" "-r") |
| 487 | (vc-working-revision file))))) | 487 | (vc-working-revision file))))) |
| 488 | 488 | ||
| 489 | (defun vc-rcs-merge-file (file) | ||
| 490 | "Accept a file merge request, prompting for revisions." | ||
| 491 | (let* ((first-revision | ||
| 492 | (vc-read-revision | ||
| 493 | (concat "Merge " file " from branch or revision: ") | ||
| 494 | (list file) | ||
| 495 | 'RCS)) | ||
| 496 | second-revision) | ||
| 497 | (cond | ||
| 498 | ((string= first-revision "") | ||
| 499 | (error "A starting RCS revision is required")) | ||
| 500 | (t | ||
| 501 | (if (not (vc-branch-p first-revision)) | ||
| 502 | (setq second-revision | ||
| 503 | (vc-read-revision | ||
| 504 | "Second RCS revision: " | ||
| 505 | (list file) 'RCS nil | ||
| 506 | (concat (vc-branch-part first-revision) "."))) | ||
| 507 | ;; We want to merge an entire branch. Set revisions | ||
| 508 | ;; accordingly, so that vc-rcs-merge understands us. | ||
| 509 | (setq second-revision first-revision) | ||
| 510 | ;; first-revision must be the starting point of the branch | ||
| 511 | (setq first-revision (vc-branch-part first-revision))))) | ||
| 512 | (vc-rcs-merge file first-revision second-revision))) | ||
| 513 | |||
| 489 | (defun vc-rcs-merge (file first-version &optional second-version) | 514 | (defun vc-rcs-merge (file first-version &optional second-version) |
| 490 | "Merge changes into current working copy of FILE. | 515 | "Merge changes into current working copy of FILE. |
| 491 | The changes are between FIRST-VERSION and SECOND-VERSION." | 516 | The changes are between FIRST-VERSION and SECOND-VERSION." |
diff --git a/lisp/vc/vc-svn.el b/lisp/vc/vc-svn.el index c3efcc59b5a..00a0388c599 100644 --- a/lisp/vc/vc-svn.el +++ b/lisp/vc/vc-svn.el | |||
| @@ -379,6 +379,29 @@ FILE is a file wildcard, relative to the root directory of DIRECTORY." | |||
| 379 | (unless contents-done | 379 | (unless contents-done |
| 380 | (vc-svn-command nil 0 file "revert"))) | 380 | (vc-svn-command nil 0 file "revert"))) |
| 381 | 381 | ||
| 382 | (defun vc-svn-merge-file (file) | ||
| 383 | "Accept a file merge request, prompting for revisions." | ||
| 384 | (let* ((first-revision | ||
| 385 | (vc-read-revision | ||
| 386 | (concat "Merge " file | ||
| 387 | " from SVN revision " | ||
| 388 | "(default news on current branch): ") | ||
| 389 | (list file) | ||
| 390 | 'SVN)) | ||
| 391 | second-revision | ||
| 392 | status) | ||
| 393 | (cond | ||
| 394 | ((string= first-revision "") | ||
| 395 | (setq status (vc-svn-merge-news file))) | ||
| 396 | (t | ||
| 397 | (setq second-revision | ||
| 398 | (vc-read-revision | ||
| 399 | "Second SVN revision: " | ||
| 400 | (list file) 'SVN nil | ||
| 401 | first-revision)) | ||
| 402 | (setq status (vc-svn-merge file first-revision second-revision)))) | ||
| 403 | status)) | ||
| 404 | |||
| 382 | (defun vc-svn-merge (file first-version &optional second-version) | 405 | (defun vc-svn-merge (file first-version &optional second-version) |
| 383 | "Merge changes into current working copy of FILE. | 406 | "Merge changes into current working copy of FILE. |
| 384 | The changes are between FIRST-VERSION and SECOND-VERSION." | 407 | The changes are between FIRST-VERSION and SECOND-VERSION." |
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index a30581efb4a..b6ba2d3e863 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el | |||
| @@ -289,10 +289,11 @@ | |||
| 289 | ;; 'cancel-version' and took a single file arg, not a list of | 289 | ;; 'cancel-version' and took a single file arg, not a list of |
| 290 | ;; files.) | 290 | ;; files.) |
| 291 | ;; | 291 | ;; |
| 292 | ;; - merge (file rev1 rev2) | 292 | ;; - merge-file (file rev1 rev2) |
| 293 | ;; | 293 | ;; |
| 294 | ;; Merge the changes between REV1 and REV2 into the current working file | 294 | ;; Merge the changes between REV1 and REV2 into the current working |
| 295 | ;; (for non-distributed VCS). | 295 | ;; file (for non-distributed VCS). It is expected that with an |
| 296 | ;; empty first revision this will behave like the merge-news method. | ||
| 296 | ;; | 297 | ;; |
| 297 | ;; - merge-branch () | 298 | ;; - merge-branch () |
| 298 | ;; | 299 | ;; |
| @@ -594,6 +595,11 @@ | |||
| 594 | ;; RCS has setting the initial revision been even possible, let alone | 595 | ;; RCS has setting the initial revision been even possible, let alone |
| 595 | ;; sane. | 596 | ;; sane. |
| 596 | ;; | 597 | ;; |
| 598 | ;; - The backend operation for non-distributed VCSes formerly called | ||
| 599 | ;; "merge" is now "merge-file" (to contrast with merge-branch), and | ||
| 600 | ;; does its own prompting for revisions. (This fixes a layer violation | ||
| 601 | ;; that produced bad behavior under SVN.) | ||
| 602 | ;; | ||
| 597 | ;; workfile-unchanged-p is no longer a public back-end method. It | 603 | ;; workfile-unchanged-p is no longer a public back-end method. It |
| 598 | ;; was redundant with vc-state and usually implemented with a trivial | 604 | ;; was redundant with vc-state and usually implemented with a trivial |
| 599 | ;; call to it. A few older back ends retain versions for internal use in | 605 | ;; call to it. A few older back ends retain versions for internal use in |
| @@ -2060,42 +2066,17 @@ changes from the current branch." | |||
| 2060 | (vc-buffer-sync) | 2066 | (vc-buffer-sync) |
| 2061 | (dolist (file files) | 2067 | (dolist (file files) |
| 2062 | (let* ((state (vc-state file)) | 2068 | (let* ((state (vc-state file)) |
| 2063 | first-revision second-revision status) | 2069 | status) |
| 2064 | (cond | 2070 | (cond |
| 2065 | ((stringp state) ;; Locking VCses only | 2071 | ((stringp state) ;; Locking VCses only |
| 2066 | (error "File %s is locked by %s" file state)) | 2072 | (error "File %s is locked by %s" file state)) |
| 2067 | ((not (vc-editable-p file)) | 2073 | ((not (vc-editable-p file)) |
| 2068 | (vc-checkout file t))) | 2074 | (vc-checkout file t))) |
| 2069 | (setq first-revision | 2075 | (setq status (vc-call-backend backend 'merge-file file)) |
| 2070 | (vc-read-revision | ||
| 2071 | (concat "Merge " file | ||
| 2072 | " from branch or revision " | ||
| 2073 | "(default news on current branch): ") | ||
| 2074 | (list file) | ||
| 2075 | backend)) | ||
| 2076 | (cond | ||
| 2077 | ((string= first-revision "") | ||
| 2078 | (setq status (vc-call-backend backend 'merge-news file))) | ||
| 2079 | (t | ||
| 2080 | (if (not (vc-branch-p first-revision)) | ||
| 2081 | (setq second-revision | ||
| 2082 | (vc-read-revision | ||
| 2083 | "Second revision: " | ||
| 2084 | (list file) backend nil | ||
| 2085 | ;; FIXME: This is CVS/RCS/SCCS specific. | ||
| 2086 | (concat (vc-branch-part first-revision) "."))) | ||
| 2087 | ;; We want to merge an entire branch. Set revisions | ||
| 2088 | ;; accordingly, so that vc-BACKEND-merge understands us. | ||
| 2089 | (setq second-revision first-revision) | ||
| 2090 | ;; first-revision must be the starting point of the branch | ||
| 2091 | (setq first-revision (vc-branch-part first-revision))) | ||
| 2092 | (setq status (vc-call-backend backend 'merge file | ||
| 2093 | first-revision second-revision)))) | ||
| 2094 | (vc-maybe-resolve-conflicts file status "WORKFILE" "MERGE SOURCE")))) | 2076 | (vc-maybe-resolve-conflicts file status "WORKFILE" "MERGE SOURCE")))) |
| 2095 | (t | 2077 | (t |
| 2096 | (error "Sorry, merging is not implemented for %s" backend))))) | 2078 | (error "Sorry, merging is not implemented for %s" backend))))) |
| 2097 | 2079 | ||
| 2098 | |||
| 2099 | (defun vc-maybe-resolve-conflicts (file status &optional _name-A _name-B) | 2080 | (defun vc-maybe-resolve-conflicts (file status &optional _name-A _name-B) |
| 2100 | (vc-resynch-buffer file t (not (buffer-modified-p))) | 2081 | (vc-resynch-buffer file t (not (buffer-modified-p))) |
| 2101 | (if (zerop status) (message "Merge successful") | 2082 | (if (zerop status) (message "Merge successful") |