summaryrefslogtreecommitdiff
path: root/admin/gitmerge.el
diff options
context:
space:
mode:
Diffstat (limited to 'admin/gitmerge.el')
-rw-r--r--admin/gitmerge.el132
1 files changed, 101 insertions, 31 deletions
diff --git a/admin/gitmerge.el b/admin/gitmerge.el
index 1058088cce9..71b1761970c 100644
--- a/admin/gitmerge.el
+++ b/admin/gitmerge.el
@@ -50,11 +50,22 @@
(defvar gitmerge-skip-regexp
;; We used to include "sync" in there, but in my experience it only
;; caused false positives. --Stef
- "back[- ]?port\\|cherry picked from commit\\|\\(do\\( no\\|n['’]\\)t\\|no need to\\) merge\\|\
-re-?generate\\|bump version\\|from trunk\\|Auto-commit"
+ (let ((skip "back[- ]?port\\|cherry picked from commit\\|\
+\\(do\\( no\\|n['’]\\)t\\|no need to\\) merge\\|\
+bump version\\|Auto-commit"))
+ (if noninteractive skip
+ ;; "Regenerate" is quite prone to false positives.
+ ;; We only want to skip merging things like AUTHORS and ldefs-boot.
+ ;; These should be covered by "bump version" and "auto-commit".
+ ;; It doesn't do much harm if we merge one of those files by mistake.
+ ;; So it's better to err on the side of false negatives.
+ (concat skip "\\|re-?generate\\|from trunk")))
"Regexp matching logs of revisions that might be skipped.
`gitmerge-missing' will ask you if it should skip any matches.")
+(defvar gitmerge-minimum-missing 10
+ "Minimum number of missing commits to consider merging in batch mode.")
+
(defvar gitmerge-status-file (expand-file-name "gitmerge-status"
user-emacs-directory)
"File where missing commits will be saved between sessions.")
@@ -67,8 +78,9 @@ re-?generate\\|bump version\\|from trunk\\|Auto-commit"
'((t (:strike-through t)))
"Face for skipped commits.")
-(defconst gitmerge-default-branch "origin/emacs-25"
- "Default for branch that should be merged.")
+(defvar gitmerge-default-branch nil
+ "Default for branch that should be merged.
+If nil, the function `gitmerge-default-branch' guesses.")
(defconst gitmerge-buffer "*gitmerge*"
"Working buffer for gitmerge.")
@@ -103,6 +115,21 @@ re-?generate\\|bump version\\|from trunk\\|Auto-commit"
(defvar gitmerge--commits nil)
(defvar gitmerge--from nil)
+(defun gitmerge-emacs-version (&optional branch)
+ "Return the major version of Emacs, optionally in BRANCH."
+ (with-temp-buffer
+ (if (not branch)
+ (insert-file-contents "configure.ac")
+ (call-process "git" nil t nil "show" (format "%s:configure.ac" branch))
+ (goto-char (point-min)))
+ (re-search-forward "^AC_INIT([^,]+, \\([0-9]+\\)\\.")
+ (string-to-number (match-string 1))))
+
+(defun gitmerge-default-branch ()
+ "Default for branch that should be merged; eg \"origin/emacs-26\"."
+ (or gitmerge-default-branch
+ (format "origin/emacs-%s" (1- (gitmerge-emacs-version)))))
+
(defun gitmerge-get-sha1 ()
"Get SHA1 from commit at point."
(save-excursion
@@ -182,11 +209,13 @@ Will detect a default set of skipped revision by looking at
cherry mark and search for `gitmerge-skip-regexp'. The result is
a list with entries of the form (SHA1 . SKIP), where SKIP denotes
if and why this commit should be skipped."
+ (message "Finding missing commits...")
(let (commits)
;; Go through the log and remember all commits that match
;; `gitmerge-skip-regexp' or are marked by --cherry-mark.
(with-temp-buffer
(call-process "git" nil t nil "log" "--cherry-mark" "--left-only"
+ "--no-decorate"
(concat from "..." (car (vc-git-branches))))
(goto-char (point-max))
(while (re-search-backward "^commit \\(.+\\) \\([0-9a-f]+\\).*" nil t)
@@ -203,6 +232,7 @@ if and why this commit should be skipped."
(when (re-search-forward gitmerge-skip-regexp nil t)
(setcdr (car commits) "R"))))))
(delete-region (point) (point-max))))
+ (message "Finding missing commits...done")
(nreverse commits)))
(defun gitmerge-setup-log-buffer (commits from)
@@ -291,23 +321,47 @@ Returns non-nil if conflicts remain."
;; (pop-to-buffer (current-buffer)) (debug 'before-resolve)
))
;; Try to resolve the conflicts.
- (cond
- ((member file '("configure" "lisp/ldefs-boot.el"
- "lisp/emacs-lisp/cl-loaddefs.el"))
- ;; We are in the file's buffer, so names are relative.
- (call-process "git" nil t nil "checkout" "--"
- (file-name-nondirectory file))
- (revert-buffer nil 'noconfirm))
- (t
- (goto-char (point-max))
- (while (re-search-backward smerge-begin-re nil t)
- (save-excursion
- (ignore-errors
- (smerge-match-conflict)
- (smerge-resolve))))
- ;; (when (derived-mode-p 'change-log-mode)
- ;; (pop-to-buffer (current-buffer)) (debug 'after-resolve))
- (save-buffer)))
+ (let (temp)
+ (cond
+ ((and (equal file "etc/NEWS")
+ (ignore-errors
+ (setq temp
+ (format "NEWS.%s"
+ (gitmerge-emacs-version gitmerge--from))))
+ (file-exists-p temp)
+ (or noninteractive
+ (y-or-n-p "Try to fix NEWS conflict? ")))
+ (let ((relfile (file-name-nondirectory file))
+ (tempfile (make-temp-file "gitmerge")))
+ (unwind-protect
+ (progn
+ (call-process "git" nil `(:file ,tempfile) nil "diff"
+ (format ":1:%s" file)
+ (format ":3:%s" file))
+ (call-process "git" nil t nil "reset" "--" relfile)
+ (call-process "git" nil t nil "checkout" "--" relfile)
+ (revert-buffer nil 'noconfirm)
+ (call-process "patch" tempfile nil nil temp)
+ (call-process "git" nil t nil "add" "--" temp))
+ (delete-file tempfile))))
+ ;; Generated files.
+ ((member file '("lisp/ldefs-boot.el"))
+ ;; We are in the file's buffer, so names are relative.
+ (call-process "git" nil t nil "reset" "--"
+ (file-name-nondirectory file))
+ (call-process "git" nil t nil "checkout" "--"
+ (file-name-nondirectory file))
+ (revert-buffer nil 'noconfirm))
+ (t
+ (goto-char (point-max))
+ (while (re-search-backward smerge-begin-re nil t)
+ (save-excursion
+ (ignore-errors
+ (smerge-match-conflict)
+ (smerge-resolve))))
+ ;; (when (derived-mode-p 'change-log-mode)
+ ;; (pop-to-buffer (current-buffer)) (debug 'after-resolve))
+ (save-buffer))))
(goto-char (point-min))
(prog1 (re-search-forward smerge-begin-re nil t)
(unless exists (kill-buffer))))))))
@@ -387,7 +441,9 @@ Throw an user-error if we cannot resolve automatically."
(setq conflicted t)
;; Mark as resolved
(call-process "git" nil t nil "add" file)))
- (when conflicted
+ (if (not conflicted)
+ (and files (not (gitmerge-commit))
+ (error "Error committing resolution - fix it manually"))
(with-current-buffer (get-buffer-create gitmerge-warning-buffer)
(erase-buffer)
(insert "For the following files, conflicts could\n"
@@ -413,6 +469,12 @@ Throw an user-error if we cannot resolve automatically."
"diff" "--name-only")
(zerop (buffer-size))))
+(defun gitmerge-commit ()
+ "Commit, and return non-nil if it succeeds."
+ (with-current-buffer (get-buffer-create gitmerge-output-buffer)
+ (erase-buffer)
+ (eq 0 (call-process "git" nil t nil "commit" "--no-edit"))))
+
(defun gitmerge-maybe-resume ()
"Check if we have to resume a merge.
If so, add no longer conflicted files and commit."
@@ -425,7 +487,7 @@ If so, add no longer conflicted files and commit."
(not (gitmerge-repo-clean)))
(user-error "Repository is not clean"))
(when statusexist
- (if (not (y-or-n-p "Resume merge? "))
+ (if (or noninteractive (not (y-or-n-p "Resume merge? ")))
(progn
(delete-file gitmerge-status-file)
;; No resume.
@@ -434,11 +496,8 @@ If so, add no longer conflicted files and commit."
(gitmerge-resolve-unmerged)
;; Commit the merge.
(when mergehead
- (with-current-buffer (get-buffer-create gitmerge-output-buffer)
- (erase-buffer)
- (unless (zerop (call-process "git" nil t nil
- "commit" "--no-edit"))
- (error "Git error during merge - fix it manually"))))
+ (or (gitmerge-commit)
+ (error "Git error during merge - fix it manually")))
;; Successfully resumed.
t))))
@@ -494,8 +553,12 @@ Branch FROM will be prepended to the list."
(list
(if (gitmerge-maybe-resume)
'resume
- (completing-read "Merge branch: " (gitmerge-get-all-branches)
- nil t gitmerge-default-branch))))))
+ (if noninteractive
+ (or (pop command-line-args-left)
+ (gitmerge-default-branch))
+ (completing-read "Merge branch: "
+ (gitmerge-get-all-branches)
+ nil t (gitmerge-default-branch))))))))
(let ((default-directory (vc-git-root default-directory)))
(if (eq from 'resume)
(progn
@@ -507,6 +570,12 @@ Branch FROM will be prepended to the list."
(setq gitmerge--from from)
(when (null gitmerge--commits)
(user-error "Nothing to merge"))
+ (and noninteractive
+ gitmerge-minimum-missing
+ (< (length gitmerge--commits) gitmerge-minimum-missing)
+ (user-error "Number of missing commits (%s) is less than %s"
+ (length gitmerge--commits)
+ gitmerge-minimum-missing))
(with-current-buffer
(gitmerge-setup-log-buffer gitmerge--commits gitmerge--from)
(goto-char (point-min))
@@ -517,7 +586,8 @@ Branch FROM will be prepended to the list."
"(C) Detected backport (cherry-mark), (R) Log matches "
"regexp, (M) Manually picked\n\n")
(gitmerge-mode)
- (pop-to-buffer (current-buffer))))))
+ (pop-to-buffer (current-buffer))
+ (if noninteractive (gitmerge-start-merge))))))
(defun gitmerge-start-merge ()
(interactive)