فهرست منبع

sync: Enable use of git clone --reference

Use git clone to initialize a new repository, and when possible
allow callers to use --reference to reuse an existing checkout as
the initial object storage area for the new checkout.

Change-Id: Ie27f760247f311ce484c6d3e85a90d94da2febfc
Signed-off-by: Shawn O. Pearce <sop@google.com>
Shawn O. Pearce 15 سال پیش
والد
کامیت
88443387b1
3فایلهای تغییر یافته به همراه111 افزوده شده و 9 حذف شده
  1. 94 7
      project.py
  2. 4 1
      repo
  3. 13 1
      subcmds/init.py

+ 94 - 7
project.py

@@ -622,13 +622,14 @@ class Project(object):
     """Perform only the network IO portion of the sync process.
     """Perform only the network IO portion of the sync process.
        Local working directory/branch state is not affected.
        Local working directory/branch state is not affected.
     """
     """
-    if not self.Exists:
+    is_new = not self.Exists
+    if is_new:
       print >>sys.stderr
       print >>sys.stderr
       print >>sys.stderr, 'Initializing project %s ...' % self.name
       print >>sys.stderr, 'Initializing project %s ...' % self.name
       self._InitGitDir()
       self._InitGitDir()
 
 
     self._InitRemote()
     self._InitRemote()
-    if not self._RemoteFetch():
+    if not self._RemoteFetch(initial = is_new):
       return False
       return False
 
 
     #Check that the requested ref was found after fetch
     #Check that the requested ref was found after fetch
@@ -1024,7 +1025,7 @@ class Project(object):
 
 
 ## Direct Git Commands ##
 ## Direct Git Commands ##
 
 
-  def _RemoteFetch(self, name=None, tag=None):
+  def _RemoteFetch(self, name=None, tag=None, initial=False):
     if not name:
     if not name:
       name = self.remote.name
       name = self.remote.name
 
 
@@ -1032,6 +1033,60 @@ class Project(object):
     if self.GetRemote(name).PreConnectFetch():
     if self.GetRemote(name).PreConnectFetch():
       ssh_proxy = True
       ssh_proxy = True
 
 
+    if initial:
+      alt = os.path.join(self.gitdir, 'objects/info/alternates')
+      try:
+        fd = open(alt, 'rb')
+        try:
+          ref_dir = fd.readline()
+          if ref_dir and ref_dir.endswith('\n'):
+            ref_dir = ref_dir[:-1]
+        finally:
+          fd.close()
+      except IOError, e:
+        ref_dir = None
+
+      if ref_dir and 'objects' == os.path.basename(ref_dir):
+        ref_dir = os.path.dirname(ref_dir)
+        packed_refs = os.path.join(self.gitdir, 'packed-refs')
+        remote = self.GetRemote(name)
+
+        all = self.bare_ref.all
+        ids = set(all.values())
+        tmp = set()
+
+        for r, id in GitRefs(ref_dir).all.iteritems():
+          if r not in all:
+            if r.startswith(R_TAGS) or remote.WritesTo(r):
+              all[r] = id
+              ids.add(id)
+              continue
+
+          if id in ids:
+            continue
+
+          r = 'refs/_alt/%s' % id
+          all[r] = id
+          ids.add(id)
+          tmp.add(r)
+
+        ref_names = list(all.keys())
+        ref_names.sort()
+
+        tmp_packed = ''
+        old_packed = ''
+
+        for r in ref_names:
+          line = '%s %s\n' % (all[r], r)
+          tmp_packed += line
+          if r not in tmp:
+            old_packed += line
+
+        _lwrite(packed_refs, tmp_packed)
+
+      else:
+        ref_dir = None
+
     cmd = ['fetch']
     cmd = ['fetch']
     if not self.worktree:
     if not self.worktree:
       cmd.append('--update-head-ok')
       cmd.append('--update-head-ok')
@@ -1039,10 +1094,21 @@ class Project(object):
     if tag is not None:
     if tag is not None:
       cmd.append('tag')
       cmd.append('tag')
       cmd.append(tag)
       cmd.append(tag)
-    return GitCommand(self,
-                      cmd,
-                      bare = True,
-                      ssh_proxy = ssh_proxy).Wait() == 0
+
+    ok = GitCommand(self,
+                    cmd,
+                    bare = True,
+                    ssh_proxy = ssh_proxy).Wait() == 0
+
+    if initial:
+      if ref_dir:
+        if old_packed != '':
+          _lwrite(packed_refs, old_packed)
+        else:
+          os.remove(packed_refs)
+      self.bare_git.pack_refs('--all', '--prune')
+
+    return ok
 
 
   def _Checkout(self, rev, quiet=False):
   def _Checkout(self, rev, quiet=False):
     cmd = ['checkout']
     cmd = ['checkout']
@@ -1080,6 +1146,27 @@ class Project(object):
       os.makedirs(self.gitdir)
       os.makedirs(self.gitdir)
       self.bare_git.init()
       self.bare_git.init()
 
 
+      mp = self.manifest.manifestProject
+      ref_dir = mp.config.GetString('repo.reference')
+
+      if ref_dir:
+        mirror_git = os.path.join(ref_dir, self.name + '.git')
+        repo_git = os.path.join(ref_dir, '.repo', 'projects',
+                                self.relpath + '.git')
+
+        if os.path.exists(mirror_git):
+          ref_dir = mirror_git
+
+        elif os.path.exists(repo_git):
+          ref_dir = repo_git
+
+        else:
+          ref_dir = None
+
+        if ref_dir:
+          _lwrite(os.path.join(self.gitdir, 'objects/info/alternates'),
+                  os.path.join(ref_dir, 'objects') + '\n')
+
       if self.manifest.IsMirror:
       if self.manifest.IsMirror:
         self.config.SetString('core.bare', 'true')
         self.config.SetString('core.bare', 'true')
       else:
       else:

+ 4 - 1
repo

@@ -28,7 +28,7 @@ if __name__ == '__main__':
 del magic
 del magic
 
 
 # increment this whenever we make important changes to this script
 # increment this whenever we make important changes to this script
-VERSION = (1, 8)
+VERSION = (1, 9)
 
 
 # increment this if the MAINTAINER_KEYS block is modified
 # increment this if the MAINTAINER_KEYS block is modified
 KEYRING_VERSION = (1,0)
 KEYRING_VERSION = (1,0)
@@ -118,6 +118,9 @@ group.add_option('-m', '--manifest-name',
 group.add_option('--mirror',
 group.add_option('--mirror',
                  dest='mirror', action='store_true',
                  dest='mirror', action='store_true',
                  help='mirror the forrest')
                  help='mirror the forrest')
+group.add_option('--reference',
+                 dest='reference',
+                 help='location of mirror directory', metavar='DIR')
 
 
 # Tool
 # Tool
 group = init_optparse.add_option_group('repo Version options')
 group = init_optparse.add_option_group('repo Version options')

+ 13 - 1
subcmds/init.py

@@ -41,6 +41,13 @@ The optional -m argument can be used to specify an alternate manifest
 to be used. If no manifest is specified, the manifest default.xml
 to be used. If no manifest is specified, the manifest default.xml
 will be used.
 will be used.
 
 
+The --reference option can be used to point to a directory that
+has the content of a --mirror sync. This will make the working
+directory use as much data as possible from the local reference
+directory when fetching from the server. This will make the sync
+go a lot faster by reducing data traffic on the network.
+
+
 Switching Manifest Branches
 Switching Manifest Branches
 ---------------------------
 ---------------------------
 
 
@@ -71,7 +78,9 @@ to update the working directory files.
     g.add_option('--mirror',
     g.add_option('--mirror',
                  dest='mirror', action='store_true',
                  dest='mirror', action='store_true',
                  help='mirror the forrest')
                  help='mirror the forrest')
-
+    g.add_option('--reference',
+                 dest='reference',
+                 help='location of mirror directory', metavar='DIR')
 
 
     # Tool
     # Tool
     g = p.add_option_group('repo Version options')
     g = p.add_option_group('repo Version options')
@@ -115,6 +124,9 @@ to update the working directory files.
       r.ResetFetch()
       r.ResetFetch()
       r.Save()
       r.Save()
 
 
+    if opt.reference:
+      m.config.SetString('repo.reference', opt.reference)
+
     if opt.mirror:
     if opt.mirror:
       if is_new:
       if is_new:
         m.config.SetString('repo.mirror', 'true')
         m.config.SetString('repo.mirror', 'true')