aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2010-11-22 20:15:08 -0500
committerChong Yidong2010-11-22 20:15:08 -0500
commit2c3160c54e5e58ebd9cf3b2c499a55d43b0271cc (patch)
treed11648c6733cd4179018ce88478ee0bc96f52535
parentef6a29070d822e6b35d6b978d2f070f8a5854b30 (diff)
downloademacs-2c3160c54e5e58ebd9cf3b2c499a55d43b0271cc.tar.gz
emacs-2c3160c54e5e58ebd9cf3b2c499a55d43b0271cc.zip
Initial support for unified DVCS pull and merge.
* lisp/vc/vc-bzr.el (vc-bzr-admin-branchconf, vc-bzr-history): New vars. (vc-bzr--branch-conf, vc-bzr-async-command, vc-bzr-pull) (vc-bzr-merge-branch): New functions, implementing merge-branch and pull operations. * lisp/vc/vc.el (vc-merge): Use vc-BACKEND-merge-branch if available. Accept optional prefix arg meaning to prompt for a command. (vc-update): Use vc-BACKEND-pull if available. Accept optional prefix arg meaning to prompt for a command. (vc-pull): Alias for vc-update.
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/vc/vc-bzr.el93
-rw-r--r--lisp/vc/vc.el198
3 files changed, 224 insertions, 80 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 763d73c883b..f86ff355fa9 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,16 @@
12010-11-23 Chong Yidong <cyd@stupidchicken.com>
2
3 * vc/vc.el (vc-merge): Use vc-BACKEND-merge-branch if available.
4 Accept optional prefix arg meaning to prompt for a command.
5 (vc-update): Use vc-BACKEND-pull if available. Accept optional
6 prefix arg meaning to prompt for a command.
7 (vc-pull): Alias for vc-update.
8
9 * vc/vc-bzr.el (vc-bzr-admin-branchconf, vc-bzr-history): New vars.
10 (vc-bzr--branch-conf, vc-bzr-async-command, vc-bzr-pull)
11 (vc-bzr-merge-branch): New functions, implementing merge-branch
12 and pull operations.
13
12010-11-22 Stefan Monnier <monnier@iro.umontreal.ca> 142010-11-22 Stefan Monnier <monnier@iro.umontreal.ca>
2 15
3 * Makefile.in: Fix up last merge. 16 * Makefile.in: Fix up last merge.
diff --git a/lisp/vc/vc-bzr.el b/lisp/vc/vc-bzr.el
index 78441772bd4..9f8a018cec5 100644
--- a/lisp/vc/vc-bzr.el
+++ b/lisp/vc/vc-bzr.el
@@ -115,6 +115,8 @@ Invoke the bzr command adding `BZR_PROGRESS_BAR=none' and
115 (concat vc-bzr-admin-dirname "/branch/revision-history")) 115 (concat vc-bzr-admin-dirname "/branch/revision-history"))
116(defconst vc-bzr-admin-lastrev 116(defconst vc-bzr-admin-lastrev
117 (concat vc-bzr-admin-dirname "/branch/last-revision")) 117 (concat vc-bzr-admin-dirname "/branch/last-revision"))
118(defconst vc-bzr-admin-branchconf
119 (concat vc-bzr-admin-dirname "/branch/branch.conf"))
118 120
119;;;###autoload (defun vc-bzr-registered (file) 121;;;###autoload (defun vc-bzr-registered (file)
120;;;###autoload (if (vc-find-root file vc-bzr-admin-checkout-format-file) 122;;;###autoload (if (vc-find-root file vc-bzr-admin-checkout-format-file)
@@ -129,6 +131,13 @@ Invoke the bzr command adding `BZR_PROGRESS_BAR=none' and
129 (let ((root (vc-find-root file vc-bzr-admin-checkout-format-file))) 131 (let ((root (vc-find-root file vc-bzr-admin-checkout-format-file)))
130 (when root (vc-file-setprop file 'bzr-root root))))) 132 (when root (vc-file-setprop file 'bzr-root root)))))
131 133
134(defun vc-bzr--branch-conf (file)
135 "Return the Bzr branch config for file FILE, as a string."
136 (with-temp-buffer
137 (insert-file-contents
138 (expand-file-name vc-bzr-admin-branchconf (vc-bzr-root file)))
139 (buffer-string)))
140
132(require 'sha1) ;For sha1-program 141(require 'sha1) ;For sha1-program
133 142
134(defun vc-bzr-sha1 (file) 143(defun vc-bzr-sha1 (file)
@@ -228,6 +237,9 @@ Invoke the bzr command adding `BZR_PROGRESS_BAR=none' and
228 "added\\|ignored\\|kind changed\\|modified\\|removed\\|renamed\\|unknown" 237 "added\\|ignored\\|kind changed\\|modified\\|removed\\|renamed\\|unknown"
229 "Regexp matching file status words as reported in `bzr' output.") 238 "Regexp matching file status words as reported in `bzr' output.")
230 239
240;; History of Bzr commands.
241(defvar vc-bzr-history nil)
242
231(defun vc-bzr-file-name-relative (filename) 243(defun vc-bzr-file-name-relative (filename)
232 "Return file name FILENAME stripped of the initial Bzr repository path." 244 "Return file name FILENAME stripped of the initial Bzr repository path."
233 (lexical-let* 245 (lexical-let*
@@ -236,6 +248,87 @@ Invoke the bzr command adding `BZR_PROGRESS_BAR=none' and
236 (when rootdir 248 (when rootdir
237 (file-relative-name filename* rootdir)))) 249 (file-relative-name filename* rootdir))))
238 250
251(defun vc-bzr-async-command (command args)
252 "Run Bzr COMMAND asynchronously with ARGS, displaying the result.
253Send the output to a buffer named \"*vc-bzr : NAME*\", where NAME
254is the root of the current Bzr branch. Display the buffer in
255some window, but don't select it."
256 ;; TODO: set up hyperlinks.
257 (let* ((dir default-directory)
258 (root (vc-bzr-root default-directory))
259 (buffer (get-buffer-create (format "*vc-bzr : %s*" root))))
260 (with-current-buffer buffer
261 (setq default-directory root)
262 (goto-char (point-max))
263 (unless (eq (point) (point-min))
264 (insert " \n"))
265 (insert "Running \"" vc-bzr-program " " command)
266 (dolist (arg args)
267 (insert " " arg))
268 (insert "\"...\n")
269 ;; Run bzr in the original working directory.
270 (let ((default-directory dir))
271 (apply 'vc-bzr-command command t 'async nil args)))
272 (display-buffer buffer)))
273
274(defun vc-bzr-pull (prompt)
275 "Pull changes into the current Bzr branch.
276Normally, this runs \"bzr pull\". However, if the branch is a
277bound branch, run \"bzr update\" instead. If there is no default
278location from which to pull or update, or if PROMPT is non-nil,
279prompt for the Bzr command to run."
280 (let* ((vc-bzr-program vc-bzr-program)
281 (branch-conf (vc-bzr--branch-conf default-directory))
282 ;; Check whether the branch is bound.
283 (bound (string-match "^bound\\s-*=\\s-*True" branch-conf))
284 ;; If we need to do a "bzr pull", check for a parent. If it
285 ;; does not exist, bzr will need a pull location.
286 (parent (unless bound
287 (string-match
288 "^parent_location\\s-*=\\s-*[^\n[:space:]]+"
289 branch-conf)))
290 (command (if bound "update" "pull"))
291 args buf)
292 ;; If necessary, prompt for the exact command.
293 (when (or prompt (not (or bound parent)))
294 (setq args (split-string
295 (read-shell-command
296 "Run Bzr (like this): "
297 (concat vc-bzr-program " " command)
298 'vc-bzr-history)
299 " " t))
300 (setq vc-bzr-program (car args)
301 command (cadr args)
302 args (cddr args)))
303 (vc-bzr-async-command command args)))
304
305(defun vc-bzr-merge-branch (prompt)
306 "Merge another Bzr branch into the current one.
307If a default merge source is defined (i.e. an upstream branch or
308a previous merge source), this normally runs \"bzr merge --pull\".
309If optional PROMPT is non-nil or no default merge source is
310defined, prompt for the Bzr command to run."
311 (let* ((vc-bzr-program vc-bzr-program)
312 (command "merge")
313 (args '("--pull"))
314 command-string args buf)
315 (when (or prompt
316 ;; Prompt if there is no default merge source.
317 (null
318 (string-match
319 "^\\(parent_location\\|submit_branch\\)\\s-*=\\s-*[^\n[:space:]]+"
320 (vc-bzr--branch-conf default-directory))))
321 (setq args (split-string
322 (read-shell-command
323 "Run Bzr (like this): "
324 (concat vc-bzr-program " " command " --pull")
325 'vc-bzr-history)
326 " " t))
327 (setq vc-bzr-program (car args)
328 command (cadr args)
329 args (cddr args)))
330 (vc-bzr-async-command command args)))
331
239(defun vc-bzr-status (file) 332(defun vc-bzr-status (file)
240 "Return FILE status according to Bzr. 333 "Return FILE status according to Bzr.
241Return value is a cons (STATUS . WARNING), where WARNING is a 334Return value is a cons (STATUS . WARNING), where WARNING is a
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 56bf353b6b4..d8741c3752e 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -100,7 +100,7 @@
100;; In the list of functions below, each identifier needs to be prepended 100;; In the list of functions below, each identifier needs to be prepended
101;; with `vc-sys-'. Some of the functions are mandatory (marked with a 101;; with `vc-sys-'. Some of the functions are mandatory (marked with a
102;; `*'), others are optional (`-'). 102;; `*'), others are optional (`-').
103;; 103
104;; BACKEND PROPERTIES 104;; BACKEND PROPERTIES
105;; 105;;
106;; * revision-granularity 106;; * revision-granularity
@@ -109,7 +109,7 @@
109;; that return 'file have per-file revision numbering; backends 109;; that return 'file have per-file revision numbering; backends
110;; that return 'repository have per-repository revision numbering, 110;; that return 'repository have per-repository revision numbering,
111;; so a revision level implicitly identifies a changeset 111;; so a revision level implicitly identifies a changeset
112;; 112
113;; STATE-QUERYING FUNCTIONS 113;; STATE-QUERYING FUNCTIONS
114;; 114;;
115;; * registered (file) 115;; * registered (file)
@@ -313,11 +313,24 @@
313;; 313;;
314;; - merge (file rev1 rev2) 314;; - merge (file rev1 rev2)
315;; 315;;
316;; Merge the changes between REV1 and REV2 into the current working file. 316;; Merge the changes between REV1 and REV2 into the current working file
317;; (for non-distributed VCS).
318;;
319;; - merge-branch (prompt)
320;;
321;; Merge another branch into the current one. If PROMPT is non-nil,
322;; or if necessary, prompt for a location to merge from.
317;; 323;;
318;; - merge-news (file) 324;; - merge-news (file)
319;; 325;;
320;; Merge recent changes from the current branch into FILE. 326;; Merge recent changes from the current branch into FILE.
327;; (for non-distributed VCS).
328;;
329;; - pull (prompt)
330;;
331;; Pull "upstream" changes into the current branch (for distributed
332;; VCS). If PROMPT is non-nil, or if necessary, prompt for a
333;; location to pull from.
321;; 334;;
322;; - steal-lock (file &optional revision) 335;; - steal-lock (file &optional revision)
323;; 336;;
@@ -335,7 +348,7 @@
335;; 348;;
336;; Mark conflicts as resolved. Some VC systems need to run a 349;; Mark conflicts as resolved. Some VC systems need to run a
337;; command to mark conflicts as resolved. 350;; command to mark conflicts as resolved.
338;; 351
339;; HISTORY FUNCTIONS 352;; HISTORY FUNCTIONS
340;; 353;;
341;; * print-log (files buffer &optional shortlog start-revision limit) 354;; * print-log (files buffer &optional shortlog start-revision limit)
@@ -440,7 +453,7 @@
440;; If the backend supports annotating through copies and renames, 453;; If the backend supports annotating through copies and renames,
441;; and displays a file name and a revision, then return a cons 454;; and displays a file name and a revision, then return a cons
442;; (REVISION . FILENAME). 455;; (REVISION . FILENAME).
443;; 456
444;; TAG SYSTEM 457;; TAG SYSTEM
445;; 458;;
446;; - create-tag (dir name branchp) 459;; - create-tag (dir name branchp)
@@ -461,7 +474,7 @@
461;; does a sanity check whether there aren't any uncommitted changes at 474;; does a sanity check whether there aren't any uncommitted changes at
462;; or below DIR, and then performs a tree walk, using the `checkout' 475;; or below DIR, and then performs a tree walk, using the `checkout'
463;; function to retrieve the corresponding revisions. 476;; function to retrieve the corresponding revisions.
464;; 477
465;; MISCELLANEOUS 478;; MISCELLANEOUS
466;; 479;;
467;; - make-version-backups-p (file) 480;; - make-version-backups-p (file)
@@ -1815,54 +1828,67 @@ The headers are reset to their non-expanded form."
1815 'modify-change-comment files rev comment)))))) 1828 'modify-change-comment files rev comment))))))
1816 1829
1817;;;###autoload 1830;;;###autoload
1818(defun vc-merge () 1831(defun vc-merge (&optional arg)
1819 "Merge changes between two revisions into the current buffer's file. 1832 "Perform a version control merge operation.
1820This asks for two revisions to merge from in the minibuffer. If the 1833On a distributed version control system, this runs a \"merge\"
1821first revision is a branch number, then merge all changes from that 1834operation to incorporate changes from another branch onto the
1822branch. If the first revision is empty, merge news, i.e. recent changes 1835current branch, prompting for an argument list if required.
1823from the current branch. 1836Optional prefix ARG forces a prompt.
1824 1837
1825See Info node `Merging'." 1838On a non-distributed version control system, this merges changes
1826 (interactive) 1839between two revisions into the current fileset. This asks for
1827 (vc-ensure-vc-buffer) 1840two revisions to merge from in the minibuffer. If the first
1828 (vc-buffer-sync) 1841revision is a branch number, then merge all changes from that
1829 (let* ((file buffer-file-name) 1842branch. If the first revision is empty, merge the most recent
1830 (backend (vc-backend file)) 1843changes from the current branch."
1831 (state (vc-state file)) 1844 (interactive "P")
1832 first-revision second-revision status) 1845 (let* ((vc-fileset (vc-deduce-fileset t))
1846 (backend (car vc-fileset))
1847 (files (cadr vc-fileset)))
1833 (cond 1848 (cond
1834 ((stringp state) ;; Locking VCses only 1849 ;; If a branch-merge operation is defined, use it.
1835 (error "File is locked by %s" state)) 1850 ((vc-find-backend-function backend 'merge-branch)
1836 ((not (vc-editable-p file)) 1851 (vc-call-backend backend 'merge-branch arg))
1837 (if (y-or-n-p 1852 ;; Otherwise, do a per-file merge.
1838 "File must be checked out for merging. Check out now? ") 1853 ((vc-find-backend-function backend 'merge)
1839 (vc-checkout file t) 1854 (vc-buffer-sync)
1840 (error "Merge aborted")))) 1855 (dolist (file files)
1841 (setq first-revision 1856 (let* ((state (vc-state file))
1842 (vc-read-revision 1857 first-revision second-revision status)
1843 (concat "Branch or revision to merge from " 1858 (cond
1844 "(default news on current branch): ") 1859 ((stringp state) ;; Locking VCses only
1845 (list file) 1860 (error "File %s is locked by %s" file state))
1846 backend)) 1861 ((not (vc-editable-p file))
1847 (if (string= first-revision "") 1862 (vc-checkout file t)))
1848 (setq status (vc-call-backend backend 'merge-news file)) 1863 (setq first-revision
1849 (if (not (vc-find-backend-function backend 'merge)) 1864 (vc-read-revision
1850 (error "Sorry, merging is not implemented for %s" backend) 1865 (concat "Merge " file
1851 (if (not (vc-branch-p first-revision)) 1866 "from branch or revision "
1852 (setq second-revision 1867 "(default news on current branch): ")
1853 (vc-read-revision 1868 (list file)
1854 "Second revision: " 1869 backend))
1855 (list file) backend nil 1870 (cond
1856 ;; FIXME: This is CVS/RCS/SCCS specific. 1871 ((string= first-revision "")
1857 (concat (vc-branch-part first-revision) "."))) 1872 (setq status (vc-call-backend backend 'merge-news file)))
1858 ;; We want to merge an entire branch. Set revisions 1873 (t
1859 ;; accordingly, so that vc-BACKEND-merge understands us. 1874 (if (not (vc-branch-p first-revision))
1860 (setq second-revision first-revision) 1875 (setq second-revision
1861 ;; first-revision must be the starting point of the branch 1876 (vc-read-revision
1862 (setq first-revision (vc-branch-part first-revision))) 1877 "Second revision: "
1863 (setq status (vc-call-backend backend 'merge file 1878 (list file) backend nil
1864 first-revision second-revision)))) 1879 ;; FIXME: This is CVS/RCS/SCCS specific.
1865 (vc-maybe-resolve-conflicts file status "WORKFILE" "MERGE SOURCE"))) 1880 (concat (vc-branch-part first-revision) ".")))
1881 ;; We want to merge an entire branch. Set revisions
1882 ;; accordingly, so that vc-BACKEND-merge understands us.
1883 (setq second-revision first-revision)
1884 ;; first-revision must be the starting point of the branch
1885 (setq first-revision (vc-branch-part first-revision)))
1886 (setq status (vc-call-backend backend 'merge file
1887 first-revision second-revision))))
1888 (vc-maybe-resolve-conflicts file status "WORKFILE" "MERGE SOURCE"))))
1889 (t
1890 (error "Sorry, merging is not implemented for %s" backend)))))
1891
1866 1892
1867(defun vc-maybe-resolve-conflicts (file status &optional name-A name-B) 1893(defun vc-maybe-resolve-conflicts (file status &optional name-A name-B)
1868 (vc-resynch-buffer file t (not (buffer-modified-p))) 1894 (vc-resynch-buffer file t (not (buffer-modified-p)))
@@ -2274,35 +2300,47 @@ depending on the underlying version-control system."
2274(define-obsolete-function-alias 'vc-revert-buffer 'vc-revert "23.1") 2300(define-obsolete-function-alias 'vc-revert-buffer 'vc-revert "23.1")
2275 2301
2276;;;###autoload 2302;;;###autoload
2277(defun vc-update () 2303(defun vc-update (&optional arg)
2278 "Update the current fileset's files to their tip revisions. 2304 "Update the current fileset or branch.
2279For each one that contains no changes, and is not locked, then this simply 2305On a distributed version control system, this runs a \"pull\"
2280replaces the work file with the latest revision on its branch. If the file 2306operation to update the current branch, prompting for an argument
2281contains changes, and the backend supports merging news, then any recent 2307list if required. Optional prefix ARG forces a prompt.
2282changes from the current branch are merged into the working file." 2308
2283 (interactive) 2309On a non-distributed version control system, update the current
2284 (let* ((vc-fileset (vc-deduce-fileset)) 2310fileset to the tip revisions. For each unchanged and unlocked
2311file, this simply replaces the work file with the latest revision
2312on its branch. If the file contains changes, any changes in the
2313tip revision are merged into the working file."
2314 (interactive "P")
2315 (let* ((vc-fileset (vc-deduce-fileset t))
2285 (backend (car vc-fileset)) 2316 (backend (car vc-fileset))
2286 (files (cadr vc-fileset))) 2317 (files (cadr vc-fileset)))
2287 (save-some-buffers ; save buffers visiting files 2318 (cond
2288 nil (lambda () 2319 ;; If a pull operation is defined, use it.
2289 (and (buffer-modified-p) 2320 ((vc-find-backend-function backend 'pull)
2290 (let ((file (buffer-file-name))) 2321 (vc-call-backend backend 'pull arg))
2291 (and file (member file files)))))) 2322 ;; If VCS has `merge-news' functionality (CVS and SVN), use it.
2292 (dolist (file files) 2323 ((vc-find-backend-function backend 'merge-news)
2293 (if (vc-up-to-date-p file) 2324 (save-some-buffers ; save buffers visiting files
2294 (vc-checkout file nil t) 2325 nil (lambda ()
2295 (if (eq (vc-checkout-model backend (list file)) 'locking) 2326 (and (buffer-modified-p)
2296 (if (eq (vc-state file) 'edited) 2327 (let ((file (buffer-file-name)))
2297 (error "%s" 2328 (and file (member file files))))))
2298 (substitute-command-keys 2329 (dolist (file files)
2299 "File is locked--type \\[vc-revert] to discard changes")) 2330 (if (vc-up-to-date-p file)
2300 (error "Unexpected file state (%s) -- type %s" 2331 (vc-checkout file nil t)
2301 (vc-state file) 2332 (vc-maybe-resolve-conflicts
2302 (substitute-command-keys 2333 file (vc-call-backend backend 'merge-news file)))))
2303 "\\[vc-next-action] to correct"))) 2334 ;; For a locking VCS, check out each file.
2304 (vc-maybe-resolve-conflicts 2335 ((eq (vc-checkout-model backend files) 'locking)
2305 file (vc-call-backend backend 'merge-news file))))))) 2336 (dolist (file files)
2337 (if (vc-up-to-date-p file)
2338 (vc-checkout file nil t))))
2339 (t
2340 (error "VC update is unsupported for `%s'" backend)))))
2341
2342;;;###autoload
2343(defalias 'vc-pull 'vc-update)
2306 2344
2307(defun vc-version-backup-file (file &optional rev) 2345(defun vc-version-backup-file (file &optional rev)
2308 "Return name of backup file for revision REV of FILE. 2346 "Return name of backup file for revision REV of FILE.