summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/reconcile-open-repos.el78
1 files changed, 53 insertions, 25 deletions
diff --git a/modules/reconcile-open-repos.el b/modules/reconcile-open-repos.el
index ea22dda8..648de222 100644
--- a/modules/reconcile-open-repos.el
+++ b/modules/reconcile-open-repos.el
@@ -1,29 +1,47 @@
;;; reconcile-open-repos.el --- reconcile open repos -*- lexical-binding: t; coding: utf-8; -*-
;; author: Craig Jennings <c@cjennings.net>
+;;
;;; Commentary:
-;; I have tried to keep this Emacs config as general as possible, and move all
-;; config related to my personal workflows here.
-
-;; I typically work with multiple git repositories the day, and can forget to
-;; commit uncommitted work. Also, I often forget to start a session by pulling
-;; changes. So, making it a habit to run cj/check-for-open-work when starting
-;; and ending the work session allows me to know that I've iterated through all
-;; git repositories in my projects and code directories and have reconciled all
+;;
+;; Git repository reconciliation workflow for multiple projects. Ensures all git
+;; repositories in your projects/ and code/ directories are synchronized with
+;; remotes and have no uncommitted work at the start and end of work sessions.
+;; The workflow iterates through all git repositories in projects-dir and
+;; code-dir, skips local-only repos and http/https remotes (reference clones),
+;; silently pulls latest changes for clean repos, and for dirty repos stashes
+;; changes, pulls, pops stash, and opens Magit for review. Also checks org-dir
+;; and user-emacs-directory individually.
+;;
+;; Main function: cj/check-for-open-work (bound to M-P)
+;;
+;; Dependencies: Requires projects-dir, code-dir, and org-dir to be defined in
+;; init.el. Uses Magit for manual intervention when repositories have uncommitted
;; changes.
;;; Code:
+;; Forward declarations for variables defined in init.el
+(eval-when-compile
+ (defvar projects-dir)
+ (defvar code-dir)
+ (defvar org-dir))
+
+;; Forward declaration for magit
+(declare-function magit-status "magit" (&optional directory cache))
+
;; -------------------------- Reconcile Git Directory --------------------------
(defun cj/reconcile-git-directory (directory)
- "Reconcile unopened work in a git project directory leveraging magit."
+ "Reconcile unopened work in a git project DIRECTORY.
+Skips local-only repos and http/https remotes. For clean repos, silently pulls
+latest changes. For dirty repos, stashes changes, pulls, pops stash, and opens
+Magit for review."
(message "checking: %s" directory)
(let ((default-directory directory))
;; Check for the presence of the .git directory
(if (file-directory-p (expand-file-name ".git" directory))
(progn
- (let ((remote-url (shell-command-to-string "git config --get remote.origin.url")))
- (setq remote-url (string-trim remote-url))
+ (let ((remote-url (string-trim (shell-command-to-string "git config --get remote.origin.url"))))
;; skip local git repos, or remote URLs that are http or https,
;; these are typically cloned for reference only
@@ -33,40 +51,50 @@
;; if git directory is clean, pulling generates no errors
(if (string-empty-p (shell-command-to-string "git status --porcelain"))
(progn
- ;; (message "%s is a clean git repository" directory)
- (shell-command "git pull --quiet"))
+ (let ((pull-result (shell-command "git pull --quiet")))
+ (unless (= pull-result 0)
+ (message "Warning: git pull failed for %s (exit code: %d)" directory pull-result))))
;; if directory not clean, pull latest changes and display Magit for manual intervention
(progn
(message "%s contains uncommitted work" directory)
- (shell-command "git stash --quiet")
- (shell-command "git pull --quiet")
- (shell-command "git stash pop --quiet")
- (call-interactively #'magit-status)
- ;; pause until magit buffer is closed
- (while (buffer-live-p (get-buffer (format "*magit: %s*" (file-name-nondirectory directory))))
- (sit-for 0.5))))))))))
+ (let ((stash-result (shell-command "git stash --quiet")))
+ (if (= stash-result 0)
+ (progn
+ (let ((pull-result (shell-command "git pull --quiet")))
+ (if (= pull-result 0)
+ (let ((stash-pop-result (shell-command "git stash pop --quiet")))
+ (unless (= stash-pop-result 0)
+ (message "Warning: git stash pop failed for %s - opening Magit" directory)))
+ (message "Warning: git pull failed for %s - opening Magit" directory)))
+ (magit-status directory))
+ (message "Warning: git stash failed for %s - opening Magit" directory)
+ (magit-status directory)))))))))))
;; ---------------------------- Check For Open Work ----------------------------
+;;;###autoload
(defun cj/check-for-open-work ()
"Check all project directories for open work."
(interactive)
;; these are constants defined in init.el
;; children of these directories will be checked
(dolist (base-dir (list projects-dir code-dir))
- (when (file-directory-p base-dir)
+ (when (and (boundp 'base-dir) base-dir (file-directory-p base-dir))
(dolist (child-dir (directory-files base-dir t "^[^.]+$" 'nosort))
(when (file-directory-p child-dir)
(cj/reconcile-git-directory child-dir)))))
;; check these directories individually
- (cj/reconcile-git-directory org-dir)
- (cj/reconcile-git-directory user-emacs-directory)
+ (when (and (boundp 'org-dir) org-dir (file-directory-p org-dir))
+ (cj/reconcile-git-directory org-dir))
+ (when (and (boundp 'user-emacs-directory) user-emacs-directory (file-directory-p user-emacs-directory))
+ (cj/reconcile-git-directory user-emacs-directory))
;; communicate when finished.
- (message "Complete. All project repositories checked for uncommitted work and code updated from remote repository"))
-(global-set-key (kbd "M-P") 'cj/check-for-open-work)
+ (message "Complete. All repositories checked and updated"))
+
+;;;###autoload (keymap-global-set "M-P" #'cj/check-for-open-work)
(provide 'reconcile-open-repos)
;;; reconcile-open-repos.el ends here.