mirror of
https://github.com/facebook/sapling.git
synced 2024-10-06 06:47:41 +03:00
git: support simple clone
Summary: Support cloning a git repo using `git+` URLs. Reviewed By: DurhamG Differential Revision: D33351383 fbshipit-source-id: 684ac78111b201e44256b0dfebe2aa52d46f7693
This commit is contained in:
parent
cf612fcd26
commit
80845a4fb9
@ -145,6 +145,7 @@ from edenscm.mercurial import (
|
||||
error,
|
||||
exchange,
|
||||
extensions,
|
||||
git,
|
||||
hg,
|
||||
localrepo,
|
||||
match,
|
||||
@ -290,8 +291,10 @@ def wrappackers():
|
||||
packermap["03"] = (shallowbundle.shallowcg3packer, packermap03[1])
|
||||
|
||||
|
||||
def cloneshallow(orig, ui, repo, *args, **opts):
|
||||
if opts.get("shallow"):
|
||||
def cloneshallow(orig, ui, source, *args, **opts):
|
||||
# skip for (full) git repos
|
||||
giturl = git.maybegiturl(source)
|
||||
if opts.get("shallow") and giturl is None:
|
||||
repos = []
|
||||
|
||||
def pull_shallow(orig, self, *args, **kwargs):
|
||||
@ -333,7 +336,7 @@ def cloneshallow(orig, ui, repo, *args, **opts):
|
||||
|
||||
wrapfunction(localrepo, "newreporequirements", newreporequirements)
|
||||
|
||||
orig(ui, repo, *args, **opts)
|
||||
orig(ui, source, *args, **opts)
|
||||
|
||||
|
||||
def debugdatashallow(orig, *args, **kwds):
|
||||
|
@ -1618,18 +1618,25 @@ def clone(ui, source, dest=None, **opts):
|
||||
"""
|
||||
if opts.get("noupdate") and opts.get("updaterev"):
|
||||
raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
|
||||
|
||||
r = hg.clone(
|
||||
ui,
|
||||
opts,
|
||||
source,
|
||||
dest,
|
||||
pull=opts.get("pull"),
|
||||
stream=opts.get("stream") or opts.get("uncompressed"),
|
||||
rev=opts.get("rev"),
|
||||
update=opts.get("updaterev") or not opts.get("noupdate"),
|
||||
shallow=opts.get("shallow"),
|
||||
)
|
||||
giturl = git.maybegiturl(source)
|
||||
if giturl is not None:
|
||||
if opts.get("noupdate"):
|
||||
update = False
|
||||
else:
|
||||
update = opts.get("updaterev") or True
|
||||
r = git.clone(ui, giturl, dest, update)
|
||||
else:
|
||||
r = hg.clone(
|
||||
ui,
|
||||
opts,
|
||||
source,
|
||||
dest,
|
||||
pull=opts.get("pull"),
|
||||
stream=opts.get("stream") or opts.get("uncompressed"),
|
||||
rev=opts.get("rev"),
|
||||
update=opts.get("updaterev") or not opts.get("noupdate"),
|
||||
shallow=opts.get("shallow"),
|
||||
)
|
||||
|
||||
return r is None
|
||||
|
||||
|
@ -1557,12 +1557,7 @@ def debuginitgit(ui, destpath, **opts):
|
||||
if not os.path.exists(os.path.join(gitdir, "refs")):
|
||||
raise error.Abort(_("invalid --git-dir: %s") % gitdir)
|
||||
repo = hg.repository(ui, ui.expandpath(destpath), create=True).local()
|
||||
with repo.lock(), repo.transaction("initgit"):
|
||||
repo.svfs.writeutf8(git.GIT_DIR_FILE, gitdir)
|
||||
repo.storerequirements.add(git.GIT_REQUIREMENT)
|
||||
repo._writestorerequirements()
|
||||
repo.invalidatechangelog()
|
||||
visibility.add(repo, repo.changelog.dageval(lambda: heads(all())))
|
||||
git.initgit(repo, gitdir)
|
||||
|
||||
|
||||
@command("debuginstall", [] + cmdutil.formatteropts, "", norepo=True)
|
||||
|
@ -8,6 +8,8 @@ utilities for git support
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
import bindings
|
||||
@ -39,11 +41,107 @@ def isgit(repo):
|
||||
return GIT_REQUIREMENT in repo.storerequirements
|
||||
|
||||
|
||||
def clone(ui, url, destpath=None, update=True):
|
||||
"""Clone a git repo, then create a repo at dest backed by the git repo.
|
||||
update can be False, or True, or a node to update to.
|
||||
- False: do not update, leave an empty working copy.
|
||||
- True: upate to git HEAD.
|
||||
- other: update to `other` (node, or name).
|
||||
"""
|
||||
from . import hg
|
||||
|
||||
if destpath is None:
|
||||
# use basename as fallback, but strip ".git" or "/.git".
|
||||
basename = os.path.basename(url)
|
||||
if basename == ".git":
|
||||
basename = os.path.basename(os.path.dirname(url))
|
||||
elif basename.endswith(".git"):
|
||||
basename = basename[:-4]
|
||||
destpath = os.path.realpath(basename)
|
||||
|
||||
repo = hg.repository(ui, ui.expandpath(destpath), create=True).local()
|
||||
try:
|
||||
ret = clonegitbare(ui, url, repo.svfs.join("git"))
|
||||
if ret != 0:
|
||||
raise error.Abort(_("git clone was not successful"))
|
||||
initgit(repo, "git")
|
||||
except Exception:
|
||||
repo = None
|
||||
shutil.rmtree(destpath, ignore_errors=True)
|
||||
raise
|
||||
if update is not False:
|
||||
if update is True:
|
||||
update = None
|
||||
postpullupdate(repo, update)
|
||||
return repo
|
||||
|
||||
|
||||
def initgit(repo, gitdir):
|
||||
"""Change a repo to be backed by a bare git repo in `gitdir`.
|
||||
This should only be called for newly created repos.
|
||||
"""
|
||||
from . import visibility
|
||||
|
||||
hgrc = "%include builtin:git.rc\n"
|
||||
|
||||
with repo.lock(), repo.transaction("initgit"):
|
||||
repo.svfs.writeutf8(GIT_DIR_FILE, gitdir)
|
||||
repo.storerequirements.add(GIT_REQUIREMENT)
|
||||
repo._writestorerequirements()
|
||||
repo.invalidatechangelog()
|
||||
visibility.add(repo, repo.changelog.dageval(lambda: heads(all())))
|
||||
repo.sharedvfs.writeutf8("hgrc", hgrc)
|
||||
repo.ui.reloadconfigs(repo.root)
|
||||
|
||||
|
||||
def maybegiturl(url):
|
||||
"""Return normalized url if url is a git url, or None otherwise.
|
||||
|
||||
For now url schemes "git", "git+file", "git+ftp", "git+http", "git+https",
|
||||
"git+ssh" are considered git urls. The "git+" part will be stripped.
|
||||
"""
|
||||
parsed = util.url(url)
|
||||
if parsed.scheme == "git":
|
||||
return url
|
||||
if parsed.scheme in {
|
||||
"git+file",
|
||||
"git+ftp",
|
||||
"git+ftps",
|
||||
"git+http",
|
||||
"git+https",
|
||||
"git+ssh",
|
||||
}:
|
||||
if url.startswith("git+"):
|
||||
return url[4:]
|
||||
return None
|
||||
|
||||
|
||||
def clonegitbare(ui, giturl, destpath):
|
||||
"""Clone a git repo into local path `dest` as a git bare repo.
|
||||
This does not prepare working copy or `.hg`.
|
||||
"""
|
||||
# not using 'git clone --bare' because it writes refs to refs/heads/,
|
||||
# not in desirable refs/remotes/origin/heads/.
|
||||
for gitdir, cmd in [
|
||||
(None, ["init", "-q", "-b", "default", "--bare", destpath]),
|
||||
(destpath, ["remote", "add", "origin", giturl]),
|
||||
(destpath, ["fetch", "origin"]),
|
||||
]:
|
||||
ret = rungitnorepo(ui, cmd, gitdir=gitdir)
|
||||
if ret != 0:
|
||||
return ret
|
||||
return 0
|
||||
|
||||
|
||||
@cached
|
||||
def readgitdir(repo):
|
||||
"""Return the path of the GIT_DIR, if the repo is backed by git"""
|
||||
if isgit(repo):
|
||||
return repo.svfs.readutf8(GIT_DIR_FILE)
|
||||
path = repo.svfs.readutf8(GIT_DIR_FILE)
|
||||
if os.path.isabs(path):
|
||||
return path
|
||||
else:
|
||||
return repo.svfs.join(path)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
@ -176,3 +176,33 @@ Test pull:
|
||||
|
||||
- infinitepush compatibility
|
||||
$ hg pull --config extensions.infinitepush=
|
||||
|
||||
Test clone with flags (--noupdate, --updaterev):
|
||||
|
||||
$ mkdir $TESTTMP/clonetest
|
||||
$ cd $TESTTMP/clonetest
|
||||
|
||||
$ hg clone -q --noupdate "git+file://$TESTTMP/gitrepo"
|
||||
$ cd gitrepo
|
||||
$ hg log -r . -T '{node|short}\n'
|
||||
000000000000
|
||||
$ cd ..
|
||||
|
||||
$ hg clone "git+file://$TESTTMP/gitrepo" cloned1
|
||||
From file:/*/$TESTTMP/gitrepo (glob)
|
||||
* [new branch] foo -> origin/foo
|
||||
* [new branch] master -> origin/master
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
$ hg --cwd cloned1 log -r . -T '{node|short} {remotenames} {desc}\n'
|
||||
5c9a5ee451a8 origin/foo alpha3
|
||||
$ cd ..
|
||||
|
||||
$ hg clone --updaterev origin/foo "git+file://$TESTTMP/gitrepo" cloned2
|
||||
From file:/*/$TESTTMP/gitrepo (glob)
|
||||
* [new branch] foo -> origin/foo
|
||||
* [new branch] master -> origin/master
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
$ hg --cwd cloned2 log -r . -T '{node|short} {remotenames} {desc}\n'
|
||||
5c9a5ee451a8 origin/foo alpha3
|
||||
$ cd ..
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user