Skip to content

Instantly share code, notes, and snippets.

@jkbjh
Last active February 8, 2023 19:47
Show Gist options
  • Save jkbjh/7c2fdf66a38113946cccca908207cb70 to your computer and use it in GitHub Desktop.
Save jkbjh/7c2fdf66a38113946cccca908207cb70 to your computer and use it in GitHub Desktop.
push to a remote checked out repository (by pushing into a temporary branch and then ssh-ing to the repository and performing the merge)
#!/usr/bin/env python
import argparse
import re
import subprocess
import sys
import uuid
url_rex = re.compile(
"^(?P<user>.*?)@(?P<host>.*?):(?:(?P<port>[0-9]*?))?(?P<path>.*?/.*?)$"
)
refspec_match = re.compile("^(?P<noff>[+]?)(?P<src>[^:]+):(?P<dst>[^:]+)$").match
def build_ssh_url(urldict):
port_str = ":" + str(urldict["port"]) if urldict["port"] else ""
return "{username}@{host}{port_str}".format(
username=urldict["user"], host=urldict["host"], port_str=port_str
)
def get_url(url_or_origin):
print((">%r<" % (url_or_origin,)))
match = url_rex.match(url_or_origin)
if match:
return None, url_or_origin, match.groupdict()
return (url_or_origin,) + get_url(
subprocess.check_output(["git", "remote", "get-url", url_or_origin]).decode("utf-8").strip()
)[1:]
if __name__ == "__main__":
TMP_BRANCH = "COPUSH_TMP_" + uuid.uuid4().hex
print((repr(sys.argv)))
parser = argparse.ArgumentParser(
epilog=f"{sys.argv[0]} REMOTE local_branch:remote_branch"
)
parser.add_argument("remote", help="remote.")
parser.add_argument("refspec", help="refspec")
try:
args = parser.parse_args(sys.argv[1:])
except SystemExit as e:
if e.code != 0:
parser.print_help()
raise
remote, url, urldict = get_url(args.remote)
print(("remote:", remote))
refspecdict = refspec_match(args.refspec).groupdict()
print(f"Remote branch: {TMP_BRANCH}")
print(("urldict", urldict))
print(("refspecdict", refspecdict))
print("-------------------")
assert not refspecdict["noff"] # non-fast-forward not yet supported
cmd = ["git", "push", url, "%s:%s" % (refspecdict["src"], TMP_BRANCH)]
print((repr(cmd)))
result = subprocess.check_call(cmd)
sshcmd = ("cd {path}; "
"if [ $(git symbolic-ref -q HEAD --short) = '{dst}' ]; then " # test whether the branch {dst} is currently checked out (HEAD)
"git merge {tmp_branch} --ff-only --no-commit; " # if it is checked out, perform a non-merging merge (fast-forward) without merge-commits (--no-commit)
"else "
"git fetch . {tmp_branch}:{dst}; " # if it isn't checked out, we don't need to merge but just fetch.
"fi; "
"git branch -D {tmp_branch}" # delete the temporary COPUSH branch.
).format(
path=urldict["path"], tmp_branch=TMP_BRANCH, dst=refspecdict["dst"]
)
cmd = ["ssh", build_ssh_url(urldict), sshcmd]
result = subprocess.check_call(cmd)
if remote is not None:
subprocess.check_call(["git", "fetch", remote])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment