mirror of
https://gerrit.googlesource.com/git-repo
synced 2024-12-21 07:16:21 +00:00
Add option to correct gitdir when syncing
In some cases, a user may wish to continue with a sync even though it would require overwriting an existing git directory. This behavior is not safe as a default because it could result in the loss of some user data, but as an optional flag it allows the user more flexibility. To support this, add a --force-sync flag to the sync command that will attempt to overwrite the existing git dir if it is specified and the existing git dir points to the wrong obj dir. Change-Id: Ieddda8ad54e264a1eb4a9d54881dd6ebc8a03833
This commit is contained in:
parent
7cccfb2cf0
commit
abaa7f312f
40
project.py
40
project.py
@ -32,7 +32,7 @@ import traceback
|
|||||||
from color import Coloring
|
from color import Coloring
|
||||||
from git_command import GitCommand, git_require
|
from git_command import GitCommand, git_require
|
||||||
from git_config import GitConfig, IsId, GetSchemeFromUrl, ID_RE
|
from git_config import GitConfig, IsId, GetSchemeFromUrl, ID_RE
|
||||||
from error import GitError, HookError, UploadError
|
from error import GitError, HookError, UploadError, DownloadError
|
||||||
from error import ManifestInvalidRevisionError
|
from error import ManifestInvalidRevisionError
|
||||||
from error import NoManifestException
|
from error import NoManifestException
|
||||||
from trace import IsTrace, Trace
|
from trace import IsTrace, Trace
|
||||||
@ -1101,6 +1101,7 @@ class Project(object):
|
|||||||
quiet=False,
|
quiet=False,
|
||||||
is_new=None,
|
is_new=None,
|
||||||
current_branch_only=False,
|
current_branch_only=False,
|
||||||
|
force_sync=False,
|
||||||
clone_bundle=True,
|
clone_bundle=True,
|
||||||
no_tags=False,
|
no_tags=False,
|
||||||
archive=False,
|
archive=False,
|
||||||
@ -1140,7 +1141,7 @@ class Project(object):
|
|||||||
if is_new is None:
|
if is_new is None:
|
||||||
is_new = not self.Exists
|
is_new = not self.Exists
|
||||||
if is_new:
|
if is_new:
|
||||||
self._InitGitDir()
|
self._InitGitDir(force_sync=force_sync)
|
||||||
else:
|
else:
|
||||||
self._UpdateHooks()
|
self._UpdateHooks()
|
||||||
self._InitRemote()
|
self._InitRemote()
|
||||||
@ -1233,11 +1234,11 @@ class Project(object):
|
|||||||
'revision %s in %s not found' % (self.revisionExpr,
|
'revision %s in %s not found' % (self.revisionExpr,
|
||||||
self.name))
|
self.name))
|
||||||
|
|
||||||
def Sync_LocalHalf(self, syncbuf):
|
def Sync_LocalHalf(self, syncbuf, force_sync=False):
|
||||||
"""Perform only the local IO portion of the sync process.
|
"""Perform only the local IO portion of the sync process.
|
||||||
Network access is not required.
|
Network access is not required.
|
||||||
"""
|
"""
|
||||||
self._InitWorkTree()
|
self._InitWorkTree(force_sync=force_sync)
|
||||||
all_refs = self.bare_ref.all
|
all_refs = self.bare_ref.all
|
||||||
self.CleanPublishedCache(all_refs)
|
self.CleanPublishedCache(all_refs)
|
||||||
revid = self.GetRevisionId(all_refs)
|
revid = self.GetRevisionId(all_refs)
|
||||||
@ -2164,7 +2165,7 @@ class Project(object):
|
|||||||
if GitCommand(self, cmd).Wait() != 0:
|
if GitCommand(self, cmd).Wait() != 0:
|
||||||
raise GitError('%s merge %s ' % (self.name, head))
|
raise GitError('%s merge %s ' % (self.name, head))
|
||||||
|
|
||||||
def _InitGitDir(self, mirror_git=None):
|
def _InitGitDir(self, mirror_git=None, force_sync=False):
|
||||||
init_git_dir = not os.path.exists(self.gitdir)
|
init_git_dir = not os.path.exists(self.gitdir)
|
||||||
init_obj_dir = not os.path.exists(self.objdir)
|
init_obj_dir = not os.path.exists(self.objdir)
|
||||||
try:
|
try:
|
||||||
@ -2181,7 +2182,20 @@ class Project(object):
|
|||||||
if init_obj_dir or init_git_dir:
|
if init_obj_dir or init_git_dir:
|
||||||
self._ReferenceGitDir(self.objdir, self.gitdir, share_refs=False,
|
self._ReferenceGitDir(self.objdir, self.gitdir, share_refs=False,
|
||||||
copy_all=True)
|
copy_all=True)
|
||||||
|
try:
|
||||||
self._CheckDirReference(self.objdir, self.gitdir, share_refs=False)
|
self._CheckDirReference(self.objdir, self.gitdir, share_refs=False)
|
||||||
|
except GitError as e:
|
||||||
|
print("Retrying clone after deleting %s" % force_sync, file=sys.stderr)
|
||||||
|
if force_sync:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(os.path.realpath(self.gitdir))
|
||||||
|
if self.worktree and os.path.exists(
|
||||||
|
os.path.realpath(self.worktree)):
|
||||||
|
shutil.rmtree(os.path.realpath(self.worktree))
|
||||||
|
return self._InitGitDir(mirror_git=mirror_git, force_sync=False)
|
||||||
|
except:
|
||||||
|
raise e
|
||||||
|
raise e
|
||||||
|
|
||||||
if init_git_dir:
|
if init_git_dir:
|
||||||
mp = self.manifest.manifestProject
|
mp = self.manifest.manifestProject
|
||||||
@ -2308,7 +2322,8 @@ class Project(object):
|
|||||||
src = os.path.realpath(os.path.join(srcdir, name))
|
src = os.path.realpath(os.path.join(srcdir, name))
|
||||||
# Fail if the links are pointing to the wrong place
|
# Fail if the links are pointing to the wrong place
|
||||||
if src != dst:
|
if src != dst:
|
||||||
raise GitError('cannot overwrite a local work tree')
|
raise GitError('--force-sync not enabled; cannot overwrite a local '
|
||||||
|
'work tree')
|
||||||
|
|
||||||
def _ReferenceGitDir(self, gitdir, dotgit, share_refs, copy_all):
|
def _ReferenceGitDir(self, gitdir, dotgit, share_refs, copy_all):
|
||||||
"""Update |dotgit| to reference |gitdir|, using symlinks where possible.
|
"""Update |dotgit| to reference |gitdir|, using symlinks where possible.
|
||||||
@ -2361,11 +2376,11 @@ class Project(object):
|
|||||||
shutil.copy(src, dst)
|
shutil.copy(src, dst)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.EPERM:
|
if e.errno == errno.EPERM:
|
||||||
raise GitError('filesystem must support symlinks')
|
raise DownloadError('filesystem must support symlinks')
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _InitWorkTree(self):
|
def _InitWorkTree(self, force_sync=False):
|
||||||
dotgit = os.path.join(self.worktree, '.git')
|
dotgit = os.path.join(self.worktree, '.git')
|
||||||
init_dotgit = not os.path.exists(dotgit)
|
init_dotgit = not os.path.exists(dotgit)
|
||||||
try:
|
try:
|
||||||
@ -2374,7 +2389,16 @@ class Project(object):
|
|||||||
self._ReferenceGitDir(self.gitdir, dotgit, share_refs=True,
|
self._ReferenceGitDir(self.gitdir, dotgit, share_refs=True,
|
||||||
copy_all=False)
|
copy_all=False)
|
||||||
|
|
||||||
|
try:
|
||||||
self._CheckDirReference(self.gitdir, dotgit, share_refs=True)
|
self._CheckDirReference(self.gitdir, dotgit, share_refs=True)
|
||||||
|
except GitError as e:
|
||||||
|
if force_sync:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(dotgit)
|
||||||
|
return self._InitWorkTree(force_sync=False)
|
||||||
|
except:
|
||||||
|
raise e
|
||||||
|
raise e
|
||||||
|
|
||||||
if init_dotgit:
|
if init_dotgit:
|
||||||
_lwrite(os.path.join(dotgit, HEAD), '%s\n' % self.GetRevisionId())
|
_lwrite(os.path.join(dotgit, HEAD), '%s\n' % self.GetRevisionId())
|
||||||
|
@ -119,6 +119,11 @@ credentials.
|
|||||||
The -f/--force-broken option can be used to proceed with syncing
|
The -f/--force-broken option can be used to proceed with syncing
|
||||||
other projects if a project sync fails.
|
other projects if a project sync fails.
|
||||||
|
|
||||||
|
The --force-sync option can be used to overwrite existing git
|
||||||
|
directories if they have previously been linked to a different
|
||||||
|
object direcotry. WARNING: This may cause data to be lost since
|
||||||
|
refs may be removed when overwriting.
|
||||||
|
|
||||||
The --no-clone-bundle option disables any attempt to use
|
The --no-clone-bundle option disables any attempt to use
|
||||||
$URL/clone.bundle to bootstrap a new Git repository from a
|
$URL/clone.bundle to bootstrap a new Git repository from a
|
||||||
resumeable bundle file on a content delivery network. This
|
resumeable bundle file on a content delivery network. This
|
||||||
@ -174,6 +179,11 @@ later is required to fix a server side protocol bug.
|
|||||||
p.add_option('-f', '--force-broken',
|
p.add_option('-f', '--force-broken',
|
||||||
dest='force_broken', action='store_true',
|
dest='force_broken', action='store_true',
|
||||||
help="continue sync even if a project fails to sync")
|
help="continue sync even if a project fails to sync")
|
||||||
|
p.add_option('--force-sync',
|
||||||
|
dest='force_sync', action='store_true',
|
||||||
|
help="overwrite an existing git directory if it needs to "
|
||||||
|
"point to a different object directory. WARNING: this "
|
||||||
|
"may cause loss of data")
|
||||||
p.add_option('-l', '--local-only',
|
p.add_option('-l', '--local-only',
|
||||||
dest='local_only', action='store_true',
|
dest='local_only', action='store_true',
|
||||||
help="only update working tree, don't fetch")
|
help="only update working tree, don't fetch")
|
||||||
@ -281,6 +291,7 @@ later is required to fix a server side protocol bug.
|
|||||||
success = project.Sync_NetworkHalf(
|
success = project.Sync_NetworkHalf(
|
||||||
quiet=opt.quiet,
|
quiet=opt.quiet,
|
||||||
current_branch_only=opt.current_branch_only,
|
current_branch_only=opt.current_branch_only,
|
||||||
|
force_sync=opt.force_sync,
|
||||||
clone_bundle=not opt.no_clone_bundle,
|
clone_bundle=not opt.no_clone_bundle,
|
||||||
no_tags=opt.no_tags, archive=self.manifest.IsArchive,
|
no_tags=opt.no_tags, archive=self.manifest.IsArchive,
|
||||||
optimized_fetch=opt.optimized_fetch)
|
optimized_fetch=opt.optimized_fetch)
|
||||||
@ -696,7 +707,7 @@ later is required to fix a server side protocol bug.
|
|||||||
for project in all_projects:
|
for project in all_projects:
|
||||||
pm.update()
|
pm.update()
|
||||||
if project.worktree:
|
if project.worktree:
|
||||||
project.Sync_LocalHalf(syncbuf)
|
project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
|
||||||
pm.end()
|
pm.end()
|
||||||
print(file=sys.stderr)
|
print(file=sys.stderr)
|
||||||
if not syncbuf.Finish():
|
if not syncbuf.Finish():
|
||||||
|
Loading…
Reference in New Issue
Block a user