Pushing to Multiple Git Repositories Simultaneously
Some of my projects have multiple remote repositories. I was trying to figure a way to push to all of them simultaneously through some flag or option of "git push", but as this post points out, this cannot be done.
The correct paradigm is to issue multiple "git push <remote-name>" commands as neccessary.
A First Approach to Reducing Keystrokes
A convenience which achieves the same thing was suggested by Linus in the above-mentioned post, and involves adding the following to the ".git/config" file:[remote "all"]
url=ssh://user@server/repos/g0.git
url=ssh://user@server/repos/g1.git
url=ssh://user@server/repos/g2.git
url=ssh://user@server/repos/g3.git
# etc.Now, "git push all [--all]" should push to all the remotes simultaneousl (with the "--all" flag denoting that you are also pushing all branches).
If you have:
[branch "master"]
remote = g0
merge = refs/heads/master
[remote "g0"]
url = ssh://user@server/repos/g0.git
fetch = +refs/heads/*:refs/remotes/g0/*Then "pulls" and "fetch"'s while on the master branch should only only target "ssh://user@server/repos/g0.git".
Better yet:
[branch "master"]
remote = origin
merge = refs/heads/master
[remote "origin"]
url = ssh://user@server/repos/g0.git
fetch = +refs/heads/*:refs/remotes/g0/*Then "ssh://user@server/repos/g0.git" is the default remote ("origin") for pulls and fetches if no remote name is specified.
As always, you should use the "--dry-run -v" flags to make sure you see, understand, and approve of all that is going to happen before it happens.
A Second Approach to Reducing Keystrokes
As it happens, however, the above solution is not entirely satisfactory as it leads to git getting the status of your local with respect to the remotes confused. Or, alternatively, git gets it right and I am confused in my expectations. Either way, after a "git push all", my local is one commit behind and I have to "git pull" to sync up, even though there is absolutely no difference in source tree. So, my preferred solution now is to run a custom script that parses out all the remotes of the local git repository, and pushes to them individually:
#! /usr/bin/env python
############################################################################
## ygit-push-all.py
##
## Copyright 2008 Jeet Sukumaran.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this programm. If not, see <http://www.gnu.org/licenses/>.
##
############################################################################
"""
Simultaneously push to all remote repositories.
"""
import sys
import os
import subprocess
from optparse import OptionGroup
from optparse import OptionParser
_prog_usage = '%prog [options] <ACTION> <REPO-URL>'
_prog_version = 'ygit-push-all Version 1.1'
_prog_description = """\
Push out to all remote repositories"""
_prog_author = 'Jeet Sukumaran'
_prog_copyright = 'Copyright (C) 2008 Jeet Sukumaran.'
def show_command(command, opts):
if opts.show_commands:
sys.stdout.write("[" + command + "]\n")
def main():
"""
Main CLI handler.
"""
parser = OptionParser(usage=_prog_usage,
add_help_option=True,
version=_prog_version,
description=_prog_description)
parser.add_option('-q', '--quiet',
action='store_true',
dest='ygit_quiet',
default=False,
help='suppress all ygit wrapper messages')
parser.add_option('-Q', '--all-quiet',
action='store_true',
dest='all_quiet',
default=False,
help='suppress all messages from both ygit and git subprocesses')
parser.add_option('-x', '--show',
action='store_true',
dest='show_commands',
default=False,
help='show commands as they are executed')
parser.add_option('--dry-run',
action='store_true',
dest='dry_run',
default=False,
help='do not actually do anything')
parser.add_option('-f', '--force',
action='store_true',
dest='force',
default=False,
help='force push')
(opts, args) = parser.parse_args()
if opts.all_quiet:
ygit_stdout = open(os.devnull)
git_stdout = subprocess.PIPE
elif opts.ygit_quiet:
ygit_stdout = open(os.devnull)
git_stdout = None
else:
ygit_stdout = sys.stdout
git_stdout = None
# get remote repositories
command = "git remote"
show_command(command, opts)
proc = subprocess.Popen(command,
shell=True,
stdout=subprocess.PIPE)
retcode = proc.wait()
if retcode:
sys.exit(1)
else:
remotes = []
for remote in proc.stdout:
remotes.append(remote.replace("\n",""))
if opts.force:
force = "-f "
else:
force = ""
for remote in remotes:
command = "git push %s%s" % (force, remote)
show_command(command, opts)
push = subprocess.Popen(command,
shell=True,
stdout=git_stdout)
retcode = push.wait()
if __name__ == '__main__':
main()
feed
Comments
2 comments postedPost new comment