6

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 non-Emacs / non-Magit related thread ( https://stackoverflow.com/a/3195446/2112489) , with comments stating that it is the definitive answer on pushing to a remote and to Github, and it has a few hundred thumbs-up. I assume (perhaps incorrectly) that is a good starting point for the local .gitconfig file in the $HOME directory on my computer.

[remote "GitHub"] url = [email protected]:elliottcable/Paws.o.git fetch = +refs/heads/*:refs/remotes/GitHub/* [branch "Master"] remote = GitHub merge = refs/heads/Master [remote "Codaset"] url = [email protected]:elliottcable/paws-o.git fetch = +refs/heads/*:refs/remotes/Codaset/* [remote "Paws"] url = [email protected]:Paws/Paws.o.git fetch = +refs/heads/*:refs/remotes/Paws/* 

The basic Push command in Emacs / Magit only pushes one at a time:

C-u P P [and then use arrow keys to select from the choices in the minibuffer] RET 

See the Magit cheatsheet of available commands: http://daemianmack.com/magit-cheatsheet.html


Tentative thinking -- use /usr/local/git/bin/git remote -v to obtain a listing of remotes that have already been configured, and then use the results to push to each one . . . doable, but complex.

$ MP:my_project.git HOME$ /usr/local/git/bin/git remote -v origin [email protected]:lawlist/my_project.git (fetch) origin [email protected]:lawlist/my_project.git (push) remote_website [email protected]:my_project.git (fetch) remote_website [email protected]:my_project.git (push) 

COMMAND-LINE RECIPE -- pushing separately to the remote and to Github:

;; Setup the remote repository and the hook; and the remote destination folder. ssh [email protected] mkdir /home/lawlist/my_project.git cd my_project.git git init --bare ;; git update-server-info # If planning to serve via HTTP cat > /home/lawlist/my_project.git/hooks/post-receive ;; RET #!/bin/sh ;; RET GIT_WORK_TREE=/home/lawlist/my_project git checkout -f ;; RET ;; C-d chmod 755 /home/lawlist/my_project.git/hooks/post-receive mkdir /home/lawlist/my_project exit ;; On local machine. mkdir /Users/HOME/.0.data/.0.emacs/elpa/my_project.git touch /Users/HOME/.0.data/.0.emacs/elpa/my_project.git/README.md cd /Users/HOME/.0.data/.0.emacs/elpa/my_project.git /usr/local/git/bin/git init /usr/local/git/bin/git add . /usr/local/git/bin/git commit -m "First commit." curl -u lawlist:12345678 https://api.github.com/user/repos -d '{"name":"my_project.git"}' /usr/local/git/bin/git remote add origin [email protected]:lawlist/my_project.git /usr/local/git/bin/git remote add remote_website [email protected]:my_project.git /usr/local/git/bin/git push origin master /usr/local/git/bin/git push remote_website master ;; For modification of local files /usr/local/git/bin/git add . /usr/local/git/bin/git commit -m "This is a modification . . . ." /usr/local/git/bin/git push origin master /usr/local/git/bin/git push remote_website master 
0

1 Answer 1

4

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)) )) 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.