mirror of
https://github.com/mnauw/git-remote-hg.git
synced 2026-01-21 21:52:05 +01:00
Add support for automagic hg revision identification and pushing
This commit is contained in:
@@ -217,6 +217,7 @@ class ParserContext:
|
||||
self.localref = None
|
||||
self.remoteref = None
|
||||
self.gitmarks = None
|
||||
self.hghelper = None
|
||||
|
||||
class Parser:
|
||||
|
||||
@@ -907,6 +908,45 @@ def parse_commit(parser):
|
||||
parsed_refs[ref] = None
|
||||
return
|
||||
|
||||
# check if this is an hg commit we have in some other repo
|
||||
gitmarks = parser.context.gitmarks
|
||||
if gitmarks:
|
||||
gitcommit = gitmarks.to_rev(commit_mark)
|
||||
hgrev = get_rev_hg(gitcommit)
|
||||
if hgrev:
|
||||
hghelper = parser.context.hghelper
|
||||
if not hghelper:
|
||||
print "error %s rejected not pushing hg based commit %s" % (ref, gitcommit)
|
||||
raise UserWarning("check-hg-commits")
|
||||
# must be in some local repo
|
||||
# find it and push it to the target local repo
|
||||
# (rather than making a commit into it)
|
||||
# probably not already in target repo, but let's make sure
|
||||
if hgrev not in parser.repo:
|
||||
srepo = hghelper.githgrepo.find_hg_repo(hgrev)
|
||||
if not srepo:
|
||||
# pretty bad, if identified as hg revision, we should have it somewhere
|
||||
# but is possible if the originating repo has been removed now
|
||||
# warn elaborately and fail given the current settings
|
||||
description = "\n" \
|
||||
"commit %s corresponds \nto hg revision %s,\n" \
|
||||
"but could not find latter in any fetched hg repo.\n" \
|
||||
"Please resolve the inconsistency or disable pushing hg commits" \
|
||||
% (gitcommit, hgrev)
|
||||
die(description)
|
||||
warn('Pushing hg changeset %s for %s' % (hgrev, gitcommit))
|
||||
# target is local repo so should have a root
|
||||
# force push since otherwise forcibly commit anyway
|
||||
# (and needed for multiple head case etc)
|
||||
push(srepo, hg.peer(srepo.ui, {}, parser.repo.root), [hgbin(hgrev)], True)
|
||||
else:
|
||||
# could already be present, particularly in shared proxy repo
|
||||
warn('Using hg changeset %s for %s' % (hgrev, gitcommit))
|
||||
# track mark and are done here
|
||||
parsed_refs[ref] = hgrev
|
||||
marks.new_mark(hgrev, commit_mark)
|
||||
return
|
||||
|
||||
def getfilectx(repo, memctx, f):
|
||||
of = files[f]
|
||||
if 'deleted' in of:
|
||||
@@ -1420,20 +1460,48 @@ def do_push_refspec(parser, refspec):
|
||||
marks = os.path.join(dirname, 'marks-git')
|
||||
if os.path.exists(marks):
|
||||
cmd.append('--import-marks=%s' % marks)
|
||||
# optionally reuse existing hg commits in local repos
|
||||
check_hg_commits = get_config('remote-hg.check-hg-commits').strip()
|
||||
use_hg_commits = check_hg_commits in ('fail', 'push')
|
||||
# no commit of marks if dry-dry_run
|
||||
# and only commit if all went ok,
|
||||
# otherwise some commits may no longer be exported next time/try around
|
||||
tmpmarks = ''
|
||||
if not dry_run:
|
||||
if use_hg_commits or not dry_run:
|
||||
tmpmarks = os.path.join(dirname, 'marks-git-%d' % (os.getpid()))
|
||||
cmd.append('--export-marks=%s' % tmpmarks)
|
||||
cmd.append(refs[0])
|
||||
export = subprocess.Popen(cmd, stdin=None, stdout=subprocess.PIPE)
|
||||
# a parameter would obviously be nicer here ...
|
||||
force_push = force
|
||||
ok = False
|
||||
tmpfastexport = None
|
||||
try:
|
||||
ok = do_push_hg(Parser(parser.repo, export.stdout, ctx))
|
||||
if use_hg_commits:
|
||||
# we need the mapping from marks to commit
|
||||
# so store the output first to a file (and marks get saved also),
|
||||
# and then process that file
|
||||
tmpfastexport = open(os.path.join(dirname, 'git-fast-export-%d' % (os.getpid())), 'w+b')
|
||||
subprocess.check_call(cmd, stdin=None, stdout=tmpfastexport)
|
||||
try:
|
||||
import imp
|
||||
ctx.hghelper = imp.load_source('hghelper', \
|
||||
os.path.join(os.path.dirname(__file__), 'git-hg-helper'))
|
||||
ctx.hghelper.init_git(gitdir)
|
||||
ctx.gitmarks = ctx.hghelper.GitMarks(tmpmarks)
|
||||
# let processing know it should not bother pushing if not requested
|
||||
if check_hg_commits != 'push':
|
||||
ctx.hghelper = None
|
||||
except:
|
||||
die("check-hg-commits setup failed; is git-hg-helper also installed?")
|
||||
tmpfastexport.seek(0)
|
||||
try:
|
||||
ok = do_push_hg(Parser(parser.repo, tmpfastexport, ctx))
|
||||
except UserWarning:
|
||||
ok = False
|
||||
else:
|
||||
# simply feed fast-export directly to processing
|
||||
export = subprocess.Popen(cmd, stdin=None, stdout=subprocess.PIPE)
|
||||
ok = do_push_hg(Parser(parser.repo, export.stdout, ctx))
|
||||
finally:
|
||||
if tmpmarks and os.path.exists(tmpmarks):
|
||||
if ok and not dry_run:
|
||||
@@ -1441,6 +1509,9 @@ def do_push_refspec(parser, refspec):
|
||||
os.rename(tmpmarks, marks)
|
||||
else:
|
||||
os.remove(tmpmarks)
|
||||
if tmpfastexport and os.path.exists(tmpfastexport.name):
|
||||
tmpfastexport.close()
|
||||
os.remove(tmpfastexport.name)
|
||||
|
||||
def do_push(parser):
|
||||
if os.environ.get('GIT_REMOTE_HG_DEBUG_PUSH'):
|
||||
|
||||
@@ -61,4 +61,89 @@ test_expect_success 'source:dest bookmark' '
|
||||
check_bookmark hgrepo feature-a one
|
||||
'
|
||||
|
||||
setup_check_hg_commits_repo () {
|
||||
(
|
||||
rm -rf hgrepo* &&
|
||||
hg init hgrepo &&
|
||||
cd hgrepo &&
|
||||
echo zero > content &&
|
||||
hg add content &&
|
||||
hg commit -m zero
|
||||
) &&
|
||||
|
||||
git clone "hg::hgrepo" gitrepo &&
|
||||
hg clone hgrepo hgrepo.second &&
|
||||
|
||||
(
|
||||
cd gitrepo &&
|
||||
git remote add second hg::../hgrepo.second &&
|
||||
git fetch second
|
||||
) &&
|
||||
|
||||
(
|
||||
cd hgrepo &&
|
||||
echo one > content &&
|
||||
hg commit -m one &&
|
||||
echo two > content &&
|
||||
hg commit -m two &&
|
||||
echo three > content &&
|
||||
hg commit -m three &&
|
||||
hg move content content-move &&
|
||||
hg commit -m moved &&
|
||||
hg move content-move content &&
|
||||
hg commit -m restored
|
||||
)
|
||||
}
|
||||
|
||||
git config --global remote-hg.check-hg-commits fail
|
||||
test_expect_success 'check-hg-commits with fail mode' '
|
||||
test_when_finished "rm -rf gitrepo* hgrepo*" &&
|
||||
|
||||
setup_check_hg_commits_repo &&
|
||||
|
||||
(
|
||||
cd gitrepo &&
|
||||
git fetch origin &&
|
||||
git reset --hard origin/master &&
|
||||
! git push second master 2>../error
|
||||
)
|
||||
|
||||
cat error &&
|
||||
grep rejected error | grep hg
|
||||
'
|
||||
|
||||
git config --global remote-hg.check-hg-commits push
|
||||
# codepath for push is slightly different depending on shared proxy involved
|
||||
# so tweak to test both
|
||||
check_hg_commits_push () {
|
||||
test_when_finished "rm -rf gitrepo* hgrepo*" &&
|
||||
|
||||
setup_check_hg_commits_repo &&
|
||||
|
||||
(
|
||||
cd gitrepo &&
|
||||
git fetch origin &&
|
||||
git reset --hard origin/master &&
|
||||
git push second master 2> ../error
|
||||
) &&
|
||||
|
||||
cat error &&
|
||||
grep "hg changeset" error &&
|
||||
|
||||
hg log -R hgrepo > expected &&
|
||||
hg log -R hgrepo.second | grep -v bookmark > actual &&
|
||||
test_cmp expected actual
|
||||
}
|
||||
|
||||
unset GIT_REMOTE_HG_TEST_REMOTE
|
||||
test_expect_success 'check-hg-commits with push mode - no local proxy' '
|
||||
check_hg_commits_push
|
||||
'
|
||||
|
||||
GIT_REMOTE_HG_TEST_REMOTE=1 &&
|
||||
export GIT_REMOTE_HG_TEST_REMOTE
|
||||
test_expect_success 'check-hg-commits with push mode - with local proxy' '
|
||||
check_hg_commits_push
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
Reference in New Issue
Block a user