mirror of
				https://github.com/mnauw/git-remote-hg.git
				synced 2025-11-03 18:15:49 +01:00 
			
		
		
		
	Compare commits
	
		
			183 Commits
		
	
	
		
			topic_note
			...
			v1.0.4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					426ed618b2 | ||
| 
						 | 
					5f34d049b9 | ||
| 
						 | 
					ea7e9bf31a | ||
| 
						 | 
					a3a36883c5 | ||
| 
						 | 
					0fdd28319a | ||
| 
						 | 
					dfa3ad5fca | ||
| 
						 | 
					ebd5bdb111 | ||
| 
						 | 
					00ac711fb2 | ||
| 
						 | 
					aadc899982 | ||
| 
						 | 
					4d38bff053 | ||
| 
						 | 
					a8cd6a92b3 | ||
| 
						 | 
					a08ad9d2b4 | ||
| 
						 | 
					8c08b6de21 | ||
| 
						 | 
					949345fb11 | ||
| 
						 | 
					0d49f75131 | ||
| 
						 | 
					7159e4a030 | ||
| 
						 | 
					cdcd70b453 | ||
| 
						 | 
					f5c38f3a59 | ||
| 
						 | 
					3b11156e69 | ||
| 
						 | 
					afc1f3a2c2 | ||
| 
						 | 
					e596a5f457 | ||
| 
						 | 
					ec654d4682 | ||
| 
						 | 
					7913920a97 | ||
| 
						 | 
					da60201ae3 | ||
| 
						 | 
					704869df29 | ||
| 
						 | 
					5769e965eb | ||
| 
						 | 
					1ee28bd233 | ||
| 
						 | 
					1796289df3 | ||
| 
						 | 
					929ae262f5 | ||
| 
						 | 
					4328aa1c19 | ||
| 
						 | 
					919678be4a | ||
| 
						 | 
					ac8f659620 | ||
| 
						 | 
					28ed63b707 | ||
| 
						 | 
					dc91c58e1c | ||
| 
						 | 
					46178f546a | ||
| 
						 | 
					4c0e8e6439 | ||
| 
						 | 
					59b5a8c848 | ||
| 
						 | 
					be2445963b | ||
| 
						 | 
					8b4bfe7e87 | ||
| 
						 | 
					741b440fcc | ||
| 
						 | 
					03b1ac9845 | ||
| 
						 | 
					f3a8546406 | ||
| 
						 | 
					ccc9e55b7e | ||
| 
						 | 
					b516aa9326 | ||
| 
						 | 
					08626200d0 | ||
| 
						 | 
					b60eb47173 | ||
| 
						 | 
					76162ce148 | ||
| 
						 | 
					7ae03f7640 | ||
| 
						 | 
					95da53badd | ||
| 
						 | 
					a0608664ca | ||
| 
						 | 
					9d6d135855 | ||
| 
						 | 
					60a6c7b36d | ||
| 
						 | 
					74d1aa14ac | ||
| 
						 | 
					1d85449b0b | ||
| 
						 | 
					fe8b8c1a61 | ||
| 
						 | 
					510441bba9 | ||
| 
						 | 
					fa3484e08b | ||
| 
						 | 
					d1544e2ccd | ||
| 
						 | 
					153a216f47 | ||
| 
						 | 
					b3cdbe8e96 | ||
| 
						 | 
					d11509cab7 | ||
| 
						 | 
					4d01165b1b | ||
| 
						 | 
					a030d603ac | ||
| 
						 | 
					3d4a5a6d7e | ||
| 
						 | 
					7fb9d9b642 | ||
| 
						 | 
					fad59f53eb | ||
| 
						 | 
					e17e147fb1 | ||
| 
						 | 
					4878023a8b | ||
| 
						 | 
					0dfae24d21 | ||
| 
						 | 
					c7dbb5612b | ||
| 
						 | 
					cc4e5659d9 | ||
| 
						 | 
					2c993b3433 | ||
| 
						 | 
					4944a384cd | ||
| 
						 | 
					f29c42c645 | ||
| 
						 | 
					7b7c65f72d | ||
| 
						 | 
					cee3ed7c00 | ||
| 
						 | 
					01c9a981c7 | ||
| 
						 | 
					d0a5888580 | ||
| 
						 | 
					a5dfc9025b | ||
| 
						 | 
					4d337cff06 | ||
| 
						 | 
					5cc271ef18 | ||
| 
						 | 
					c8fff2cd06 | ||
| 
						 | 
					c95fba3c18 | ||
| 
						 | 
					aaef56a2a3 | ||
| 
						 | 
					a16c69a99c | ||
| 
						 | 
					00e95fd8df | ||
| 
						 | 
					5bf7aad6e3 | ||
| 
						 | 
					9b8e0ec2c0 | ||
| 
						 | 
					b309562574 | ||
| 
						 | 
					e25d3d78cd | ||
| 
						 | 
					ed5a70706a | ||
| 
						 | 
					0faf2c9189 | ||
| 
						 | 
					ada49422a7 | ||
| 
						 | 
					580cea0d31 | ||
| 
						 | 
					1f376e437f | ||
| 
						 | 
					4108665799 | ||
| 
						 | 
					fc28115a53 | ||
| 
						 | 
					e3009683f8 | ||
| 
						 | 
					54cec85f94 | ||
| 
						 | 
					5ad322c54d | ||
| 
						 | 
					13bbc8a342 | ||
| 
						 | 
					673b50d3f4 | ||
| 
						 | 
					35ecb45fda | ||
| 
						 | 
					1456e68129 | ||
| 
						 | 
					de95133416 | ||
| 
						 | 
					e0b752be8f | ||
| 
						 | 
					f050de1bcc | ||
| 
						 | 
					0bf3db826b | ||
| 
						 | 
					3698638e98 | ||
| 
						 | 
					765f9ae287 | ||
| 
						 | 
					5ddcdd33ec | ||
| 
						 | 
					435373ee83 | ||
| 
						 | 
					5e96683f67 | ||
| 
						 | 
					144f48df44 | ||
| 
						 | 
					ad36a25064 | ||
| 
						 | 
					679e016943 | ||
| 
						 | 
					9f6c541a2c | ||
| 
						 | 
					476ffcbde0 | ||
| 
						 | 
					76be528c0d | ||
| 
						 | 
					6c2f4d8ff4 | ||
| 
						 | 
					e9c37f78d8 | ||
| 
						 | 
					dfa6910cab | ||
| 
						 | 
					2ab9ae9073 | ||
| 
						 | 
					f21923b052 | ||
| 
						 | 
					45866dbeba | ||
| 
						 | 
					eaa9361ab0 | ||
| 
						 | 
					f0e4c95bf5 | ||
| 
						 | 
					e467b22dd3 | ||
| 
						 | 
					40c9eafcc9 | ||
| 
						 | 
					0bfbc0da4b | ||
| 
						 | 
					a1ca279d92 | ||
| 
						 | 
					e19dd84571 | ||
| 
						 | 
					1d94ba2d42 | ||
| 
						 | 
					85b585b824 | ||
| 
						 | 
					e8c88c70d9 | ||
| 
						 | 
					a35f93cbc1 | ||
| 
						 | 
					a59e1246a2 | ||
| 
						 | 
					cbbbaddc41 | ||
| 
						 | 
					5d429d2da1 | ||
| 
						 | 
					94bb2488e8 | ||
| 
						 | 
					e759d5232d | ||
| 
						 | 
					af96a84c98 | ||
| 
						 | 
					2ce962c5ab | ||
| 
						 | 
					8ac5532eb1 | ||
| 
						 | 
					9528e757d3 | ||
| 
						 | 
					628c45a4a9 | ||
| 
						 | 
					55689eb0a8 | ||
| 
						 | 
					7be9bf3db4 | ||
| 
						 | 
					20e923cf91 | ||
| 
						 | 
					a7ea76788c | ||
| 
						 | 
					5999a10519 | ||
| 
						 | 
					0853bc0230 | ||
| 
						 | 
					b3fccddd9f | ||
| 
						 | 
					7f99aa2565 | ||
| 
						 | 
					63c742e4a6 | ||
| 
						 | 
					6cff0327aa | ||
| 
						 | 
					5acd0028b4 | ||
| 
						 | 
					4f910f65d9 | ||
| 
						 | 
					7d82847d52 | ||
| 
						 | 
					37cd2f24ac | ||
| 
						 | 
					585e36edb9 | ||
| 
						 | 
					dd08e25665 | ||
| 
						 | 
					5905eb2231 | ||
| 
						 | 
					ebdd2f32ab | ||
| 
						 | 
					f8709175bf | ||
| 
						 | 
					38741e0bbf | ||
| 
						 | 
					e2f68018cd | ||
| 
						 | 
					e62984edde | ||
| 
						 | 
					7b53adef7b | ||
| 
						 | 
					858ca2c68a | ||
| 
						 | 
					093cb8ba94 | ||
| 
						 | 
					cd742bee40 | ||
| 
						 | 
					1d0c78eebc | ||
| 
						 | 
					8e81bc8515 | ||
| 
						 | 
					bd2e030cb0 | ||
| 
						 | 
					410e0d74ec | ||
| 
						 | 
					93dd913590 | ||
| 
						 | 
					418af65bf0 | ||
| 
						 | 
					d7db83bd2c | ||
| 
						 | 
					3ea455e7e7 | ||
| 
						 | 
					fd210eb002 | ||
| 
						 | 
					b852ee18b2 | ||
| 
						 | 
					c3f02d39ad | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					/build/
 | 
				
			||||||
 | 
					/dist/
 | 
				
			||||||
 | 
					/git_remote_hg.egg-info/
 | 
				
			||||||
							
								
								
									
										36
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,28 +1,20 @@
 | 
				
			|||||||
language: python
 | 
					dist: xenial
 | 
				
			||||||
 | 
					language: minimal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install:
 | 
					cache:
 | 
				
			||||||
  - if [ "$HG_VERSION" != "dev" ];
 | 
					  directories:
 | 
				
			||||||
    then pip install -q Mercurial${HG_VERSION+==$HG_VERSION};
 | 
					    - $HOME/.cache/git-remote-hg
 | 
				
			||||||
    else pip install -q http://selenic.com/repo/hg/archive/tip.tar.gz;
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
  - pip install -q dulwich hg-git==0.6.1 || true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
before_script:
 | 
					 | 
				
			||||||
  - hg --version || true
 | 
					 | 
				
			||||||
  - pip show hg-git dulwich
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
script:
 | 
					script:
 | 
				
			||||||
  - make test
 | 
					  - ./tools/check-versions hg:$HG_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
matrix:
 | 
					matrix:
 | 
				
			||||||
  include:
 | 
					  include:
 | 
				
			||||||
    - env: HG_VERSION=2.9.1
 | 
					    - env:
 | 
				
			||||||
    - env: HG_VERSION=2.8.2
 | 
					    - env: HG_VERSION=@
 | 
				
			||||||
    - env: HG_VERSION=2.7.2
 | 
					    - env: HG_VERSION=5.0
 | 
				
			||||||
    - env: HG_VERSION=3.0
 | 
					    - env: HG_VERSION=4.9
 | 
				
			||||||
    - env: HG_VERSION=3.5.2
 | 
					    - env: HG_VERSION=4.8
 | 
				
			||||||
    - env: HG_VERSION=3.6.3
 | 
					    - env: HG_VERSION=4.7
 | 
				
			||||||
    - env: HG_VERSION=3.7
 | 
					    - env: HG_VERSION=4.6
 | 
				
			||||||
    - env: HG_VERSION=dev
 | 
					    - env: HG_VERSION=4.5
 | 
				
			||||||
    - python: 2.7
 | 
					 | 
				
			||||||
    - python: 2.6
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										43
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								Makefile
									
									
									
									
									
								
							@@ -3,7 +3,28 @@ prefix := $(HOME)
 | 
				
			|||||||
bindir := $(prefix)/bin
 | 
					bindir := $(prefix)/bin
 | 
				
			||||||
mandir := $(prefix)/share/man/man1
 | 
					mandir := $(prefix)/share/man/man1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all: doc
 | 
					all: build doc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					build:
 | 
				
			||||||
 | 
						if [ -n "$$PYTHON" ] && "$$PYTHON" -c 'import mercurial' 2> /dev/null ; then \
 | 
				
			||||||
 | 
							: Use chosen Python version ; \
 | 
				
			||||||
 | 
						elif python3 -c 'import mercurial' 2> /dev/null ; then \
 | 
				
			||||||
 | 
							PYTHON=python3 ; \
 | 
				
			||||||
 | 
						elif python2 -c 'import mercurial' 2> /dev/null ; then \
 | 
				
			||||||
 | 
							PYTHON=python2 ; \
 | 
				
			||||||
 | 
						elif python -c 'import mercurial' 2> /dev/null ; then \
 | 
				
			||||||
 | 
							PYTHON=python ; \
 | 
				
			||||||
 | 
						else \
 | 
				
			||||||
 | 
							echo 'Python with Mercurial not available' >&2 ; \
 | 
				
			||||||
 | 
							exit 1 ; \
 | 
				
			||||||
 | 
						fi ; \
 | 
				
			||||||
 | 
						mkdir -p bin ; \
 | 
				
			||||||
 | 
						for s in git-remote-hg git-hg-helper ; do \
 | 
				
			||||||
 | 
							printf "%s\n" "#!/usr/bin/env $$PYTHON" > "bin/$$s" ; \
 | 
				
			||||||
 | 
							tail -n +2 "./$$s" >> "bin/$$s" ; \
 | 
				
			||||||
 | 
							chmod 755 "bin/$$s" ; \
 | 
				
			||||||
 | 
							touch -r "./$$s" "bin/$$s" ; \
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
doc: doc/git-remote-hg.1
 | 
					doc: doc/git-remote-hg.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,15 +36,29 @@ doc/git-remote-hg.1: doc/git-remote-hg.txt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	$(RM) doc/git-remote-hg.1
 | 
						$(RM) doc/git-remote-hg.1
 | 
				
			||||||
 | 
						$(RM) -r bin/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
D = $(DESTDIR)
 | 
					D = $(DESTDIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install:
 | 
					install: build
 | 
				
			||||||
	install -d -m 755 $(D)$(bindir)/
 | 
						install -d -m 755 $(D)$(bindir)/
 | 
				
			||||||
	install -m 755 git-remote-hg $(D)$(bindir)/git-remote-hg
 | 
						install -m 755 bin/git-remote-hg $(D)$(bindir)/git-remote-hg
 | 
				
			||||||
 | 
						install -m 755 bin/git-hg-helper $(D)$(bindir)/git-hg-helper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install-doc: doc
 | 
					install-doc: doc
 | 
				
			||||||
	install -d -m 755 $(D)$(mandir)/
 | 
						install -d -m 755 $(D)$(mandir)/
 | 
				
			||||||
	install -m 644 doc/git-remote-hg.1 $(D)$(mandir)/git-remote-hg.1
 | 
						install -m 644 doc/git-remote-hg.1 $(D)$(mandir)/git-remote-hg.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: all test install install-doc clean
 | 
					pypi:
 | 
				
			||||||
 | 
						version=`git describe --tags ${REV}` && \
 | 
				
			||||||
 | 
							sed -i "s/version = .*/version = '$$version'[1:]/" setup.py
 | 
				
			||||||
 | 
						-rm -rf dist build
 | 
				
			||||||
 | 
						python setup.py sdist bdist_wheel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pypi-upload:
 | 
				
			||||||
 | 
						twine upload dist/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pypi-test:
 | 
				
			||||||
 | 
						twine upload --repository-url https://test.pypi.org/legacy/ dist/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: all build test install install-doc clean pypy pypy-upload
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										300
									
								
								README.asciidoc
									
									
									
									
									
								
							
							
						
						
									
										300
									
								
								README.asciidoc
									
									
									
									
									
								
							@@ -9,14 +9,38 @@ git clone "hg::http://selenic.com/repo/hello"
 | 
				
			|||||||
To enable this, simply add the 'git-remote-hg' script anywhere in your `$PATH`:
 | 
					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
 | 
					wget https://raw.github.com/mnauw/git-remote-hg/master/git-remote-hg -O ~/bin/git-remote-hg
 | 
				
			||||||
chmod +x ~/bin/git-remote-hg
 | 
					chmod +x ~/bin/git-remote-hg
 | 
				
			||||||
--------------------------------------
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In Windows, you also need to put and an NTFS symbolic link named `python2.exe` somewhere
 | 
				
			||||||
 | 
					on your `$PATH` pointing to your Python 2 executable:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					mklink <path to link> <path to python.exe>
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
That's it :)
 | 
					That's it :)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Obviously you will need Mercurial installed.
 | 
					Obviously you will need Mercurial installed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					****
 | 
				
			||||||
 | 
					At present, this "working copy"/fork <<add-features, adds the following features>>
 | 
				
			||||||
 | 
					(and I would prefer it is indeed rather a "working copy"
 | 
				
			||||||
 | 
					to be appropriately merged upstream):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* eliminates a number of <<limitations, limitations>> as mentioned below
 | 
				
			||||||
 | 
					* properly annotates copy/rename when pushing new commits to Mercurial
 | 
				
			||||||
 | 
					* adds a 'git-hg-helper' script than can aid in the git-hg interaction workflow
 | 
				
			||||||
 | 
					* provides enhanced bidirectional git-hg safety
 | 
				
			||||||
 | 
					* avoids clutter of `refs/hg/...` by keeping these implementation details really private
 | 
				
			||||||
 | 
					* more robust and efficient fetching, especially so when fetching or cloning from multiple
 | 
				
			||||||
 | 
					  Mercurial clones which will only process changesets not yet fetched from elsewhere
 | 
				
			||||||
 | 
					  (as opposed to processing everything all over again)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See sections below or sidemarked notes for more details.
 | 
				
			||||||
 | 
					****
 | 
				
			||||||
 | 
					
 | 
				
			||||||
== Configuration ==
 | 
					== Configuration ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you want to see Mercurial revisions as Git commit notes:
 | 
					If you want to see Mercurial revisions as Git commit notes:
 | 
				
			||||||
@@ -91,6 +115,23 @@ 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
 | 
					so you might have better luck simply specifying the username and password in
 | 
				
			||||||
the URL.
 | 
					the URL.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Submodules ===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Hg repositories can be used as git submodule, but this requires to allow the hg procotol to be used by git submodule commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					git config protocol.hg.allow always
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Or adding manually the following to your git configuration file:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					[protocol "hg"]
 | 
				
			||||||
 | 
					        allow = always
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This can be done per-repository, every time after a clone, or globally in the global .gitconfig (using the --global command-line option).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
=== Caveats ===
 | 
					=== Caveats ===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The only major incompatibility is that Git octopus merges (a merge with more
 | 
					The only major incompatibility is that Git octopus merges (a merge with more
 | 
				
			||||||
@@ -107,17 +148,31 @@ 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
 | 
					reopen. Additionally in certain rare situations a synchronization issue can
 | 
				
			||||||
occur (https://github.com/felipec/git/issues/65[Bug #65]).
 | 
					occur (https://github.com/felipec/git/issues/65[Bug #65]).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[limitations]]
 | 
				
			||||||
Limitations of the remote-helpers' framework apply. In particular, these
 | 
					Limitations of the remote-helpers' framework apply. In particular, these
 | 
				
			||||||
commands don't work:
 | 
					commands don't work:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `git push origin :branch-to-delete`
 | 
					* `git push origin :branch-to-delete`
 | 
				
			||||||
* `git push origin old:new` (it will push 'old') (patches available)
 | 
					
 | 
				
			||||||
* `git push --dry-run origin branch` (it will push) (patches available)
 | 
					****
 | 
				
			||||||
 | 
					Another limitation is that if `git log` reports a rename, this will not survive
 | 
				
			||||||
 | 
					the push and Mercurial will not be aware of a rename (and similarly so for copy).
 | 
				
			||||||
 | 
					Though Mercurial would know about it if you *manually* ran `git-format-patch`
 | 
				
			||||||
 | 
					followed by a `hg apply -s`, which is not the nice way to go obviously.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Actually, scratch the limitations above ascribed to the remote-helpers framework.
 | 
				
			||||||
 | 
					They are not limitations of the framework, but are due to how the original
 | 
				
			||||||
 | 
					implementation of 'git-remote-hg' interacts with it.
 | 
				
			||||||
 | 
					Using the remote-helpers framework in only a slightly different way has none
 | 
				
			||||||
 | 
					of the above limitations.  See the <<no-limitations, relevant section>>
 | 
				
			||||||
 | 
					below for more details.
 | 
				
			||||||
 | 
					****
 | 
				
			||||||
 | 
					
 | 
				
			||||||
== Other projects ==
 | 
					== Other projects ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There are other 'git-remote-hg' projects out there, do not confuse this one,
 | 
					There are other 'git-remote-hg' projects out there, do not confuse this one,
 | 
				
			||||||
this is the one distributed officially by the Git project:
 | 
					this is the one distributed officially by the Git project
 | 
				
			||||||
 | 
					(_though actually no longer so nowadays_):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* https://github.com/msysgit/msysgit/wiki/Guide-to-git-remote-hg[msysgit's git-remote-hg]
 | 
					* 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]
 | 
					* https://github.com/rfk/git-remote-hg[rfk's git-remote-hg]
 | 
				
			||||||
@@ -125,7 +180,240 @@ this is the one distributed officially by the Git project:
 | 
				
			|||||||
For a comparison between these and other projects go
 | 
					For a comparison between these and other projects go
 | 
				
			||||||
https://github.com/felipec/git/wiki/Comparison-of-git-remote-hg-alternatives[here].
 | 
					https://github.com/felipec/git/wiki/Comparison-of-git-remote-hg-alternatives[here].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[no-limitations]]
 | 
				
			||||||
 | 
					== Limitations (or not) ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If interested in some of technical details behind this explanation, then also
 | 
				
			||||||
 | 
					see the relevant section in 'git-remote-hg' manpage.  Otherwise, the general
 | 
				
			||||||
 | 
					idea is presented here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					More precisely and simply, the <<limitations, mentioned limitations>> are indeed
 | 
				
			||||||
 | 
					limitations of the `export` capability of
 | 
				
			||||||
 | 
					https://www.kernel.org/pub/software/scm/git/docs/gitremote-helpers.html[gitremote-helpers(1)]
 | 
				
			||||||
 | 
					framework.  However, the framework also supports a `push` capability and when this
 | 
				
			||||||
 | 
					is used appropriately in the remote helper the aforementioned limitations do not apply.
 | 
				
			||||||
 | 
					In the case of `export` capability, git-core will internally invoke `git-fast-export`
 | 
				
			||||||
 | 
					and the helper will process this data and hand over generated changesets to Mercurial.
 | 
				
			||||||
 | 
					In the case of `push` capability, git informs the helper what (refs) should go where,
 | 
				
			||||||
 | 
					and the helper is free to ponder about this and take the required action, such as
 | 
				
			||||||
 | 
					to invoke `git-fast-export` itself (with suitable options) and process its output
 | 
				
			||||||
 | 
					the same way as before (and over to Mercurial).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And so;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `git push origin :branch-to-delete` will delete the bookmark `branch-to-delete` on remote
 | 
				
			||||||
 | 
					* `git push --dry-run origin branch` will not touch the remote
 | 
				
			||||||
 | 
					(or any local state, except for local helper proxy repo)
 | 
				
			||||||
 | 
					* `git push origin old:new` will push `old` onto `new` in the remote
 | 
				
			||||||
 | 
					* `git push origin <history-with-copy/rename>` will push copy/rename aware Mercurial revisions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To tweak how 'git-remote-hg' decides on a copy/rename, use e.g:
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.fast-export-options '-M -C -C'
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[add-features]]
 | 
				
			||||||
 | 
					== Additional Features ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Miscellaneous Tweaks ===
 | 
				
			||||||
 | 
					Other than <<no-limitations, removing the limitations>> as mentioned above,
 | 
				
			||||||
 | 
					a number of issues (either so reported in
 | 
				
			||||||
 | 
					https://github.com/felipec/git-remote-hg/issues[issue tracking] or not) have been
 | 
				
			||||||
 | 
					addressed here, e.g. notes handling, `fetch --prune` support, correctly fetching
 | 
				
			||||||
 | 
					after a `strip` on remote repo, tracking remote changes to import (if any) in a
 | 
				
			||||||
 | 
					safe, robust and efficient way, etc.  Some of these have been highlighted above.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example, the `refs/hg/...` refs are really an implementation detail
 | 
				
			||||||
 | 
					that need not clutter up the (visible) ref space.  So, in as much as they
 | 
				
			||||||
 | 
					are still relevant, these are now kept elsewhere out of sight.
 | 
				
			||||||
 | 
					If somehow your workflow relies on having these in the old place:
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.show-private-refs true
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					More importantly, a significantly more efficient workflow is achieved using
 | 
				
			||||||
 | 
					one set of shared marks files for all remotes (which also forces a local repo
 | 
				
			||||||
 | 
					to use an internal proxy clone).
 | 
				
			||||||
 | 
					The practical consequence is that fetching from a newly added remote hg repo
 | 
				
			||||||
 | 
					does not require another (lengthy) complete import
 | 
				
			||||||
 | 
					(as the original clone) but will only fetch additional changesets (if any).
 | 
				
			||||||
 | 
					The same goes for subsequent fetching from any hg remote; what was fetched
 | 
				
			||||||
 | 
					and imported from some remote need not be imported again from another.
 | 
				
			||||||
 | 
					Operating in this shared mode also has the added advantage
 | 
				
			||||||
 | 
					of correctly pushing after a `strip` on a remote.
 | 
				
			||||||
 | 
					This shared-marks-files behaviour is the default on a fresh repo clone.  It can
 | 
				
			||||||
 | 
					also be enabled on an existing one by the following setting.
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.shared-marks true
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					Note, however, that one should then perform a fetch from each relevant remote
 | 
				
			||||||
 | 
					to fully complete the conversion (prior to subsequent pushing).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Some Mercurial names (of branches, bookmarks, tags) may not be a valid git
 | 
				
			||||||
 | 
					refname. See e.g. `man git-check-ref-format` for a rather involved set of rules.
 | 
				
			||||||
 | 
					Moreover, while a slash `/` is allowed, it is not supported to have both a `parent`
 | 
				
			||||||
 | 
					and `parent/child` branch (though only the latter is allowed). Even though
 | 
				
			||||||
 | 
					it is not quite (bidirectionally) safe, a (percentage) URL encoding
 | 
				
			||||||
 | 
					(with some additional twist) is performed to obtain sane git refnames, at least
 | 
				
			||||||
 | 
					so for most cases.  If some nasty cases still slip through, then likely only
 | 
				
			||||||
 | 
					a few instances (out of a whole Mercurial repo) are
 | 
				
			||||||
 | 
					problematic.  This could be handled by a single-branch clone and/or configuring
 | 
				
			||||||
 | 
					a suitable refspec.  However, it might be more convenient to simply filter out a
 | 
				
			||||||
 | 
					few unimportant pesky cases, which can be done by configuring a regural
 | 
				
			||||||
 | 
					expression in following setting:
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config remote-hg.ignore-name nasty/nested/name
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					Recall also that a config setting can be provided at clone time
 | 
				
			||||||
 | 
					(command line using `--config` option).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.remove-username-quotes false
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By default, for backwards compatibility with earlier versions,
 | 
				
			||||||
 | 
					git-remote-hg removes quotation marks from git usernames
 | 
				
			||||||
 | 
					(e.g. 'Raffaello "Raphael" Sanzio da Urbino <raphael@example.com>'
 | 
				
			||||||
 | 
					would become 'Raffaello Raphael Sanzio da Urbino
 | 
				
			||||||
 | 
					<raphael@example.com>').  This breaks round-trip compatibility; a git
 | 
				
			||||||
 | 
					commit by an author with quotes would become an hg commit without,
 | 
				
			||||||
 | 
					and if re-imported into git, would get a different SHA1.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To restore round-trip compatibility (at the cost of backwards
 | 
				
			||||||
 | 
					compatibility with commits converted by older versions of
 | 
				
			||||||
 | 
					git-remote-hg), turn 'remote-hg.remove-username-quotes' off.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Helper Commands ===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Beyond that, a 'git-hg-helper' script has been added that can aid in the git-hg
 | 
				
			||||||
 | 
					interaction workflow with a number of subcommands that are not in the purview of
 | 
				
			||||||
 | 
					a remote helper.  This is similar to e.g. 'git-svn' being a separate program
 | 
				
			||||||
 | 
					altogether.  These subcommands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* provide conversion from a hg changeset id to a git commit hash, or vice versa
 | 
				
			||||||
 | 
					* provide consistency and cleanup maintenance on internal `git-remote-hg` metadata marks
 | 
				
			||||||
 | 
					* provide optimization of git marks of a fetch-only remote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See the helper script commands' help description for further details.
 | 
				
			||||||
 | 
					It should simply be installed (`$PATH` accessible) next to 'git-remote-hg'.
 | 
				
			||||||
 | 
					Following git alias is probably also convenient as it allows invoking the helper
 | 
				
			||||||
 | 
					as `git hg`:
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global alias.hg '!git-hg-helper'
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					With that in place, running `git hg gc <remote>` after initial fetch from (large)
 | 
				
			||||||
 | 
					<remote> will save quite some space in the git marks file.  Not to mention some time
 | 
				
			||||||
 | 
					each time it is loaded and saved again (upon fetch).  If the remote is ever pushed
 | 
				
			||||||
 | 
					to, the marks file will similarly be squashed, but for a fetch-only <remote>
 | 
				
			||||||
 | 
					the aforementioned command will do.  It may also be needed to run aforementioned
 | 
				
			||||||
 | 
					command after a `git gc` has been performed.  You will notice the need
 | 
				
			||||||
 | 
					when `git-fast-import` or `git-fast-export` complain about not finding objects ;-)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition, the helper also provides support routines for `git-remote-hg` that
 | 
				
			||||||
 | 
					provide for increased (or at least safer) git-hg bidirectionality.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Before explaining how it helps, let's first elaborate on what is really
 | 
				
			||||||
 | 
					meant by the above _bidirectionality_ since it can be regarded in 2 directions.
 | 
				
			||||||
 | 
					From the git repo point of view, one can push to a hg repo and then fetch (or
 | 
				
			||||||
 | 
					clone) back to git. Or one could have fetched a changeset from some hg repo and
 | 
				
			||||||
 | 
					then push this back to (another) hg clone.  So what happens in either case? In the
 | 
				
			||||||
 | 
					former case, from git to hg and then back, things work out ok whether or not in
 | 
				
			||||||
 | 
					hg-git compatibility mode.  In the latter case, it is very likely (but
 | 
				
			||||||
 | 
					ultimately not guaranteed) that it works out in hg-git compatibility mode, and far
 | 
				
			||||||
 | 
					less likely otherwise.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Most approaches on bidirectionality try to go for the "mapping" way.
 | 
				
			||||||
 | 
					That is, find a way to map all Mercurial (meta)data somewhere into git;
 | 
				
			||||||
 | 
					in the commit message, or in non-standard ways in extra headers in commit objects
 | 
				
			||||||
 | 
					(e.g. the latest hg-git approach).  The upside of this is that such a git repo can be
 | 
				
			||||||
 | 
					cloned to another git repo, and then one can push back into hg which will/should
 | 
				
			||||||
 | 
					turn out ok.  The downside is setting up such a mapping in the first place,
 | 
				
			||||||
 | 
					avoiding the slightest error in translating authors, timestamps etc,
 | 
				
			||||||
 | 
					and maintaining all that whenever there is some Mercurial API/ABI breakage.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The approach here is to consider a typical git-hg interaction workflow and to
 | 
				
			||||||
 | 
					ensure simple/safe bidirectionality in such a setting.  That is, you are (obviously)
 | 
				
			||||||
 | 
					in a situation having to deal with some Mercurial repo and quite probably
 | 
				
			||||||
 | 
					with various clones as well. The objective is to fetch from these repos/clones,
 | 
				
			||||||
 | 
					work in git and then push back.  And in the latter case, one needs to make sure
 | 
				
			||||||
 | 
					that hg changesets from one hg clone end up *exactly* that way in another hg
 | 
				
			||||||
 | 
					clone (or the git-hg bridge usage might not be so appreciated).  Such pushes are
 | 
				
			||||||
 | 
					probably not recommended workflow practice, but no accidents or issues should
 | 
				
			||||||
 | 
					arise from any push in these circumstances. There is less interest in this setting,
 | 
				
			||||||
 | 
					however, for (git-wise) cloning around the derived git repo.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Now, depending on your workflow and to ensure the above behaves well,
 | 
				
			||||||
 | 
					following setting can be enabled as preferred:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.check-hg-commits fail
 | 
				
			||||||
 | 
					% git config --global remote-hg.check-hg-commits push
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If not set, the behaviour is as before; pushing a commit based on hg changeset
 | 
				
			||||||
 | 
					will again transform the latter into a new hg changeset which may or may not
 | 
				
			||||||
 | 
					match the original (as described above).
 | 
				
			||||||
 | 
					If set to `fail`, it will reject and abort the push.
 | 
				
			||||||
 | 
					If set to `push`, it will re-use the original changeset in a Mercurial native
 | 
				
			||||||
 | 
					way (rather than creating a new one).  The latter guarantees the changeset ends
 | 
				
			||||||
 | 
					up elsewhere as expected (regardless of conversion mapping or ABI).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that identifying and re-using the hg changeset relies on metadata
 | 
				
			||||||
 | 
					(`refs/notes/hg` and marks files) that is not managed or maintained by any
 | 
				
			||||||
 | 
					git-to-git fetch (or clone).
 | 
				
			||||||
 | 
					As such (and as said), this approach aims for plain-and-simple safety, but only
 | 
				
			||||||
 | 
					within a local scope (git repo).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Mercurial Subrepository Support ===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Both Git and Mercurial support a submodule/subrepo system.
 | 
				
			||||||
 | 
					In case of Git, URLs are managed in `.gitmodules`, submodule state is tracked
 | 
				
			||||||
 | 
					in tree objects and only Git submodules are supported.
 | 
				
			||||||
 | 
					Mercurial manages URLs in `.hgsub`, records subrepo state in `.hgsubstate` and
 | 
				
			||||||
 | 
					supports Git, Mercurial and Subversion subrepos (at time of writing).
 | 
				
			||||||
 | 
					Merely the latter diversity in subrepo types shows that somehow mapping Mercurial
 | 
				
			||||||
 | 
					"natively" to git submodules is not quite evident.  Moreover, while one might
 | 
				
			||||||
 | 
					conceivably devise such a mapping restricted to git and hg subrepos, any such would
 | 
				
			||||||
 | 
					seem error-prone and fraught with all sorts of tricky cases and inconvenient
 | 
				
			||||||
 | 
					workflow handling (innovative robust suggestions are welcome though ...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					So, rather than overtaking the plumbing and ending up with stuffed drain further on,
 | 
				
			||||||
 | 
					the approach here is (again) to keep it plain-and-simple.  That is, provide some
 | 
				
			||||||
 | 
					git-ish look-and-feel helper script commands for setting up and manipulating
 | 
				
			||||||
 | 
					subrepos.  And so (if the alias mentioned above has been defined), `git hg sub`
 | 
				
			||||||
 | 
					provides commands similar to `git submodule` that accomplish what is otherwise
 | 
				
			||||||
 | 
					taken care of by the Mercurial subrepo support.
 | 
				
			||||||
 | 
					The latter is obviously extended to be git-aware in that e.g. a Mercurial subrepo
 | 
				
			||||||
 | 
					is cloned as a git-hg subrepo and translation back-and-forth between hg changeset id
 | 
				
			||||||
 | 
					and git commit hash is also performed where needed.  There is no support though
 | 
				
			||||||
 | 
					for Subversion subrepos.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As with the other commands, see the help description for the proper details,
 | 
				
			||||||
 | 
					but the following example session may clarify the principle:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git clone hg::hgparentrepo
 | 
				
			||||||
 | 
					# bring in subrepos in proper location:
 | 
				
			||||||
 | 
					% git hg sub update
 | 
				
			||||||
 | 
					# do some work
 | 
				
			||||||
 | 
					% git pull --rebase origin
 | 
				
			||||||
 | 
					# update subrepo state:
 | 
				
			||||||
 | 
					% git hg sub update
 | 
				
			||||||
 | 
					# do work in subrepo and push
 | 
				
			||||||
 | 
					% ( cd subrepo && git push origin HEAD:master )
 | 
				
			||||||
 | 
					# fetch to update refs/notes/hg (or enable remote-hg.push-updates-notes)
 | 
				
			||||||
 | 
					% ( cd subrepo && git fetch origin )
 | 
				
			||||||
 | 
					# update .hgsubstate to subrepo HEAD:
 | 
				
			||||||
 | 
					% git hg sub upstate
 | 
				
			||||||
 | 
					% git add .hgsubstate
 | 
				
			||||||
 | 
					# add more, commit and push as intended
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that the refspec `HEAD:master` is needed if working with detached `HEAD`
 | 
				
			||||||
 | 
					in subrepo, and that pushing such refspec is actually supported now in a git-hg subrepo
 | 
				
			||||||
 | 
					as explained <<no-limitations, earlier>>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
== Contributing ==
 | 
					== Contributing ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Send your patches to the mailing list git-fc@googlegroups.com (no need to
 | 
					Please file an issue with some patches or a pull-request.
 | 
				
			||||||
subscribe).
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,6 +58,50 @@ If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly
 | 
				
			|||||||
% git config --global remote-hg.hg-git-compat true
 | 
					% git config --global remote-hg.hg-git-compat true
 | 
				
			||||||
--------------------------------------
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you would like (why?) the old behaviour (export capability)
 | 
				
			||||||
 | 
					where various limitations apply:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.capability-push false
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the new behaviour, performing a git push will make git search for and detect
 | 
				
			||||||
 | 
					file rename and copy and turn this into Mercurial commit metadata.  To tweak how this
 | 
				
			||||||
 | 
					detection happens, e.g. have it search even more:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.fast-export-options '-M -C -C'
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The default otherwise is simply `-M -C`.  See also e.g.
 | 
				
			||||||
 | 
					https://www.kernel.org/pub/software/scm/git/docs/git-log.html[git-log(1) manpage]
 | 
				
			||||||
 | 
					for more details on the options used to tweak this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As the old refs/hg/... are actually an implementation detail, they are now
 | 
				
			||||||
 | 
					maintained not so visibly.  If that, however, would be preferred:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.show-private-refs true
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Use of shared marks files is the default in a new repo, but can also be enabled
 | 
				
			||||||
 | 
					for an existing repo:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.shared-marks true
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that one should perform a fetch from each remote to properly complete the
 | 
				
			||||||
 | 
					conversion to shared marks files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Mercurial name(s) (of a branch or bookmark) that are not a valid git refname,
 | 
				
			||||||
 | 
					can be ignored by configuring a suitable regular expression, e.g. avoiding
 | 
				
			||||||
 | 
					the invalid '~'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					% git config --global remote-hg.ignore-name ~
 | 
				
			||||||
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NOTES
 | 
					NOTES
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,3 +163,49 @@ would only see the latest head.
 | 
				
			|||||||
Closed branches are not supported; they are not shown and you can't close or
 | 
					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
 | 
					reopen. Additionally in certain rare situations a synchronization issue can
 | 
				
			||||||
occur (https://github.com/felipec/git/issues/65[Bug #65]).
 | 
					occur (https://github.com/felipec/git/issues/65[Bug #65]).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TECHNICAL DISCUSSION
 | 
				
			||||||
 | 
					--------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As `git-remote-hg` is a developer tool after all, it might be interesting to know a
 | 
				
			||||||
 | 
					bit about what is going on behind the scenes, without necessarily going into all the
 | 
				
			||||||
 | 
					details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					So let's first have a look in the `.git/hg` directory, which typically
 | 
				
			||||||
 | 
					contains a subdirectory for each remote Mercurial repo alias, as well as a `.hg`
 | 
				
			||||||
 | 
					subdirectory.  If the Mercurial repo is a local one, it will (again typically)
 | 
				
			||||||
 | 
					only contain a `marks-git` and a `marks-hg` file.  If the repo is a remote one,
 | 
				
			||||||
 | 
					then the `clone` contains, well, a local clone of the remote.  However, all
 | 
				
			||||||
 | 
					these clones share storage through the `.hg` directory mentioned previously (so
 | 
				
			||||||
 | 
					they do not add up separately). During a fetch/push, the local (proxy) repo is
 | 
				
			||||||
 | 
					used as an intermediate stage. If you would also prefer such an intermediate
 | 
				
			||||||
 | 
					stage for local repos, then setting the environment variable
 | 
				
			||||||
 | 
					`GIT_REMOTE_HG_TEST_REMOTE` will also use a proxy repo clone for a local repo.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As for the marks files, `marks-git` is created and used by `git-fast-export`
 | 
				
			||||||
 | 
					and `git-fast-import` and contains a mapping from mark to commit hash, where a
 | 
				
			||||||
 | 
					mark is essentially a plain number.  `marks-hg` similarly contains a (JSON) based
 | 
				
			||||||
 | 
					mapping between such mark and hg revision hash.  Together they provide for a
 | 
				
			||||||
 | 
					(consistent) view of the synchronization state of things.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When operating with shared-marks files, the `marks-git` and `marks-hg` files
 | 
				
			||||||
 | 
					are shared among all repos.  As such, they are then found in the `.git/hg`
 | 
				
			||||||
 | 
					directory (rather than a repo subdirectory).
 | 
				
			||||||
 | 
					As there is really only one hg repository
 | 
				
			||||||
 | 
					(the shared storage "union bag" in `.git/hg/.hg`), only 1 set of marks files
 | 
				
			||||||
 | 
					should track the mapping between commit hash and revision hash.
 | 
				
			||||||
 | 
					Each individual remote then only adds some metadata (e.g regarding heads).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Upon a fetch, the helper uses the `marks-hg` file to decide what is already present
 | 
				
			||||||
 | 
					and what not.  The required parts are then retrieved from Mercurial and turned
 | 
				
			||||||
 | 
					into a `git-fast-import` stream as expected by `import` capability of
 | 
				
			||||||
 | 
					https://www.kernel.org/pub/software/scm/git/docs/gitremote-helpers.html[gitremote-helpers(1)].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Upon a push, the helper has specified the `push` capability in the new approach, and
 | 
				
			||||||
 | 
					so git will provide a list of refspecs indicating what should go where.
 | 
				
			||||||
 | 
					If the refspecs indicates a remote delete, it is performed appropriately the Mercurial way.
 | 
				
			||||||
 | 
					If it is a regular push, then git-fast-export is invoked (using the existing `marks-git`)
 | 
				
			||||||
 | 
					and the stream is processed and turned into Mercurial commits (along with bookmarks, etc).
 | 
				
			||||||
 | 
					If the refspec specifies a `src:dest` rename, then the requested remote refname is tracked
 | 
				
			||||||
 | 
					accordingly.  If a dry-run is requested, no remote is touched and no (marks) state of
 | 
				
			||||||
 | 
					the run is retained.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1031
									
								
								git-hg-helper
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1031
									
								
								git-hg-helper
									
									
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1442
									
								
								git-remote-hg
									
									
									
									
									
								
							
							
						
						
									
										1442
									
								
								git-remote-hg
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										45
									
								
								setup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								setup.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# git-remote-hg setuptools script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import setuptools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# strip leading v
 | 
				
			||||||
 | 
					version = 'v1.0.4'[1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# check for released version
 | 
				
			||||||
 | 
					assert (len(version) > 0)
 | 
				
			||||||
 | 
					assert (version.find('-') < 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					long_description = \
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					'git-remote-hg' is a gitremote protocol helper for Mercurial.
 | 
				
			||||||
 | 
					It allows you to clone, fetch and push to and from Mercurial repositories as if
 | 
				
			||||||
 | 
					they were Git ones using a hg::some-url URL.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See the homepage for much more explanation.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CLASSIFIERS = [
 | 
				
			||||||
 | 
					    "Programming Language :: Python",
 | 
				
			||||||
 | 
					    "Programming Language :: Python :: 2",
 | 
				
			||||||
 | 
					    "Programming Language :: Python :: 2.7",
 | 
				
			||||||
 | 
					    "Programming Language :: Python :: 3",
 | 
				
			||||||
 | 
					    "Programming Language :: Python :: 3.6",
 | 
				
			||||||
 | 
					    "License :: OSI Approved",
 | 
				
			||||||
 | 
					    "License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
 | 
				
			||||||
 | 
					    "Development Status :: 5 - Production/Stable",
 | 
				
			||||||
 | 
					    "Intended Audience :: Developers",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setuptools.setup(name="git-remote-hg",
 | 
				
			||||||
 | 
					      version=version,
 | 
				
			||||||
 | 
					      author="Mark Nauwelaerts",
 | 
				
			||||||
 | 
					      author_email="mnauw@users.sourceforge.net",
 | 
				
			||||||
 | 
					      url="http://github.com/mnauw/git-remote-hg",
 | 
				
			||||||
 | 
					      description="access hg repositories as git remotes",
 | 
				
			||||||
 | 
					      long_description=long_description,
 | 
				
			||||||
 | 
					      license="GPLv2",
 | 
				
			||||||
 | 
					      keywords="git hg mercurial",
 | 
				
			||||||
 | 
					      scripts=["git-remote-hg", "git-hg-helper"],
 | 
				
			||||||
 | 
					      classifiers=CLASSIFIERS
 | 
				
			||||||
 | 
					     )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
RM ?= rm -f
 | 
					RM ?= rm -f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
T = main.t bidi.t
 | 
					T = main.t main-push.t bidi.t helper.t
 | 
				
			||||||
TEST_DIRECTORY := $(CURDIR)
 | 
					TEST_DIRECTORY := $(CURDIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export TEST_DIRECTORY
 | 
					export TEST_DIRECTORY
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										57
									
								
								test/bidi.t
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								test/bidi.t
									
									
									
									
									
								
							@@ -13,13 +13,7 @@ test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if ! test_have_prereq PYTHON
 | 
					if ! test_have_prereq PYTHON
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	skip_all='skipping remote-hg tests; python not available'
 | 
						skip_all='skipping remote-hg tests; python with mercurial not available'
 | 
				
			||||||
	test_done
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if ! python2 -c 'import mercurial' > /dev/null 2>&1
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
	skip_all='skipping remote-hg tests; mercurial not available'
 | 
					 | 
				
			||||||
	test_done
 | 
						test_done
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,7 +45,7 @@ hg_push () {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hg_log () {
 | 
					hg_log () {
 | 
				
			||||||
	hg -R $1 log --graph --debug
 | 
						hg -R $1 log --debug
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setup () {
 | 
					setup () {
 | 
				
			||||||
@@ -204,8 +198,9 @@ test_expect_success 'hg branch' '
 | 
				
			|||||||
	: Back to the common revision &&
 | 
						: Back to the common revision &&
 | 
				
			||||||
	(cd hgrepo && hg checkout default) &&
 | 
						(cd hgrepo && hg checkout default) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hg_log hgrepo > expected &&
 | 
						# fetch does not affect phase, but pushing now does
 | 
				
			||||||
	hg_log hgrepo2 > actual &&
 | 
						hg_log hgrepo | grep -v phase > expected &&
 | 
				
			||||||
 | 
						hg_log hgrepo2 | grep -v phase > actual &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test_cmp expected actual
 | 
						test_cmp expected actual
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
@@ -232,7 +227,47 @@ test_expect_success 'hg tags' '
 | 
				
			|||||||
	) &&
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hg_push hgrepo gitrepo &&
 | 
						hg_push hgrepo gitrepo &&
 | 
				
			||||||
	hg_clone gitrepo hgrepo2 &&
 | 
						# pushing a fetched tag is a problem ...
 | 
				
			||||||
 | 
						{ hg_clone gitrepo hgrepo2 || true ; } &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# fetch does not affect phase, but pushing now does
 | 
				
			||||||
 | 
						hg_log hgrepo | grep -v phase > expected &&
 | 
				
			||||||
 | 
						hg_log hgrepo2 | grep -v phase > actual &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'test timezones' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						git init -q gitrepo &&
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo alpha > alpha &&
 | 
				
			||||||
 | 
						git add alpha &&
 | 
				
			||||||
 | 
						git commit -m "add alpha" --date="2007-01-01 00:00:00 +0000" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo beta > beta &&
 | 
				
			||||||
 | 
						git add beta &&
 | 
				
			||||||
 | 
						git commit -m "add beta" --date="2007-01-01 00:00:00 +0100" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo gamma > gamma &&
 | 
				
			||||||
 | 
						git add gamma &&
 | 
				
			||||||
 | 
						git commit -m "add gamma" --date="2007-01-01 00:00:00 -0100" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo delta > delta &&
 | 
				
			||||||
 | 
						git add delta &&
 | 
				
			||||||
 | 
						git commit -m "add delta" --date="2007-01-01 00:00:00 +0130" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo epsilon > epsilon &&
 | 
				
			||||||
 | 
						git add epsilon &&
 | 
				
			||||||
 | 
						git commit -m "add epsilon" --date="2007-01-01 00:00:00 -0130"
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg_clone gitrepo hgrepo &&
 | 
				
			||||||
 | 
						git_clone hgrepo gitrepo2 &&
 | 
				
			||||||
 | 
						hg_clone gitrepo2 hgrepo2 &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hg_log hgrepo > expected &&
 | 
						hg_log hgrepo > expected &&
 | 
				
			||||||
	hg_log hgrepo2 > actual &&
 | 
						hg_log hgrepo2 > actual &&
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										541
									
								
								test/helper.t
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										541
									
								
								test/helper.t
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,541 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Copyright (c) 2016 Mark Nauwelaerts
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Base commands from hg-git tests:
 | 
				
			||||||
 | 
					# https://bitbucket.org/durin42/hg-git/src
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_description='Test git-hg-helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
				
			||||||
 | 
					. "$TEST_DIRECTORY"/test-lib.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ! test_have_prereq PYTHON
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						skip_all='skipping remote-hg tests; python with mercurial not available'
 | 
				
			||||||
 | 
						test_done
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup () {
 | 
				
			||||||
 | 
						cat > "$HOME"/.hgrc <<-EOF &&
 | 
				
			||||||
 | 
						[ui]
 | 
				
			||||||
 | 
						username = H G Wells <wells@example.com>
 | 
				
			||||||
 | 
						[extensions]
 | 
				
			||||||
 | 
						mq =
 | 
				
			||||||
 | 
						strip =
 | 
				
			||||||
 | 
						[subrepos]
 | 
				
			||||||
 | 
						git:allowed = true
 | 
				
			||||||
 | 
						EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" &&
 | 
				
			||||||
 | 
						GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" &&
 | 
				
			||||||
 | 
						export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup_repos () {
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand help' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						test_expect_code 2 git-hg-helper help 2> ../help
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						# remotes should be in help output
 | 
				
			||||||
 | 
						grep origin help
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git config --global remote-hg.shared-marks false
 | 
				
			||||||
 | 
					test_expect_success 'subcommand repo - no local proxy' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						pwd >../expected
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper repo origin > ../actual
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git config --global --unset remote-hg.shared-marks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GIT_REMOTE_HG_TEST_REMOTE=1 &&
 | 
				
			||||||
 | 
					export GIT_REMOTE_HG_TEST_REMOTE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand repo - with local proxy' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						export gitdir=`git rev-parse --git-dir`
 | 
				
			||||||
 | 
						# trick to normalize path
 | 
				
			||||||
 | 
						( cd $gitdir/hg/origin/clone && pwd ) >../expected &&
 | 
				
			||||||
 | 
						( cd `git-hg-helper repo origin` && pwd ) > ../actual
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommands hg-rev and git-rev' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git rev-parse HEAD > rev-HEAD &&
 | 
				
			||||||
 | 
						test -s rev-HEAD &&
 | 
				
			||||||
 | 
						git-hg-helper hg-rev `cat rev-HEAD` > hg-HEAD &&
 | 
				
			||||||
 | 
						git-hg-helper git-rev `cat hg-HEAD` > git-HEAD &&
 | 
				
			||||||
 | 
						test_cmp rev-HEAD git-HEAD
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand gc' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero
 | 
				
			||||||
 | 
						echo one > content &&
 | 
				
			||||||
 | 
						hg commit -m one &&
 | 
				
			||||||
 | 
						echo two > content &&
 | 
				
			||||||
 | 
						hg commit -m two &&
 | 
				
			||||||
 | 
						echo three > content &&
 | 
				
			||||||
 | 
						hg commit -m three
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						hg strip -r 1 &&
 | 
				
			||||||
 | 
						echo four > content &&
 | 
				
			||||||
 | 
						hg commit -m four
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git fetch origin &&
 | 
				
			||||||
 | 
						git reset --hard origin/master &&
 | 
				
			||||||
 | 
						git gc &&
 | 
				
			||||||
 | 
						git-hg-helper gc --check-hg origin > output &&
 | 
				
			||||||
 | 
						cat output &&
 | 
				
			||||||
 | 
						grep "hg marks" output &&
 | 
				
			||||||
 | 
						grep "git marks" output
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand [some-repo]' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo one > content &&
 | 
				
			||||||
 | 
						hg commit -m one
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git fetch origin
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg log -R hgrepo > expected &&
 | 
				
			||||||
 | 
						# not inside gitrepo; test shared path handling
 | 
				
			||||||
 | 
						GIT_DIR=gitrepo/.git git-hg-helper origin log > actual
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup_repo () {
 | 
				
			||||||
 | 
					    kind=$1 &&
 | 
				
			||||||
 | 
					    repo=$2 &&
 | 
				
			||||||
 | 
					    $kind init $repo &&
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					    cd $repo &&
 | 
				
			||||||
 | 
					    echo zero > content_$repo &&
 | 
				
			||||||
 | 
					    $kind add content_$repo &&
 | 
				
			||||||
 | 
					    $kind commit -m zero_$repo
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check () {
 | 
				
			||||||
 | 
						echo $3 > expected &&
 | 
				
			||||||
 | 
						git --git-dir=$1/.git log --format='%s' -1 $2 > actual &&
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check_branch () {
 | 
				
			||||||
 | 
						if test -n "$3"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo $3 > expected &&
 | 
				
			||||||
 | 
							hg -R $1 log -r $2 --template '{desc}\n' > actual &&
 | 
				
			||||||
 | 
							test_cmp expected actual
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							hg -R $1 branches > out &&
 | 
				
			||||||
 | 
							! grep $2 out
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub initial update (hg and git subrepos)' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repo hg hgrepo &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg_a &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg_b &&
 | 
				
			||||||
 | 
						setup_repo git sub_git &&
 | 
				
			||||||
 | 
						echo "sub_hg_a = sub_hg_a" > .hgsub &&
 | 
				
			||||||
 | 
						echo "sub_hg_b = sub_hg_b" >> .hgsub &&
 | 
				
			||||||
 | 
						echo "sub_git = [git]sub_git" >> .hgsub &&
 | 
				
			||||||
 | 
						hg add .hgsub &&
 | 
				
			||||||
 | 
						hg commit -m substate
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub update --force &&
 | 
				
			||||||
 | 
						test -f content_hgrepo &&
 | 
				
			||||||
 | 
						test -f sub_hg_a/content_sub_hg_a &&
 | 
				
			||||||
 | 
						test -f sub_hg_b/content_sub_hg_b &&
 | 
				
			||||||
 | 
						test -f sub_git/content_sub_git
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check gitrepo HEAD substate &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_a HEAD zero_sub_hg_a &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_b HEAD zero_sub_hg_b &&
 | 
				
			||||||
 | 
						check gitrepo/sub_git HEAD zero_sub_git
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup_subrepos () {
 | 
				
			||||||
 | 
						setup_repo hg hgrepo &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg_a &&
 | 
				
			||||||
 | 
							(
 | 
				
			||||||
 | 
							cd sub_hg_a &&
 | 
				
			||||||
 | 
							setup_repo hg sub_hg_a_x &&
 | 
				
			||||||
 | 
							echo "sub_hg_a_x = sub_hg_a_x" > .hgsub &&
 | 
				
			||||||
 | 
							hg add .hgsub &&
 | 
				
			||||||
 | 
							hg commit -m substate_hg_a
 | 
				
			||||||
 | 
							) &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg_b &&
 | 
				
			||||||
 | 
							(
 | 
				
			||||||
 | 
							cd sub_hg_b &&
 | 
				
			||||||
 | 
							setup_repo git sub_git &&
 | 
				
			||||||
 | 
							echo "sub_git = [git]sub_git" > .hgsub &&
 | 
				
			||||||
 | 
							hg add .hgsub &&
 | 
				
			||||||
 | 
							hg commit -m substate_hg_b
 | 
				
			||||||
 | 
							) &&
 | 
				
			||||||
 | 
						echo "sub_hg_a = sub_hg_a" > .hgsub &&
 | 
				
			||||||
 | 
						echo "sub_hg_b = sub_hg_b" >> .hgsub &&
 | 
				
			||||||
 | 
						hg add .hgsub &&
 | 
				
			||||||
 | 
						hg commit -m substate
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub initial recursive update' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_subrepos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub --recursive update --force &&
 | 
				
			||||||
 | 
						test -f content_hgrepo &&
 | 
				
			||||||
 | 
						test -f sub_hg_a/content_sub_hg_a &&
 | 
				
			||||||
 | 
						test -f sub_hg_a/sub_hg_a_x/content_sub_hg_a_x &&
 | 
				
			||||||
 | 
						test -f sub_hg_b/content_sub_hg_b &&
 | 
				
			||||||
 | 
						test -f sub_hg_b/sub_git/content_sub_git
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check gitrepo HEAD substate &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_a HEAD substate_hg_a &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_b HEAD substate_hg_b &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_a/sub_hg_a_x HEAD zero_sub_hg_a_x &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_b/sub_git HEAD zero_sub_git
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sub_update () {
 | 
				
			||||||
 | 
						export option=$1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_subrepos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub --recursive update --force
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
							(
 | 
				
			||||||
 | 
							 cd sub_hg_a &&
 | 
				
			||||||
 | 
								(
 | 
				
			||||||
 | 
								cd sub_hg_a_x &&
 | 
				
			||||||
 | 
								echo one > content_sub_hg_a_x &&
 | 
				
			||||||
 | 
								hg commit -m one_sub_hg_a_x
 | 
				
			||||||
 | 
								) &&
 | 
				
			||||||
 | 
							hg commit -m substate_updated_hg_a
 | 
				
			||||||
 | 
							) &&
 | 
				
			||||||
 | 
						hg commit -m substate_updated
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git fetch origin &&
 | 
				
			||||||
 | 
						git merge origin/master &&
 | 
				
			||||||
 | 
						git-hg-helper sub --recursive update --force $option &&
 | 
				
			||||||
 | 
						test -f content_hgrepo &&
 | 
				
			||||||
 | 
						test -f sub_hg_a/content_sub_hg_a &&
 | 
				
			||||||
 | 
						test -f sub_hg_a/sub_hg_a_x/content_sub_hg_a_x &&
 | 
				
			||||||
 | 
						test -f sub_hg_b/content_sub_hg_b &&
 | 
				
			||||||
 | 
						test -f sub_hg_b/sub_git/content_sub_git
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check gitrepo HEAD substate_updated &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_a HEAD substate_updated_hg_a &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_b HEAD substate_hg_b &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_a/sub_hg_a_x HEAD one_sub_hg_a_x &&
 | 
				
			||||||
 | 
						check gitrepo/sub_hg_b/sub_git HEAD zero_sub_git
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub subsequent recursive update' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_sub_update
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub subsequent recursive update -- rebase' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_sub_update --rebase
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub subsequent recursive update -- merge' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_sub_update --merge
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check_foreach_vars () {
 | 
				
			||||||
 | 
						cat $1 | while read kind sha1 rev path remainder
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
						    ok=0
 | 
				
			||||||
 | 
						    if test "$kind" = "hg" ; then
 | 
				
			||||||
 | 
								if test "$sha1" != "$rev" ; then
 | 
				
			||||||
 | 
									ok=1
 | 
				
			||||||
 | 
								fi
 | 
				
			||||||
 | 
						    else
 | 
				
			||||||
 | 
								if test "$sha1" = "$rev" ; then
 | 
				
			||||||
 | 
									ok=1
 | 
				
			||||||
 | 
								fi
 | 
				
			||||||
 | 
						    fi
 | 
				
			||||||
 | 
						    test $ok -eq 1 || echo "invalid $kind $sha1 $rev $path"
 | 
				
			||||||
 | 
						    test $ok -eq 1 || return 1
 | 
				
			||||||
 | 
						done &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sub_foreach () {
 | 
				
			||||||
 | 
						setup_subrepos &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub --recursive update --force &&
 | 
				
			||||||
 | 
						git-hg-helper sub --recursive --quiet foreach 'echo $kind $sha1 $rev $path $toplevel' > output &&
 | 
				
			||||||
 | 
						cat output &&
 | 
				
			||||||
 | 
						echo 1 > expected_git &&
 | 
				
			||||||
 | 
						grep -c ^git output > actual_git &&
 | 
				
			||||||
 | 
						test_cmp expected_git actual_git &&
 | 
				
			||||||
 | 
						echo 3 > expected_hg &&
 | 
				
			||||||
 | 
						grep -c ^hg output > actual_hg &&
 | 
				
			||||||
 | 
						test_cmp expected_hg actual_hg &&
 | 
				
			||||||
 | 
						grep '\(hg\|git\) [0-9a-f]* [0-9a-f]* sub[^ ]* /.*' output > actual &&
 | 
				
			||||||
 | 
						test_cmp output actual &&
 | 
				
			||||||
 | 
						check_foreach_vars output
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub foreach' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_sub_foreach
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub sync' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repo hg hgrepo &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg &&
 | 
				
			||||||
 | 
						echo "sub_hg = sub_hg" > .hgsub &&
 | 
				
			||||||
 | 
						hg add .hgsub &&
 | 
				
			||||||
 | 
						hg commit -m substate
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub update --force &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							(
 | 
				
			||||||
 | 
							cd sub_hg &&
 | 
				
			||||||
 | 
							grep url .git/config > ../expected &&
 | 
				
			||||||
 | 
							git config remote.origin.url foobar &&
 | 
				
			||||||
 | 
							grep foobar .git/config
 | 
				
			||||||
 | 
							) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git-hg-helper sub sync &&
 | 
				
			||||||
 | 
						grep url sub_hg/.git/config > actual &&
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub addstate' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repo hg hgrepo &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg &&
 | 
				
			||||||
 | 
						setup_repo git sub_git &&
 | 
				
			||||||
 | 
						echo "sub_hg = sub_hg" > .hgsub &&
 | 
				
			||||||
 | 
						echo "sub_git = [git]sub_git" >> .hgsub &&
 | 
				
			||||||
 | 
						hg add .hgsub &&
 | 
				
			||||||
 | 
						hg commit -m substate
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub update --force &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							(
 | 
				
			||||||
 | 
							cd sub_hg &&
 | 
				
			||||||
 | 
							echo one > content_sub_hg &&
 | 
				
			||||||
 | 
							git add content_sub_hg &&
 | 
				
			||||||
 | 
							git commit -m one_sub_hg &&
 | 
				
			||||||
 | 
							# detached HEAD
 | 
				
			||||||
 | 
							git push origin HEAD:master &&
 | 
				
			||||||
 | 
							# also fetch to ensure notes are updated
 | 
				
			||||||
 | 
							git fetch origin
 | 
				
			||||||
 | 
							) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							(
 | 
				
			||||||
 | 
							cd sub_git &&
 | 
				
			||||||
 | 
							echo one > content_sub_git &&
 | 
				
			||||||
 | 
							git add content_sub_git &&
 | 
				
			||||||
 | 
							git commit -m one_sub_git &&
 | 
				
			||||||
 | 
							# detached HEAD; push revision to other side ... anywhere
 | 
				
			||||||
 | 
							git push origin HEAD:refs/heads/new
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub upstate &&
 | 
				
			||||||
 | 
						git diff &&
 | 
				
			||||||
 | 
						git status --porcelain | grep .hgsubstate &&
 | 
				
			||||||
 | 
						git add .hgsubstate &&
 | 
				
			||||||
 | 
						git commit -m update_sub &&
 | 
				
			||||||
 | 
						git push origin master
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg clone hgrepo hgclone &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgclone &&
 | 
				
			||||||
 | 
						hg update
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check_branch hgclone default update_sub &&
 | 
				
			||||||
 | 
						check_branch hgclone/sub_hg default one_sub_hg &&
 | 
				
			||||||
 | 
						check hgclone/sub_git HEAD one_sub_git
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'subcommand sub status' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_repo hg hgrepo &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg_a &&
 | 
				
			||||||
 | 
						setup_repo hg sub_hg_b &&
 | 
				
			||||||
 | 
						setup_repo git sub_git &&
 | 
				
			||||||
 | 
						echo "sub_hg_a = sub_hg_a" > .hgsub &&
 | 
				
			||||||
 | 
						echo "sub_hg_b = sub_hg_b" >> .hgsub &&
 | 
				
			||||||
 | 
						echo "sub_git = [git]sub_git" >> .hgsub &&
 | 
				
			||||||
 | 
						hg add .hgsub &&
 | 
				
			||||||
 | 
						hg commit -m substate
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone hg::hgrepo gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git-hg-helper sub update --force sub_hg_a  &&
 | 
				
			||||||
 | 
						git-hg-helper sub update --force sub_git &&
 | 
				
			||||||
 | 
							(
 | 
				
			||||||
 | 
							# advance and add a tag to the git repo
 | 
				
			||||||
 | 
							cd sub_git &&
 | 
				
			||||||
 | 
							echo one > content_sub_git &&
 | 
				
			||||||
 | 
							git add content_sub_git &&
 | 
				
			||||||
 | 
							git commit -m one_sub_git &&
 | 
				
			||||||
 | 
							git tag feature-a
 | 
				
			||||||
 | 
							) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git-hg-helper sub status --cached > output &&
 | 
				
			||||||
 | 
						cat output &&
 | 
				
			||||||
 | 
						grep "^ .*sub_hg_a (.*master.*)$" output &&
 | 
				
			||||||
 | 
						grep "^-.*sub_hg_b$" output &&
 | 
				
			||||||
 | 
						grep "^+.*sub_git (feature-a~1)$" output &&
 | 
				
			||||||
 | 
						git-hg-helper sub status sub_git > output &&
 | 
				
			||||||
 | 
						cat output &&
 | 
				
			||||||
 | 
						grep "^+.*sub_git (feature-a)$" output > actual &&
 | 
				
			||||||
 | 
						test_cmp output actual
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_done
 | 
				
			||||||
@@ -13,20 +13,14 @@ test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if ! test_have_prereq PYTHON
 | 
					if ! test_have_prereq PYTHON
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	skip_all='skipping remote-hg tests; python not available'
 | 
						skip_all='skipping remote-hg tests; python with mercurial not available'
 | 
				
			||||||
	test_done
 | 
						test_done
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ! python2 -c 'import mercurial' > /dev/null 2>&1
 | 
					if "$PYTHON" -c 'import hggit' > /dev/null 2>&1
 | 
				
			||||||
then
 | 
					 | 
				
			||||||
	skip_all='skipping remote-hg tests; mercurial not available'
 | 
					 | 
				
			||||||
	test_done
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if python2 -c 'import hggit' > /dev/null 2>&1
 | 
					 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	hggit=hggit
 | 
						hggit=hggit
 | 
				
			||||||
elif python2 -c 'import hgext.git' > /dev/null 2>&1
 | 
					elif "$PYTHON" -c 'import hgext.git' > /dev/null 2>&1
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	hggit=hgext.git
 | 
						hggit=hgext.git
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
@@ -34,15 +28,6 @@ else
 | 
				
			|||||||
	test_done
 | 
						test_done
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hg_version=$(python2 -c 'from mercurial import util; print util.version()')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
case $hg_version in
 | 
					 | 
				
			||||||
3.0*+*)
 | 
					 | 
				
			||||||
	skip_all='skipping remote-hg tests; unsuported version of hg by hg-git'
 | 
					 | 
				
			||||||
	test_done
 | 
					 | 
				
			||||||
	;;
 | 
					 | 
				
			||||||
esac
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# clone to a git repo with git
 | 
					# clone to a git repo with git
 | 
				
			||||||
git_clone_git () {
 | 
					git_clone_git () {
 | 
				
			||||||
	git clone -q "hg::$1" $2 &&
 | 
						git clone -q "hg::$1" $2 &&
 | 
				
			||||||
@@ -117,10 +102,13 @@ setup () {
 | 
				
			|||||||
	[extensions]
 | 
						[extensions]
 | 
				
			||||||
	$hggit =
 | 
						$hggit =
 | 
				
			||||||
	graphlog =
 | 
						graphlog =
 | 
				
			||||||
 | 
						[git]
 | 
				
			||||||
 | 
						debugextrainmessage = 1
 | 
				
			||||||
	EOF
 | 
						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
 | 
				
			||||||
 | 
						git config --global remote-hg.shared-marks false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HGEDITOR=true
 | 
						HGEDITOR=true
 | 
				
			||||||
	HGMERGE=true
 | 
						HGMERGE=true
 | 
				
			||||||
@@ -132,6 +120,31 @@ setup () {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
setup
 | 
					setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'rename' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo1 &&
 | 
				
			||||||
 | 
						cd hgrepo1 &&
 | 
				
			||||||
 | 
						echo alpha > alpha &&
 | 
				
			||||||
 | 
						hg add alpha &&
 | 
				
			||||||
 | 
						hg commit -m "add alpha" &&
 | 
				
			||||||
 | 
						hg mv alpha beta &&
 | 
				
			||||||
 | 
						hg commit -m "rename alpha to beta"
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for x in hg git
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
							git_clone_$x hgrepo1 gitrepo-$x &&
 | 
				
			||||||
 | 
							hg_clone_$x gitrepo-$x hgrepo2-$x &&
 | 
				
			||||||
 | 
							hg_log hgrepo2-$x > "hg-log-$x" &&
 | 
				
			||||||
 | 
							git_log gitrepo-$x > "git-log-$x"
 | 
				
			||||||
 | 
						done &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_cmp hg-log-hg hg-log-git &&
 | 
				
			||||||
 | 
						test_cmp git-log-hg git-log-git
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_success 'executable bit' '
 | 
					test_expect_success 'executable bit' '
 | 
				
			||||||
	test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										314
									
								
								test/main-push.t
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										314
									
								
								test/main-push.t
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,314 @@
 | 
				
			|||||||
 | 
					CAPABILITY_PUSH=t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
				
			||||||
 | 
					. "$TEST_DIRECTORY"/main.t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# .. and some push mode only specific tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'remote delete bookmark' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf hgrepo* gitrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero
 | 
				
			||||||
 | 
						hg bookmark feature-a
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone "hg::hgrepo" gitrepo &&
 | 
				
			||||||
 | 
						check_bookmark hgrepo feature-a zero &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git push --quiet origin :feature-a
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check_bookmark hgrepo feature-a ''
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'source:dest bookmark' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf hgrepo gitrepo" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone "hg::hgrepo" gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						echo one > content &&
 | 
				
			||||||
 | 
						git commit -a -m one &&
 | 
				
			||||||
 | 
						git push --quiet origin master:feature-b &&
 | 
				
			||||||
 | 
						git push --quiet origin master^:refs/heads/feature-a
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check_bookmark hgrepo feature-a zero &&
 | 
				
			||||||
 | 
						check_bookmark hgrepo feature-b one &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git push --quiet origin master:feature-a
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# a shared bag would make all of the following pretty trivial
 | 
				
			||||||
 | 
					git config --global remote-hg.shared-marks false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup_check_shared_marks_repo () {
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
						rm -rf hgrepo* &&
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone "hg::hgrepo" gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git remote add second hg::../hgrepo &&
 | 
				
			||||||
 | 
						git fetch second
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check_marks () {
 | 
				
			||||||
 | 
						dir=$1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ls -al $dir &&
 | 
				
			||||||
 | 
						if test "$2" = "y"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							test -f $dir/marks-git && test -f $dir/marks-hg
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							test ! -f $dir/marks-git && test ! -f $dir/marks-hg
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# cleanup setting
 | 
				
			||||||
 | 
					git config --global --unset remote-hg.shared-marks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'shared-marks unset' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_check_shared_marks_repo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						check_marks .git/hg y &&
 | 
				
			||||||
 | 
						check_marks .git/hg/origin n &&
 | 
				
			||||||
 | 
						check_marks .git/hg/second n
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'shared-marks set to unset' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git config --global remote-hg.shared-marks true &&
 | 
				
			||||||
 | 
						setup_check_shared_marks_repo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						check_marks .git/hg y &&
 | 
				
			||||||
 | 
						check_marks .git/hg/origin n &&
 | 
				
			||||||
 | 
						check_marks .git/hg/second n
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git config --global remote-hg.shared-marks false &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
							cd gitrepo &&
 | 
				
			||||||
 | 
							git fetch origin &&
 | 
				
			||||||
 | 
							check_marks .git/hg n &&
 | 
				
			||||||
 | 
							check_marks .git/hg/origin y &&
 | 
				
			||||||
 | 
							check_marks .git/hg/second y
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'shared-marks unset to set' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git config --global remote-hg.shared-marks false &&
 | 
				
			||||||
 | 
						setup_check_shared_marks_repo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						check_marks .git/hg n &&
 | 
				
			||||||
 | 
						check_marks .git/hg/origin y &&
 | 
				
			||||||
 | 
						check_marks .git/hg/second y
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git config --global --unset remote-hg.shared-marks &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
							cd gitrepo &&
 | 
				
			||||||
 | 
							git fetch origin &&
 | 
				
			||||||
 | 
							check_marks .git/hg n &&
 | 
				
			||||||
 | 
							check_marks .git/hg/origin y &&
 | 
				
			||||||
 | 
							check_marks .git/hg/second y
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git config --global remote-hg.shared-marks true &&
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
							cd gitrepo &&
 | 
				
			||||||
 | 
							git fetch origin &&
 | 
				
			||||||
 | 
							check_marks .git/hg y &&
 | 
				
			||||||
 | 
							check_marks .git/hg/origin n &&
 | 
				
			||||||
 | 
							check_marks .git/hg/second n
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'push with renamed executable preserves executable bit' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						git init gitrepo &&
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git remote add origin "hg::../hgrepo" &&
 | 
				
			||||||
 | 
						echo one > content &&
 | 
				
			||||||
 | 
						chmod a+x content &&
 | 
				
			||||||
 | 
						git add content &&
 | 
				
			||||||
 | 
						git commit -a -m one &&
 | 
				
			||||||
 | 
						git mv content content2 &&
 | 
				
			||||||
 | 
						git commit -a -m two &&
 | 
				
			||||||
 | 
						git push origin master
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						umask 0 &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						hg update &&
 | 
				
			||||||
 | 
						stat content2 >expected &&
 | 
				
			||||||
 | 
						grep -- -r.xr.xr.x expected
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'push with submodule' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf sub hgrepo gitrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						git init sub &&
 | 
				
			||||||
 | 
						cd sub &&
 | 
				
			||||||
 | 
						: >empty &&
 | 
				
			||||||
 | 
						git add empty &&
 | 
				
			||||||
 | 
						git commit -m init
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						git init gitrepo &&
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git submodule add ../sub sub &&
 | 
				
			||||||
 | 
						git remote add origin "hg::../hgrepo" &&
 | 
				
			||||||
 | 
						git commit -a -m sub &&
 | 
				
			||||||
 | 
						git push origin master
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						hg update &&
 | 
				
			||||||
 | 
						expected="[git-remote-hg: skipped import of submodule at $(git -C ../sub rev-parse HEAD)]"
 | 
				
			||||||
 | 
						test "$expected" = "$(cat sub)"
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# cleanup setting
 | 
				
			||||||
 | 
					git config --global --unset remote-hg.shared-marks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_done
 | 
				
			||||||
							
								
								
									
										365
									
								
								test/main.t
									
									
									
									
									
								
							
							
						
						
									
										365
									
								
								test/main.t
									
									
									
									
									
								
							@@ -11,15 +11,18 @@ test_description='Test remote-hg'
 | 
				
			|||||||
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
					test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
				
			||||||
. "$TEST_DIRECTORY"/test-lib.sh
 | 
					. "$TEST_DIRECTORY"/test-lib.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ! test_have_prereq PYTHON
 | 
					if test "$CAPABILITY_PUSH" = "t"
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	skip_all='skipping remote-hg tests; python not available'
 | 
						git config --global remote-hg.capability-push true
 | 
				
			||||||
	test_done
 | 
						git config --global remote-hg.push-updates-notes true
 | 
				
			||||||
 | 
						git config --global remote-hg.fast-export-options '-C -C -M'
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						git config --global remote-hg.capability-push false
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ! python2 -c 'import mercurial' > /dev/null 2>&1
 | 
					if ! test_have_prereq PYTHON
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	skip_all='skipping remote-hg tests; mercurial not available'
 | 
						skip_all='skipping remote-hg tests; python with mercurial not available'
 | 
				
			||||||
	test_done
 | 
						test_done
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,23 +84,20 @@ check_push () {
 | 
				
			|||||||
		'non-fast-forward')
 | 
							'non-fast-forward')
 | 
				
			||||||
			grep "^ ! \[rejected\] *${branch} -> ${branch} (non-fast-forward)$" error || ref_ret=1
 | 
								grep "^ ! \[rejected\] *${branch} -> ${branch} (non-fast-forward)$" error || ref_ret=1
 | 
				
			||||||
			;;
 | 
								;;
 | 
				
			||||||
		'fetch-first')
 | 
					 | 
				
			||||||
			grep "^ ! \[rejected\] *${branch} -> ${branch} (fetch first)$" error || ref_ret=1
 | 
					 | 
				
			||||||
			;;
 | 
					 | 
				
			||||||
		'forced-update')
 | 
							'forced-update')
 | 
				
			||||||
			grep "^ + [a-f0-9]*\.\.\.[a-f0-9]* *${branch} -> ${branch} (forced update)$" error || ref_ret=1
 | 
								grep "^ + [a-f0-9]*\.\.\.[a-f0-9]* *${branch} -> ${branch} (forced update)$" error || ref_ret=1
 | 
				
			||||||
			;;
 | 
								;;
 | 
				
			||||||
		'')
 | 
							'')
 | 
				
			||||||
			grep "^   [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1
 | 
								grep "^   [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1
 | 
				
			||||||
			;;
 | 
								;;
 | 
				
			||||||
 | 
							*)
 | 
				
			||||||
 | 
								echo "BUG: wrong kind '$kind'" && return 3
 | 
				
			||||||
 | 
								;;
 | 
				
			||||||
		esac
 | 
							esac
 | 
				
			||||||
		test $ref_ret -ne 0 && echo "match for '$branch' failed" && break
 | 
							test $ref_ret -ne 0 && echo "match for '$branch' failed" && return 2
 | 
				
			||||||
	done
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if test $expected_ret -ne $ret || test $ref_ret -ne 0
 | 
						test $expected_ret -ne $ret && return 1
 | 
				
			||||||
	then
 | 
					 | 
				
			||||||
		return 1
 | 
					 | 
				
			||||||
	fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0
 | 
						return 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -176,7 +176,7 @@ test_expect_success 'update bookmark' '
 | 
				
			|||||||
	git checkout --quiet devel &&
 | 
						git checkout --quiet devel &&
 | 
				
			||||||
	echo devel > content &&
 | 
						echo devel > content &&
 | 
				
			||||||
	git commit -a -m devel &&
 | 
						git commit -a -m devel &&
 | 
				
			||||||
	git push --quiet
 | 
						git push --quiet origin devel
 | 
				
			||||||
	) &&
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	check_bookmark hgrepo devel devel
 | 
						check_bookmark hgrepo devel devel
 | 
				
			||||||
@@ -442,7 +442,7 @@ test_expect_success 'remote update bookmark diverge' '
 | 
				
			|||||||
	echo diverge > content &&
 | 
						echo diverge > content &&
 | 
				
			||||||
	git commit -a -m diverge &&
 | 
						git commit -a -m diverge &&
 | 
				
			||||||
	check_push 1 <<-\EOF
 | 
						check_push 1 <<-\EOF
 | 
				
			||||||
	diverge:fetch-first
 | 
						diverge:non-fast-forward
 | 
				
			||||||
	EOF
 | 
						EOF
 | 
				
			||||||
	) &&
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -467,6 +467,52 @@ test_expect_success 'remote new bookmark multiple branch head' '
 | 
				
			|||||||
# cleanup previous stuff
 | 
					# cleanup previous stuff
 | 
				
			||||||
rm -rf hgrepo
 | 
					rm -rf hgrepo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					testcopyrenamedesc='push commits with copy and rename'
 | 
				
			||||||
 | 
					testcopyrename='
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo hgrepo" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone "hg::hgrepo" gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						cp content content-copy &&
 | 
				
			||||||
 | 
						# recent git-fast-export is (too) picky in recognizing copies
 | 
				
			||||||
 | 
						# although git-log is not as picky;
 | 
				
			||||||
 | 
						# since https://github.com/git/git/commit/8096e1d385660c159d9d47e69b2be63cf22e4f31
 | 
				
			||||||
 | 
						# a copy is only marked if source filed not modified as well
 | 
				
			||||||
 | 
						# (though destination file can be modified)
 | 
				
			||||||
 | 
						echo one >> content-copy &&
 | 
				
			||||||
 | 
						git add content content-copy &&
 | 
				
			||||||
 | 
						git commit -m copy &&
 | 
				
			||||||
 | 
						git mv content-copy content-moved
 | 
				
			||||||
 | 
						git commit -m moved &&
 | 
				
			||||||
 | 
						git push origin master
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg -R hgrepo update &&
 | 
				
			||||||
 | 
						test_cmp gitrepo/content hgrepo/content
 | 
				
			||||||
 | 
						test_cmp gitrepo/content-moved hgrepo/content-moved
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						test `hg log -f content-moved | grep -c changeset` -eq 3
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if test "$CAPABILITY_PUSH" = "t"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					test_expect_success "$testcopyrenamedesc" "$testcopyrename"
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					test_expect_failure "$testcopyrenamedesc" "$testcopyrename"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_success 'fetch special filenames' '
 | 
					test_expect_success 'fetch special filenames' '
 | 
				
			||||||
	test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
 | 
						test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -618,17 +664,31 @@ test_expect_success 'remote big push' '
 | 
				
			|||||||
	EOF
 | 
						EOF
 | 
				
			||||||
	) &&
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if test "$CAPABILITY_PUSH" = "t"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							# cap push handles refs one by one
 | 
				
			||||||
 | 
							# so it will push all requested it can
 | 
				
			||||||
 | 
							check_branch hgrepo default six &&
 | 
				
			||||||
 | 
							check_branch hgrepo good_branch eight &&
 | 
				
			||||||
 | 
							check_branch hgrepo bad_branch "bad branch" &&
 | 
				
			||||||
 | 
							check_branch hgrepo new_branch ten &&
 | 
				
			||||||
 | 
							check_bookmark hgrepo good_bmark three &&
 | 
				
			||||||
 | 
							check_bookmark hgrepo bad_bmark1 one &&
 | 
				
			||||||
 | 
							check_bookmark hgrepo bad_bmark2 one &&
 | 
				
			||||||
 | 
							check_bookmark hgrepo new_bmark six
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		check_branch hgrepo default one &&
 | 
							check_branch hgrepo default one &&
 | 
				
			||||||
		check_branch hgrepo good_branch "good branch" &&
 | 
							check_branch hgrepo good_branch "good branch" &&
 | 
				
			||||||
		check_branch hgrepo bad_branch "bad branch" &&
 | 
							check_branch hgrepo bad_branch "bad branch" &&
 | 
				
			||||||
	check_branch hgrepo new_branch '' &&
 | 
							check_branch hgrepo new_branch &&
 | 
				
			||||||
		check_bookmark hgrepo good_bmark one &&
 | 
							check_bookmark hgrepo good_bmark one &&
 | 
				
			||||||
		check_bookmark hgrepo bad_bmark1 one &&
 | 
							check_bookmark hgrepo bad_bmark1 one &&
 | 
				
			||||||
		check_bookmark hgrepo bad_bmark2 one &&
 | 
							check_bookmark hgrepo bad_bmark2 one &&
 | 
				
			||||||
	check_bookmark hgrepo new_bmark ''
 | 
							check_bookmark hgrepo new_bmark
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_success 'remote big push fetch first' '
 | 
					test_expect_success 'remote big push non fast forward' '
 | 
				
			||||||
	test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
						test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	(
 | 
						(
 | 
				
			||||||
@@ -677,22 +737,33 @@ test_expect_success 'remote big push fetch first' '
 | 
				
			|||||||
	check_push 1 --all <<-\EOF &&
 | 
						check_push 1 --all <<-\EOF &&
 | 
				
			||||||
	master
 | 
						master
 | 
				
			||||||
	good_bmark
 | 
						good_bmark
 | 
				
			||||||
	bad_bmark:fetch-first
 | 
						bad_bmark:non-fast-forward
 | 
				
			||||||
	branches/bad_branch:festch-first
 | 
						branches/bad_branch:non-fast-forward
 | 
				
			||||||
	EOF
 | 
						EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	git fetch &&
 | 
						git fetch &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if test "$CAPABILITY_PUSH" = "t"
 | 
				
			||||||
 | 
					        then
 | 
				
			||||||
 | 
					                # cap push handles refs one by one
 | 
				
			||||||
 | 
							# so it will already have pushed some above previously
 | 
				
			||||||
 | 
							# (and master is a fake one that jumps around a bit)
 | 
				
			||||||
 | 
							check_push 1 --all <<-\EOF
 | 
				
			||||||
 | 
							bad_bmark:non-fast-forward
 | 
				
			||||||
 | 
							branches/bad_branch:non-fast-forward
 | 
				
			||||||
 | 
							EOF
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		check_push 1 --all <<-\EOF
 | 
							check_push 1 --all <<-\EOF
 | 
				
			||||||
		master
 | 
							master
 | 
				
			||||||
		good_bmark
 | 
							good_bmark
 | 
				
			||||||
		bad_bmark:non-fast-forward
 | 
							bad_bmark:non-fast-forward
 | 
				
			||||||
		branches/bad_branch:non-fast-forward
 | 
							branches/bad_branch:non-fast-forward
 | 
				
			||||||
		EOF
 | 
							EOF
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_failure 'remote big push force' '
 | 
					test_expect_success 'remote big push force' '
 | 
				
			||||||
	test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
						test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setup_big_push
 | 
						setup_big_push
 | 
				
			||||||
@@ -700,6 +771,19 @@ test_expect_failure 'remote big push force' '
 | 
				
			|||||||
	(
 | 
						(
 | 
				
			||||||
	cd gitrepo &&
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if test "$CAPABILITY_PUSH" = "t"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							check_push 0 --force --all <<-\EOF
 | 
				
			||||||
 | 
							master:forced-update
 | 
				
			||||||
 | 
							good_bmark:forced-update
 | 
				
			||||||
 | 
							branches/good_branch:forced-update
 | 
				
			||||||
 | 
							new_bmark:new
 | 
				
			||||||
 | 
							branches/new_branch:new
 | 
				
			||||||
 | 
							bad_bmark1:forced-update
 | 
				
			||||||
 | 
							bad_bmark2:forced-update
 | 
				
			||||||
 | 
							branches/bad_branch:forced-update
 | 
				
			||||||
 | 
							EOF
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		check_push 0 --force --all <<-\EOF
 | 
							check_push 0 --force --all <<-\EOF
 | 
				
			||||||
		master
 | 
							master
 | 
				
			||||||
		good_bmark
 | 
							good_bmark
 | 
				
			||||||
@@ -710,9 +794,9 @@ test_expect_failure 'remote big push force' '
 | 
				
			|||||||
		bad_bmark2:forced-update
 | 
							bad_bmark2:forced-update
 | 
				
			||||||
		branches/bad_branch:forced-update
 | 
							branches/bad_branch:forced-update
 | 
				
			||||||
		EOF
 | 
							EOF
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
	) &&
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	check_branch hgrepo default six &&
 | 
					 | 
				
			||||||
	check_branch hgrepo good_branch eight &&
 | 
						check_branch hgrepo good_branch eight &&
 | 
				
			||||||
	check_branch hgrepo bad_branch nine &&
 | 
						check_branch hgrepo bad_branch nine &&
 | 
				
			||||||
	check_branch hgrepo new_branch ten &&
 | 
						check_branch hgrepo new_branch ten &&
 | 
				
			||||||
@@ -722,7 +806,7 @@ test_expect_failure 'remote big push force' '
 | 
				
			|||||||
	check_bookmark hgrepo new_bmark six
 | 
						check_bookmark hgrepo new_bmark six
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_failure 'remote big push dry-run' '
 | 
					test_expect_success 'remote big push dry-run' '
 | 
				
			||||||
	test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
						test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setup_big_push
 | 
						setup_big_push
 | 
				
			||||||
@@ -753,11 +837,55 @@ test_expect_failure 'remote big push dry-run' '
 | 
				
			|||||||
	check_branch hgrepo default one &&
 | 
						check_branch hgrepo default one &&
 | 
				
			||||||
	check_branch hgrepo good_branch "good branch" &&
 | 
						check_branch hgrepo good_branch "good branch" &&
 | 
				
			||||||
	check_branch hgrepo bad_branch "bad branch" &&
 | 
						check_branch hgrepo bad_branch "bad branch" &&
 | 
				
			||||||
	check_branch hgrepo new_branch '' &&
 | 
						check_branch hgrepo new_branch &&
 | 
				
			||||||
	check_bookmark hgrepo good_bmark one &&
 | 
						check_bookmark hgrepo good_bmark one &&
 | 
				
			||||||
	check_bookmark hgrepo bad_bmark1 one &&
 | 
						check_bookmark hgrepo bad_bmark1 one &&
 | 
				
			||||||
	check_bookmark hgrepo bad_bmark2 one &&
 | 
						check_bookmark hgrepo bad_bmark2 one &&
 | 
				
			||||||
	check_bookmark hgrepo new_bmark ''
 | 
						check_bookmark hgrepo new_bmark
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'remote big push force dry-run' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_big_push
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if test "$CAPABILITY_PUSH" = "t"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							check_push 0 --force --dry-run --all <<-\EOF
 | 
				
			||||||
 | 
							master:forced-update
 | 
				
			||||||
 | 
							good_bmark:forced-update
 | 
				
			||||||
 | 
							branches/good_branch:forced-update
 | 
				
			||||||
 | 
							new_bmark:new
 | 
				
			||||||
 | 
							branches/new_branch:new
 | 
				
			||||||
 | 
							bad_bmark1:forced-update
 | 
				
			||||||
 | 
							bad_bmark2:forced-update
 | 
				
			||||||
 | 
							branches/bad_branch:forced-update
 | 
				
			||||||
 | 
							EOF
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							check_push 0 --force --dry-run --all <<-\EOF
 | 
				
			||||||
 | 
							master
 | 
				
			||||||
 | 
							good_bmark
 | 
				
			||||||
 | 
							branches/good_branch
 | 
				
			||||||
 | 
							new_bmark:new
 | 
				
			||||||
 | 
							branches/new_branch:new
 | 
				
			||||||
 | 
							bad_bmark1:forced-update
 | 
				
			||||||
 | 
							bad_bmark2:forced-update
 | 
				
			||||||
 | 
							branches/bad_branch:forced-update
 | 
				
			||||||
 | 
							EOF
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check_branch hgrepo default one &&
 | 
				
			||||||
 | 
						check_branch hgrepo good_branch "good branch" &&
 | 
				
			||||||
 | 
						check_branch hgrepo bad_branch "bad branch" &&
 | 
				
			||||||
 | 
						check_branch hgrepo new_branch &&
 | 
				
			||||||
 | 
						check_bookmark hgrepo good_bmark one &&
 | 
				
			||||||
 | 
						check_bookmark hgrepo bad_bmark1 one &&
 | 
				
			||||||
 | 
						check_bookmark hgrepo bad_bmark2 one &&
 | 
				
			||||||
 | 
						check_bookmark hgrepo new_bmark
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_success 'remote double failed push' '
 | 
					test_expect_success 'remote double failed push' '
 | 
				
			||||||
@@ -783,6 +911,78 @@ test_expect_success 'remote double failed push' '
 | 
				
			|||||||
	test_expect_code 1 git push
 | 
						test_expect_code 1 git push
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					test_expect_success 'fetch prune' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo hgrepo" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero &&
 | 
				
			||||||
 | 
						echo feature-a > content &&
 | 
				
			||||||
 | 
						hg commit -m feature-a
 | 
				
			||||||
 | 
						hg bookmark feature-a
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone "hg::hgrepo" gitrepo &&
 | 
				
			||||||
 | 
						check gitrepo origin/feature-a feature-a &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						hg bookmark -d feature-a
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git fetch --prune origin
 | 
				
			||||||
 | 
						git branch -a > out &&
 | 
				
			||||||
 | 
						! grep feature-a out
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'fetch multiple independent histories' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf gitrepo hgrepo" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						echo zero > content &&
 | 
				
			||||||
 | 
						hg add content &&
 | 
				
			||||||
 | 
						hg commit -m zero &&
 | 
				
			||||||
 | 
						hg up -r null &&
 | 
				
			||||||
 | 
						echo another > ocontent &&
 | 
				
			||||||
 | 
						hg add ocontent &&
 | 
				
			||||||
 | 
						hg commit -m one
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# -r 1 acts as master
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						git init --bare gitrepo && cd gitrepo &&
 | 
				
			||||||
 | 
						git remote add origin hg::../hgrepo &&
 | 
				
			||||||
 | 
						git fetch origin refs/heads/*:refs/heads/*
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
						hg up 0 &&
 | 
				
			||||||
 | 
						echo two > content &&
 | 
				
			||||||
 | 
						hg commit -m two
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# now master already exists
 | 
				
			||||||
 | 
						# -r 2 becomes master head which has rev 0 as ancestor
 | 
				
			||||||
 | 
						# so when importing (parentless) rev 0, a reset is needed
 | 
				
			||||||
 | 
						# (to ensure rev 0 is not given a parent commit)
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						cd gitrepo &&
 | 
				
			||||||
 | 
						git fetch origin &&
 | 
				
			||||||
 | 
						git log --format="%s" origin/master > ../actual
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg -R hgrepo log -r . -f --template "{desc}\n" > expected &&
 | 
				
			||||||
 | 
						test_cmp actual expected
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_success 'clone remote with null bookmark, then push' '
 | 
					test_expect_success 'clone remote with null bookmark, then push' '
 | 
				
			||||||
	test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
						test_when_finished "rm -rf gitrepo* hgrepo*" &&
 | 
				
			||||||
@@ -828,7 +1028,8 @@ test_expect_success 'notes' '
 | 
				
			|||||||
	test_cmp expected actual
 | 
						test_cmp expected actual
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_failure 'push updates notes' '
 | 
					testpushupdatesnotesdesc='push updates notes'
 | 
				
			||||||
 | 
					testpushupdatesnotes='
 | 
				
			||||||
	test_when_finished "rm -rf hgrepo gitrepo" &&
 | 
						test_when_finished "rm -rf hgrepo gitrepo" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	(
 | 
						(
 | 
				
			||||||
@@ -844,7 +1045,7 @@ test_expect_failure 'push updates notes' '
 | 
				
			|||||||
	(
 | 
						(
 | 
				
			||||||
	cd gitrepo &&
 | 
						cd gitrepo &&
 | 
				
			||||||
	echo two > content &&
 | 
						echo two > content &&
 | 
				
			||||||
	git commit -a -m two
 | 
						git commit -a -m two &&
 | 
				
			||||||
	git push
 | 
						git push
 | 
				
			||||||
	) &&
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -853,6 +1054,38 @@ test_expect_failure 'push updates notes' '
 | 
				
			|||||||
	test_cmp expected actual
 | 
						test_cmp expected actual
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if test "$CAPABILITY_PUSH" = "t"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					test_expect_success "$testpushupdatesnotesdesc" "$testpushupdatesnotes"
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					test_expect_failure "$testpushupdatesnotesdesc" "$testpushupdatesnotes"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'push bookmark without changesets' '
 | 
				
			||||||
 | 
						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 origin master &&
 | 
				
			||||||
 | 
						git branch feature-a &&
 | 
				
			||||||
 | 
						git push origin feature-a
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						check_bookmark hgrepo feature-a two
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_success 'pull tags' '
 | 
					test_expect_success 'pull tags' '
 | 
				
			||||||
	test_when_finished "rm -rf hgrepo gitrepo" &&
 | 
						test_when_finished "rm -rf hgrepo gitrepo" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -898,7 +1131,7 @@ test_expect_success 'push merged named branch' '
 | 
				
			|||||||
	git push
 | 
						git push
 | 
				
			||||||
	) &&
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cat > expected <<-EOF
 | 
						cat > expected <<-EOF &&
 | 
				
			||||||
	Merge
 | 
						Merge
 | 
				
			||||||
	three
 | 
						three
 | 
				
			||||||
	two
 | 
						two
 | 
				
			||||||
@@ -939,7 +1172,7 @@ test_expect_success 'push tag different branch' '
 | 
				
			|||||||
	cd hgrepo &&
 | 
						cd hgrepo &&
 | 
				
			||||||
	echo one > content &&
 | 
						echo one > content &&
 | 
				
			||||||
	hg add content &&
 | 
						hg add content &&
 | 
				
			||||||
	hg commit -m one
 | 
						hg commit -m one &&
 | 
				
			||||||
	hg branch feature &&
 | 
						hg branch feature &&
 | 
				
			||||||
	echo two > content &&
 | 
						echo two > content &&
 | 
				
			||||||
	hg commit -m two
 | 
						hg commit -m two
 | 
				
			||||||
@@ -1024,4 +1257,78 @@ test_expect_success 'clone replace directory with a file' '
 | 
				
			|||||||
	check_files gitrepo "dir_or_file"
 | 
						check_files gitrepo "dir_or_file"
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'clone can ignore invalid refnames' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf hgrepo gitrepo" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
						cd hgrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						touch test.txt &&
 | 
				
			||||||
 | 
						hg add test.txt &&
 | 
				
			||||||
 | 
						hg commit -m master &&
 | 
				
			||||||
 | 
						hg branch parent &&
 | 
				
			||||||
 | 
						echo test >test.txt &&
 | 
				
			||||||
 | 
						hg commit -m test &&
 | 
				
			||||||
 | 
						hg branch parent/child &&
 | 
				
			||||||
 | 
						echo test1 >test.txt &&
 | 
				
			||||||
 | 
						hg commit -m test1
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone -c remote-hg.ignore-name=child "hg::hgrepo" gitrepo &&
 | 
				
			||||||
 | 
						check_files gitrepo "test.txt"
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'push annotated tag' '
 | 
				
			||||||
 | 
						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 -m "Version 1.0" v1.0 &&
 | 
				
			||||||
 | 
						git push --tags
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cat > expected <<-\EOF &&
 | 
				
			||||||
 | 
						tip:Version 1.0:C O Mitter <committer@example.com>
 | 
				
			||||||
 | 
						v1.0:one:H G Wells <wells@example.com>
 | 
				
			||||||
 | 
						EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg -R hgrepo log --template "{tags}:{desc}:{author}\n" > actual &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'timezone issues with negative offsets' '
 | 
				
			||||||
 | 
						test_when_finished "rm -rf hgrepo gitrepo1 gitrepo2" &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hg init hgrepo &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						git clone "hg::hgrepo" gitrepo1 &&
 | 
				
			||||||
 | 
						cd gitrepo1 &&
 | 
				
			||||||
 | 
						echo two >> content &&
 | 
				
			||||||
 | 
						git add content &&
 | 
				
			||||||
 | 
						git commit -m two --date="2016-09-26 00:00:00 -0230" &&
 | 
				
			||||||
 | 
						git push
 | 
				
			||||||
 | 
						) &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git clone "hg::hgrepo" gitrepo2 &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git --git-dir=gitrepo1/.git log -1 --format="%ai" > expected &&
 | 
				
			||||||
 | 
						git --git-dir=gitrepo2/.git log -1 --format="%ai" > actual &&
 | 
				
			||||||
 | 
						test_cmp expected actual
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if test "$CAPABILITY_PUSH" != "t"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
test_done
 | 
					test_done
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										394
									
								
								test/sharness.sh
									
									
									
									
									
								
							
							
						
						
									
										394
									
								
								test/sharness.sh
									
									
									
									
									
								
							@@ -18,33 +18,80 @@
 | 
				
			|||||||
# along with this program.  If not, see http://www.gnu.org/licenses/ .
 | 
					# along with this program.  If not, see http://www.gnu.org/licenses/ .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Current version of Sharness.
 | 
					# Public: Current version of Sharness.
 | 
				
			||||||
SHARNESS_VERSION="0.3.0"
 | 
					SHARNESS_VERSION="1.1.0"
 | 
				
			||||||
export SHARNESS_VERSION
 | 
					export SHARNESS_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: The file extension for tests.  By default, it is set to "t".
 | 
					# Public: The file extension for tests.  By default, it is set to "t".
 | 
				
			||||||
: ${SHARNESS_TEST_EXTENSION:=t}
 | 
					: "${SHARNESS_TEST_EXTENSION:=t}"
 | 
				
			||||||
export SHARNESS_TEST_EXTENSION
 | 
					export SHARNESS_TEST_EXTENSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Keep the original TERM for say_color
 | 
					# Public: Root directory containing tests. Tests can override this variable,
 | 
				
			||||||
ORIGINAL_TERM=$TERM
 | 
					# e.g. for testing Sharness itself.
 | 
				
			||||||
 | 
					if test -z "$SHARNESS_TEST_DIRECTORY"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						SHARNESS_TEST_DIRECTORY=$(pwd)
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						# ensure that SHARNESS_TEST_DIRECTORY is an absolute path so that it
 | 
				
			||||||
 | 
						# is valid even if the current working directory is changed
 | 
				
			||||||
 | 
						SHARNESS_TEST_DIRECTORY=$(cd "$SHARNESS_TEST_DIRECTORY" && pwd) || exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					export SHARNESS_TEST_DIRECTORY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if test -z "$SHARNESS_TEST_OUTPUT_DIRECTORY"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						# Similarly, override this to store the test-results subdir
 | 
				
			||||||
 | 
						# elsewhere
 | 
				
			||||||
 | 
						SHARNESS_TEST_OUTPUT_DIRECTORY=$SHARNESS_TEST_DIRECTORY
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#  Reset TERM to original terminal if found, otherwise save original TERM
 | 
				
			||||||
 | 
					[ "x" = "x$SHARNESS_ORIG_TERM" ] &&
 | 
				
			||||||
 | 
							SHARNESS_ORIG_TERM="$TERM" ||
 | 
				
			||||||
 | 
							TERM="$SHARNESS_ORIG_TERM"
 | 
				
			||||||
 | 
					# Public: The unsanitized TERM under which sharness is originally run
 | 
				
			||||||
 | 
					export SHARNESS_ORIG_TERM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Export SHELL_PATH
 | 
				
			||||||
 | 
					: "${SHELL_PATH:=$SHELL}"
 | 
				
			||||||
 | 
					export SHELL_PATH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# if --tee was passed, write the output not only to the terminal, but
 | 
				
			||||||
 | 
					# additionally to the file test-results/$BASENAME.out, too.
 | 
				
			||||||
 | 
					case "$SHARNESS_TEST_TEE_STARTED, $* " in
 | 
				
			||||||
 | 
					done,*)
 | 
				
			||||||
 | 
						# do not redirect again
 | 
				
			||||||
 | 
						;;
 | 
				
			||||||
 | 
					*' --tee '*|*' --verbose-log '*)
 | 
				
			||||||
 | 
						mkdir -p "$SHARNESS_TEST_OUTPUT_DIRECTORY/test-results"
 | 
				
			||||||
 | 
						BASE="$SHARNESS_TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" ".$SHARNESS_TEST_EXTENSION")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Make this filename available to the sub-process in case it is using
 | 
				
			||||||
 | 
						# --verbose-log.
 | 
				
			||||||
 | 
						SHARNESS_TEST_TEE_OUTPUT_FILE="$BASE.out"
 | 
				
			||||||
 | 
						export SHARNESS_TEST_TEE_OUTPUT_FILE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Truncate before calling "tee -a" to get rid of the results
 | 
				
			||||||
 | 
						# from any previous runs.
 | 
				
			||||||
 | 
						: >"$SHARNESS_TEST_TEE_OUTPUT_FILE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(SHARNESS_TEST_TEE_STARTED="done" ${SHELL_PATH} "$0" "$@" 2>&1;
 | 
				
			||||||
 | 
						 echo $? >"$BASE.exit") | tee -a "$SHARNESS_TEST_TEE_OUTPUT_FILE"
 | 
				
			||||||
 | 
						test "$(cat "$BASE.exit")" = 0
 | 
				
			||||||
 | 
						exit
 | 
				
			||||||
 | 
						;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# For repeatability, reset the environment to a known state.
 | 
					# For repeatability, reset the environment to a known state.
 | 
				
			||||||
 | 
					# TERM is sanitized below, after saving color control sequences.
 | 
				
			||||||
LANG=C
 | 
					LANG=C
 | 
				
			||||||
LC_ALL=C
 | 
					LC_ALL=C
 | 
				
			||||||
PAGER=cat
 | 
					PAGER="cat"
 | 
				
			||||||
TZ=UTC
 | 
					TZ=UTC
 | 
				
			||||||
TERM=dumb
 | 
					 | 
				
			||||||
EDITOR=:
 | 
					EDITOR=:
 | 
				
			||||||
export LANG LC_ALL PAGER TZ TERM EDITOR
 | 
					export LANG LC_ALL PAGER TZ EDITOR
 | 
				
			||||||
unset VISUAL CDPATH GREP_OPTIONS
 | 
					unset VISUAL CDPATH GREP_OPTIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Line feed
 | 
					[ "x$TERM" != "xdumb" ] && (
 | 
				
			||||||
LF='
 | 
					 | 
				
			||||||
'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[ "x$ORIGINAL_TERM" != "xdumb" ] && (
 | 
					 | 
				
			||||||
		TERM=$ORIGINAL_TERM &&
 | 
					 | 
				
			||||||
		export TERM &&
 | 
					 | 
				
			||||||
		[ -t 1 ] &&
 | 
							[ -t 1 ] &&
 | 
				
			||||||
		tput bold >/dev/null 2>&1 &&
 | 
							tput bold >/dev/null 2>&1 &&
 | 
				
			||||||
		tput setaf 1 >/dev/null 2>&1 &&
 | 
							tput setaf 1 >/dev/null 2>&1 &&
 | 
				
			||||||
@@ -60,6 +107,8 @@ while test "$#" -ne 0; do
 | 
				
			|||||||
		immediate=t; shift ;;
 | 
							immediate=t; shift ;;
 | 
				
			||||||
	-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
 | 
						-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
 | 
				
			||||||
		TEST_LONG=t; export TEST_LONG; shift ;;
 | 
							TEST_LONG=t; export TEST_LONG; shift ;;
 | 
				
			||||||
 | 
						--in|--int|--inte|--inter|--intera|--interac|--interact|--interacti|--interactiv|--interactive|--interactive-|--interactive-t|--interactive-te|--interactive-tes|--interactive-test|--interactive-tests):
 | 
				
			||||||
 | 
							TEST_INTERACTIVE=t; export TEST_INTERACTIVE; verbose=t; shift ;;
 | 
				
			||||||
	-h|--h|--he|--hel|--help)
 | 
						-h|--h|--he|--hel|--help)
 | 
				
			||||||
		help=t; shift ;;
 | 
							help=t; shift ;;
 | 
				
			||||||
	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
 | 
						-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
 | 
				
			||||||
@@ -68,49 +117,69 @@ while test "$#" -ne 0; do
 | 
				
			|||||||
		# Ignore --quiet under a TAP::Harness. Saying how many tests
 | 
							# Ignore --quiet under a TAP::Harness. Saying how many tests
 | 
				
			||||||
		# passed without the ok/not ok details is always an error.
 | 
							# passed without the ok/not ok details is always an error.
 | 
				
			||||||
		test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
 | 
							test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
 | 
				
			||||||
 | 
						--chain-lint)
 | 
				
			||||||
 | 
							chain_lint=t; shift ;;
 | 
				
			||||||
 | 
						--no-chain-lint)
 | 
				
			||||||
 | 
							chain_lint=; shift ;;
 | 
				
			||||||
	--no-color)
 | 
						--no-color)
 | 
				
			||||||
		color=; shift ;;
 | 
							color=; shift ;;
 | 
				
			||||||
 | 
						--tee)
 | 
				
			||||||
 | 
							shift ;; # was handled already
 | 
				
			||||||
	--root=*)
 | 
						--root=*)
 | 
				
			||||||
		root=$(expr "z$1" : 'z[^=]*=\(.*\)')
 | 
							root=$(expr "z$1" : 'z[^=]*=\(.*\)')
 | 
				
			||||||
		shift ;;
 | 
							shift ;;
 | 
				
			||||||
 | 
						--verbose-log)
 | 
				
			||||||
 | 
							verbose_log=t
 | 
				
			||||||
 | 
							shift ;;
 | 
				
			||||||
	*)
 | 
						*)
 | 
				
			||||||
		echo "error: unknown test option '$1'" >&2; exit 1 ;;
 | 
							echo "error: unknown test option '$1'" >&2; exit 1 ;;
 | 
				
			||||||
	esac
 | 
						esac
 | 
				
			||||||
done
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if test -n "$color"; then
 | 
					if test -n "$color"; then
 | 
				
			||||||
 | 
						# Save the color control sequences now rather than run tput
 | 
				
			||||||
 | 
						# each time say_color() is called.  This is done for two
 | 
				
			||||||
 | 
						# reasons:
 | 
				
			||||||
 | 
						#   * TERM will be changed to dumb
 | 
				
			||||||
 | 
						#   * HOME will be changed to a temporary directory and tput
 | 
				
			||||||
 | 
						#     might need to read ~/.terminfo from the original HOME
 | 
				
			||||||
 | 
						#     directory to get the control sequences
 | 
				
			||||||
 | 
						# Note:  This approach assumes the control sequences don't end
 | 
				
			||||||
 | 
						# in a newline for any terminal of interest (command
 | 
				
			||||||
 | 
						# substitutions strip trailing newlines).  Given that most
 | 
				
			||||||
 | 
						# (all?) terminals in common use are related to ECMA-48, this
 | 
				
			||||||
 | 
						# shouldn't be a problem.
 | 
				
			||||||
 | 
						say_color_error=$(tput bold; tput setaf 1) # bold red
 | 
				
			||||||
 | 
						say_color_skip=$(tput setaf 4) # blue
 | 
				
			||||||
 | 
						say_color_warn=$(tput setaf 3) # brown/yellow
 | 
				
			||||||
 | 
						say_color_pass=$(tput setaf 2) # green
 | 
				
			||||||
 | 
						say_color_info=$(tput setaf 6) # cyan
 | 
				
			||||||
 | 
						say_color_reset=$(tput sgr0)
 | 
				
			||||||
 | 
						say_color_raw="" # no formatting for normal text
 | 
				
			||||||
	say_color() {
 | 
						say_color() {
 | 
				
			||||||
		(
 | 
							test -z "$1" && test -n "$quiet" && return
 | 
				
			||||||
		TERM=$ORIGINAL_TERM
 | 
					 | 
				
			||||||
		export TERM
 | 
					 | 
				
			||||||
		case "$1" in
 | 
							case "$1" in
 | 
				
			||||||
		error)
 | 
								error) say_color_color=$say_color_error ;;
 | 
				
			||||||
			tput bold; tput setaf 1;; # bold red
 | 
								skip) say_color_color=$say_color_skip ;;
 | 
				
			||||||
		skip)
 | 
								warn) say_color_color=$say_color_warn ;;
 | 
				
			||||||
			tput setaf 4;; # blue
 | 
								pass) say_color_color=$say_color_pass ;;
 | 
				
			||||||
		warn)
 | 
								info) say_color_color=$say_color_info ;;
 | 
				
			||||||
			tput setaf 3;; # brown/yellow
 | 
								*) say_color_color=$say_color_raw ;;
 | 
				
			||||||
		pass)
 | 
					 | 
				
			||||||
			tput setaf 2;; # green
 | 
					 | 
				
			||||||
		info)
 | 
					 | 
				
			||||||
			tput setaf 6;; # cyan
 | 
					 | 
				
			||||||
		*)
 | 
					 | 
				
			||||||
			test -n "$quiet" && return;;
 | 
					 | 
				
			||||||
		esac
 | 
							esac
 | 
				
			||||||
		shift
 | 
							shift
 | 
				
			||||||
		printf "%s" "$*"
 | 
							printf '%s%s%s\n' "$say_color_color" "$*" "$say_color_reset"
 | 
				
			||||||
		tput sgr0
 | 
					 | 
				
			||||||
		echo
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
	say_color() {
 | 
						say_color() {
 | 
				
			||||||
		test -z "$1" && test -n "$quiet" && return
 | 
							test -z "$1" && test -n "$quiet" && return
 | 
				
			||||||
		shift
 | 
							shift
 | 
				
			||||||
		printf "%s\n" "$*"
 | 
							printf '%s\n' "$*"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TERM=dumb
 | 
				
			||||||
 | 
					export TERM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error() {
 | 
					error() {
 | 
				
			||||||
	say_color error "error: $*"
 | 
						say_color error "error: $*"
 | 
				
			||||||
	EXIT_OK=t
 | 
						EXIT_OK=t
 | 
				
			||||||
@@ -121,7 +190,7 @@ say() {
 | 
				
			|||||||
	say_color info "$*"
 | 
						say_color info "$*"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test -n "$test_description" || error "Test script did not set test_description."
 | 
					test -n "${test_description:-}" || error "Test script did not set test_description."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if test "$help" = "t"; then
 | 
					if test "$help" = "t"; then
 | 
				
			||||||
	echo "$test_description"
 | 
						echo "$test_description"
 | 
				
			||||||
@@ -130,7 +199,11 @@ fi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
exec 5>&1
 | 
					exec 5>&1
 | 
				
			||||||
exec 6<&0
 | 
					exec 6<&0
 | 
				
			||||||
if test "$verbose" = "t"; then
 | 
					if test "$verbose_log" = "t"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						exec 3>>"$SHARNESS_TEST_TEE_OUTPUT_FILE" 4>&3
 | 
				
			||||||
 | 
					elif test "$verbose" = "t"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
	exec 4>&2 3>&1
 | 
						exec 4>&2 3>&1
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
	exec 4>/dev/null 3>/dev/null
 | 
						exec 4>/dev/null 3>/dev/null
 | 
				
			||||||
@@ -161,7 +234,7 @@ trap 'die' EXIT
 | 
				
			|||||||
# implicitly by specifying the prerequisite name in calls to test_expect_success
 | 
					# implicitly by specifying the prerequisite name in calls to test_expect_success
 | 
				
			||||||
# or test_expect_failure.
 | 
					# or test_expect_failure.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# $1 - Name of prerequiste (a simple word, in all capital letters by convention)
 | 
					# $1 - Name of prerequisite (a simple word, in all capital letters by convention)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Examples
 | 
					# Examples
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -198,7 +271,7 @@ test_have_prereq() {
 | 
				
			|||||||
	# prerequisites can be concatenated with ','
 | 
						# prerequisites can be concatenated with ','
 | 
				
			||||||
	save_IFS=$IFS
 | 
						save_IFS=$IFS
 | 
				
			||||||
	IFS=,
 | 
						IFS=,
 | 
				
			||||||
	set -- $*
 | 
						set -- $@
 | 
				
			||||||
	IFS=$save_IFS
 | 
						IFS=$save_IFS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	total_prereq=0
 | 
						total_prereq=0
 | 
				
			||||||
@@ -215,7 +288,7 @@ test_have_prereq() {
 | 
				
			|||||||
			negative_prereq=
 | 
								negative_prereq=
 | 
				
			||||||
		esac
 | 
							esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		total_prereq=$(($total_prereq + 1))
 | 
							total_prereq=$((total_prereq + 1))
 | 
				
			||||||
		case "$satisfied_prereq" in
 | 
							case "$satisfied_prereq" in
 | 
				
			||||||
		*" $prerequisite "*)
 | 
							*" $prerequisite "*)
 | 
				
			||||||
			satisfied_this_prereq=t
 | 
								satisfied_this_prereq=t
 | 
				
			||||||
@@ -226,7 +299,7 @@ test_have_prereq() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		case "$satisfied_this_prereq,$negative_prereq" in
 | 
							case "$satisfied_this_prereq,$negative_prereq" in
 | 
				
			||||||
		t,|,t)
 | 
							t,|,t)
 | 
				
			||||||
			ok_prereq=$(($ok_prereq + 1))
 | 
								ok_prereq=$((ok_prereq + 1))
 | 
				
			||||||
			;;
 | 
								;;
 | 
				
			||||||
		*)
 | 
							*)
 | 
				
			||||||
			# Keep a list of missing prerequisites; restore
 | 
								# Keep a list of missing prerequisites; restore
 | 
				
			||||||
@@ -247,12 +320,12 @@ test_have_prereq() {
 | 
				
			|||||||
# the text_expect_* functions instead.
 | 
					# the text_expect_* functions instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_ok_() {
 | 
					test_ok_() {
 | 
				
			||||||
	test_success=$(($test_success + 1))
 | 
						test_success=$((test_success + 1))
 | 
				
			||||||
	say_color "" "ok $test_count - $@"
 | 
						say_color "" "ok $test_count - $*"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_failure_() {
 | 
					test_failure_() {
 | 
				
			||||||
	test_failure=$(($test_failure + 1))
 | 
						test_failure=$((test_failure + 1))
 | 
				
			||||||
	say_color error "not ok $test_count - $1"
 | 
						say_color error "not ok $test_count - $1"
 | 
				
			||||||
	shift
 | 
						shift
 | 
				
			||||||
	echo "$@" | sed -e 's/^/#	/'
 | 
						echo "$@" | sed -e 's/^/#	/'
 | 
				
			||||||
@@ -260,13 +333,13 @@ test_failure_() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_known_broken_ok_() {
 | 
					test_known_broken_ok_() {
 | 
				
			||||||
	test_fixed=$(($test_fixed + 1))
 | 
						test_fixed=$((test_fixed + 1))
 | 
				
			||||||
	say_color error "ok $test_count - $@ # TODO known breakage vanished"
 | 
						say_color error "ok $test_count - $* # TODO known breakage vanished"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_known_broken_failure_() {
 | 
					test_known_broken_failure_() {
 | 
				
			||||||
	test_broken=$(($test_broken + 1))
 | 
						test_broken=$((test_broken + 1))
 | 
				
			||||||
	say_color warn "not ok $test_count - $@ # TODO known breakage"
 | 
						say_color warn "not ok $test_count - $* # TODO known breakage"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Execute commands in debug mode.
 | 
					# Public: Execute commands in debug mode.
 | 
				
			||||||
@@ -287,10 +360,29 @@ test_debug() {
 | 
				
			|||||||
	test "$debug" = "" || eval "$1"
 | 
						test "$debug" = "" || eval "$1"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Public: Stop execution and start a shell.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This is useful for debugging tests and only makes sense together with "-v".
 | 
				
			||||||
 | 
					# Be sure to remove all invocations of this command before submitting.
 | 
				
			||||||
 | 
					test_pause() {
 | 
				
			||||||
 | 
						if test "$verbose" = t; then
 | 
				
			||||||
 | 
							"$SHELL_PATH" <&6 >&3 2>&4
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							error >&5 "test_pause requires --verbose"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_eval_() {
 | 
					test_eval_() {
 | 
				
			||||||
	# This is a separate function because some tests use
 | 
						# This is a separate function because some tests use
 | 
				
			||||||
	# "return" to end a test_expect_success block early.
 | 
						# "return" to end a test_expect_success block early.
 | 
				
			||||||
 | 
						case ",$test_prereq," in
 | 
				
			||||||
 | 
						*,INTERACTIVE,*)
 | 
				
			||||||
 | 
							eval "$*"
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						*)
 | 
				
			||||||
		eval </dev/null >&3 2>&4 "$*"
 | 
							eval </dev/null >&3 2>&4 "$*"
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						esac
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_run_() {
 | 
					test_run_() {
 | 
				
			||||||
@@ -299,6 +391,13 @@ test_run_() {
 | 
				
			|||||||
	test_eval_ "$1"
 | 
						test_eval_ "$1"
 | 
				
			||||||
	eval_ret=$?
 | 
						eval_ret=$?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if test "$chain_lint" = "t"; then
 | 
				
			||||||
 | 
							test_eval_ "(exit 117) && $1"
 | 
				
			||||||
 | 
							if test "$?" != 117; then
 | 
				
			||||||
 | 
								error "bug in the test script: broken &&-chain: $1"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then
 | 
						if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then
 | 
				
			||||||
		test_eval_ "$test_cleanup"
 | 
							test_eval_ "$test_cleanup"
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
@@ -309,7 +408,7 @@ test_run_() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_skip_() {
 | 
					test_skip_() {
 | 
				
			||||||
	test_count=$(($test_count + 1))
 | 
						test_count=$((test_count + 1))
 | 
				
			||||||
	to_skip=
 | 
						to_skip=
 | 
				
			||||||
	for skp in $SKIP_TESTS; do
 | 
						for skp in $SKIP_TESTS; do
 | 
				
			||||||
		case $this_test.$test_count in
 | 
							case $this_test.$test_count in
 | 
				
			||||||
@@ -328,7 +427,7 @@ test_skip_() {
 | 
				
			|||||||
			of_prereq=" of $test_prereq"
 | 
								of_prereq=" of $test_prereq"
 | 
				
			||||||
		fi
 | 
							fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		say_color skip >&3 "skipping test: $@"
 | 
							say_color skip >&3 "skipping test: $*"
 | 
				
			||||||
		say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
 | 
							say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
 | 
				
			||||||
		: true
 | 
							: true
 | 
				
			||||||
		;;
 | 
							;;
 | 
				
			||||||
@@ -426,6 +525,44 @@ test_expect_failure() {
 | 
				
			|||||||
	echo >&3 ""
 | 
						echo >&3 ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Public: Run test commands and expect anything from them. Used when a
 | 
				
			||||||
 | 
					# test is not stable or not finished for some reason.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# When the test passed, an "ok" message is printed, but the number of
 | 
				
			||||||
 | 
					# fixed tests is not incremented.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# When it failed, a "not ok ... # TODO known breakage" message is
 | 
				
			||||||
 | 
					# printed, and the number of tests still broken is incremented.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Failures from these tests won't cause --immediate to stop.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Usually takes two arguments:
 | 
				
			||||||
 | 
					# $1 - Test description
 | 
				
			||||||
 | 
					# $2 - Commands to be executed.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# With three arguments, the first will be taken to be a prerequisite:
 | 
				
			||||||
 | 
					# $1 - Comma-separated list of test prerequisites. The test will be skipped if
 | 
				
			||||||
 | 
					#      not all of the given prerequisites are set. To negate a prerequisite,
 | 
				
			||||||
 | 
					#      put a "!" in front of it.
 | 
				
			||||||
 | 
					# $2 - Test description
 | 
				
			||||||
 | 
					# $3 - Commands to be executed.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Returns nothing.
 | 
				
			||||||
 | 
					test_expect_unstable() {
 | 
				
			||||||
 | 
						test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
 | 
				
			||||||
 | 
						test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_unstable"
 | 
				
			||||||
 | 
						export test_prereq
 | 
				
			||||||
 | 
						if ! test_skip_ "$@"; then
 | 
				
			||||||
 | 
							say >&3 "checking unstable test: $2"
 | 
				
			||||||
 | 
							if test_run_ "$2" unstable; then
 | 
				
			||||||
 | 
								test_ok_ "$1"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								test_known_broken_failure_ "$1"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						echo >&3 ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Run command and ensure that it fails in a controlled way.
 | 
					# Public: Run command and ensure that it fails in a controlled way.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Use it instead of "! <command>". For example, when <command> dies due to a
 | 
					# Use it instead of "! <command>". For example, when <command> dies due to a
 | 
				
			||||||
@@ -518,7 +655,7 @@ test_expect_code() {
 | 
				
			|||||||
	shift
 | 
						shift
 | 
				
			||||||
	"$@"
 | 
						"$@"
 | 
				
			||||||
	exit_code=$?
 | 
						exit_code=$?
 | 
				
			||||||
	if test $exit_code = $want_code; then
 | 
						if test "$exit_code" = "$want_code"; then
 | 
				
			||||||
		return 0
 | 
							return 0
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -528,7 +665,7 @@ test_expect_code() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Public: Compare two files to see if expected output matches actual output.
 | 
					# Public: Compare two files to see if expected output matches actual output.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# The TEST_CMP variable defines the command used for the comparision; it
 | 
					# The TEST_CMP variable defines the command used for the comparison; it
 | 
				
			||||||
# defaults to "diff -u". Only when the test script was started with --verbose,
 | 
					# defaults to "diff -u". Only when the test script was started with --verbose,
 | 
				
			||||||
# will the command's output, the diff, be printed to the standard output.
 | 
					# will the command's output, the diff, be printed to the standard output.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -551,6 +688,79 @@ test_cmp() {
 | 
				
			|||||||
	${TEST_CMP:-diff -u} "$@"
 | 
						${TEST_CMP:-diff -u} "$@"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Public: portably print a sequence of numbers.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# seq is not in POSIX and GNU seq might not be available everywhere,
 | 
				
			||||||
 | 
					# so it is nice to have a seq implementation, even a very simple one.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# $1 - Starting number.
 | 
				
			||||||
 | 
					# $2 - Ending number.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Examples
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   test_expect_success 'foo works 10 times' '
 | 
				
			||||||
 | 
					#       for i in $(test_seq 1 10)
 | 
				
			||||||
 | 
					#       do
 | 
				
			||||||
 | 
					#           foo || return
 | 
				
			||||||
 | 
					#       done
 | 
				
			||||||
 | 
					#   '
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Returns 0 if all the specified numbers can be displayed.
 | 
				
			||||||
 | 
					test_seq() {
 | 
				
			||||||
 | 
						i="$1"
 | 
				
			||||||
 | 
						j="$2"
 | 
				
			||||||
 | 
						while test "$i" -le "$j"
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
							echo "$i" || return
 | 
				
			||||||
 | 
							i=$(("$i" + 1))
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Public: Check if the file expected to be empty is indeed empty, and barfs
 | 
				
			||||||
 | 
					# otherwise.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# $1 - File to check for emptiness.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Returns 0 if file is empty, 1 otherwise.
 | 
				
			||||||
 | 
					test_must_be_empty() {
 | 
				
			||||||
 | 
						if test -s "$1"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo "'$1' is not empty, it contains:"
 | 
				
			||||||
 | 
							cat "$1"
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# debugging-friendly alternatives to "test [-f|-d|-e]"
 | 
				
			||||||
 | 
					# The commands test the existence or non-existence of $1. $2 can be
 | 
				
			||||||
 | 
					# given to provide a more precise diagnosis.
 | 
				
			||||||
 | 
					test_path_is_file () {
 | 
				
			||||||
 | 
						if ! test -f "$1"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo "File $1 doesn't exist. $2"
 | 
				
			||||||
 | 
							false
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_path_is_dir () {
 | 
				
			||||||
 | 
						if ! test -d "$1"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo "Directory $1 doesn't exist. $2"
 | 
				
			||||||
 | 
							false
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if the directory exists and is empty as expected, barf otherwise.
 | 
				
			||||||
 | 
					test_dir_is_empty () {
 | 
				
			||||||
 | 
						test_path_is_dir "$1" &&
 | 
				
			||||||
 | 
						if test -n "$(find "$1" -mindepth 1 -maxdepth 1)"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo "Directory '$1' is not empty, it contains:"
 | 
				
			||||||
 | 
							ls -la "$1"
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Schedule cleanup commands to be run unconditionally at the end of a
 | 
					# Public: Schedule cleanup commands to be run unconditionally at the end of a
 | 
				
			||||||
# test.
 | 
					# test.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -576,6 +786,23 @@ test_when_finished() {
 | 
				
			|||||||
		} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
 | 
							} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Public: Schedule cleanup commands to be run unconditionally when all tests
 | 
				
			||||||
 | 
					# have run.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This can be used to clean up things like test databases. It is not needed to
 | 
				
			||||||
 | 
					# clean up temporary files, as test_done already does that.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Examples:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   cleanup mysql -e "DROP DATABASE mytest"
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Returns the exit code of the last cleanup command executed.
 | 
				
			||||||
 | 
					final_cleanup=
 | 
				
			||||||
 | 
					cleanup() {
 | 
				
			||||||
 | 
						final_cleanup="{ $*
 | 
				
			||||||
 | 
							} && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Summarize test results and exit with an appropriate error code.
 | 
					# Public: Summarize test results and exit with an appropriate error code.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Must be called at the end of each test script.
 | 
					# Must be called at the end of each test script.
 | 
				
			||||||
@@ -600,9 +827,9 @@ test_done() {
 | 
				
			|||||||
	EXIT_OK=t
 | 
						EXIT_OK=t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if test -z "$HARNESS_ACTIVE"; then
 | 
						if test -z "$HARNESS_ACTIVE"; then
 | 
				
			||||||
		test_results_dir="$SHARNESS_TEST_DIRECTORY/test-results"
 | 
							test_results_dir="$SHARNESS_TEST_OUTPUT_DIRECTORY/test-results"
 | 
				
			||||||
		mkdir -p "$test_results_dir"
 | 
							mkdir -p "$test_results_dir"
 | 
				
			||||||
		test_results_path="$test_results_dir/${SHARNESS_TEST_FILE%.$SHARNESS_TEST_EXTENSION}.$$.counts"
 | 
							test_results_path="$test_results_dir/$this_test.$$.counts"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cat >>"$test_results_path" <<-EOF
 | 
							cat >>"$test_results_path" <<-EOF
 | 
				
			||||||
		total $test_count
 | 
							total $test_count
 | 
				
			||||||
@@ -621,7 +848,7 @@ test_done() {
 | 
				
			|||||||
		say_color warn "# still have $test_broken known breakage(s)"
 | 
							say_color warn "# still have $test_broken known breakage(s)"
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
	if test "$test_broken" != 0 || test "$test_fixed" != 0; then
 | 
						if test "$test_broken" != 0 || test "$test_fixed" != 0; then
 | 
				
			||||||
		test_remaining=$(( $test_count - $test_broken - $test_fixed ))
 | 
							test_remaining=$((test_count - test_broken - test_fixed))
 | 
				
			||||||
		msg="remaining $test_remaining test(s)"
 | 
							msg="remaining $test_remaining test(s)"
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		test_remaining=$test_count
 | 
							test_remaining=$test_count
 | 
				
			||||||
@@ -641,6 +868,8 @@ test_done() {
 | 
				
			|||||||
		fi
 | 
							fi
 | 
				
			||||||
		say "1..$test_count$skip_all"
 | 
							say "1..$test_count$skip_all"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							test_eval_ "$final_cleanup"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		test -d "$remove_trash" &&
 | 
							test -d "$remove_trash" &&
 | 
				
			||||||
		cd "$(dirname "$remove_trash")" &&
 | 
							cd "$(dirname "$remove_trash")" &&
 | 
				
			||||||
		rm -rf "$(basename "$remove_trash")"
 | 
							rm -rf "$(basename "$remove_trash")"
 | 
				
			||||||
@@ -656,14 +885,15 @@ test_done() {
 | 
				
			|||||||
	esac
 | 
						esac
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Root directory containing tests. Tests can override this variable,
 | 
					# Public: Source directory of test code and sharness library.
 | 
				
			||||||
# e.g. for testing Sharness itself.
 | 
					# This directory may be different from the directory in which tests are
 | 
				
			||||||
: ${SHARNESS_TEST_DIRECTORY:=$(pwd)}
 | 
					# being run.
 | 
				
			||||||
export SHARNESS_TEST_DIRECTORY
 | 
					: "${SHARNESS_TEST_SRCDIR:=$(cd "$(dirname "$0")" && pwd)}"
 | 
				
			||||||
 | 
					export SHARNESS_TEST_SRCDIR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Build directory that will be added to PATH. By default, it is set to
 | 
					# Public: Build directory that will be added to PATH. By default, it is set to
 | 
				
			||||||
# the parent directory of SHARNESS_TEST_DIRECTORY.
 | 
					# the parent directory of SHARNESS_TEST_DIRECTORY.
 | 
				
			||||||
: ${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}
 | 
					: "${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}"
 | 
				
			||||||
PATH="$SHARNESS_BUILD_DIRECTORY:$PATH"
 | 
					PATH="$SHARNESS_BUILD_DIRECTORY:$PATH"
 | 
				
			||||||
export PATH SHARNESS_BUILD_DIRECTORY
 | 
					export PATH SHARNESS_BUILD_DIRECTORY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -672,19 +902,43 @@ SHARNESS_TEST_FILE="$0"
 | 
				
			|||||||
export SHARNESS_TEST_FILE
 | 
					export SHARNESS_TEST_FILE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Prepare test area.
 | 
					# Prepare test area.
 | 
				
			||||||
test_dir="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
 | 
					SHARNESS_TRASH_DIRECTORY="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
 | 
				
			||||||
test -n "$root" && test_dir="$root/$test_dir"
 | 
					test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY"
 | 
				
			||||||
case "$test_dir" in
 | 
					case "$SHARNESS_TRASH_DIRECTORY" in
 | 
				
			||||||
/*) SHARNESS_TRASH_DIRECTORY="$test_dir" ;;
 | 
					/*) ;; # absolute path is good
 | 
				
			||||||
 *) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$test_dir" ;;
 | 
					 *) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_OUTPUT_DIRECTORY/$SHARNESS_TRASH_DIRECTORY" ;;
 | 
				
			||||||
esac
 | 
					esac
 | 
				
			||||||
test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY"
 | 
					test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY"
 | 
				
			||||||
rm -rf "$test_dir" || {
 | 
					rm -rf "$SHARNESS_TRASH_DIRECTORY" || {
 | 
				
			||||||
	EXIT_OK=t
 | 
						EXIT_OK=t
 | 
				
			||||||
	echo >&5 "FATAL: Cannot prepare test area"
 | 
						echo >&5 "FATAL: Cannot prepare test area"
 | 
				
			||||||
	exit 1
 | 
						exit 1
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#  Load any extensions in $srcdir/sharness.d/*.sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					if test -d "${SHARNESS_TEST_SRCDIR}/sharness.d"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						for file in "${SHARNESS_TEST_SRCDIR}"/sharness.d/*.sh
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
							# Ensure glob was not an empty match:
 | 
				
			||||||
 | 
							test -e "${file}" || break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if test -n "$debug"
 | 
				
			||||||
 | 
							then
 | 
				
			||||||
 | 
								echo >&5 "sharness: loading extensions from ${file}"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							. "${file}"
 | 
				
			||||||
 | 
							if test $? != 0
 | 
				
			||||||
 | 
							then
 | 
				
			||||||
 | 
								echo >&5 "sharness: Error loading ${file}. Aborting."
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Public: Empty trash directory, the test area, provided for each test. The HOME
 | 
					# Public: Empty trash directory, the test area, provided for each test. The HOME
 | 
				
			||||||
# variable is set to that directory too.
 | 
					# variable is set to that directory too.
 | 
				
			||||||
export SHARNESS_TRASH_DIRECTORY
 | 
					export SHARNESS_TRASH_DIRECTORY
 | 
				
			||||||
@@ -692,10 +946,10 @@ export SHARNESS_TRASH_DIRECTORY
 | 
				
			|||||||
HOME="$SHARNESS_TRASH_DIRECTORY"
 | 
					HOME="$SHARNESS_TRASH_DIRECTORY"
 | 
				
			||||||
export HOME
 | 
					export HOME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkdir -p "$test_dir" || exit 1
 | 
					mkdir -p "$SHARNESS_TRASH_DIRECTORY" || exit 1
 | 
				
			||||||
# Use -P to resolve symlinks in our working directory so that the cwd
 | 
					# Use -P to resolve symlinks in our working directory so that the cwd
 | 
				
			||||||
# in subprocesses like git equals our $PWD (for pathname comparisons).
 | 
					# in subprocesses like git equals our $PWD (for pathname comparisons).
 | 
				
			||||||
cd -P "$test_dir" || exit 1
 | 
					cd -P "$SHARNESS_TRASH_DIRECTORY" || exit 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
this_test=${SHARNESS_TEST_FILE##*/}
 | 
					this_test=${SHARNESS_TEST_FILE##*/}
 | 
				
			||||||
this_test=${this_test%.$SHARNESS_TEST_EXTENSION}
 | 
					this_test=${this_test%.$SHARNESS_TEST_EXTENSION}
 | 
				
			||||||
@@ -708,4 +962,10 @@ for skp in $SKIP_TESTS; do
 | 
				
			|||||||
	esac
 | 
						esac
 | 
				
			||||||
done
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test -n "$TEST_LONG" && test_set_prereq EXPENSIVE
 | 
				
			||||||
 | 
					test -n "$TEST_INTERACTIVE" && test_set_prereq INTERACTIVE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Make sure this script ends with code 0
 | 
				
			||||||
 | 
					:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# vi: set ts=4 sw=4 noet :
 | 
					# vi: set ts=4 sw=4 noet :
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,60 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
. ./sharness.sh
 | 
					if [ -z "$SHARNESS" ] ; then
 | 
				
			||||||
 | 
						for d in \
 | 
				
			||||||
 | 
							"." \
 | 
				
			||||||
 | 
							"$HOME/share/sharness" \
 | 
				
			||||||
 | 
							"/usr/local/share/sharness" \
 | 
				
			||||||
 | 
							"/usr/share/sharness"
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
							f="$d/sharness.sh"
 | 
				
			||||||
 | 
							if [ -f "$f" ] ; then
 | 
				
			||||||
 | 
								SHARNESS="$f"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					if [ -z "$SHARNESS" ] || [ ! -f "$SHARNESS" ] ; then
 | 
				
			||||||
 | 
						echo "sharness.sh not found" >&2
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_set_prereq PYTHON
 | 
					# Prevent sharness from adding the source directory to PATH
 | 
				
			||||||
 | 
					# since the scripts use unversioned python for their shebang
 | 
				
			||||||
 | 
					# but tests should run under the python with mercurial support
 | 
				
			||||||
 | 
					# so create an empty directory and strip it from PATH afterwards
 | 
				
			||||||
 | 
					SHARNESS_BUILD_DIRECTORY="$(mktemp -d)"
 | 
				
			||||||
 | 
					. "$SHARNESS"
 | 
				
			||||||
 | 
					export PATH="${PATH#*:}"
 | 
				
			||||||
 | 
					rmdir "$SHARNESS_BUILD_DIRECTORY"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ -z "$TEST_INSTALLED_SCRIPTS" ] ; then
 | 
				
			||||||
 | 
						if [ -n "$PYTHON" ] && "$PYTHON" -c 'import mercurial' 2> /dev/null ; then
 | 
				
			||||||
 | 
							: Use chosen Python version
 | 
				
			||||||
 | 
						elif python3 -c 'import mercurial' 2> /dev/null ; then
 | 
				
			||||||
 | 
							PYTHON=python3
 | 
				
			||||||
 | 
						elif python2 -c 'import mercurial' 2> /dev/null ; then
 | 
				
			||||||
 | 
							PYTHON=python2
 | 
				
			||||||
 | 
						elif python -c 'import mercurial' 2> /dev/null ; then
 | 
				
			||||||
 | 
							PYTHON=python
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						if [ -n "$PYTHON" ] ; then
 | 
				
			||||||
 | 
							test_set_prereq PYTHON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Change shebang on a copy of scripts to chosen Python version
 | 
				
			||||||
 | 
							TEST_BIN="$SHARNESS_TRASH_DIRECTORY/bin"
 | 
				
			||||||
 | 
							mkdir -p "$TEST_BIN"
 | 
				
			||||||
 | 
							for s in git-remote-hg git-hg-helper ; do
 | 
				
			||||||
 | 
								printf "%s\n" "#!/usr/bin/env $PYTHON" > "$TEST_BIN/$s"
 | 
				
			||||||
 | 
								tail -n +2 "$SHARNESS_TEST_DIRECTORY/../$s" >> "$TEST_BIN/$s"
 | 
				
			||||||
 | 
								chmod u+x "$TEST_BIN/$s"
 | 
				
			||||||
 | 
							done
 | 
				
			||||||
 | 
							export PATH="$TEST_BIN${PATH:+:$PATH}"
 | 
				
			||||||
 | 
							unset TEST_BIN
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						# The build/install process ensures Python is available
 | 
				
			||||||
 | 
						test_set_prereq PYTHON
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GIT_AUTHOR_EMAIL=author@example.com
 | 
					GIT_AUTHOR_EMAIL=author@example.com
 | 
				
			||||||
GIT_AUTHOR_NAME='A U Thor'
 | 
					GIT_AUTHOR_NAME='A U Thor'
 | 
				
			||||||
@@ -10,3 +62,7 @@ GIT_COMMITTER_EMAIL=committer@example.com
 | 
				
			|||||||
GIT_COMMITTER_NAME='C O Mitter'
 | 
					GIT_COMMITTER_NAME='C O Mitter'
 | 
				
			||||||
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 | 
					export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 | 
				
			||||||
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 | 
					export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 | 
				
			||||||
 | 
					# maintain backwards compatible default
 | 
				
			||||||
 | 
					# (as used in remote helper)
 | 
				
			||||||
 | 
					git config --global init.defaultBranch master
 | 
				
			||||||
 | 
					git config --global protocol.file.allow always
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								tools/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tools/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					results.txt
 | 
				
			||||||
							
								
								
									
										303
									
								
								tools/check-versions
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										303
									
								
								tools/check-versions
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,303 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Copyright (c) 2019 Felipe Contreras
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This script runs the tests for all versions of the components:
 | 
				
			||||||
 | 
					#   hg, hggit and dulwich
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You can run it without arguments, in which case it reads the file
 | 
				
			||||||
 | 
					# 'versions.txt' and executes all those checks.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Or you can pass the versions to check manually, like:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   ./check-versions hg:4.7 hggit:0.8.12 dulwich:0.19.7
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Or you can pass just the hg version, the other versions are fetched from
 | 
				
			||||||
 | 
					# 'versions.txt':
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   ./check-versions hg:5.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'fileutils'
 | 
				
			||||||
 | 
					require 'tmpdir'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$tests = %w[main.t bidi.t hg-git.t]
 | 
				
			||||||
 | 
					$workdir = "#{Dir.home}/.cache/git-remote-hg"
 | 
				
			||||||
 | 
					$builddir = Dir.mktmpdir("git-remote-hg-build-")
 | 
				
			||||||
 | 
					$testoutdir = Dir.mktmpdir("git-remote-hg-tests-")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					at_exit {
 | 
				
			||||||
 | 
					  FileUtils.remove_entry($builddir)
 | 
				
			||||||
 | 
					  FileUtils.remove_entry($testoutdir)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QUIET, LOW, HIGH = (1..3).to_a
 | 
				
			||||||
 | 
					$verbosity = LOW
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Util {{{1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def section(text)
 | 
				
			||||||
 | 
					  puts [nil, text, '=' * text.size]
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def title(text)
 | 
				
			||||||
 | 
					  puts [nil, text, '-' * text.size] unless $verbosity < HIGH
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run_cmd(cmd, fatal: true)
 | 
				
			||||||
 | 
					  puts cmd.join(' ') unless $verbosity < HIGH
 | 
				
			||||||
 | 
					  result = system(*cmd)
 | 
				
			||||||
 | 
					  unless result or not fatal
 | 
				
			||||||
 | 
					    STDERR.puts "Failed to run command '%s'" % cmd.join(' ')
 | 
				
			||||||
 | 
					    exit -1
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  result
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check_version(a, b)
 | 
				
			||||||
 | 
					  return true if a == '@'
 | 
				
			||||||
 | 
					  a = a.split('.').map(&:to_i)
 | 
				
			||||||
 | 
					  b = b.split('.').map(&:to_i)
 | 
				
			||||||
 | 
					  (a <=> b) >= 0
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Component {{{1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  attr_reader :id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize(id, url, kind: nil, **args)
 | 
				
			||||||
 | 
					    @id = id
 | 
				
			||||||
 | 
					    @url = url
 | 
				
			||||||
 | 
					    @kind = kind || (url.start_with?('git') ? :git : :hg)
 | 
				
			||||||
 | 
					    @tool = @kind.to_s
 | 
				
			||||||
 | 
					    @checkout_fix = args[:checkout_fix]
 | 
				
			||||||
 | 
					    @version_format = args[:version_format]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def dir
 | 
				
			||||||
 | 
					    "#{$workdir}/#{@id}"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def get_version(version)
 | 
				
			||||||
 | 
					    return @kind == :hg ? 'tip' : '@' if version == '@'
 | 
				
			||||||
 | 
					    @version_format ? @version_format % version : version
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def clone
 | 
				
			||||||
 | 
					    run_cmd [@tool, 'clone', '-q', @url, dir]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def checkout(version)
 | 
				
			||||||
 | 
					    Dir.chdir(dir) do
 | 
				
			||||||
 | 
					      case @kind
 | 
				
			||||||
 | 
					      when :hg
 | 
				
			||||||
 | 
					        cmd = %w[update --clean]
 | 
				
			||||||
 | 
					      when :git
 | 
				
			||||||
 | 
					        cmd = %w[reset --hard]
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        cmd = %w[checkout]
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      run_cmd [@tool] + cmd + ['-q', get_version(version)]
 | 
				
			||||||
 | 
					      @checkout_fix.call(version) if @checkout_fix
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def build
 | 
				
			||||||
 | 
					    Dir.chdir(dir) do
 | 
				
			||||||
 | 
					      targets = %w[build_py build_ext].map { |e| [e, '--build-lib', "#{$builddir}/python"] }
 | 
				
			||||||
 | 
					      run_cmd %w[python setup.py --quiet] + targets.flatten
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Functions {{{1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def setup
 | 
				
			||||||
 | 
					  dirs = %w[bin python]
 | 
				
			||||||
 | 
					  FileUtils.mkdir_p(dirs.map { |e| "#{$builddir}/#{e}" })
 | 
				
			||||||
 | 
					  FileUtils.mkdir_p($workdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $components.each do |id, component|
 | 
				
			||||||
 | 
					    next if File.exists?(component.dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if $verbosity < HIGH
 | 
				
			||||||
 | 
					      puts "Cloning #{component.id}"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      title "Cloning #{component.id}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    component.clone
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_env(paths: nil)
 | 
				
			||||||
 | 
					  old = ENV.to_h
 | 
				
			||||||
 | 
					  paths.each do |id, path|
 | 
				
			||||||
 | 
					    name = id.to_s
 | 
				
			||||||
 | 
					    ENV[name] = "#{path}:#{ENV[name]}"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  r = yield
 | 
				
			||||||
 | 
					  ENV.replace(old)
 | 
				
			||||||
 | 
					  return r
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run_tests(tests)
 | 
				
			||||||
 | 
					  title "Running tests"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Dir.chdir("#{__dir__}/../test") do
 | 
				
			||||||
 | 
					    case $verbosity
 | 
				
			||||||
 | 
					    when QUIET
 | 
				
			||||||
 | 
					      tests_opt = tests.join(' ')
 | 
				
			||||||
 | 
					      cmd = "prove -q #{tests_opt} :: -i"
 | 
				
			||||||
 | 
					    when LOW
 | 
				
			||||||
 | 
					      tests_opt = "T='%s'" % tests.join(' ')
 | 
				
			||||||
 | 
					      cmd = "make -j1 #{tests_opt}"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      tests_opt = "T='%s'" % tests.join(' ')
 | 
				
			||||||
 | 
					      cmd = "TEST_OPTS='-v -i' make -j1 #{tests_opt}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    system(cmd)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def versions_to_s(versions)
 | 
				
			||||||
 | 
					  versions.map { |k,v| "#{k}:#{v}" }.join(' ')
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def versions_from_args(args)
 | 
				
			||||||
 | 
					  args.map { |e| k, v = e.split(':'); [k.to_sym, v] }.to_h
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def versions_from_s(str)
 | 
				
			||||||
 | 
					  versions_from_args(str.split(' '))
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check(versions)
 | 
				
			||||||
 | 
					  section versions_to_s(versions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  versions.each do |id, version|
 | 
				
			||||||
 | 
					    component = $components[id]
 | 
				
			||||||
 | 
					    next unless component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    title "Checking out #{component.id} #{version}"
 | 
				
			||||||
 | 
					    component.checkout(version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    title "Building #{component.id}"
 | 
				
			||||||
 | 
					    component.build
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  paths = {
 | 
				
			||||||
 | 
					    PATH: "#{$builddir}/bin",
 | 
				
			||||||
 | 
					    PYTHONPATH: "#{$builddir}/python",
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test_env(paths: paths) do
 | 
				
			||||||
 | 
					    ENV['SHARNESS_TEST_OUTPUT_DIRECTORY'] = $testoutdir
 | 
				
			||||||
 | 
					    run_tests($tests)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add components {{{1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$components = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def add_component(id, url, **args)
 | 
				
			||||||
 | 
					  $components[id] = Component.new(id, url, **args)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hg_checkout_fix = lambda do |version|
 | 
				
			||||||
 | 
					  FileUtils.cp('hg', "#{$builddir}/bin/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return if check_version(version, '4.3')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if run_cmd %W[hg import -q --no-commit #{__dir__}/hg_setup_hack_2.4.patch], fatal: false
 | 
				
			||||||
 | 
					    File.write('.hg_force_version', "%s\n" % version)
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    File.write('mercurial/__version__.py', "version = \"%s\"\n" % version)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_component(:hg, 'https://www.mercurial-scm.org/repo/hg', checkout_fix: hg_checkout_fix)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hggit_checkout_fix = lambda do |version|
 | 
				
			||||||
 | 
					  return unless check_version(version, '0.8.0')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run_cmd %W[hg import -q --no-commit #{__dir__}/hggit_rename_fix_0.8.0.patch], fatal: false
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_component(:hggit, 'https://bitbucket.org/durin42/hg-git', checkout_fix: hggit_checkout_fix)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_component(:dulwich, 'https://github.com/dulwich/dulwich.git', version_format: 'dulwich-%s', kind: :git)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load_checks(file)
 | 
				
			||||||
 | 
					  file.each do |e|
 | 
				
			||||||
 | 
					    e.chomp!
 | 
				
			||||||
 | 
					    next if e.empty? or e.start_with?('#')
 | 
				
			||||||
 | 
					    content, comment = e.split(' # ')
 | 
				
			||||||
 | 
					    versions = versions_from_s(content)
 | 
				
			||||||
 | 
					    $checks << versions
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def store_results(file)
 | 
				
			||||||
 | 
					  $results.each do |versions, result|
 | 
				
			||||||
 | 
					    content = versions_to_s(versions)
 | 
				
			||||||
 | 
					    comment = result ? 'OK' : 'FAIL'
 | 
				
			||||||
 | 
					    file.puts '%s # %s' % [content, comment]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Main {{{1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$checks = []
 | 
				
			||||||
 | 
					$results = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$versions = versions_from_args(ARGV)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					File.open("#{__dir__}/versions.txt") do |f|
 | 
				
			||||||
 | 
					  load_checks(f)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if $versions.size == 1 and $versions.key?(:hg)
 | 
				
			||||||
 | 
					  # mode 1
 | 
				
			||||||
 | 
					  $verbosity = LOW
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ['@', nil].include?($versions[:hg])
 | 
				
			||||||
 | 
					    versions = $checks.last
 | 
				
			||||||
 | 
					    versions[:hg] = $versions[:hg] if $versions[:hg]
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    versions = $checks.find { |e| e[:hg] == $versions[:hg] }
 | 
				
			||||||
 | 
					    exit 1 unless versions
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exit check(versions) ? 0 : 1
 | 
				
			||||||
 | 
					elsif not $versions.empty?
 | 
				
			||||||
 | 
					  # mode 2
 | 
				
			||||||
 | 
					  $verbosity = HIGH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exit check(versions) ? 0 : 1
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					  # mode 3
 | 
				
			||||||
 | 
					  $verbosity = QUIET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  at_exit do
 | 
				
			||||||
 | 
					    File.open("#{__dir__}/results.txt", 'w') do |f|
 | 
				
			||||||
 | 
					      store_results(f)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  failures = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $checks.each do |versions|
 | 
				
			||||||
 | 
					    result = check(versions)
 | 
				
			||||||
 | 
					    failures += 1 unless result
 | 
				
			||||||
 | 
					    $results << [versions, result]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exit 1 unless failures == 0
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										15
									
								
								tools/hg_setup_hack_2.4.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tools/hg_setup_hack_2.4.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					diff --git a/setup.py b/setup.py
 | 
				
			||||||
 | 
					--- a/setup.py
 | 
				
			||||||
 | 
					+++ b/setup.py
 | 
				
			||||||
 | 
					@@ -181,7 +181,10 @@
 | 
				
			||||||
 | 
					     # error 0xc0150004. See: http://bugs.python.org/issue3440
 | 
				
			||||||
 | 
					     env['SystemRoot'] = os.environ['SystemRoot']
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					-if os.path.isdir('.hg'):
 | 
				
			||||||
 | 
					+if os.path.exists('.hg_force_version'):
 | 
				
			||||||
 | 
					+    with open('.hg_force_version') as f:
 | 
				
			||||||
 | 
					+        version = f.read().rstrip('\n')
 | 
				
			||||||
 | 
					+elif os.path.isdir('.hg'):
 | 
				
			||||||
 | 
					     cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
 | 
				
			||||||
 | 
					     numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
 | 
				
			||||||
 | 
					     hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
 | 
				
			||||||
							
								
								
									
										22
									
								
								tools/hggit_rename_fix_0.8.0.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tools/hggit_rename_fix_0.8.0.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					diff --git a/hggit/git_handler.py b/hggit/git_handler.py
 | 
				
			||||||
 | 
					--- a/hggit/git_handler.py
 | 
				
			||||||
 | 
					+++ b/hggit/git_handler.py
 | 
				
			||||||
 | 
					@@ -693,6 +693,8 @@
 | 
				
			||||||
 | 
					     def import_git_commit(self, commit):
 | 
				
			||||||
 | 
					         self.ui.debug(_("importing: %s\n") % commit.id)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					+        extra_in_message = self.ui.configbool('git', 'debugextrainmessage', False)
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					         detect_renames = False
 | 
				
			||||||
 | 
					         (strip_message, hg_renames,
 | 
				
			||||||
 | 
					          hg_branch, extra) = git2hg.extract_hg_metadata(
 | 
				
			||||||
 | 
					@@ -703,7 +705,8 @@
 | 
				
			||||||
 | 
					             # renames detected from Git. This is because we export an extra
 | 
				
			||||||
 | 
					             # 'HG:rename-source' Git parameter when this isn't set, which will
 | 
				
			||||||
 | 
					             # break bidirectionality.
 | 
				
			||||||
 | 
					-            extra['hg-git-rename-source'] = 'git'
 | 
				
			||||||
 | 
					+            if not extra_in_message:
 | 
				
			||||||
 | 
					+                extra['hg-git-rename-source'] = 'git'
 | 
				
			||||||
 | 
					         else:
 | 
				
			||||||
 | 
					             renames = hg_renames
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
							
								
								
									
										33
									
								
								tools/versions.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tools/versions.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					# vi: ft=ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hg:2.4 hggit:0.4.0 dulwich:0.9.0 # 2013_02
 | 
				
			||||||
 | 
					hg:2.5 hggit:0.4.0 dulwich:0.9.0 # 2013_02
 | 
				
			||||||
 | 
					hg:2.6 hggit:0.4.0 dulwich:0.9.0 # 2013_02
 | 
				
			||||||
 | 
					hg:2.7 hggit:0.4.0 dulwich:0.9.0 # 2013_02
 | 
				
			||||||
 | 
					hg:2.8 hggit:0.4.0 dulwich:0.9.0 # 2013_02
 | 
				
			||||||
 | 
					hg:2.9 hggit:0.4.0 dulwich:0.9.0 # 2013_02
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hg:3.0 hggit:0.7.0 dulwich:0.10.0 # 2014_11
 | 
				
			||||||
 | 
					hg:3.1 hggit:0.7.0 dulwich:0.10.0 # 2014_11
 | 
				
			||||||
 | 
					hg:3.2 hggit:0.7.0 dulwich:0.10.0 # 2014_11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hg:3.3 hggit:0.8.4 dulwich:0.13.0 # 2016_01
 | 
				
			||||||
 | 
					hg:3.4 hggit:0.8.4 dulwich:0.13.0 # 2016_01
 | 
				
			||||||
 | 
					hg:3.5 hggit:0.8.4 dulwich:0.13.0 # 2016_01
 | 
				
			||||||
 | 
					hg:3.6 hggit:0.8.4 dulwich:0.13.0 # 2016_01
 | 
				
			||||||
 | 
					hg:3.7 hggit:0.8.4 dulwich:0.13.0 # 2016_01
 | 
				
			||||||
 | 
					hg:3.8 hggit:0.8.4 dulwich:0.13.0 # 2016_01
 | 
				
			||||||
 | 
					hg:3.9 hggit:0.8.4 dulwich:0.13.0 # 2016_01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hg:4.0 hggit:0.8.10 dulwich:0.18.0 # 2017_11
 | 
				
			||||||
 | 
					hg:4.1 hggit:0.8.10 dulwich:0.18.0 # 2017_11
 | 
				
			||||||
 | 
					hg:4.2 hggit:0.8.10 dulwich:0.18.0 # 2017_11
 | 
				
			||||||
 | 
					hg:4.3 hggit:0.8.10 dulwich:0.18.0 # 2017_11
 | 
				
			||||||
 | 
					hg:4.4 hggit:0.8.10 dulwich:0.18.0 # 2017_11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hg:4.5 hggit:0.8.11 dulwich:0.18.0 # 2018_02
 | 
				
			||||||
 | 
					hg:4.6 hggit:0.8.12 dulwich:0.19.7 # 2018_10
 | 
				
			||||||
 | 
					hg:4.7 hggit:0.8.12 dulwich:0.19.7 # 2018_10
 | 
				
			||||||
 | 
					hg:4.8 hggit:@ dulwich:0.19.11
 | 
				
			||||||
 | 
					hg:4.9 hggit:@ dulwich:0.19.11
 | 
				
			||||||
 | 
					hg:5.0 hggit:@ dulwich:0.19.11
 | 
				
			||||||
		Reference in New Issue
	
	Block a user