mirror of
				https://github.com/mnauw/git-remote-hg.git
				synced 2025-10-31 00:25:48 +01:00 
			
		
		
		
	Compare commits
	
		
			25 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 776e36c147 | ||
|  | 5b6d5283cb | ||
|  | 5738ee42d8 | ||
|  | 1d27390dd0 | ||
|  | cad5c95465 | ||
|  | 259838a342 | ||
|  | 55bbd81a75 | ||
|  | 8db5b9a537 | ||
|  | bbc4009acf | ||
|  | c84feb364b | ||
|  | 990152c0c8 | ||
|  | 6ba42cdf98 | ||
|  | ef00e40d7c | ||
|  | 1c72617831 | ||
|  | 184551c71d | ||
|  | 32d4f36f22 | ||
|  | ccb3f13d69 | ||
|  | 2958556bec | ||
|  | 4ea2fa76b3 | ||
|  | 84b8b482a4 | ||
|  | 978314a4be | ||
|  | 51eabd4a17 | ||
|  | 98c3535c3f | ||
|  | 3abf376e9e | ||
|  | 0b71ca38e7 | 
							
								
								
									
										25
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | language: python | ||||||
|  |  | ||||||
|  | install: | ||||||
|  |   - if [ "$HG_VERSION" != "dev" ]; | ||||||
|  |     then pip install -q Mercurial${HG_VERSION+==$HG_VERSION}; | ||||||
|  |     else pip install -q http://selenic.com/repo/hg/archive/tip.tar.gz; | ||||||
|  |     fi | ||||||
|  |   - pip install -q dulwich hg-git || true | ||||||
|  |  | ||||||
|  | before_script: | ||||||
|  |   - hg --version || true | ||||||
|  |   - pip show hg-git dulwich | ||||||
|  |  | ||||||
|  | script: | ||||||
|  |   - make test | ||||||
|  |  | ||||||
|  | matrix: | ||||||
|  |   include: | ||||||
|  |     - env: HG_VERSION=2.9.1 | ||||||
|  |     - env: HG_VERSION=2.8.2 | ||||||
|  |     - env: HG_VERSION=2.7.2 | ||||||
|  |     - env: HG_VERSION=3.0 | ||||||
|  |     - env: HG_VERSION=dev | ||||||
|  |     - python: 2.7 | ||||||
|  |     - python: 2.6 | ||||||
							
								
								
									
										17
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,6 +1,23 @@ | |||||||
|  | prefix := $(HOME) | ||||||
|  |  | ||||||
| all: | all: | ||||||
|  |  | ||||||
|  | doc: doc/git-remote-hg.1 | ||||||
|  |  | ||||||
| test: | test: | ||||||
| 	$(MAKE) -C test | 	$(MAKE) -C test | ||||||
|  |  | ||||||
|  | doc/git-remote-hg.1: doc/git-remote-hg.txt | ||||||
|  | 	a2x -d manpage -f manpage $< | ||||||
|  |  | ||||||
|  | D = $(DESTDIR) | ||||||
|  |  | ||||||
|  | install: | ||||||
|  | 	install -D -m 755 git-remote-hg \ | ||||||
|  | 		$(D)$(prefix)/bin/git-remote-hg | ||||||
|  |  | ||||||
|  | install-doc: doc | ||||||
|  | 	install -D -m 644 doc/git-remote-hg.1 \ | ||||||
|  | 		$(D)$(prefix)/share/man/man1/git-remote-hg.1 | ||||||
|  |  | ||||||
| .PHONY: all test | .PHONY: all test | ||||||
|   | |||||||
							
								
								
									
										124
									
								
								README.asciidoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								README.asciidoc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | |||||||
|  | 'git-remote-hg' is the semi-official Mercurial bridge from Git project, once | ||||||
|  | installed, it allows you to clone, fetch and push to and from Mercurial | ||||||
|  | repositories as if they were Git ones: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | git clone "hg::http://selenic.com/repo/hello" | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | To enable this, simply add the 'git-remote-hg' script anywhere in your `$PATH`: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | wget https://raw.github.com/felipec/git-remote-hg/master/git-remote-hg -O ~/bin/git-remote-hg | ||||||
|  | chmod +x ~/bin/git-remote-hg | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | That's it :) | ||||||
|  |  | ||||||
|  | == Configuration == | ||||||
|  |  | ||||||
|  | If you want to see Mercurial revisions as Git commit notes: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config core.notesRef refs/notes/hg | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | If you are not interested in Mercurial permanent and global branches (aka. commit labels): | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config --global remote-hg.track-branches false | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | With this configuration, the 'branches/foo' refs won't appear. | ||||||
|  |  | ||||||
|  | If you want the equivalent of 'hg clone --insecure': | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config --global remote-hg.insecure true | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly the same commits: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config --global remote-hg.hg-git-compat true | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | == Notes == | ||||||
|  |  | ||||||
|  | Remember to run `git gc --aggressive` after cloning a repository, specially if | ||||||
|  | it's a big one. Otherwise lots of space will be wasted. | ||||||
|  |  | ||||||
|  | The oldest version of mercurial supported is 1.9. For the most part 1.8 works, | ||||||
|  | but you might experience some issues. | ||||||
|  |  | ||||||
|  | === Pushing branches === | ||||||
|  |  | ||||||
|  | To push a branch, you need to use the "branches/" prefix: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git checkout branches/next | ||||||
|  | # do stuff | ||||||
|  | % git push origin branches/next | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | All the pushed commits will receive the "next" Mercurial named branch. | ||||||
|  |  | ||||||
|  | *Note*: Make sure you don't have +remote-hg.track-branches+ disabled. | ||||||
|  |  | ||||||
|  | === Cloning HTTPS === | ||||||
|  |  | ||||||
|  | The simplest way is to specify the user and password in the URL: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | git clone hg::https://user:password@bitbucket.org/user/repo | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | You can also use the http://mercurial.selenic.com/wiki/SchemesExtension[schemes extension]: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | [auth] | ||||||
|  | bb.prefix = https://bitbucket.org/user/ | ||||||
|  | bb.username = user | ||||||
|  | bb.password = password | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | Finally, you can also use the | ||||||
|  | https://pypi.python.org/pypi/mercurial_keyring[keyring extension]. | ||||||
|  |  | ||||||
|  | However, some of these features require very new versions of 'git-remote-hg', | ||||||
|  | so you might have better luck simply specifying the username and password in | ||||||
|  | the URL. | ||||||
|  |  | ||||||
|  | === Caveats === | ||||||
|  |  | ||||||
|  | The only major incompatibility is that Git octopus merges (a merge with more | ||||||
|  | than two parents) are not supported. | ||||||
|  |  | ||||||
|  | Mercurial branches and bookmarks have some limitations of Git branches: you | ||||||
|  | can't have both 'dev/feature' and 'dev' (as Git uses files and directories to | ||||||
|  | store them). | ||||||
|  |  | ||||||
|  | Multiple anonymous heads (which are useless anyway) are not supported; you | ||||||
|  | would only see the latest head. | ||||||
|  |  | ||||||
|  | Closed branches are not supported; they are not shown and you can't close or | ||||||
|  | reopen. Additionally in certain rare situations a synchronization issue can | ||||||
|  | occur (https://github.com/felipec/git/issues/65[Bug #65]). | ||||||
|  |  | ||||||
|  | Limitations of the remote-helpers' framework apply. In particular, these | ||||||
|  | commands don't work: | ||||||
|  |  | ||||||
|  | * `git push origin :branch-to-delete` | ||||||
|  | * `git push origin old:new` (it will push 'old') (Git v2.0) | ||||||
|  | * `git push --dry-run origin branch` (it will push) (Git v2.0) | ||||||
|  |  | ||||||
|  | == Other projects == | ||||||
|  |  | ||||||
|  | There are other 'git-remote-hg' projects out there, do not confuse this one, | ||||||
|  | this is the one distributed officially by the Git project: | ||||||
|  |  | ||||||
|  | * https://github.com/msysgit/msysgit/wiki/Guide-to-git-remote-hg[msysgit's git-remote-hg] | ||||||
|  | * https://github.com/rfk/git-remote-hg[rfk's git-remote-hg] | ||||||
|  |  | ||||||
|  | For a comparison between these and other projects go | ||||||
|  | https://github.com/felipec/git/wiki/Comparison-of-git-remote-hg-alternatives[here]. | ||||||
							
								
								
									
										121
									
								
								doc/git-remote-hg.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								doc/git-remote-hg.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | git-remote-hg(1) | ||||||
|  | ================ | ||||||
|  |  | ||||||
|  | NAME | ||||||
|  | ---- | ||||||
|  | git-remote-hg - bidirectional bridge between Git and Mercurial | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SYNOPSIS | ||||||
|  | -------- | ||||||
|  | [verse] | ||||||
|  | 'git clone' hg::<hg repository> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DESCRIPTION | ||||||
|  | ----------- | ||||||
|  |  | ||||||
|  | This tool allows you to transparently clone, fetch and push to and from Mercurial | ||||||
|  | repositories as if they were Git ones. | ||||||
|  |  | ||||||
|  | To use it you simply need to use the "'hg::'" prefix when specifying a remote URL | ||||||
|  | (e.g. when cloning). | ||||||
|  |  | ||||||
|  |  | ||||||
|  | EXAMPLE | ||||||
|  | ------- | ||||||
|  | ------------ | ||||||
|  | $ git clone hg::http://selenic.com/repo/hello | ||||||
|  | ------------ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIGURATION | ||||||
|  | ------------- | ||||||
|  |  | ||||||
|  | If you want to see Mercurial revisions as Git commit notes: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config core.notesRef refs/notes/hg | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | If you are not interested in Mercurial permanent and global branches (aka. commit labels): | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config --global remote-hg.track-branches false | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | With this configuration, the 'branches/foo' refs won't appear. | ||||||
|  |  | ||||||
|  | If you want the equivalent of `hg clone --insecure`: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config --global remote-hg.insecure true | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly the same commits: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git config --global remote-hg.hg-git-compat true | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | NOTES | ||||||
|  | ----- | ||||||
|  |  | ||||||
|  | Remember to run `git gc --aggressive` after cloning a repository, specially if | ||||||
|  | it's a big one. Otherwise lots of space will be wasted. | ||||||
|  |  | ||||||
|  | The oldest version of Mercurial supported is 1.9. For the most part 1.8 works, | ||||||
|  | but you might experience some issues. | ||||||
|  |  | ||||||
|  | Pushing branches | ||||||
|  | ~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  | To push a Mercurial named branch, you need to use the "branches/" prefix: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | % git checkout branches/next | ||||||
|  | # do stuff | ||||||
|  | % git push origin branches/next | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | All the pushed commits will receive the "next" Mercurial named branch. | ||||||
|  |  | ||||||
|  | *Note*: Make sure you don't have +remote-hg.track-branches+ disabled. | ||||||
|  |  | ||||||
|  | Cloning HTTPS | ||||||
|  | ~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  | The simplest way is to specify the user and password in the URL: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | git clone hg::https://user:password@bitbucket.org/user/repo | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | You can also use the http://mercurial.selenic.com/wiki/SchemesExtension[schemes extension]: | ||||||
|  |  | ||||||
|  | -------------------------------------- | ||||||
|  | [auth] | ||||||
|  | bb.prefix = https://bitbucket.org/user/ | ||||||
|  | bb.username = user | ||||||
|  | bb.password = password | ||||||
|  | -------------------------------------- | ||||||
|  |  | ||||||
|  | Finally, you can also use the | ||||||
|  | https://pypi.python.org/pypi/mercurial_keyring[keyring extension]. | ||||||
|  |  | ||||||
|  | CAVEATS | ||||||
|  | ------- | ||||||
|  |  | ||||||
|  | The only major incompatibility is that Git octopus merges (a merge with more | ||||||
|  | than two parents) are not supported. | ||||||
|  |  | ||||||
|  | Mercurial branches and bookmarks have some limitations of Git branches: you | ||||||
|  | can't have both 'dev/feature' and 'dev' (as Git uses files and directories to | ||||||
|  | store them). | ||||||
|  |  | ||||||
|  | Multiple anonymous heads (which are useless anyway) are not supported; you | ||||||
|  | would only see the latest head. | ||||||
|  |  | ||||||
|  | Closed branches are not supported; they are not shown and you can't close or | ||||||
|  | reopen. Additionally in certain rare situations a synchronization issue can | ||||||
|  | occur (https://github.com/felipec/git/issues/65[Bug #65]). | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| #!/usr/bin/env python | #!/usr/bin/env python2 | ||||||
| # | # | ||||||
| # Copyright (c) 2012 Felipe Contreras | # Copyright (c) 2012 Felipe Contreras | ||||||
| # | # | ||||||
| @@ -13,6 +13,7 @@ | |||||||
| # "$GIT_DIR/hg/origin/clone/.hg/". | # "$GIT_DIR/hg/origin/clone/.hg/". | ||||||
|  |  | ||||||
| from mercurial import hg, ui, bookmarks, context, encoding, node, error, extensions, discovery, util | from mercurial import hg, ui, bookmarks, context, encoding, node, error, extensions, discovery, util | ||||||
|  | from mercurial import changegroup | ||||||
|  |  | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
| @@ -53,7 +54,7 @@ import time as ptime | |||||||
| NAME_RE = re.compile('^([^<>]+)') | NAME_RE = re.compile('^([^<>]+)') | ||||||
| AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)') | AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)') | ||||||
| EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)') | EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)') | ||||||
| AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$') | AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.*))?$') | ||||||
| RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)') | RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)') | ||||||
|  |  | ||||||
| VERSION = 2 | VERSION = 2 | ||||||
| @@ -260,6 +261,7 @@ class Parser: | |||||||
|         return (user, int(date), -tz) |         return (user, int(date), -tz) | ||||||
|  |  | ||||||
| def fix_file_path(path): | def fix_file_path(path): | ||||||
|  |     path = os.path.normpath(path) | ||||||
|     if not os.path.isabs(path): |     if not os.path.isabs(path): | ||||||
|         return path |         return path | ||||||
|     return os.path.relpath(path, '/') |     return os.path.relpath(path, '/') | ||||||
| @@ -421,7 +423,7 @@ def get_repo(url, alias): | |||||||
|  |  | ||||||
|         repo = hg.repository(myui, local_path) |         repo = hg.repository(myui, local_path) | ||||||
|         try: |         try: | ||||||
|             peer = hg.peer(myui, {}, url) |             peer = hg.peer(repo.ui, {}, url) | ||||||
|         except: |         except: | ||||||
|             die('Repository error') |             die('Repository error') | ||||||
|         repo.pull(peer, heads=None, force=True) |         repo.pull(peer, heads=None, force=True) | ||||||
| @@ -436,16 +438,46 @@ def rev_to_mark(rev): | |||||||
| def mark_to_rev(mark): | def mark_to_rev(mark): | ||||||
|     return marks.to_rev(mark) |     return marks.to_rev(mark) | ||||||
|  |  | ||||||
|  | # Get a range of revisions in the form of a..b (git committish) | ||||||
|  | def gitrange(repo, a, b): | ||||||
|  |     positive = [] | ||||||
|  |     pending = set([int(b)]) | ||||||
|  |     negative = set([int(a)]) | ||||||
|  |     for cur in xrange(b, -1, -1): | ||||||
|  |         if not pending: | ||||||
|  |             break | ||||||
|  |  | ||||||
|  |         parents = [p for p in repo.changelog.parentrevs(cur) if p >= 0] | ||||||
|  |  | ||||||
|  |         if cur in pending: | ||||||
|  |             positive.append(cur) | ||||||
|  |             pending.remove(cur) | ||||||
|  |             for p in parents: | ||||||
|  |                 if not p in negative: | ||||||
|  |                     pending.add(p) | ||||||
|  |         elif cur in negative: | ||||||
|  |             negative.remove(cur) | ||||||
|  |             for p in parents: | ||||||
|  |                 if not p in pending: | ||||||
|  |                     negative.add(p) | ||||||
|  |                 else: | ||||||
|  |                     pending.discard(p) | ||||||
|  |  | ||||||
|  |     positive.reverse() | ||||||
|  |     return positive | ||||||
|  |  | ||||||
| def export_ref(repo, name, kind, head): | def export_ref(repo, name, kind, head): | ||||||
|     ename = '%s/%s' % (kind, name) |     ename = '%s/%s' % (kind, name) | ||||||
|     try: |     try: | ||||||
|         tip = marks.get_tip(ename) |         tip = marks.get_tip(ename) | ||||||
|         tip = repo[tip].rev() |         tip = repo[tip] | ||||||
|     except: |     except: | ||||||
|         tip = 0 |         tip = repo[-1] | ||||||
|  |  | ||||||
|  |     revs = gitrange(repo, tip, head) | ||||||
|  |  | ||||||
|     revs = xrange(tip, head.rev() + 1) |  | ||||||
|     total = len(revs) |     total = len(revs) | ||||||
|  |     tip = tip.rev() | ||||||
|  |  | ||||||
|     for rev in revs: |     for rev in revs: | ||||||
|  |  | ||||||
| @@ -460,8 +492,12 @@ def export_ref(repo, name, kind, head): | |||||||
|  |  | ||||||
|         author = "%s %d %s" % (fixup_user(user), time, gittz(tz)) |         author = "%s %d %s" % (fixup_user(user), time, gittz(tz)) | ||||||
|         if 'committer' in extra: |         if 'committer' in extra: | ||||||
|             user, time, tz = extra['committer'].rsplit(' ', 2) |             try: | ||||||
|             committer = "%s %s %s" % (user, time, gittz(int(tz))) |                 cuser, ctime, ctz = extra['committer'].rsplit(' ', 2) | ||||||
|  |                 committer = "%s %s %s" % (cuser, ctime, gittz(int(ctz))) | ||||||
|  |             except ValueError: | ||||||
|  |                 cuser = extra['committer'] | ||||||
|  |                 committer = "%s %d %s" % (fixup_user(cuser), time, gittz(tz)) | ||||||
|         else: |         else: | ||||||
|             committer = author |             committer = author | ||||||
|  |  | ||||||
| @@ -643,6 +679,9 @@ def do_list(parser): | |||||||
|             print "? refs/heads/branches/%s" % gitref(branch) |             print "? refs/heads/branches/%s" % gitref(branch) | ||||||
|  |  | ||||||
|     for bmark in bmarks: |     for bmark in bmarks: | ||||||
|  |         if  bmarks[bmark].hex() == '0' * 40: | ||||||
|  |             warn("Ignoring invalid bookmark '%s'", bmark) | ||||||
|  |         else: | ||||||
|             print "? refs/heads/%s" % gitref(bmark) |             print "? refs/heads/%s" % gitref(bmark) | ||||||
|  |  | ||||||
|     for tag, node in repo.tagslist(): |     for tag, node in repo.tagslist(): | ||||||
| @@ -909,6 +948,11 @@ def checkheads_bmark(repo, ref, ctx): | |||||||
|  |  | ||||||
|     ctx_old = bmarks[bmark] |     ctx_old = bmarks[bmark] | ||||||
|     ctx_new = ctx |     ctx_new = ctx | ||||||
|  |  | ||||||
|  |     if not ctx.rev(): | ||||||
|  |         print "error %s unknown" % ref | ||||||
|  |         return False | ||||||
|  |  | ||||||
|     if not repo.changelog.descendant(ctx_old.rev(), ctx_new.rev()): |     if not repo.changelog.descendant(ctx_old.rev(), ctx_new.rev()): | ||||||
|         if force_push: |         if force_push: | ||||||
|             print "ok %s forced update" % ref |             print "ok %s forced update" % ref | ||||||
| @@ -981,15 +1025,26 @@ def push_unsafe(repo, remote, parsed_refs, p_revs): | |||||||
|     if not checkheads(repo, remote, p_revs): |     if not checkheads(repo, remote, p_revs): | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
|  |     if check_version(3, 0): | ||||||
|  |         cg = changegroup.getbundle(repo, 'push', heads=list(p_revs), common=common) | ||||||
|  |     else: | ||||||
|         cg = repo.getbundle('push', heads=list(p_revs), common=common) |         cg = repo.getbundle('push', heads=list(p_revs), common=common) | ||||||
|  |  | ||||||
|     unbundle = remote.capable('unbundle') |     unbundle = remote.capable('unbundle') | ||||||
|     if unbundle: |     if unbundle: | ||||||
|         if force: |         if force: | ||||||
|             remoteheads = ['force'] |             remoteheads = ['force'] | ||||||
|         return remote.unbundle(cg, remoteheads, 'push') |         ret = remote.unbundle(cg, remoteheads, 'push') | ||||||
|     else: |     else: | ||||||
|         return remote.addchangegroup(cg, 'push', repo.url()) |         ret = remote.addchangegroup(cg, 'push', repo.url()) | ||||||
|  |  | ||||||
|  |     phases = remote.listkeys('phases') | ||||||
|  |     if phases: | ||||||
|  |         for head in p_revs: | ||||||
|  |             # update to public | ||||||
|  |             remote.pushkey('phases', hghex(head), '1', '0') | ||||||
|  |  | ||||||
|  |     return ret | ||||||
|  |  | ||||||
| def push(repo, remote, parsed_refs, p_revs): | def push(repo, remote, parsed_refs, p_revs): | ||||||
|     if hasattr(remote, 'canpush') and not remote.canpush(): |     if hasattr(remote, 'canpush') and not remote.canpush(): | ||||||
| @@ -1242,12 +1297,10 @@ def main(args): | |||||||
|             die('unhandled command: %s' % line) |             die('unhandled command: %s' % line) | ||||||
|         sys.stdout.flush() |         sys.stdout.flush() | ||||||
|  |  | ||||||
| def bye(): |  | ||||||
|     if not marks: |  | ||||||
|         return |  | ||||||
|     if not is_tmp: |  | ||||||
|     marks.store() |     marks.store() | ||||||
|     else: |  | ||||||
|  | def bye(): | ||||||
|  |     if is_tmp: | ||||||
|         shutil.rmtree(dirname) |         shutil.rmtree(dirname) | ||||||
|  |  | ||||||
| atexit.register(bye) | atexit.register(bye) | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								test/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								test/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | test-results/ | ||||||
|  | trash directory.*/ | ||||||
|  | .prove | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| RM ?= rm -f | RM ?= rm -f | ||||||
|  |  | ||||||
| T = $(wildcard ../test-*.sh) | T = $(wildcard *.t) | ||||||
| TEST_DIRECTORY := $(CURDIR) | TEST_DIRECTORY := $(CURDIR) | ||||||
|  |  | ||||||
| export TEST_DIRECTORY | export TEST_DIRECTORY | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ then | |||||||
| 	test_done | 	test_done | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| if ! python -c 'import mercurial' | if ! python2 -c 'import mercurial' > /dev/null 2>&1 | ||||||
| then | then | ||||||
| 	skip_all='skipping remote-hg tests; mercurial not available' | 	skip_all='skipping remote-hg tests; mercurial not available' | ||||||
| 	test_done | 	test_done | ||||||
| @@ -54,17 +54,17 @@ hg_log () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| setup () { | setup () { | ||||||
| 	( | 	cat > "$HOME"/.hgrc <<-EOF && | ||||||
| 	echo "[ui]" | 	[ui] | ||||||
| 	echo "username = A U Thor <author@example.com>" | 	username = A U Thor <author@example.com> | ||||||
| 	echo "[defaults]" | 	[defaults] | ||||||
| 	echo "backout = -d \"0 0\"" | 	backout = -d "0 0" | ||||||
| 	echo "commit = -d \"0 0\"" | 	commit = -d "0 0" | ||||||
| 	echo "debugrawcommit = -d \"0 0\"" | 	debugrawcommit = -d "0 0" | ||||||
| 	echo "tag = -d \"0 0\"" | 	tag = -d "0 0" | ||||||
| 	echo "[extensions]" | 	[extensions]" | ||||||
| 	echo "graphlog =" | 	graphlog = | ||||||
| 	) >>"$HOME"/.hgrc && | 	EOF | ||||||
| 	git config --global remote-hg.hg-git-compat true | 	git config --global remote-hg.hg-git-compat true | ||||||
| 	git config --global remote-hg.track-branches true | 	git config --global remote-hg.track-branches true | ||||||
| 
 | 
 | ||||||
| @@ -16,13 +16,13 @@ then | |||||||
| 	test_done | 	test_done | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| if ! python -c 'import mercurial' | if ! python2 -c 'import mercurial' > /dev/null 2>&1 | ||||||
| then | then | ||||||
| 	skip_all='skipping remote-hg tests; mercurial not available' | 	skip_all='skipping remote-hg tests; mercurial not available' | ||||||
| 	test_done | 	test_done | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| if ! python -c 'import hggit' | if ! python2 -c 'import hggit' > /dev/null 2>&1 | ||||||
| then | then | ||||||
| 	skip_all='skipping remote-hg tests; hg-git not available' | 	skip_all='skipping remote-hg tests; hg-git not available' | ||||||
| 	test_done | 	test_done | ||||||
| @@ -91,19 +91,19 @@ git_log () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| setup () { | setup () { | ||||||
| 	( | 	cat > "$HOME"/.hgrc <<-EOF && | ||||||
| 	echo "[ui]" | 	[ui] | ||||||
| 	echo "username = A U Thor <author@example.com>" | 	username = A U Thor <author@example.com> | ||||||
| 	echo "[defaults]" | 	[defaults] | ||||||
| 	echo "backout = -d \"0 0\"" | 	backout = -d "0 0" | ||||||
| 	echo "commit = -d \"0 0\"" | 	commit = -d "0 0" | ||||||
| 	echo "debugrawcommit = -d \"0 0\"" | 	debugrawcommit = -d "0 0" | ||||||
| 	echo "tag = -d \"0 0\"" | 	tag = -d "0 0" | ||||||
| 	echo "[extensions]" | 	[extensions] | ||||||
| 	echo "hgext.bookmarks =" | 	hgext.bookmarks = | ||||||
| 	echo "hggit =" | 	hggit = | ||||||
| 	echo "graphlog =" | 	graphlog = | ||||||
| 	) >>"$HOME"/.hgrc && | 	EOF | ||||||
| 	git config --global receive.denycurrentbranch warn | 	git config --global receive.denycurrentbranch warn | ||||||
| 	git config --global remote-hg.hg-git-compat true | 	git config --global remote-hg.hg-git-compat true | ||||||
| 	git config --global remote-hg.track-branches false | 	git config --global remote-hg.track-branches false | ||||||
| @@ -17,7 +17,7 @@ then | |||||||
| 	test_done | 	test_done | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| if ! python -c 'import mercurial' | if ! python2 -c 'import mercurial' > /dev/null 2>&1 | ||||||
| then | then | ||||||
| 	skip_all='skipping remote-hg tests; mercurial not available' | 	skip_all='skipping remote-hg tests; mercurial not available' | ||||||
| 	test_done | 	test_done | ||||||
| @@ -25,7 +25,7 @@ fi | |||||||
| 
 | 
 | ||||||
| check () { | check () { | ||||||
| 	echo $3 > expected && | 	echo $3 > expected && | ||||||
| 	git --git-dir=$1/.git log --format='%s' -1 $2 >actual | 	git --git-dir=$1/.git log --format='%s' -1 $2 > actual && | ||||||
| 	test_cmp expected actual | 	test_cmp expected actual | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -53,6 +53,17 @@ check_bookmark () { | |||||||
| 	fi | 	fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | check_files () { | ||||||
|  | 	git --git-dir=$1/.git ls-files > actual && | ||||||
|  | 	if test $# -gt 1 | ||||||
|  | 	then | ||||||
|  | 		printf "%s\n" "$2" > expected | ||||||
|  | 	else | ||||||
|  | 		> expected | ||||||
|  | 	fi && | ||||||
|  | 	test_cmp expected actual | ||||||
|  | } | ||||||
|  | 
 | ||||||
| check_push () { | check_push () { | ||||||
| 	expected_ret=$1 ret=0 ref_ret=0 | 	expected_ret=$1 ret=0 ref_ret=0 | ||||||
| 
 | 
 | ||||||
| @@ -92,12 +103,12 @@ check_push () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| setup () { | setup () { | ||||||
| 	( | 	cat > "$HOME"/.hgrc <<-EOF && | ||||||
| 	echo "[ui]" | 	[ui] | ||||||
| 	echo "username = H G Wells <wells@example.com>" | 	username = H G Wells <wells@example.com> | ||||||
| 	echo "[extensions]" | 	[extensions] | ||||||
| 	echo "mq =" | 	mq = | ||||||
| 	) >>"$HOME"/.hgrc && | 	EOF | ||||||
| 
 | 
 | ||||||
| 	GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" && | 	GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" && | ||||||
| 	GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" && | 	GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" && | ||||||
| @@ -106,17 +117,18 @@ setup () { | |||||||
| 
 | 
 | ||||||
| setup | setup | ||||||
| 
 | 
 | ||||||
| test_expect_success 'cloning' ' | test_expect_success 'setup' ' | ||||||
| 	test_when_finished "rm -rf gitrepo*" && |  | ||||||
| 
 |  | ||||||
| 	( | 	( | ||||||
| 	hg init hgrepo && | 	hg init hgrepo && | ||||||
| 	cd hgrepo && | 	cd hgrepo && | ||||||
| 	echo zero > content && | 	echo zero > content && | ||||||
| 	hg add content && | 	hg add content && | ||||||
| 	hg commit -m zero | 	hg commit -m zero | ||||||
| 	) && | 	) | ||||||
|  | ' | ||||||
| 
 | 
 | ||||||
|  | test_expect_success 'cloning' ' | ||||||
|  | 	test_when_finished "rm -rf gitrepo*" && | ||||||
| 	git clone "hg::hgrepo" gitrepo && | 	git clone "hg::hgrepo" gitrepo && | ||||||
| 	check gitrepo HEAD zero | 	check gitrepo HEAD zero | ||||||
| ' | ' | ||||||
| @@ -772,4 +784,244 @@ test_expect_success 'remote double failed push' ' | |||||||
| 	) | 	) | ||||||
| ' | ' | ||||||
| 
 | 
 | ||||||
|  | test_expect_success 'clone remote with null bookmark, then push' ' | ||||||
|  | 	test_when_finished "rm -rf gitrepo* hgrepo*" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 	echo a > a && | ||||||
|  | 	hg add a && | ||||||
|  | 	hg commit -m a && | ||||||
|  | 	hg bookmark -r null bookmark | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	check gitrepo HEAD a && | ||||||
|  | 	cd gitrepo && | ||||||
|  | 	git checkout --quiet -b bookmark && | ||||||
|  | 	git remote -v && | ||||||
|  | 	echo b > b && | ||||||
|  | 	git add b && | ||||||
|  | 	git commit -m b && | ||||||
|  | 	git push origin bookmark | ||||||
|  | 	) | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'notes' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 	echo one > content && | ||||||
|  | 	hg add content && | ||||||
|  | 	hg commit -m one && | ||||||
|  | 	echo two > content && | ||||||
|  | 	hg commit -m two | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	hg -R hgrepo log --template "{node}\n\n" > expected && | ||||||
|  | 	git --git-dir=gitrepo/.git log --pretty="tformat:%N" --notes=hg > actual && | ||||||
|  | 	test_cmp expected actual | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_failure 'push updates notes' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 	echo one > content && | ||||||
|  | 	hg add content && | ||||||
|  | 	hg commit -m one | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	cd gitrepo && | ||||||
|  | 	echo two > content && | ||||||
|  | 	git commit -a -m two | ||||||
|  | 	git push | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	hg -R hgrepo log --template "{node}\n\n" > expected && | ||||||
|  | 	git --git-dir=gitrepo/.git log --pretty="tformat:%N" --notes=hg > actual && | ||||||
|  | 	test_cmp expected actual | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'pull tags' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 	echo one > content && | ||||||
|  | 	hg add content && | ||||||
|  | 	hg commit -m one | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 
 | ||||||
|  | 	(cd hgrepo && hg tag v1.0) && | ||||||
|  | 	(cd gitrepo && git pull) && | ||||||
|  | 
 | ||||||
|  | 	echo "v1.0" > expected && | ||||||
|  | 	git --git-dir=gitrepo/.git tag > actual && | ||||||
|  | 	test_cmp expected actual | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'push merged named branch' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 	echo one > content && | ||||||
|  | 	hg add content && | ||||||
|  | 	hg commit -m one && | ||||||
|  | 	hg branch feature && | ||||||
|  | 	echo two > content && | ||||||
|  | 	hg commit -m two && | ||||||
|  | 	hg update default && | ||||||
|  | 	echo three > content && | ||||||
|  | 	hg commit -m three | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	cd gitrepo && | ||||||
|  | 	git merge -m Merge -Xtheirs origin/branches/feature && | ||||||
|  | 	git push | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	cat > expected <<-EOF | ||||||
|  | 	Merge | ||||||
|  | 	three | ||||||
|  | 	two | ||||||
|  | 	one | ||||||
|  | 	EOF | ||||||
|  | 	hg -R hgrepo log --template "{desc}\n" > actual && | ||||||
|  | 	test_cmp expected actual | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'light tag sets author' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 	echo one > content && | ||||||
|  | 	hg add content && | ||||||
|  | 	hg commit -m one | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	cd gitrepo && | ||||||
|  | 	git tag v1.0 && | ||||||
|  | 	git push --tags | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	echo "C O Mitter <committer@example.com>" > expected && | ||||||
|  | 	hg -R hgrepo log --template "{author}\n" -r tip > actual && | ||||||
|  | 	test_cmp expected actual | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'push tag different branch' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 	echo one > content && | ||||||
|  | 	hg add content && | ||||||
|  | 	hg commit -m one | ||||||
|  | 	hg branch feature && | ||||||
|  | 	echo two > content && | ||||||
|  | 	hg commit -m two | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	cd gitrepo && | ||||||
|  | 	git branch && | ||||||
|  | 	git checkout branches/feature && | ||||||
|  | 	git tag v1.0 && | ||||||
|  | 	git push --tags | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	echo feature > expected && | ||||||
|  | 	hg -R hgrepo log --template="{branch}\n" -r tip > actual && | ||||||
|  | 	test_cmp expected actual | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'cloning a removed file works' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 
 | ||||||
|  | 	echo test > test_file && | ||||||
|  | 	hg add test_file && | ||||||
|  | 	hg commit -m add && | ||||||
|  | 
 | ||||||
|  | 	hg rm test_file && | ||||||
|  | 	hg commit -m remove | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	check_files gitrepo | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'cloning a file replaced with a directory' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 
 | ||||||
|  | 	echo test > dir_or_file && | ||||||
|  | 	hg add dir_or_file && | ||||||
|  | 	hg commit -m add && | ||||||
|  | 
 | ||||||
|  | 	hg rm dir_or_file && | ||||||
|  | 	mkdir dir_or_file && | ||||||
|  | 	echo test > dir_or_file/test_file && | ||||||
|  | 	hg add dir_or_file/test_file && | ||||||
|  | 	hg commit -m replase | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	check_files gitrepo "dir_or_file/test_file" | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | test_expect_success 'clone replace directory with a file' ' | ||||||
|  | 	test_when_finished "rm -rf hgrepo gitrepo" && | ||||||
|  | 
 | ||||||
|  | 	( | ||||||
|  | 	hg init hgrepo && | ||||||
|  | 	cd hgrepo && | ||||||
|  | 
 | ||||||
|  | 	mkdir dir_or_file && | ||||||
|  | 	echo test > dir_or_file/test_file && | ||||||
|  | 	hg add dir_or_file/test_file && | ||||||
|  | 	hg commit -m add && | ||||||
|  | 
 | ||||||
|  | 	hg rm dir_or_file/test_file && | ||||||
|  | 	echo test > dir_or_file && | ||||||
|  | 	hg add dir_or_file && | ||||||
|  | 	hg commit -m add && | ||||||
|  | 
 | ||||||
|  | 	hg rm dir_or_file | ||||||
|  | 	) && | ||||||
|  | 
 | ||||||
|  | 	git clone "hg::hgrepo" gitrepo && | ||||||
|  | 	check_files gitrepo "dir_or_file" | ||||||
|  | ' | ||||||
|  | 
 | ||||||
| test_done | test_done | ||||||
		Reference in New Issue
	
	Block a user