commit | author | age
|
5cb5f7
|
1 |
;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*- |
C |
2 |
|
|
3 |
;; Copyright (C) 2008-2018 The Magit Project Contributors |
|
4 |
;; |
|
5 |
;; You should have received a copy of the AUTHORS.md file which |
|
6 |
;; lists all contributors. If not, see http://magit.vc/authors. |
|
7 |
|
|
8 |
;; Author: Jonas Bernoulli <jonas@bernoul.li> |
|
9 |
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li> |
|
10 |
|
|
11 |
;; Magit is free software; you can redistribute it and/or modify it |
|
12 |
;; under the terms of the GNU General Public License as published by |
|
13 |
;; the Free Software Foundation; either version 3, or (at your option) |
|
14 |
;; any later version. |
|
15 |
;; |
|
16 |
;; Magit is distributed in the hope that it will be useful, but WITHOUT |
|
17 |
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|
18 |
;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
|
19 |
;; License for more details. |
|
20 |
;; |
|
21 |
;; You should have received a copy of the GNU General Public License |
|
22 |
;; along with Magit. If not, see http://www.gnu.org/licenses. |
|
23 |
|
|
24 |
;;; Commentary: |
|
25 |
|
|
26 |
;; This library implements commands for creating Git commits. These |
|
27 |
;; commands just initiate the commit, support for writing the commit |
|
28 |
;; messages is implemented in `git-commit.el'. |
|
29 |
|
|
30 |
;;; Code: |
|
31 |
|
|
32 |
(require 'magit) |
|
33 |
(require 'magit-sequence) |
|
34 |
|
|
35 |
(eval-when-compile (require 'epa)) ; for `epa-protocol' |
|
36 |
(eval-when-compile (require 'epg)) |
|
37 |
(eval-when-compile (require 'subr-x)) |
|
38 |
|
|
39 |
;;; Options |
|
40 |
|
|
41 |
(defcustom magit-commit-arguments nil |
|
42 |
"The arguments used when committing." |
|
43 |
:group 'magit-git-arguments |
|
44 |
:type '(repeat (string :tag "Argument"))) |
|
45 |
|
|
46 |
(defcustom magit-commit-ask-to-stage 'verbose |
|
47 |
"Whether to ask to stage all unstaged changes when committing and nothing is staged." |
|
48 |
:package-version '(magit . "2.3.0") |
|
49 |
:group 'magit-commands |
|
50 |
:type '(choice (const :tag "Ask showing diff" verbose) |
|
51 |
(const :tag "Ask" t) |
|
52 |
(const :tag "Don't ask" nil))) |
|
53 |
|
|
54 |
(defcustom magit-commit-show-diff t |
|
55 |
"Whether the relevant diff is automatically shown when committing." |
|
56 |
:package-version '(magit . "2.3.0") |
|
57 |
:group 'magit-commands |
|
58 |
:type 'boolean) |
|
59 |
|
|
60 |
(defcustom magit-commit-extend-override-date t |
|
61 |
"Whether using `magit-commit-extend' changes the committer date." |
|
62 |
:package-version '(magit . "2.3.0") |
|
63 |
:group 'magit-commands |
|
64 |
:type 'boolean) |
|
65 |
|
|
66 |
(defcustom magit-commit-reword-override-date t |
|
67 |
"Whether using `magit-commit-reword' changes the committer date." |
|
68 |
:package-version '(magit . "2.3.0") |
|
69 |
:group 'magit-commands |
|
70 |
:type 'boolean) |
|
71 |
|
|
72 |
(defcustom magit-commit-squash-confirm t |
|
73 |
"Whether the commit targeted by squash and fixup has to be confirmed. |
|
74 |
When non-nil then the commit at point (if any) is used as default |
|
75 |
choice, otherwise it has to be confirmed. This option only |
|
76 |
affects `magit-commit-squash' and `magit-commit-fixup'. The |
|
77 |
\"instant\" variants always require confirmation because making |
|
78 |
an error while using those is harder to recover from." |
|
79 |
:package-version '(magit . "2.1.0") |
|
80 |
:group 'magit-commands |
|
81 |
:type 'boolean) |
|
82 |
|
|
83 |
(defcustom magit-post-commit-hook nil |
|
84 |
"Hook run after creating a commit without the user editing a message. |
|
85 |
|
|
86 |
This hook is run by `magit-refresh' if `this-command' is a member |
|
87 |
of `magit-post-stage-hook-commands'. This only includes commands |
|
88 |
named `magit-commit-*' that do *not* require that the user edits |
|
89 |
the commit message in a buffer and then finishes by pressing |
|
90 |
\\<with-editor-mode-map>\\[with-editor-finish]. |
|
91 |
|
|
92 |
Also see `git-commit-post-finish-hook'." |
|
93 |
:package-version '(magit . "2.90.0") |
|
94 |
:group 'magit-commands |
|
95 |
:type 'hook) |
|
96 |
|
|
97 |
(defvar magit-post-commit-hook-commands |
|
98 |
'(magit-commit-extend |
|
99 |
magit-commit-fixup |
|
100 |
magit-commit-augment |
|
101 |
magit-commit-instant-fixup |
|
102 |
magit-commit-instant-squash)) |
|
103 |
|
|
104 |
;;; Popup |
|
105 |
|
|
106 |
(defun magit-commit-popup (&optional arg) |
|
107 |
"Popup console for commit commands." |
|
108 |
(interactive "P") |
|
109 |
(--if-let (magit-commit-message-buffer) |
|
110 |
(switch-to-buffer it) |
|
111 |
(magit-invoke-popup 'magit-commit-popup nil arg))) |
|
112 |
|
|
113 |
(defvar magit-commit-popup |
|
114 |
'(:variable magit-commit-arguments |
|
115 |
:man-page "git-commit" |
|
116 |
:switches ((?a "Stage all modified and deleted files" "--all") |
|
117 |
(?e "Allow empty commit" "--allow-empty") |
|
118 |
(?v "Show diff of changes to be committed" "--verbose") |
|
119 |
(?h "Disable hooks" "--no-verify") |
|
120 |
(?s "Add Signed-off-by line" "--signoff") |
|
121 |
(?R "Claim authorship and reset author date" "--reset-author")) |
|
122 |
:options ((?A "Override the author" "--author=") |
|
123 |
(?S "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key) |
|
124 |
(?C "Reuse commit message" "--reuse-message=" |
|
125 |
magit-read-reuse-message)) |
|
126 |
:actions ((?c "Commit" magit-commit-create) |
|
127 |
(?e "Extend" magit-commit-extend) |
|
128 |
(?f "Fixup" magit-commit-fixup) |
|
129 |
(?F "Instant Fixup" magit-commit-instant-fixup) nil |
|
130 |
(?w "Reword" magit-commit-reword) |
|
131 |
(?s "Squash" magit-commit-squash) |
|
132 |
(?S "Instant Squash" magit-commit-instant-squash) nil |
|
133 |
(?a "Amend" magit-commit-amend) |
|
134 |
(?A "Augment" magit-commit-augment)) |
|
135 |
:max-action-columns 4 |
|
136 |
:default-action magit-commit-create)) |
|
137 |
|
|
138 |
(magit-define-popup-keys-deferred 'magit-commit-popup) |
|
139 |
|
|
140 |
(defun magit-commit-arguments nil |
|
141 |
(if (eq magit-current-popup 'magit-commit-popup) |
|
142 |
magit-current-popup-args |
|
143 |
magit-commit-arguments)) |
|
144 |
|
|
145 |
(defvar magit-gpg-secret-key-hist nil) |
|
146 |
|
|
147 |
(defun magit-read-gpg-secret-key (prompt &optional _initial-input) |
|
148 |
(require 'epa) |
|
149 |
(let ((keys (--map (concat (epg-sub-key-id (car (epg-key-sub-key-list it))) |
|
150 |
" " |
|
151 |
(when-let ((id-obj (car (epg-key-user-id-list it)))) |
|
152 |
(let ((id-str (epg-user-id-string id-obj))) |
|
153 |
(if (stringp id-str) |
|
154 |
id-str |
|
155 |
(epg-decode-dn id-obj))))) |
|
156 |
(epg-list-keys (epg-make-context epa-protocol) nil t)))) |
|
157 |
(car (split-string (magit-completing-read |
|
158 |
prompt keys nil nil nil 'magit-gpg-secret-key-hist |
|
159 |
(car (or magit-gpg-secret-key-hist keys))) |
|
160 |
" ")))) |
|
161 |
|
|
162 |
(defun magit-read-reuse-message (prompt &optional default) |
|
163 |
(magit-completing-read prompt (magit-list-refnames) |
|
164 |
nil nil nil 'magit-revision-history |
|
165 |
(or default |
|
166 |
(and (magit-rev-verify "ORIG_HEAD") |
|
167 |
"ORIG_HEAD")))) |
|
168 |
|
|
169 |
;;; Commands |
|
170 |
|
|
171 |
;;;###autoload |
|
172 |
(defun magit-commit-create (&optional args) |
|
173 |
"Create a new commit on `HEAD'. |
|
174 |
With a prefix argument, amend to the commit at `HEAD' instead. |
|
175 |
\n(git commit [--amend] ARGS)" |
|
176 |
(interactive (if current-prefix-arg |
|
177 |
(list (cons "--amend" (magit-commit-arguments))) |
|
178 |
(list (magit-commit-arguments)))) |
|
179 |
(when (member "--all" args) |
|
180 |
(setq this-command 'magit-commit-all)) |
|
181 |
(when (setq args (magit-commit-assert args)) |
|
182 |
(let ((default-directory (magit-toplevel))) |
|
183 |
(magit-run-git-with-editor "commit" args)))) |
|
184 |
|
|
185 |
;;;###autoload |
|
186 |
(defun magit-commit-amend (&optional args) |
|
187 |
"Amend the last commit. |
|
188 |
\n(git commit --amend ARGS)" |
|
189 |
(interactive (list (magit-commit-arguments))) |
|
190 |
(magit-commit-amend-assert) |
|
191 |
(magit-run-git-with-editor "commit" "--amend" args)) |
|
192 |
|
|
193 |
;;;###autoload |
|
194 |
(defun magit-commit-extend (&optional args override-date) |
|
195 |
"Amend the last commit, without editing the message. |
|
196 |
|
|
197 |
With a prefix argument keep the committer date, otherwise change |
|
198 |
it. The option `magit-commit-extend-override-date' can be used |
|
199 |
to inverse the meaning of the prefix argument. \n(git commit |
|
200 |
--amend --no-edit)" |
|
201 |
(interactive (list (magit-commit-arguments) |
|
202 |
(if current-prefix-arg |
|
203 |
(not magit-commit-extend-override-date) |
|
204 |
magit-commit-extend-override-date))) |
|
205 |
(when (setq args (magit-commit-assert args (not override-date))) |
|
206 |
(magit-commit-amend-assert) |
|
207 |
(let ((process-environment process-environment)) |
|
208 |
(unless override-date |
|
209 |
(push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment)) |
|
210 |
(magit-run-git-with-editor "commit" "--amend" "--no-edit" args)))) |
|
211 |
|
|
212 |
;;;###autoload |
|
213 |
(defun magit-commit-reword (&optional args override-date) |
|
214 |
"Reword the last commit, ignoring staged changes. |
|
215 |
|
|
216 |
With a prefix argument keep the committer date, otherwise change |
|
217 |
it. The option `magit-commit-reword-override-date' can be used |
|
218 |
to inverse the meaning of the prefix argument. |
|
219 |
|
|
220 |
Non-interactively respect the optional OVERRIDE-DATE argument |
|
221 |
and ignore the option. |
|
222 |
\n(git commit --amend --only)" |
|
223 |
(interactive (list (magit-commit-arguments) |
|
224 |
(if current-prefix-arg |
|
225 |
(not magit-commit-reword-override-date) |
|
226 |
magit-commit-reword-override-date))) |
|
227 |
(magit-commit-amend-assert) |
|
228 |
(let ((process-environment process-environment)) |
|
229 |
(unless override-date |
|
230 |
(push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment)) |
|
231 |
(magit-run-git-with-editor "commit" "--amend" "--only" args))) |
|
232 |
|
|
233 |
;;;###autoload |
|
234 |
(defun magit-commit-fixup (&optional commit args) |
|
235 |
"Create a fixup commit. |
|
236 |
|
|
237 |
With a prefix argument the target COMMIT has to be confirmed. |
|
238 |
Otherwise the commit at point may be used without confirmation |
|
239 |
depending on the value of option `magit-commit-squash-confirm'." |
|
240 |
(interactive (list (magit-commit-at-point) |
|
241 |
(magit-commit-arguments))) |
|
242 |
(magit-commit-squash-internal "--fixup" commit args)) |
|
243 |
|
|
244 |
;;;###autoload |
|
245 |
(defun magit-commit-squash (&optional commit args) |
|
246 |
"Create a squash commit, without editing the squash message. |
|
247 |
|
|
248 |
With a prefix argument the target COMMIT has to be confirmed. |
|
249 |
Otherwise the commit at point may be used without confirmation |
|
250 |
depending on the value of option `magit-commit-squash-confirm'." |
|
251 |
(interactive (list (magit-commit-at-point) |
|
252 |
(magit-commit-arguments))) |
|
253 |
(magit-commit-squash-internal "--squash" commit args)) |
|
254 |
|
|
255 |
;;;###autoload |
|
256 |
(defun magit-commit-augment (&optional commit args) |
|
257 |
"Create a squash commit, editing the squash message. |
|
258 |
|
|
259 |
With a prefix argument the target COMMIT has to be confirmed. |
|
260 |
Otherwise the commit at point may be used without confirmation |
|
261 |
depending on the value of option `magit-commit-squash-confirm'." |
|
262 |
(interactive (list (magit-commit-at-point) |
|
263 |
(magit-commit-arguments))) |
|
264 |
(magit-commit-squash-internal "--squash" commit args nil t)) |
|
265 |
|
|
266 |
;;;###autoload |
|
267 |
(defun magit-commit-instant-fixup (&optional commit args) |
|
268 |
"Create a fixup commit targeting COMMIT and instantly rebase." |
|
269 |
(interactive (list (magit-commit-at-point) |
|
270 |
(magit-commit-arguments))) |
|
271 |
(magit-commit-squash-internal "--fixup" commit args t)) |
|
272 |
|
|
273 |
;;;###autoload |
|
274 |
(defun magit-commit-instant-squash (&optional commit args) |
|
275 |
"Create a squash commit targeting COMMIT and instantly rebase." |
|
276 |
(interactive (list (magit-commit-at-point) |
|
277 |
(magit-commit-arguments))) |
|
278 |
(magit-commit-squash-internal "--squash" commit args t)) |
|
279 |
|
|
280 |
(defun magit-commit-squash-internal |
|
281 |
(option commit &optional args rebase edit confirmed) |
|
282 |
(when-let ((args (magit-commit-assert args t))) |
|
283 |
(when commit |
|
284 |
(when (and rebase (not (magit-rev-ancestor-p commit "HEAD"))) |
|
285 |
(magit-read-char-case |
|
286 |
(format "%s isn't an ancestor of HEAD. " commit) nil |
|
287 |
(?c "[c]reate without rebasing" (setq rebase nil)) |
|
288 |
(?s "[s]elect other" (setq commit nil)) |
|
289 |
(?a "[a]bort" (user-error "Quit"))))) |
|
290 |
(when commit |
|
291 |
(setq commit (magit-rebase-interactive-assert commit t))) |
|
292 |
(if (and commit |
|
293 |
(or confirmed |
|
294 |
(not (or rebase |
|
295 |
current-prefix-arg |
|
296 |
magit-commit-squash-confirm)))) |
|
297 |
(let ((magit-commit-show-diff nil)) |
|
298 |
(push (concat option "=" commit) args) |
|
299 |
(unless edit |
|
300 |
(push "--no-edit" args)) |
|
301 |
(if rebase |
|
302 |
(magit-with-editor |
|
303 |
(magit-call-git |
|
304 |
"commit" "--no-gpg-sign" |
|
305 |
(-remove-first |
|
306 |
(apply-partially #'string-match-p "\\`--gpg-sign=") |
|
307 |
args))) |
|
308 |
(magit-run-git-with-editor "commit" args)) |
|
309 |
t) ; The commit was created; used by below lambda. |
|
310 |
(magit-log-select |
|
311 |
(lambda (commit) |
|
312 |
(when (and (magit-commit-squash-internal option commit args |
|
313 |
rebase edit t) |
|
314 |
rebase) |
|
315 |
(magit-commit-amend-assert commit) |
|
316 |
(magit-rebase-interactive-1 commit |
|
317 |
(list "--autosquash" "--autostash") |
|
318 |
"" "true" nil t))) |
|
319 |
(format "Type %%p on a commit to %s into it," |
|
320 |
(substring option 2))) |
|
321 |
(when magit-commit-show-diff |
|
322 |
(let ((magit-display-buffer-noselect t)) |
|
323 |
(apply #'magit-diff-staged nil (magit-diff-arguments))))))) |
|
324 |
|
|
325 |
(defun magit-commit-amend-assert (&optional commit) |
|
326 |
(--when-let (magit-list-publishing-branches commit) |
|
327 |
(let ((m1 "This commit has already been published to ") |
|
328 |
(m2 ".\nDo you really want to modify it")) |
|
329 |
(magit-confirm 'amend-published |
|
330 |
(concat m1 "%s" m2) |
|
331 |
(concat m1 "%i public branches" m2) |
|
332 |
nil it)))) |
|
333 |
|
|
334 |
(defun magit-commit-assert (args &optional strict) |
|
335 |
(cond |
|
336 |
((or (magit-anything-staged-p) |
|
337 |
(and (magit-anything-unstaged-p) |
|
338 |
;; ^ Everything of nothing is still nothing. |
|
339 |
(member "--all" args)) |
|
340 |
(and (not strict) |
|
341 |
;; ^ For amend variants that don't make sense otherwise. |
|
342 |
(or (member "--amend" args) |
|
343 |
(member "--allow-empty" args)))) |
|
344 |
(or args (list "--"))) |
|
345 |
((and (magit-rebase-in-progress-p) |
|
346 |
(not (magit-anything-unstaged-p)) |
|
347 |
(y-or-n-p "Nothing staged. Continue in-progress rebase? ")) |
|
348 |
(setq this-command 'magit-rebase-continue) |
|
349 |
(magit-run-git-sequencer "rebase" "--continue") |
|
350 |
nil) |
|
351 |
((and (file-exists-p (magit-git-dir "MERGE_MSG")) |
|
352 |
(not (magit-anything-unstaged-p))) |
|
353 |
(or args (list "--"))) |
|
354 |
((not (magit-anything-unstaged-p)) |
|
355 |
(user-error "Nothing staged (or unstaged)")) |
|
356 |
(magit-commit-ask-to-stage |
|
357 |
(when (eq magit-commit-ask-to-stage 'verbose) |
|
358 |
(magit-diff-unstaged)) |
|
359 |
(prog1 (when (y-or-n-p "Nothing staged. Stage and commit all unstaged changes? ") |
|
360 |
(magit-run-git "add" "-u" ".") |
|
361 |
(or args (list "--"))) |
|
362 |
(when (and (eq magit-commit-ask-to-stage 'verbose) |
|
363 |
(derived-mode-p 'magit-diff-mode)) |
|
364 |
(magit-mode-bury-buffer)))) |
|
365 |
(t |
|
366 |
(user-error "Nothing staged")))) |
|
367 |
|
|
368 |
(defvar magit--reshelve-history nil) |
|
369 |
|
|
370 |
;;;###autoload |
|
371 |
(defun magit-commit-reshelve (date) |
|
372 |
"Change the committer date and possibly the author date of `HEAD'. |
|
373 |
|
|
374 |
If you are the author of `HEAD', then both dates are changed, |
|
375 |
otherwise only the committer date. The current time is used |
|
376 |
as the initial minibuffer input and the original author (if |
|
377 |
that is you) or committer date is available as the previous |
|
378 |
history element." |
|
379 |
(interactive |
|
380 |
(let ((author-p (magit-rev-author-p "HEAD"))) |
|
381 |
(push (magit-rev-format (if author-p "%ad" "%cd") "HEAD" |
|
382 |
(concat "--date=format:%F %T %z")) |
|
383 |
magit--reshelve-history) |
|
384 |
(list (read-string (if author-p |
|
385 |
"Change author and committer dates to: " |
|
386 |
"Change committer date to: ") |
|
387 |
(cons (format-time-string "%F %T %z") 17) |
|
388 |
'magit--reshelve-history)))) |
|
389 |
(let ((process-environment process-environment)) |
|
390 |
(push (concat "GIT_COMMITTER_DATE=" date) process-environment) |
|
391 |
(magit-run-git "commit" "--amend" "--no-edit" |
|
392 |
(and (magit-rev-author-p "HEAD") |
|
393 |
(concat "--date=" date))))) |
|
394 |
|
|
395 |
;;;###autoload (autoload 'magit-commit-absorb-popup "magit-commit" nil t) |
|
396 |
(magit-define-popup magit-commit-absorb-popup |
|
397 |
"Spread unstaged changes across recent commits. |
|
398 |
Without a prefix argument just call `magit-commit-absorb'. |
|
399 |
With a prefix argument use a popup buffer to select arguments." |
|
400 |
:man-page "git-bisect" |
|
401 |
:options '((?c "Diff context lines" "--context=") |
|
402 |
(?s "Strictness" "--strict=")) |
|
403 |
:actions '((?x "Absorb" magit-commit-absorb)) |
|
404 |
:default-action 'magit-commit-absorb |
|
405 |
:use-prefix 'popup) |
|
406 |
|
|
407 |
(defun magit-commit-absorb (&optional commit args confirmed) |
|
408 |
"Spread unstaged changes across recent commits. |
|
409 |
This command requires the git-autofixup script, which is |
|
410 |
available from https://github.com/torbiak/git-autofixup." |
|
411 |
(interactive (list (magit-get-upstream-branch) |
|
412 |
(magit-commit-absorb-arguments))) |
|
413 |
(unless (executable-find "git-autofixup") |
|
414 |
(user-error "This command requires the git-autofixup script, which %s" |
|
415 |
"is available from https://github.com/torbiak/git-autofixup")) |
|
416 |
(when (magit-anything-staged-p) |
|
417 |
(user-error "Cannot absorb when there are staged changes")) |
|
418 |
(unless (magit-anything-unstaged-p) |
|
419 |
(user-error "There are no unstaged changes that could be absorbed")) |
|
420 |
(when commit |
|
421 |
(setq commit (magit-rebase-interactive-assert commit t))) |
|
422 |
(if (and commit confirmed) |
|
423 |
(progn (magit-run-git-async "autofixup" "-vv" args commit) t) |
|
424 |
(magit-log-select |
|
425 |
(lambda (commit) |
|
426 |
(magit-commit-absorb commit args t)) |
|
427 |
nil nil nil nil commit))) |
|
428 |
|
|
429 |
;;; Pending Diff |
|
430 |
|
|
431 |
(defun magit-commit-diff () |
|
432 |
(when (and git-commit-mode magit-commit-show-diff) |
|
433 |
(when-let ((diff-buffer (magit-mode-get-buffer 'magit-diff-mode))) |
|
434 |
;; This window just started displaying the commit message |
|
435 |
;; buffer. Without this that buffer would immediately be |
|
436 |
;; replaced with the diff buffer. See #2632. |
|
437 |
(unrecord-window-buffer nil diff-buffer)) |
|
438 |
(condition-case nil |
|
439 |
(let ((args (car (magit-diff-arguments))) |
|
440 |
(magit-inhibit-save-previous-winconf 'unset) |
|
441 |
(magit-display-buffer-noselect t) |
|
442 |
(inhibit-quit nil)) |
|
443 |
(message "Diffing changes to be committed (C-g to abort diffing)") |
|
444 |
(if-let ((fn (cl-case last-command |
|
445 |
(magit-commit |
|
446 |
(apply-partially 'magit-diff-staged nil)) |
|
447 |
(magit-commit-all |
|
448 |
(apply-partially 'magit-diff-working-tree nil)) |
|
449 |
((magit-commit-amend |
|
450 |
magit-commit-reword |
|
451 |
magit-rebase-reword-commit) |
|
452 |
'magit-diff-while-amending)))) |
|
453 |
(funcall fn args) |
|
454 |
(if (magit-anything-staged-p) |
|
455 |
(magit-diff-staged nil args) |
|
456 |
(magit-diff-while-amending args)))) |
|
457 |
(quit)))) |
|
458 |
|
|
459 |
;; Mention `magit-diff-while-committing' because that's |
|
460 |
;; always what I search for when I try to find this line. |
|
461 |
(add-hook 'server-switch-hook 'magit-commit-diff) |
|
462 |
|
|
463 |
(add-to-list 'with-editor-server-window-alist |
|
464 |
(cons git-commit-filename-regexp 'switch-to-buffer)) |
|
465 |
|
|
466 |
;;; Message Utilities |
|
467 |
|
|
468 |
(defun magit-commit-message-buffer () |
|
469 |
(let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG |
|
470 |
(topdir (magit-toplevel))) |
|
471 |
(--first (equal topdir (with-current-buffer it |
|
472 |
(and git-commit-mode (magit-toplevel)))) |
|
473 |
(append (buffer-list (selected-frame)) |
|
474 |
(buffer-list))))) |
|
475 |
|
|
476 |
(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert |
|
477 |
"Used by `magit-commit-add-log' to insert a single entry.") |
|
478 |
|
|
479 |
(defun magit-commit-add-log () |
|
480 |
"Add a stub for the current change into the commit message buffer. |
|
481 |
If no commit is in progress, then initiate it. Use the function |
|
482 |
specified by variable `magit-commit-add-log-insert-function' to |
|
483 |
actually insert the entry." |
|
484 |
(interactive) |
|
485 |
(let ((hunk (and (magit-section-match 'hunk) |
|
486 |
(magit-current-section))) |
|
487 |
(log (magit-commit-message-buffer)) buf pos) |
|
488 |
(save-window-excursion |
|
489 |
(call-interactively #'magit-diff-visit-file) |
|
490 |
(setq buf (current-buffer)) |
|
491 |
(setq pos (point))) |
|
492 |
(unless log |
|
493 |
(unless (magit-commit-assert nil) |
|
494 |
(user-error "Abort")) |
|
495 |
(magit-commit-create) |
|
496 |
(while (not (setq log (magit-commit-message-buffer))) |
|
497 |
(sit-for 0.01))) |
|
498 |
(save-excursion |
|
499 |
(with-current-buffer buf |
|
500 |
(goto-char pos) |
|
501 |
(funcall magit-commit-add-log-insert-function log |
|
502 |
(magit-file-relative-name) |
|
503 |
(and hunk (add-log-current-defun))))))) |
|
504 |
|
|
505 |
(defun magit-commit-add-log-insert (buffer file defun) |
|
506 |
(with-current-buffer buffer |
|
507 |
(undo-boundary) |
|
508 |
(goto-char (point-max)) |
|
509 |
(while (re-search-backward (concat "^" comment-start) nil t)) |
|
510 |
(save-restriction |
|
511 |
(narrow-to-region (point-min) (point)) |
|
512 |
(cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file) |
|
513 |
nil t) |
|
514 |
(when (equal (match-string 1) defun) |
|
515 |
(setq defun nil)) |
|
516 |
(re-search-forward ": ")) |
|
517 |
(t |
|
518 |
(when (re-search-backward "^[\\*(].+\n" nil t) |
|
519 |
(goto-char (match-end 0))) |
|
520 |
(while (re-search-forward "^[^\\*\n].*\n" nil t)) |
|
521 |
(if defun |
|
522 |
(progn (insert (format "* %s (%s): \n" file defun)) |
|
523 |
(setq defun nil)) |
|
524 |
(insert (format "* %s: \n" file))) |
|
525 |
(backward-char) |
|
526 |
(unless (looking-at "\n[\n\\']") |
|
527 |
(insert ?\n) |
|
528 |
(backward-char)))) |
|
529 |
(when defun |
|
530 |
(forward-line) |
|
531 |
(let ((limit (save-excursion |
|
532 |
(and (re-search-forward "^\\*" nil t) |
|
533 |
(point))))) |
|
534 |
(unless (or (looking-back (format "(%s): " defun) |
|
535 |
(line-beginning-position)) |
|
536 |
(re-search-forward (format "^(%s): " defun) limit t)) |
|
537 |
(while (re-search-forward "^[^\\*\n].*\n" limit t)) |
|
538 |
(insert (format "(%s): \n" defun)) |
|
539 |
(backward-char))))))) |
|
540 |
|
|
541 |
;;; _ |
|
542 |
(provide 'magit-commit) |
|
543 |
;;; magit-commit.el ends here |