Emacs — How to push a Git repository to multiple remotes

后端 未结 1 930
时光取名叫无心
时光取名叫无心 2020-12-19 10:12

I\'m looking for some assistance, please, using Emacs / Magit to push the local repository changes to the remote website and to Github in one fell-swoop.

I found a n

相关标签:
1条回答
  • 2020-12-19 10:51

    EDIT (April 23, 2014):  Added a non-Magit solution to stage all, commit all (with a default commit message), and push to all remotes.

    EDIT (April 24, 2014):  The printed output of all processes is now sent to the git-status-buffer, which is displayed at the end of the function -- with options for the user to choose what to do with the window -- e.g., delete window, delete buffer and window, or do nothing. Added some pretty coloring with (propertize "[...]" 'face 'font-lock-warning-face). The first draft of the function that relies upon a pre-existing installation of Magit has been moved to the bottom of this answer -- that function works, but is not as sophisticated as the current version that does not rely upon an installation of Magit.

    (defvar git-status-buffer "*GIT-STATUS*"
      "The buffer name of the git-status-buffer.")
    
    (defvar git-branch-name nil
    "The current branch of the working Git directory.")
    (make-variable-buffer-local 'git-branch-name)
    
    (defvar git-remote-list nil
    "List of remote locations -- e.g., lawlist_remote or github_remote.")
    (make-variable-buffer-local 'git-remote-list)
    
    (defvar git-commit-message (format "Committed -- %s" (current-time-string))
    "The predetermined Git commit message.")
    (make-variable-buffer-local 'git-commit-message)
    
    (defun git-branch-process-filter (proc string)
      (with-current-buffer (get-buffer git-status-buffer)
        (set (make-local-variable 'git-branch-name)
          (car (split-string string "\n")))))
    
    (defun git-push-process-filter (proc string)
      (when (string-match "password" string)
        (process-send-string
          proc
          (concat (read-passwd "Password:  ") "\n")))
      (when (and
          (not (string-equal "Password: " string))
          (not (string-equal "\n" string))
          (not (string-equal "stdin: is not a tty\n" string)))
        (with-current-buffer git-status-buffer
          (goto-char (point-max))
          (insert "\n" (replace-regexp-in-string "\^M" "\n" string)))))
    
    (defun git-push-process-sentinel (proc string)
      (when (= 0 (process-exit-status proc))
        (with-current-buffer (get-buffer git-status-buffer)
          (insert
            "\n"
            (propertize
              (format "Process `%s` has finished pushing to `%s`." proc git-remote-name)
              'face 'font-lock-warning-face)
            "\n"))
        (throw 'exit nil)))
    
    (defun stage-commit-push-all ()
    "This function does the following:
      * Save the current working buffer if it has been modified.
      * Obtain the name of the selected branch in the current working buffer.
      * Gather a list of all remotes associated with working directory Git project.
      * Stage all -- `/usr/local/git/bin/git add .`
      * Commit all -- `/usr/local/git/bin/git commit -m [git-commit-message]`
      * Push to all remotes:  `/usr/local/git/bin/git push -v [remote] [current-branch]`"
    (interactive)
      (when (buffer-modified-p)
        (save-buffer))
      (when (get-buffer git-status-buffer)
        (with-current-buffer (get-buffer git-status-buffer)
          (kill-local-variable 'git-remote-list)
          (kill-local-variable 'git-branch-name)
          (erase-buffer)))
      (start-process
        "current-branch"
        git-status-buffer
        "/usr/local/git/bin/git"
        "rev-parse"
        "--abbrev-ref"
        "HEAD")
      (set-process-filter (get-process "current-branch") 'git-branch-process-filter)
      (set-process-sentinel
        (get-process "current-branch")
        (lambda (p e) (when (= 0 (process-exit-status p))
          (set-process-sentinel
            (start-process
              "list-remotes"
              git-status-buffer
              "/usr/local/git/bin/git"
              "remote"
              "-v")
            (lambda (p e) (when (= 0 (process-exit-status p))
              (let* (
                  beg
                  end
                  git-remote-name)
                (with-current-buffer (get-buffer git-status-buffer)
                  (goto-char (point-max))
                  (while (re-search-backward "\(push\)" nil t)
                    (beginning-of-line 1)
                    (setq beg (point))
                    (re-search-forward "\t" nil t)
                    (setq end (- (point) 1))
                    (setq git-remote-name (buffer-substring-no-properties beg end))
                    (setq git-remote-list
                      (append (cons git-remote-name git-remote-list)))) ))
              (set-process-sentinel
                (start-process
                  "stage-all"
                  git-status-buffer
                  "/usr/local/git/bin/git"
                  "add"
                  ".")
                (lambda (p e) (when (= 0 (process-exit-status p))
                  (with-current-buffer (get-buffer git-status-buffer)
                    (goto-char (point-max))
                    (insert "\n"))
                  (set-process-sentinel
                    (start-process
                      "commit-all"
                      git-status-buffer
                      "/usr/local/git/bin/git"
                      "commit"
                      "-m"
                      git-commit-message)
                    (lambda (p e) (when (= 0 (process-exit-status p))
                      (mapcar (lambda (git-remote-name)
                        (let ((proc
                            (start-process
                              "push-process"
                              git-status-buffer
                              "/usr/local/git/bin/git"
                              "push"
                              "-v"
                              (format "%s" git-remote-name)
                              (format "%s"
                                (with-current-buffer (get-buffer git-status-buffer)
                                  git-branch-name)) )))
                          (set-process-filter proc 'git-push-process-filter)
                          (set-process-sentinel proc 'git-push-process-sentinel)
                          (recursive-edit) ))
                        (with-current-buffer (get-buffer git-status-buffer)
                          git-remote-list) )
                      (display-buffer (get-buffer git-status-buffer))
                      (message (concat
                        git-status-buffer
                        " -- ["
                        (propertize "d" 'face 'font-lock-warning-face)
                        "]elete window | ["
                        (propertize "k" 'face 'font-lock-warning-face)
                        "]ill buffer + delete window | ["
                        (propertize "n" 'face 'font-lock-warning-face)
                        "]othing"))
                      (let* (
                          (git-window-options (read-char-exclusive))
                          (target-window (get-buffer-window git-status-buffer)))
                        (cond
                          ((eq git-window-options ?d)
                            (with-current-buffer (get-buffer git-status-buffer)
                              (delete-window target-window)))
                          ((eq git-window-options ?k)
                            (with-current-buffer (get-buffer git-status-buffer)
                              (delete-window target-window)
                              (kill-buffer (get-buffer git-status-buffer))))
                          ((eq git-window-options ?n)
                            (message "Done!"))
                          (t (message "You have exited the sub-function.")) ))
                    )))))))))))))
    

    FIRST DRAFT (April 19, 2014):  This function requires a pre-existing installation of Magit. The code set forth above does not require installation of Magit.

    (defun push-to-all-remotes ()
    "This function requires a pre-existing installation of Magit, and the function assumes
    that the user has already staged and committed -- i.e., it only pushes to all remotes."
    (interactive)
      (let* (beg end remote)
        (when (get-buffer "*REMOTES*")
          (with-current-buffer (get-buffer "*REMOTES*")
            (erase-buffer)))
        (set-process-sentinel
          (start-process
            "list-remotes"
            "*REMOTES*"
            "/usr/local/git/bin/git"
            "remote"
            "-v")
          (lambda (p e) (when (= 0 (process-exit-status p))
            (with-current-buffer (get-buffer "*REMOTES*")
              (goto-char (point-max))
              (while (re-search-backward "\(push\)" nil t)
                (beginning-of-line 1)
                (setq beg (point))
                (re-search-forward "\t" nil t)
                (setq end (- (point) 1))
                (setq remote (buffer-substring-no-properties beg end))
                (magit-run-git-async
                  "push"
                  "-v"
                  remote
                  (magit-get-current-branch))) ))))
        (display-buffer (get-buffer magit-process-buffer-name)) ))
    
    0 讨论(0)
提交回复
热议问题