Commit auto-commits to separate branch...
...before merging the auto-commit back into the main branch. This protects against the following scenario: 1. You've loaded a file at commit A. 2. While your file is unsaved, the repo underneath is updated to some commit B that is a descendant of A. 3. You save your file. Emacs prompts you that the file underneath has changed. You decide to overwrite, but you've lost the differences between A and B. Now, we first switch to a temp branch and save the file as a commit on top of commit A, and then switch back to the branch with commit B and merge the temp branch (with our new change) back in.
This commit is contained in:
parent
b9d5f8c2d4
commit
666ee4350a
1 changed files with 86 additions and 3 deletions
|
@ -56,6 +56,39 @@ If non-nil a git push will be executed after each commit."
|
||||||
:group 'git-auto-commit-mode
|
:group 'git-auto-commit-mode
|
||||||
:type 'boolean)
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom gac-loaded-commit nil
|
||||||
|
"Git commit in the buffer when it was loaded.
|
||||||
|
|
||||||
|
DO NOT MODIFY - used to ensure that the saved file doesn't conflict with
|
||||||
|
changes made since the current file was loaded."
|
||||||
|
:tag "Current commit"
|
||||||
|
:group 'git-auto-commit-mode
|
||||||
|
:type 'string
|
||||||
|
:risky t)
|
||||||
|
(make-variable-buffer-local 'gac-loaded-commit)
|
||||||
|
|
||||||
|
(defcustom gac-before-save-branch nil
|
||||||
|
"Git branch active immediately before a file is saved.
|
||||||
|
|
||||||
|
DO NOT MODIFY - used to ensure that the saved file doesn't conflict with
|
||||||
|
changes made since the current file was loaded."
|
||||||
|
:tag "Current commit"
|
||||||
|
:group 'git-auto-commit-mode
|
||||||
|
:type 'string
|
||||||
|
:risky t)
|
||||||
|
(make-variable-buffer-local 'gac-before-save-branch)
|
||||||
|
|
||||||
|
(defcustom gac-merge-branch nil
|
||||||
|
"Merge branch used when saving.
|
||||||
|
|
||||||
|
DO NOT MODIFY - used to ensure that the saved file doesn't conflict with
|
||||||
|
changes made since the current file was loaded."
|
||||||
|
:tag "Current commit"
|
||||||
|
:group 'git-auto-commit-mode
|
||||||
|
:type 'string
|
||||||
|
:risky t)
|
||||||
|
(make-variable-buffer-local 'gac-merge-branch)
|
||||||
|
|
||||||
(defcustom gac-ask-for-summary-p nil
|
(defcustom gac-ask-for-summary-p nil
|
||||||
"Ask the user for a short summary each time a file is committed?"
|
"Ask the user for a short summary each time a file is committed?"
|
||||||
:tag "Ask for a summary on each commit"
|
:tag "Ask for a summary on each commit"
|
||||||
|
@ -166,6 +199,9 @@ Default to FILENAME."
|
||||||
(replace-regexp-in-string "\n\\'" ""
|
(replace-regexp-in-string "\n\\'" ""
|
||||||
(gac--shell-command-to-string-throw "git rev-parse --verify HEAD"))))
|
(gac--shell-command-to-string-throw "git rev-parse --verify HEAD"))))
|
||||||
|
|
||||||
|
(defun gac--load-current-commit ()
|
||||||
|
(setq-local gac-loaded-commit (gac--current-commit)))
|
||||||
|
|
||||||
(defun gac--current-branch ()
|
(defun gac--current-branch ()
|
||||||
"Return the current Git branch."
|
"Return the current Git branch."
|
||||||
(let* ((buffer-file (buffer-file-name))
|
(let* ((buffer-file (buffer-file-name))
|
||||||
|
@ -208,6 +244,17 @@ Standard error is inserted into a temp buffer if it's generated."
|
||||||
rv command)))
|
rv command)))
|
||||||
(delete-file err-file)))))
|
(delete-file err-file)))))
|
||||||
|
|
||||||
|
(defun gac-checkout-merge-branch ()
|
||||||
|
"Create and check out a merge branch."
|
||||||
|
(setq-local gac-before-save-branch (gac--current-branch))
|
||||||
|
(setq-local gac-merge-branch (format "gac-merge-%d" (float-time)))
|
||||||
|
(let* ((buffer-file (buffer-file-name))
|
||||||
|
(default-directory (file-name-directory buffer-file)))
|
||||||
|
(gac--shell-command-throw
|
||||||
|
(format "git checkout -b %s %s"
|
||||||
|
(shell-quote-argument gac-merge-branch)
|
||||||
|
(shell-quote-argument gac-before-save-branch)))))
|
||||||
|
|
||||||
(defun gac-commit (buffer)
|
(defun gac-commit (buffer)
|
||||||
"Commit the current buffer's file to git."
|
"Commit the current buffer's file to git."
|
||||||
(let* ((buffer-file (buffer-file-name buffer))
|
(let* ((buffer-file (buffer-file-name buffer))
|
||||||
|
@ -220,6 +267,27 @@ Standard error is inserted into a temp buffer if it's generated."
|
||||||
gac-shell-and
|
gac-shell-and
|
||||||
"git commit -m " (shell-quote-argument commit-msg)))))
|
"git commit -m " (shell-quote-argument commit-msg)))))
|
||||||
|
|
||||||
|
(defun gac-merge (buffer)
|
||||||
|
"Merge gac-merge-branch back into gac-before-save-branch."
|
||||||
|
(let* ((buffer-file (buffer-file-name))
|
||||||
|
(default-directory (file-name-directory buffer-file)))
|
||||||
|
(gac--shell-command-throw
|
||||||
|
(concat (format "git checkout %s"
|
||||||
|
(shell-quote-argument gac-before-save-branch))
|
||||||
|
gac-shell-and
|
||||||
|
(format "git merge -m %s %s"
|
||||||
|
(shell-quote-argument
|
||||||
|
(format "Merge branch '%s'"
|
||||||
|
gac-merge-branch))
|
||||||
|
(shell-quote-argument gac-merge-branch))
|
||||||
|
gac-shell-and
|
||||||
|
(format "git branch -d %s"
|
||||||
|
(shell-quote-argument gac-merge-branch))))
|
||||||
|
;; Reset variables
|
||||||
|
(setq-local gac-before-save-branch nil)
|
||||||
|
(setq-local gac-merge-branch nil)
|
||||||
|
(gac--load-current-commit)))
|
||||||
|
|
||||||
(defun gac-push (buffer)
|
(defun gac-push (buffer)
|
||||||
"Push commits to the current upstream.
|
"Push commits to the current upstream.
|
||||||
|
|
||||||
|
@ -271,6 +339,7 @@ should already have been set up."
|
||||||
(not (gac--buffer-is-tracked buffer)))
|
(not (gac--buffer-is-tracked buffer)))
|
||||||
(gac--buffer-has-changes buffer)))
|
(gac--buffer-has-changes buffer)))
|
||||||
(gac-commit buffer)
|
(gac-commit buffer)
|
||||||
|
(gac-merge buffer)
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
;; with-current-buffer required here because gac-automatically-push-p
|
;; with-current-buffer required here because gac-automatically-push-p
|
||||||
;; is buffer-local
|
;; is buffer-local
|
||||||
|
@ -286,6 +355,14 @@ should already have been set up."
|
||||||
|
|
||||||
(add-hook 'kill-buffer-hook #'gac-kill-buffer-hook)
|
(add-hook 'kill-buffer-hook #'gac-kill-buffer-hook)
|
||||||
|
|
||||||
|
(defun gac-find-file-func ()
|
||||||
|
"Store the current commit."
|
||||||
|
(gac--load-current-commit))
|
||||||
|
|
||||||
|
(defun gac-before-save-func ()
|
||||||
|
"Create and check out a merge branch."
|
||||||
|
(gac-checkout-merge-branch))
|
||||||
|
|
||||||
(defun gac-after-save-func ()
|
(defun gac-after-save-func ()
|
||||||
"Commit the current file.
|
"Commit the current file.
|
||||||
|
|
||||||
|
@ -299,9 +376,15 @@ When `gac-automatically-push-p' is non-nil also push."
|
||||||
"Automatically commit any changes made when saving with this
|
"Automatically commit any changes made when saving with this
|
||||||
mode turned on and optionally push them too."
|
mode turned on and optionally push them too."
|
||||||
:lighter " ga"
|
:lighter " ga"
|
||||||
(if git-auto-commit-mode
|
(cond (git-auto-commit-mode
|
||||||
(add-hook 'after-save-hook 'gac-after-save-func t t)
|
(gac--load-current-commit)
|
||||||
(remove-hook 'after-save-hook 'gac-after-save-func t)))
|
(add-hook 'find-file-hook 'gac-find-file-func t t)
|
||||||
|
(add-hook 'before-save-hook 'gac-before-save-func t t)
|
||||||
|
(add-hook 'after-save-hook 'gac-after-save-func t t))
|
||||||
|
(t
|
||||||
|
(remove-hook 'find-file-hook 'gac-find-file-func t)
|
||||||
|
(remove-hook 'before-save-hook 'gac-before-save-func t)
|
||||||
|
(remove-hook 'after-save-hook 'gac-after-save-func t))))
|
||||||
|
|
||||||
(provide 'git-auto-commit-mode)
|
(provide 'git-auto-commit-mode)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue