222 Commits
v0.1 ... v1.0.3

Author SHA1 Message Date
Mark Nauwelaerts
8c08b6de21 Release v1.0.3 2022-02-21 22:55:11 +01:00
Mark Nauwelaerts
949345fb11 test: drop check on default
... since default branch is updated semi-random (implementation defined) from
the last non-branch push.

Fixes mnauw/git-remote-hg#48
2022-02-20 15:38:54 +01:00
Mark Nauwelaerts
0d49f75131 test: additional basic configuration 2022-02-20 15:38:54 +01:00
Mark Nauwelaerts
7159e4a030 Ensure URL encoding of tilde when sanitizing refname
Fixes mnauw/git-remote-hg#44
2021-08-28 20:29:59 +02:00
Paul Wise
cdcd70b453 Tell git to ignore the Python setuptools build/dist/metadata dirs
This helps ensure these don't get committed by accident and
helps prevent git interacting with them in other ways.
2021-08-22 21:14:24 +02:00
Paul Wise
f5c38f3a59 Run Python scripts under the chosen version
The Python scripts have unversioned Python shebangs so tests will
fail if the chosen Python version is not unversioned Python.

Copy the scripts to tmp dirs and change the shebang to the chosen Python.

Also prevent sharness from adding the unversioned Python scripts to PATH.
2021-04-05 13:27:00 +02:00
Paul Wise
3b11156e69 Detect which Python version is available and run tests using it
Allow overriding the Python version.

Use importing the mercurial module as the test rather than just python,
and merge the python and mercurial module skipping into one test for both
since the mercurial module has to work under the chosen python version.
2021-04-05 13:27:00 +02:00
Paul Wise
afc1f3a2c2 Try to install Python scripts with versioned Python shebangs
Allow overriding the Python version.

The Python setuptools based build system already modifies shebangs.

The Python scripts have unversioned Python shebangs so they
will fail if an unversioned Python is not provided by the OS.

The Debian bullseye release will not have an unversioned Python by default.

Avoid make pattern rules and shell functions since they are not portable.
2021-04-05 13:27:00 +02:00
Paul Wise
e596a5f457 Add missing line ending at EOF 2021-04-05 13:25:36 +02:00
Paul Wise
ec654d4682 Be more flexible about the path to sharness
Some folks might want to run a different version.

Check all the common installation paths and
support using a custom path to sharness.
2021-04-03 10:29:48 +02:00
Paul Wise
7913920a97 Create temporary directories dynamically
This avoids creating them in /tmp when another tmp dir was chosen.
2021-04-03 10:03:10 +02:00
Paul Wise
da60201ae3 Clean up temporary directories on exit 2021-04-03 10:03:10 +02:00
Paul Wise
704869df29 Install git-hg-helper when using the make build system
It is used by git-remote-hg and the Python
also setuptools build system installs it.
2021-04-03 10:02:49 +02:00
Paul Wise
5769e965eb Expect success for the main pull tags test
The git bug that caused the switch to unstable has been fixed.

This reverts commit a5dfc9025b.
2021-04-03 10:01:35 +02:00
Paul Wise
1ee28bd233 Use a compatible umask for the executable bit preservation test
More restrictive umasks like 027 will cause the test to fail.

Ubuntu 21.04 will change the default umask to 027.
2021-04-03 10:00:58 +02:00
Paul Wise
1796289df3 Remove unused Python imports in the setuptools build system
Suggested-by: vulture
2021-04-03 10:00:18 +02:00
Mark Nauwelaerts
929ae262f5 Release v1.0.2.1 2020-08-03 21:07:22 +02:00
Mark Nauwelaerts
4328aa1c19 setup: add python3 as supported version 2020-08-03 21:07:22 +02:00
Mark Nauwelaerts
919678be4a Release v1.0.2 2020-07-19 19:18:17 +02:00
Mark Nauwelaerts
ac8f659620 Really use generic python reference in shebang 2020-07-19 19:08:31 +02:00
Mark Nauwelaerts
28ed63b707 test: use generic python reference rather than python2 2020-06-12 14:00:17 +02:00
Mark Nauwelaerts
dc91c58e1c Use generic python reference in shebang 2020-06-12 14:00:17 +02:00
Mark Nauwelaerts
46178f546a test: use a legacy mode for hg-git test 2020-06-12 13:42:19 +02:00
Mark Nauwelaerts
4c0e8e6439 Make tag writing more robust 2020-06-12 13:42:19 +02:00
Mark Nauwelaerts
59b5a8c848 Make python2/3 compatible
See mnauw/git-remote-hg#27
2020-06-12 13:26:45 +02:00
Mark Nauwelaerts
be2445963b test: align order of options to stable ArgumentParser expectation 2020-06-12 13:20:25 +02:00
Mark Nauwelaerts
8b4bfe7e87 test: drop check on master in push mode
... since master is picked semi-random (implementation defined) in case
of multiple default branch tips

This mainly affects push mode since a preceding command succeeds
partially (and therefore affect the random), whereas the preceding fails
completely in non-push mode.
2020-06-12 13:20:25 +02:00
Mark Nauwelaerts
741b440fcc Apply url encoding for additional refname sanitizing
Fixes mnauw/git-remote-hg#33
2020-06-12 13:20:25 +02:00
Mark Nauwelaerts
03b1ac9845 Correctly check for valid revision
Fixes mnauw/git-remote-hg#32
2020-06-12 13:20:25 +02:00
Mark Nauwelaerts
f3a8546406 Merge branch 'felipec'
Integrate changes from felipec where appropriate and still relevant.
2020-06-01 13:02:48 +02:00
Mark Nauwelaerts
ccc9e55b7e Merge remote-tracking branch 'felipec/master' into felipec
These remaining changes have been mostly superseded
(e.g. revwalk iso gitrange, no more fetch-first error).
2020-06-01 12:58:26 +02:00
Mark Nauwelaerts
b516aa9326 Merge commit 'b3cd' into felipec
These changes can be merged with limited to none conflict resolution.
2020-06-01 12:57:26 +02:00
Mark Nauwelaerts
08626200d0 Merge commit '7fb9' into felipec
An unattributed variation of existing commits that can be discarded.
2020-06-01 12:54:44 +02:00
Mark Nauwelaerts
b60eb47173 Merge commit 'fad59f' into felipec
These changes can be merged with limited to none conflict resolution.
2020-06-01 12:52:41 +02:00
Mark Nauwelaerts
76162ce148 Merge commit '4d33' into felipec
These changes are unattributed ports of existing fixes and can as such
mostly be discarded.
2020-06-01 11:53:36 +02:00
Mark Nauwelaerts
7ae03f7640 Merge commit '5cc27' into felipec
These changes can be merged with limited to none conflict resolution.
2020-06-01 11:38:52 +02:00
Mark Nauwelaerts
95da53badd test: adjust push force to push mode behavior 2020-06-01 11:12:50 +02:00
Mark Nauwelaerts
a0608664ca Remove commented remnant 2020-06-01 11:12:34 +02:00
David Turner
9d6d135855 fix race fix on local repos 2019-08-03 21:23:51 +02:00
David Turner
60a6c7b36d Fix a race condition
If new heads are created on a remote http repo after we pull but
before we request branch heads, we'll try to read a head that we don't
actually have locally.  To fix this, we request the branchmap before
fetching, and only fetch the heads that we just learned about.
2019-07-22 21:22:09 +02:00
Felipe Contreras
74d1aa14ac gitrange(): general refactoring
To make the code more readable.

No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-20 14:39:36 -05:00
Felipe Contreras
1d85449b0b gitrange(): always check negatives first
Also, always add the parents as negatives.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-20 14:36:21 -05:00
Felipe Contreras
fe8b8c1a61 gitrange(): store parentrevs method
By calling the methods through a variable the code is significantly
faster.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-20 14:36:07 -05:00
Felipe Contreras
510441bba9 gitrange(): add a == b check
Otherwise we return the whole repository. Thanks to the marks we don't
actually export it, but there's no need to return so many revs.

Reported-by: Mark Nauwelaerts <mnauw@users.sourceforge.net>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-20 14:35:45 -05:00
Mark Nauwelaerts
fa3484e08b Find outgoing changesets earlier
This way we can find if we actually need to push something.

Recent versions of Mercurial already handle this correctly, but let's
check ourselves to make sure, and make it work with all versions.

Rewritten-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-19 10:12:05 -05:00
Mark Nauwelaerts
d1544e2ccd test: pushing a bookmark without changesets
This works in recent versions of Mercurial.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-19 09:58:21 -05:00
Felipe Contreras
153a216f47 test: main: cleanup big push fetch first
In order to use setup_big_push().

No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-18 19:24:19 -05:00
Felipe Contreras
b3cdbe8e96 Allow --force --dry-run
No reason for it not to work.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-18 18:50:52 -05:00
Felipe Contreras
d11509cab7 test: main: trivial cleanup
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-18 18:45:03 -05:00
Felipe Contreras
4d01165b1b test: main: fix check_push() bug
We were not checking the kind correctly. Add a new case switch to avoid
these issues.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-18 18:18:00 -05:00
Felipe Contreras
a030d603ac test: main: cleanup check_push()
Return immediately after a failure.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-18 18:11:05 -05:00
Felipe Contreras
3d4a5a6d7e Trivial cleanup
By adding a helper function the code is more understandable.

No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-18 15:22:09 -05:00
Felipe Contreras
7fb9d9b642 Load global UI confguration
Since 4.1 there's a separate function for that.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-18 15:06:39 -05:00
Felipe Contreras
fad59f53eb Refactor timezone functions
Split them into hours and minutes, and use divmod() to make them more
readable.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-05 03:17:39 -05:00
Oliver Stueker
e17e147fb1 Fix timezone issue with negative offsets
The current code miscalculates the time-zone offsets for time zones that don't
have a full-hour offset and are located west of UTC (e.g. St. John's,
Newfoundland).

Basically it's caused because 33 // 10 == 3, but -33 // 10 != -3.

Take the example of St. John's (-0330). The correct integer timezone should be
3.5 * 3600 (12600), however, since we are not checking for negative module
arithmetic, instead of calculating the timezone for (-3, -30), we are doing it
for (-4, 70), which would be OK... if we had hours of 100 minutes:

  -4 * 100 + 70 = -330

We could fix the code to use proper negative arithmetic (mod -100), but why
bother with the extra complexity? Let's just use absolute numbers and fix the
sign later.

This fixes issue #48.

Commit message written by Felipe Contreras.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-05 03:12:47 -05:00
Felipe Contreras
4878023a8b Add helper for hg timezone
No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 15:30:38 -05:00
Oliver Stueker
0dfae24d21 test: add test for issue with negative offsets
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 15:30:36 -05:00
Felipe Contreras
c7dbb5612b Add timezone bidirectionality test
Oliver Stueker pointed out correctly that there is an issue with the way
we handle negative timestamps that don't have a full hour offset.

This test shows that.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 15:28:35 -05:00
Felipe Contreras
cc4e5659d9 Merge branch 'check-versions'
* check-versions:
  travis: use check-versions tool
  check-versions: add hack for hg-git 0.8.x
  Add tool to run tests on many versions
2019-06-04 04:02:38 -05:00
Felipe Contreras
2c993b3433 travis: use check-versions tool
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 04:02:12 -05:00
Felipe Contreras
4944a384cd check-versions: add hack for hg-git 0.8.x
They made a mistake and broke bidirectionality when debugextrainmessage
is used.

The upstream report:

  https://bitbucket.org/durin42/hg-git/issues/281/

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 04:02:12 -05:00
Felipe Contreras
f29c42c645 Add tool to run tests on many versions
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 04:02:12 -05:00
Felipe Contreras
7b7c65f72d README: remove old limitations
They work now.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 04:02:06 -05:00
Felipe Contreras
cee3ed7c00 travis: add pip cache
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 00:56:41 -05:00
Felipe Contreras
01c9a981c7 travis: install latest released version of hg
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 00:18:18 -05:00
Felipe Contreras
d0a5888580 travis: update Mercurial versions
And general cleanups.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-04 00:12:47 -05:00
Felipe Contreras
a5dfc9025b test: mark a regression in Git
The issue is reported, and a proposed fix has been sent:

  https://marc.info/?l=git&m=155961441427321

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 21:32:05 -05:00
Felipe Contreras
4d337cff06 Don't catch all exceptions in export_ref()
Just in case.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
5cc271ef18 test: hggit: add simple file rename test
The Hg-Git project has put a lot of emphasis on file renaming, better
check for that explicitly, even though we are already testing that.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
c8fff2cd06 Use changelog.isancestorrev()
The old changelog.descendant() is deprecated in 4.7, gone in 4.8.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
c95fba3c18 Don't call repo[tag] directly
Deprecated in 4.6, gone in 4.7.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
aaef56a2a3 Use marks.applychange()
Since 4.3 bookmarks are updated with applychanges() and since 4.6
anything else is deprecated.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
a16c69a99c Refactor updatebookmarks()
Also, use the proper lock, even for older versions.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
00e95fd8df Call node.rev() instead of int(node)
The int(node) method has been removed in 4.6.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
5bf7aad6e3 Fix memfilectx() params
These changed again in 4.5.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
9b8e0ec2c0 Refactor memfilectx() method
It's getting hairy.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
b309562574 Use makechangegroup()
Since 4.4 we have yet another way to push revisions.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
e25d3d78cd Use repo.vfs() instead of repo.opener()
The method() opener has been a link to vfs() since a long time, and it's
now removed in 4.3.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
ed5a70706a Fix getchangegroup() for 4.0
The arguments heads and common have been removed.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 20:23:18 -05:00
Felipe Contreras
0faf2c9189 Tell hg-git to be backwards compatible
Since version 0.7.0 hg-git stores extra information directly into the
commits, we don't support that, so we need to tell hg-git to do what it
always did: put the extra data in the message.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 19:54:48 -05:00
Felipe Contreras
ada49422a7 test: add test for annotated tags
So we make sure they keep working as expected.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 19:54:39 -05:00
Felipe Contreras
580cea0d31 Explicitly process tags
Normally tag commands come with a corresponding ref, but not since
Git v2.21.

It's not clear if Git's change is correct, but fix it our end anyway.

  fdf31b6369 (fast-export: ensure we export requested refs)

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 19:51:38 -05:00
Felipe Contreras
1f376e437f Revert "test: skip tests with broken hg-git compatibility"
We need to fix the compatibility.

This reverts commit 29a0d8a0e3.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 19:51:35 -05:00
Felipe Contreras
4108665799 Add version check for filelog creation
The functions are only present in 3.2. Older versions don't need this
code.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 19:49:54 -05:00
Felipe Contreras
fc28115a53 Avoid ManifestLookupError
In versions older than 2.6 ManifestLookupError doesn't exist.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 19:49:08 -05:00
Felipe Contreras
e3009683f8 test: add missing &&s
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 14:55:25 -05:00
Felipe Contreras
54cec85f94 test: update expected result
It seems these work since Git v2.0.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 14:55:20 -05:00
Felipe Contreras
5ad322c54d Merge branch 'sharness-output-dir'
* sharness-output-dir:
  test: sharness: add support for output directory
2019-06-03 14:54:51 -05:00
Felipe Contreras
13bbc8a342 test: sharness: add support for output directory
I don't know why this was removed from Git's version.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 14:54:44 -05:00
Felipe Contreras
673b50d3f4 test: update to sharness 1.1
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2019-06-03 14:54:29 -05:00
Mark Nauwelaerts
35ecb45fda Tweak hg to git ref name translation
Fixes mnauw/git-remote-hg#26
2019-05-19 13:01:59 +02:00
Mark Nauwelaerts
1456e68129 Really strip prefix to ensure a valid package version 2019-04-28 14:32:42 +02:00
Mark Nauwelaerts
de95133416 Release v1.0.1 2019-04-27 15:08:20 +02:00
Mark Nauwelaerts
e0b752be8f Move release version management to make stage
... to ensure setup.py does not trip some later time.

Fixes mnauw/git-remote-hg#25
2019-04-27 15:08:20 +02:00
native-api
f050de1bcc Additional installation step in Windows
fixes https://github.com/mnauw/git-remote-hg/issues/23
2019-03-19 20:41:21 +01:00
Mark Nauwelaerts
0bf3db826b Handle platform dependency in atomic file renaming 2019-01-06 15:51:42 +01:00
Mark Nauwelaerts
3698638e98 Always pass forward slash to git
Fixes mnauw/git-remote-hg#22
2019-01-06 15:51:42 +01:00
Mark Nauwelaerts
765f9ae287 Add python pip packaging
Fixes mnauw/git-remote-hg#13
2018-10-14 16:27:51 +02:00
Mark Nauwelaerts
5ddcdd33ec Adjust to Mercurial 4.7 wrt deprecated revlog method 2018-09-09 12:08:29 +02:00
Mark Nauwelaerts
435373ee83 Adjust to Mercurial 4.7 wrt more restricted changectx API
Fixes mnauw/git-remote-hg#18
2018-09-09 12:08:26 +02:00
Mark Nauwelaerts
5e96683f67 Adjust to Mercurial 4.6 wrt revision numbers
... as modified in 38f4805020437f126f5c1c8f41d78445f9ab6547

Fixes mnauw/git-remote-hg#16
2018-05-14 21:40:37 +02:00
Mark Nauwelaerts
144f48df44 Adjust to Mercurial 4.6 wrt bookmarks
... as modified in cd23423029287e299d65bbece497ff09a2a673f4
2018-05-14 21:40:37 +02:00
Mark Nauwelaerts
ad36a25064 helper: adjust to Mercurial 4.6 wrt subrepo helper functions
... now in a separate module as of 55e8efa2451a0999b56978e471dc31dc8066a0fb
2018-05-14 21:27:40 +02:00
Mark Nauwelaerts
679e016943 Adjust to modified internals of Mercurial 4.5
Fixes mnauw/git-remote-hg#12
2018-02-07 18:47:18 +01:00
Mark Nauwelaerts
9f6c541a2c test: tweak and clarify copy-rename test
... to align it with current git's more restricted behavior
2017-12-03 14:29:27 +01:00
Mark Nauwelaerts
476ffcbde0 test: adjust to recent git-fast-export which only detects exact copy
Fixes mnauw/git-remote-hg#11
2017-11-28 20:50:18 +01:00
Mark Nauwelaerts
76be528c0d Optionally ignore some remote Mercurial revision names
... in particular when these would otherwise map to unsupported refnames.

Fixes mnauw/git-remote-hg#10
2017-11-27 20:57:19 +01:00
Mark Nauwelaerts
6c2f4d8ff4 Adjust to recent Mercurial API in pushing to remote
Fixes mnauw/git-remote-hg#9
2017-11-11 17:23:46 +01:00
Mark Nauwelaerts
e9c37f78d8 test: adjust hg subrepo configuration 2017-11-11 17:23:46 +01:00
Mark Nauwelaerts
dfa6910cab Adjust to recent Mercurial API in hg-git mode tag handling 2017-09-21 13:15:20 +02:00
Mark Nauwelaerts
2ab9ae9073 Use ui.ui.load() only if available 2017-09-18 21:24:22 +02:00
Beren Minor
f21923b052 Add info about hg repos used as git submodules 2017-09-18 20:24:24 +02:00
Beren Minor
45866dbeba Use ui.ui.load() to create a new ui which loads the global and user hg config 2017-09-18 13:47:01 +02:00
Renaud Casenave-Péré
eaa9361ab0 Fix README formatting 2017-08-09 19:00:41 +02:00
Mark Nauwelaerts
f0e4c95bf5 Add test for importing multiple independent histories
Based on reproduction steps provided by Adam Bliss.
2017-05-01 14:51:19 +02:00
David Turner
e467b22dd3 Fix obscure bug with multiple independent histories
If you have a repository with multiple independent histories (perhaps
that get merged later), under some circumstances revision 0 can get
imported *after* some other revision.  "Independent histories" are those
that start from different zero-parent commits.  I have thus far failed to
get a local reproduction on this, in part because I don't understand
how git-remote-hg choses the order in which to import branches.  But
we did notice this in our production system.

If revision 0 is imported late, a reset would not be issued, and it would
be wrongly re-parented on top of whatever previous history existed, instead
of being a root-level commit.

Fix this by always issuing a reset for a parentless commit, even on
revision 0.
2017-04-21 16:47:36 -04:00
Mark Nauwelaerts
40c9eafcc9 Fix corner case version calculation 2017-03-13 20:53:44 +01:00
Mark Nauwelaerts
0bfbc0da4b Merge pull request #4 from novalis/dturner/do-not-mangle-quotes
Optionally don't mangle git usernames with quotes
2016-12-06 22:02:02 +01:00
David Turner
a1ca279d92 Optionally don't mangle git usernames with quotes
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), add an option 'remote-hg.remove-username-quotes'. This
option defaults to true (for backwards compatibility).
2016-12-05 16:08:01 -05:00
David Turner
e19dd84571 hack for submodules
A complete solution for submodules might be to convert them to hg
subrepositories.  But this would, in the general case, be quite
difficult -- for instance, local copies of all historical submodule
commits might not be available, and repositories might have moved
around.

It's better to do the conversion in some understandable way than to
crash with a weird error message, so let's do that.
2016-11-29 16:41:21 -05:00
Mark Nauwelaerts
1d94ba2d42 Add compatibility for Mercurial v4.0
Fixes felipec/git-remote-hg#66
2016-11-22 19:54:09 +01:00
Mark Nauwelaerts
85b585b824 Make unit test for executable rename slightly more resilient. 2016-11-15 20:51:21 +01:00
David Turner
e8c88c70d9 Fix mode setting in the case of moved executable files 2016-11-14 18:13:56 -05:00
Mark Nauwelaerts
a35f93cbc1 Fix duplication typos in marks file migration.
Fixes mnauw/git-remote-hg#1
2016-11-12 16:18:04 +01:00
Mark Nauwelaerts
a59e1246a2 Refactor updating of notes upon fetch and push 2016-10-18 21:32:26 +02:00
Mark Nauwelaerts
cbbbaddc41 Support using shared marks files for all remotes
... which essentially track the shared bag of revisions that
the shared proxy repo constitutes.
2016-10-18 21:32:19 +02:00
Mark Nauwelaerts
5d429d2da1 Refactor all marks file path access through common variable 2016-10-18 21:32:11 +02:00
Mark Nauwelaerts
94bb2488e8 Fix comment typo 2016-10-18 21:32:04 +02:00
Mark Nauwelaerts
e759d5232d README: clarify documentation on strip recovery 2016-10-18 21:31:57 +02:00
Mark Nauwelaerts
af96a84c98 Do not actually delete branch in case of dry-run 2016-10-18 21:31:48 +02:00
Mark Nauwelaerts
2ce962c5ab Really delete the private branch ref when deleting a branch 2016-10-18 21:31:34 +02:00
Mark Nauwelaerts
8ac5532eb1 Add to copyright for recent changes
... as there have been quite some by now.
2016-10-18 21:18:21 +02:00
Mark Nauwelaerts
9528e757d3 git-hg-helper: use an absolute path in sharedpath to refer to shared repo
... as some Mercurial commands are otherwise confused, e.g. thg.
2016-08-20 11:05:54 +02:00
Mark Nauwelaerts
628c45a4a9 Avoid bytecode generation when importing 2016-08-20 11:05:54 +02:00
Mark Nauwelaerts
55689eb0a8 git-hg-helper: refactor importing sibling module 2016-08-20 11:05:54 +02:00
Mark Nauwelaerts
7be9bf3db4 git-hg-helper: ensure proper directory tracking 2016-08-20 11:05:49 +02:00
Mark Nauwelaerts
20e923cf91 git-hg-helper: gc: resurrect Mercurial repo revision checking 2016-08-20 11:05:49 +02:00
Mark Nauwelaerts
a7ea76788c README: update documentation with latest changes on fetching 2016-08-13 14:28:04 +02:00
Mark Nauwelaerts
5999a10519 git-hg-helper: repurpose marks subcommand to gc subcommand 2016-08-13 14:28:01 +02:00
Mark Nauwelaerts
0853bc0230 Tips metadata is now obsolete on fetch as well as push
... so discard it altogether when reading marks.
All this also removes fetch-first error which is either no error at all or
is either really a non-fast-forward error.
2016-08-13 14:28:00 +02:00
Mark Nauwelaerts
b3fccddd9f Transform gitrange into a more effective revwalk
Fixes felipec/git-remote-hg#14
Fixes felipec/git-remote-hg#26
2016-08-13 14:27:57 +02:00
Mark Nauwelaerts
7f99aa2565 Ensure sane ratio in progress reporting 2016-08-13 14:27:54 +02:00
Mark Nauwelaerts
63c742e4a6 Add warning about disabling capability_push mode
... as the old mode is not so safe and on its way to deprecation.
2016-08-13 14:27:52 +02:00
Mark Nauwelaerts
6cff0327aa Always update notes on push
... at least in the sane capability_push mode.
Remove documentation on obsolete push-updates-notes setting.
2016-08-13 14:27:52 +02:00
Mark Nauwelaerts
5acd0028b4 Ensure transaction safe notes update on push 2016-08-13 14:27:52 +02:00
Mark Nauwelaerts
4f910f65d9 Also still track notes HEAD during import
Fixes felipec/git-remote-hg#58
2016-08-13 14:27:45 +02:00
Mark Nauwelaerts
7d82847d52 README: add documentation on subrepo support 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
37cd2f24ac git-hg-helper: add support for subrepo management
See felipec/git-remote-hg#1
2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
585e36edb9 README: add documentation on additional features such as git-hg-helper 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
dd08e25665 doc: extend manpage with additional config settings 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
5905eb2231 Make a push optionally update notes as well
... as configured by remote-hg.push-updates-notes setting.
2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
ebdd2f32ab Add support for automagic hg revision identification and pushing 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
f8709175bf Separate head checking and revision pushing
Also remove some superfluous function parameters and add another one
to avoid using global var.
2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
38741e0bbf Add git-hg-helper 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
e2f68018cd Allow using git-remote-hg as module 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
e62984edde README: add hiding of refs/hg 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
7b53adef7b Avoid refs/hg clutter; keep private implementation refs really private 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
858ca2c68a README: explain effects of capability push implementation 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
093cb8ba94 README: some obligatory fork adjustments 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
cd742bee40 doc: extend manpage with config settings and some technical background 2016-08-01 14:57:01 +02:00
Mark Nauwelaerts
1d0c78eebc test: expect dry-run push test to pass now 2016-08-01 14:57:00 +02:00
Mark Nauwelaerts
8e81bc8515 Add source:dest push refspec support 2016-08-01 14:57:00 +02:00
Mark Nauwelaerts
bd2e030cb0 Add remote bookmark delete support 2016-08-01 14:57:00 +02:00
Mark Nauwelaerts
410e0d74ec test: add test for rename/copy detection 2016-08-01 14:57:00 +02:00
Mark Nauwelaerts
93dd913590 Implement remote-helper push capability
Push capability is used depending on remote-hg.capability-push setting and ...
* handles dry-run properly,
* passes copy and rename information onto Mercurial

Fixes felipec/git-remote-hg#61
2016-08-01 14:56:42 +02:00
Mark Nauwelaerts
418af65bf0 Support processing git-fast-export's filecopy and filerename 2016-08-01 14:15:47 +02:00
Mark Nauwelaerts
d7db83bd2c Handle pushing bookmarks without pushing changesets
Also prevent errors when trying to push no changesets to a peer, which some
combinations of versions and extensions do not handle well;
see e.g. as in felipec/git-remote-hg#32 and felipec/git-remote-hg#22
2016-08-01 14:12:09 +02:00
Mark Nauwelaerts
3ea455e7e7 test: add failing test for pushing a bookmark without changesets 2016-08-01 12:21:30 +02:00
Mark Nauwelaerts
fd210eb002 Also ensure 2-way sync of remote bookmarks to proxy
... rather than only adding remote ones locally and never deleting.
In particular, makes fetch --prune work.

Fixes felipec/git-remote-hg#15
2016-08-01 12:21:30 +02:00
Mark Nauwelaerts
b852ee18b2 Simplify calculation of revision range to be fetched.
Fixes felipec/git-remote-hg#14
2016-08-01 12:21:30 +02:00
Mark Nauwelaerts
c3f02d39ad Add notes based on current notes ref
Fixes felipec/git-remote-hg#58
2016-08-01 12:21:25 +02:00
Felipe Contreras
822c6e4b03 Avoid deprecated bookmarks.write()
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-17 21:26:18 -05:00
Felipe Contreras
b6e9475918 readme: mention Mercurial dependency
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 23:37:08 -05:00
Lars Noschinski
517ceb91ac Fix import of broken committers
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 22:44:49 -05:00
Felipe Contreras
114804f0cb travis: add more Mercurial versions
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 22:29:50 -05:00
Felipe Contreras
b022367aef test: temporarily disable hg-git tests
They work, but they need too many changes in different packages.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 22:29:50 -05:00
Felipe Contreras
18626d346f Revert "test: use C.UTF-8 locale in tests"
This reverts commit f53a8653ab.

It turns out Debian and Fedora do provide the C.UTF-8 locale, but other
distributions don't.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 22:29:50 -05:00
Felipe Contreras
b81ec14c2e Improve hg-git compatibility
Recent versions of Mercurial check if a filectx is the same as the
parents, and avoid creating a new filelog. This is what we want, but
hg-git doesn't do that.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 22:29:50 -05:00
Felipe Contreras
1e279075dc Add compatibility for Mercurial v3.2
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 22:29:50 -05:00
Felipe Contreras
02a0a59a4b travis: force version of hg-git
The latest that works.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2016-05-16 17:56:25 -05:00
Felipe Contreras
185852eac4 test: cleanup hg-git test
We don't need hgext.bookmarks since a long long time (ever).

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-06-03 06:00:02 -05:00
Felipe Contreras
29a0d8a0e3 test: skip tests with broken hg-git compatibility
https://bitbucket.org/durin42/hg-git/issue/115/

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-06-02 18:42:17 -05:00
Felipe Contreras
aa528c9649 Fix memfilectx API change
It will change in 3.1.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-06-02 17:49:56 -05:00
Felipe Contreras
018aa4753b Improve version parsing
Development versions have extra stuff in the form of
'version+distance-id'.

Let's assume we are already in the next major version when in
development.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-06-02 17:49:29 -05:00
Felipe Contreras
f173208406 build: don't install docs by default
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-31 15:58:33 -05:00
Felipe Contreras
e7df347fab readme: fix not about v2.0
It didn't get in.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-31 15:49:28 -05:00
Brian Gernhardt
0de8aa91f4 build: avoid non-portable install -D
BSD install doesn't understand the -D option. Use a separate install
command to create the directory (with the -d option) before installing
the file.

Signed-off-by: Brian Gernhardt <brian@gernhardtsoftware.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-31 15:41:28 -05:00
Paul Wise
22d9794c11 test: add compatibility with Debian hg-git package
Debian has named the hggit python module as hgext.git.

Signed-off-by: Paul Wise <pabs3@bonedaddy.net>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-30 17:37:01 -05:00
Paul Wise
f53a8653ab test: use C.UTF-8 locale in tests
The en_US.UTF-8 locale is not guaranteed to exist, and if it doesn't,
several tests fail.

Signed-off-by: Paul Wise <pabs3@bonedaddy.net>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-30 17:37:01 -05:00
Paul Wise
b4c63539f2 Ignore the generated manual page
Signed-off-by: Paul Wise <pabs3@bonedaddy.net>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-30 17:37:01 -05:00
Paul Wise
38070007aa build: general improvements
Allow customising the bin and manual page dirs.

Signed-off-by: Paul Wise <pabs3@bonedaddy.net>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-30 17:37:01 -05:00
Felipe Contreras
fadd5f698b test: improve test locations
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-22 22:09:28 -05:00
Felipe Contreras
1eb8fa4805 readme: add contributing section
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-13 14:26:45 -05:00
Felipe Contreras
19f31c1c84 doc: add help for sending patches
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-13 14:26:32 -05:00
Felipe Contreras
ff221de459 Split multiple import lines
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-10 23:54:33 -05:00
Felipe Contreras
179fefda96 More pep8 fixes
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-10 23:49:49 -05:00
Felipe Contreras
c226ba3904 remote-hg,bzr: conform more to pep8
Reported-by: William Giokas <1007380@gmail.com>

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-10 01:01:20 -05:00
Felipe Contreras
776e36c147 build: fix install location
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 10:29:52 -05:00
Felipe Contreras
5b6d5283cb Use python2 instead of python
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 09:11:14 -05:00
Felipe Contreras
5738ee42d8 test: add missing redirection
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 09:10:57 -05:00
Felipe Contreras
1d27390dd0 readme: fix link location
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 09:09:16 -05:00
Felipe Contreras
cad5c95465 travis: add initial configuration
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 09:04:31 -05:00
Felipe Contreras
259838a342 test: fix redirection style
To be sane, a redirection operation has to have spaces, like any binary
operand: 'a > b'.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:55:51 -05:00
Felipe Contreras
55bbd81a75 test: trivial style cleanups
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:49:30 -05:00
Felipe Contreras
8db5b9a537 Add support for hg v3.0
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
bbc4009acf test: trivial cleanups and fixes
There was a broken && chain, and cat is simpler than echo in a subshell.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
c84feb364b test: dd file operation tests
Inspired by gitifyhg.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
990152c0c8 Add more tests
Inspired by the tests in gitifyhg.

One test is failing, but that's because of a limitation of
remote-helpers.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
6ba42cdf98 Simplify hg-git regex
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
ef00e40d7c remote-hg: make sure we omit multiple heads
We want to ignore secondary heads, otherwise we will import revisions
that won't have any ref pointing to them and might eventually be pruned,
which would cause problems with the synchronization of marks.

This can only be expressed properly as '::b - ::a', but that's not
efficient, specially in older versions of Mercurial.
'ancestor(a,b)::b - ancestor(a,b)::a' might be better, but it's not
particularly pretty. Mercurial v3.0 will have a new 'only(b, a)' that
does the same, but that hasn't even been released yet. Either way all of
these require repo.revs() which is only available after Mercurial v2.1.

Also, we would need special considerations for when there's no base
revision (importing from root).

It's much better to implement our own function to get a range of
revisions.

The new gitrange() is inspired by Mercurial's revset.missingancestors().

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Max Horn
1c72617831 Do not fail on invalid bookmarks
Mercurial can have bookmarks pointing to "nullid" (the empty root
revision), while Git can not have references to it.

Warn the user about the invalid reference, and do not advertise these
bookmarks as head refs, but otherwise continue the import. In
particular, we still keep track of the fact that the remote repository
has a bookmark of the given name, in case the user wants to modify that
bookmark.

Reported-by: Antoine Pelisse <apelisse@gmail.com>
Signed-off-by: Max Horn <max@quendi.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Daniel Liew
184551c71d Use internal clone's hgrc
Use the hgrc configuration file in the internal mercurial repository in
addition to the other system wide hgrc files. This is done by using the
'ui' object from the 'repository' object which will have loaded the
repository hgrc file if it exists.

Signed-off-by: Dan Liew <delcypher@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
32d4f36f22 test: split into setup test
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
ccb3f13d69 Properly detect missing contexts
This can happen when there's a synchronization issue between marks-git
and marks-hg; a key is missing in marks-hg, and when we receive a reset
command the value of ctx basically comes from None.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:07 -05:00
Felipe Contreras
2958556bec Store marks only on success
Commit 2594a79 (remote-hg: fix bad state issue) originally introduced
this code in order to avoid synchronization issues while pushing,
because `git fast-export` might end up writing the marks before a crash
in the remote helper occurs.

However, the problem is in `git fast-export`; the marks should only be
written after both have finished successfully.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:06 -05:00
Felipe Contreras
4ea2fa76b3 Update to 'public' phase when pushing
This is what Mercurial does.

Reported-by: Nathan Palmer
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:06 -05:00
Felipe Contreras
84b8b482a4 Fix parsing of custom committer
Other tools use the 'committer' extra field differently, so let's make
the parsing more reliable and don't assume it's in a certain format.

Reported-by: Kevin Cox <kevincox@kevincox.ca>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:06 -05:00
Felipe Contreras
978314a4be Always normalize paths
Apparently Mercurial can have paths such as 'foo//bar', so normalize all
paths.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:43:06 -05:00
Felipe Contreras
51eabd4a17 doc: add manpage
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:41:57 -05:00
Felipe Contreras
98c3535c3f build: add install target
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:41:57 -05:00
Felipe Contreras
3abf376e9e Add README
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:36:33 -05:00
Felipe Contreras
0b71ca38e7 Reorganize tests
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-05-09 08:33:07 -05:00
25 changed files with 5992 additions and 1357 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/build/
/dist/
/git_remote_hg.egg-info/

20
.travis.yml Normal file
View File

@@ -0,0 +1,20 @@
dist: xenial
language: minimal
cache:
directories:
- $HOME/.cache/git-remote-hg
script:
- ./tools/check-versions hg:$HG_VERSION
matrix:
include:
- env:
- env: HG_VERSION=@
- env: HG_VERSION=5.0
- env: HG_VERSION=4.9
- env: HG_VERSION=4.8
- env: HG_VERSION=4.7
- env: HG_VERSION=4.6
- env: HG_VERSION=4.5

View File

@@ -1,6 +1,64 @@
all:
prefix := $(HOME)
bindir := $(prefix)/bin
mandir := $(prefix)/share/man/man1
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 ; \
fi ; \
if [ -n "$$PYTHON" ] ; then \
PYTHON=python ; \
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
test:
$(MAKE) -C test
.PHONY: all test
doc/git-remote-hg.1: doc/git-remote-hg.txt
a2x -d manpage -f manpage $<
clean:
$(RM) doc/git-remote-hg.1
$(RM) -r bin/
D = $(DESTDIR)
install: build
install -d -m 755 $(D)$(bindir)/
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 -d -m 755 $(D)$(mandir)/
install -m 644 doc/git-remote-hg.1 $(D)$(mandir)/git-remote-hg.1
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

419
README.asciidoc Normal file
View File

@@ -0,0 +1,419 @@
'git-remote-hg' is the semi-official Mercurial bridge from Git project, once
installed, it allows you to clone, fetch and push to and from Mercurial
repositories as if they were Git ones:
--------------------------------------
git clone "hg::http://selenic.com/repo/hello"
--------------------------------------
To enable this, simply add the 'git-remote-hg' script anywhere in your `$PATH`:
--------------------------------------
wget https://raw.github.com/mnauw/git-remote-hg/master/git-remote-hg -O ~/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 :)
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 ==
If you want to see Mercurial revisions as Git commit notes:
--------------------------------------
% git config core.notesRef refs/notes/hg
--------------------------------------
If you are not interested in Mercurial permanent and global branches (aka. commit labels):
--------------------------------------
% git config --global remote-hg.track-branches false
--------------------------------------
With this configuration, the 'branches/foo' refs won't appear.
If you want the equivalent of 'hg clone --insecure':
--------------------------------------
% git config --global remote-hg.insecure true
--------------------------------------
If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly the same commits:
--------------------------------------
% git config --global remote-hg.hg-git-compat true
--------------------------------------
== Notes ==
Remember to run `git gc --aggressive` after cloning a repository, specially if
it's a big one. Otherwise lots of space will be wasted.
The oldest version of mercurial supported is 1.9. For the most part 1.8 works,
but you might experience some issues.
=== Pushing branches ===
To push a branch, you need to use the "branches/" prefix:
--------------------------------------
% git checkout branches/next
# do stuff
% git push origin branches/next
--------------------------------------
All the pushed commits will receive the "next" Mercurial named branch.
*Note*: Make sure you don't have +remote-hg.track-branches+ disabled.
=== Cloning HTTPS ===
The simplest way is to specify the user and password in the URL:
--------------------------------------
git clone hg::https://user:password@bitbucket.org/user/repo
--------------------------------------
You can also use the http://mercurial.selenic.com/wiki/SchemesExtension[schemes extension]:
--------------------------------------
[auth]
bb.prefix = https://bitbucket.org/user/
bb.username = user
bb.password = password
--------------------------------------
Finally, you can also use the
https://pypi.python.org/pypi/mercurial_keyring[keyring extension].
However, some of these features require very new versions of 'git-remote-hg',
so you might have better luck simply specifying the username and password in
the URL.
=== 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 ===
The only major incompatibility is that Git octopus merges (a merge with more
than two parents) are not supported.
Mercurial branches and bookmarks have some limitations of Git branches: you
can't have both 'dev/feature' and 'dev' (as Git uses files and directories to
store them).
Multiple anonymous heads (which are useless anyway) are not supported; you
would only see the latest head.
Closed branches are not supported; they are not shown and you can't close or
reopen. Additionally in certain rare situations a synchronization issue can
occur (https://github.com/felipec/git/issues/65[Bug #65]).
[[limitations]]
Limitations of the remote-helpers' framework apply. In particular, these
commands don't work:
* `git push origin :branch-to-delete`
****
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 ==
There are other 'git-remote-hg' projects out there, do not confuse this one,
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/rfk/git-remote-hg[rfk's git-remote-hg]
For a comparison between these and other projects go
https://github.com/felipec/git/wiki/Comparison-of-git-remote-hg-alternatives[here].
[[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 ==
Please file an issue with some patches or a pull-request.

1
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
git-remote-hg.1

5
doc/SubmittingPatches Normal file
View File

@@ -0,0 +1,5 @@
Please send your patches using `git format-patch` to the mailing list:
git-fc@googlegroups.com.
Make sure all the tests pass by running `make test`, and if possible add a new
test to exercise the code you are submitting.

211
doc/git-remote-hg.txt Normal file
View File

@@ -0,0 +1,211 @@
git-remote-hg(1)
================
NAME
----
git-remote-hg - bidirectional bridge between Git and Mercurial
SYNOPSIS
--------
[verse]
'git clone' hg::<hg repository>
DESCRIPTION
-----------
This tool allows you to transparently clone, fetch and push to and from Mercurial
repositories as if they were Git ones.
To use it you simply need to use the "'hg::'" prefix when specifying a remote URL
(e.g. when cloning).
EXAMPLE
-------
------------
$ git clone hg::http://selenic.com/repo/hello
------------
CONFIGURATION
-------------
If you want to see Mercurial revisions as Git commit notes:
--------------------------------------
% git config core.notesRef refs/notes/hg
--------------------------------------
If you are not interested in Mercurial permanent and global branches (aka. commit labels):
--------------------------------------
% git config --global remote-hg.track-branches false
--------------------------------------
With this configuration, the 'branches/foo' refs won't appear.
If you want the equivalent of `hg clone --insecure`:
--------------------------------------
% git config --global remote-hg.insecure true
--------------------------------------
If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly the same commits:
--------------------------------------
% git config --global remote-hg.hg-git-compat true
--------------------------------------
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
-----
Remember to run `git gc --aggressive` after cloning a repository, specially if
it's a big one. Otherwise lots of space will be wasted.
The oldest version of Mercurial supported is 1.9. For the most part 1.8 works,
but you might experience some issues.
Pushing branches
~~~~~~~~~~~~~~~~
To push a Mercurial named branch, you need to use the "branches/" prefix:
--------------------------------------
% git checkout branches/next
# do stuff
% git push origin branches/next
--------------------------------------
All the pushed commits will receive the "next" Mercurial named branch.
*Note*: Make sure you don't have +remote-hg.track-branches+ disabled.
Cloning HTTPS
~~~~~~~~~~~~~
The simplest way is to specify the user and password in the URL:
--------------------------------------
git clone hg::https://user:password@bitbucket.org/user/repo
--------------------------------------
You can also use the http://mercurial.selenic.com/wiki/SchemesExtension[schemes extension]:
--------------------------------------
[auth]
bb.prefix = https://bitbucket.org/user/
bb.username = user
bb.password = password
--------------------------------------
Finally, you can also use the
https://pypi.python.org/pypi/mercurial_keyring[keyring extension].
CAVEATS
-------
The only major incompatibility is that Git octopus merges (a merge with more
than two parents) are not supported.
Mercurial branches and bookmarks have some limitations of Git branches: you
can't have both 'dev/feature' and 'dev' (as Git uses files and directories to
store them).
Multiple anonymous heads (which are useless anyway) are not supported; you
would only see the latest head.
Closed branches are not supported; they are not shown and you can't close or
reopen. Additionally in certain rare situations a synchronization issue can
occur (https://github.com/felipec/git/issues/65[Bug #65]).
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.

1020
git-hg-helper Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

45
setup.py Normal file
View File

@@ -0,0 +1,45 @@
# git-remote-hg setuptools script
import setuptools
# strip leading v
version = 'v1.0.3'[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
)

View File

@@ -1,775 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2012 Felipe Contreras
#
# Base commands from hg-git tests:
# https://bitbucket.org/durin42/hg-git/src
#
test_description='Test remote-hg'
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=${0%/*}/../../t
. "$TEST_DIRECTORY"/test-lib.sh
if ! test_have_prereq PYTHON
then
skip_all='skipping remote-hg tests; python not available'
test_done
fi
if ! python -c 'import mercurial'
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
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
}
check_bookmark () {
if test -n "$3"
then
echo $3 >expected &&
hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' >actual &&
test_cmp expected actual
else
hg -R $1 bookmarks >out &&
! grep $2 out
fi
}
check_push () {
expected_ret=$1 ret=0 ref_ret=0
shift
git push origin "$@" 2>error
ret=$?
cat error
while IFS=':' read branch kind
do
case "$kind" in
'new')
grep "^ \* \[new branch\] *${branch} -> ${branch}$" error || ref_ret=1
;;
'non-fast-forward')
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')
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
;;
esac
test $ref_ret -ne 0 && echo "match for '$branch' failed" && break
done
if test $expected_ret -ne $ret || test $ref_ret -ne 0
then
return 1
fi
return 0
}
setup () {
(
echo "[ui]"
echo "username = H G Wells <wells@example.com>"
echo "[extensions]"
echo "mq ="
) >>"$HOME"/.hgrc &&
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" &&
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" &&
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
}
setup
test_expect_success 'cloning' '
test_when_finished "rm -rf gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero >content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
check gitrepo HEAD zero
'
test_expect_success 'cloning with branches' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg branch next &&
echo next >content &&
hg commit -m next
) &&
git clone "hg::hgrepo" gitrepo &&
check gitrepo origin/branches/next next
'
test_expect_success 'cloning with bookmarks' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg checkout default &&
hg bookmark feature-a &&
echo feature-a >content &&
hg commit -m feature-a
) &&
git clone "hg::hgrepo" gitrepo &&
check gitrepo origin/feature-a feature-a
'
test_expect_success 'update bookmark' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg bookmark devel
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet devel &&
echo devel >content &&
git commit -a -m devel &&
git push --quiet
) &&
check_bookmark hgrepo devel devel
'
test_expect_success 'new bookmark' '
test_when_finished "rm -rf gitrepo*" &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-b &&
echo feature-b >content &&
git commit -a -m feature-b &&
git push --quiet origin feature-b
) &&
check_bookmark hgrepo feature-b feature-b
'
# cleanup previous stuff
rm -rf hgrepo
author_test () {
echo $1 >>content &&
hg commit -u "$2" -m "add $1" &&
echo "$3" >>../expected
}
test_expect_success 'authors' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
touch content &&
hg add content &&
>../expected &&
author_test alpha "" "H G Wells <wells@example.com>" &&
author_test beta "beta" "beta <unknown>" &&
author_test gamma "gamma <test@example.com> (comment)" "gamma <test@example.com>" &&
author_test delta "<delta@example.com>" "Unknown <delta@example.com>" &&
author_test epsilon "epsilon<test@example.com>" "epsilon <test@example.com>" &&
author_test zeta "zeta <test@example.com" "zeta <test@example.com>" &&
author_test eta " eta " "eta <unknown>" &&
author_test theta "theta < test@example.com >" "theta <test@example.com>" &&
author_test iota "iota >test@example.com>" "iota <test@example.com>" &&
author_test kappa "kappa < test <at> example <dot> com>" "kappa <unknown>" &&
author_test lambda "lambda@example.com" "Unknown <lambda@example.com>" &&
author_test mu "mu.mu@example.com" "Unknown <mu.mu@example.com>"
) &&
git clone "hg::hgrepo" gitrepo &&
git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" >actual &&
test_cmp expected actual
'
test_expect_success 'strip' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo one >>content &&
hg add content &&
hg commit -m one &&
echo two >>content &&
hg commit -m two
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
hg strip 1 &&
echo three >>content &&
hg commit -m three &&
echo four >>content &&
hg commit -m four
) &&
(
cd gitrepo &&
git fetch &&
git log --format="%s" origin/master >../actual
) &&
hg -R hgrepo log --template "{desc}\n" >expected &&
test_cmp actual expected
'
test_expect_success 'remote push with master 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 master &&
echo one >content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
echo two >content &&
git commit -a -m two &&
git push
) &&
check_branch hgrepo default two
'
cat >expected <<\EOF
changeset: 0:6e2126489d3d
tag: tip
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
summary: one
EOF
test_expect_success 'remote push from master branch' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
hg init hgrepo &&
(
git init gitrepo &&
cd gitrepo &&
git remote add origin "hg::../hgrepo" &&
echo one >content &&
git add content &&
git commit -a -m one &&
git push origin master
) &&
hg -R hgrepo log >actual &&
cat actual &&
test_cmp expected actual &&
check_branch hgrepo default one
'
GIT_REMOTE_HG_TEST_REMOTE=1
export GIT_REMOTE_HG_TEST_REMOTE
test_expect_success 'remote cloning' '
test_when_finished "rm -rf gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero >content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
check gitrepo HEAD zero
'
test_expect_success 'moving remote clone' '
test_when_finished "rm -rf gitrepo*" &&
(
git clone "hg::hgrepo" gitrepo &&
mv gitrepo gitrepo2 &&
cd gitrepo2 &&
git fetch
)
'
test_expect_success 'remote update bookmark' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg bookmark devel
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet devel &&
echo devel >content &&
git commit -a -m devel &&
git push --quiet
) &&
check_bookmark hgrepo devel devel
'
test_expect_success 'remote new bookmark' '
test_when_finished "rm -rf gitrepo*" &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-b &&
echo feature-b >content &&
git commit -a -m feature-b &&
git push --quiet origin feature-b
) &&
check_bookmark hgrepo feature-b feature-b
'
test_expect_success 'remote push diverged' '
test_when_finished "rm -rf gitrepo*" &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
hg checkout default &&
echo bump >content &&
hg commit -m bump
) &&
(
cd gitrepo &&
echo diverge >content &&
git commit -a -m diverged &&
check_push 1 <<-\EOF
master:non-fast-forward
EOF
) &&
check_branch hgrepo default bump
'
test_expect_success 'remote update bookmark diverge' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg checkout tip^ &&
hg bookmark diverge
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
echo "bump bookmark" >content &&
hg commit -m "bump bookmark"
) &&
(
cd gitrepo &&
git checkout --quiet diverge &&
echo diverge >content &&
git commit -a -m diverge &&
check_push 1 <<-\EOF
diverge:fetch-first
EOF
) &&
check_bookmark hgrepo diverge "bump bookmark"
'
test_expect_success 'remote new bookmark multiple branch head' '
test_when_finished "rm -rf gitrepo*" &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-c HEAD^ &&
echo feature-c >content &&
git commit -a -m feature-c &&
git push --quiet origin feature-c
) &&
check_bookmark hgrepo feature-c feature-c
'
# cleanup previous stuff
rm -rf hgrepo
test_expect_success 'fetch special filenames' '
test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
LC_ALL=en_US.UTF-8
export LC_ALL
(
hg init hgrepo &&
cd hgrepo &&
echo test >> "æ rø" &&
hg add "æ rø" &&
echo test >> "ø~?" &&
hg add "ø~?" &&
hg commit -m add-utf-8 &&
echo test >> "æ rø" &&
hg commit -m test-utf-8 &&
hg rm "ø~?" &&
hg mv "æ rø" "ø~?" &&
hg commit -m hg-mv-utf-8
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git -c core.quotepath=false ls-files > ../actual
) &&
echo "ø~?" > expected &&
test_cmp expected actual
'
test_expect_success 'push special filenames' '
test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
mkdir -p tmp && cd tmp &&
LC_ALL=en_US.UTF-8
export LC_ALL
(
hg init hgrepo &&
cd hgrepo &&
echo one >> content &&
hg add content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
echo test >> "æ rø" &&
git add "æ rø" &&
git commit -m utf-8 &&
git push
) &&
(cd hgrepo &&
hg update &&
hg manifest > ../actual
) &&
printf "content\næ rø\n" > expected &&
test_cmp expected actual
'
setup_big_push () {
(
hg init hgrepo &&
cd hgrepo &&
echo zero >content &&
hg add content &&
hg commit -m zero &&
hg bookmark bad_bmark1 &&
echo one >content &&
hg commit -m one &&
hg bookmark bad_bmark2 &&
hg bookmark good_bmark &&
hg bookmark -i good_bmark &&
hg -q branch good_branch &&
echo "good branch" >content &&
hg commit -m "good branch" &&
hg -q branch bad_branch &&
echo "bad branch" >content &&
hg commit -m "bad branch"
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
echo two >content &&
git commit -q -a -m two &&
git checkout -q good_bmark &&
echo three >content &&
git commit -q -a -m three &&
git checkout -q bad_bmark1 &&
git reset --hard HEAD^ &&
echo four >content &&
git commit -q -a -m four &&
git checkout -q bad_bmark2 &&
git reset --hard HEAD^ &&
echo five >content &&
git commit -q -a -m five &&
git checkout -q -b new_bmark master &&
echo six >content &&
git commit -q -a -m six &&
git checkout -q branches/good_branch &&
echo seven >content &&
git commit -q -a -m seven &&
echo eight >content &&
git commit -q -a -m eight &&
git checkout -q branches/bad_branch &&
git reset --hard HEAD^ &&
echo nine >content &&
git commit -q -a -m nine &&
git checkout -q -b branches/new_branch master &&
echo ten >content &&
git commit -q -a -m ten
)
}
test_expect_success 'remote big push' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
check_push 1 --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
) &&
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 big push fetch first' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero >content &&
hg add content &&
hg commit -m zero &&
hg bookmark bad_bmark &&
hg bookmark good_bmark &&
hg bookmark -i good_bmark &&
hg -q branch good_branch &&
echo "good branch" >content &&
hg commit -m "good branch" &&
hg -q branch bad_branch &&
echo "bad branch" >content &&
hg commit -m "bad branch"
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
hg bookmark -f bad_bmark &&
echo update_bmark >content &&
hg commit -m "update bmark"
) &&
(
cd gitrepo &&
echo two >content &&
git commit -q -a -m two &&
git checkout -q good_bmark &&
echo three >content &&
git commit -q -a -m three &&
git checkout -q bad_bmark &&
echo four >content &&
git commit -q -a -m four &&
git checkout -q branches/bad_branch &&
echo five >content &&
git commit -q -a -m five &&
check_push 1 --all <<-\EOF &&
master
good_bmark
bad_bmark:fetch-first
branches/bad_branch:festch-first
EOF
git fetch &&
check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
)
'
test_expect_failure 'remote big push force' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
check_push 0 --force --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
) &&
check_branch hgrepo default six &&
check_branch hgrepo good_branch eight &&
check_branch hgrepo bad_branch nine &&
check_branch hgrepo new_branch ten &&
check_bookmark hgrepo good_bmark three &&
check_bookmark hgrepo bad_bmark1 four &&
check_bookmark hgrepo bad_bmark2 five &&
check_bookmark hgrepo new_bmark six
'
test_expect_failure 'remote big push dry-run' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
check_push 1 --dry-run --all <<-\EOF &&
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
EOF
) &&
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_when_finished "rm -rf hgrepo gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero >content &&
hg add content &&
hg commit -m zero &&
echo one >content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git reset --hard HEAD^ &&
echo two >content &&
git commit -a -m two &&
test_expect_code 1 git push &&
test_expect_code 1 git push
)
'
test_done

3
test/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
test-results/
trash directory.*/
.prove

View File

@@ -1,6 +1,6 @@
RM ?= rm -f
T = $(wildcard ../test-*.sh)
T = main.t main-push.t bidi.t helper.t
TEST_DIRECTORY := $(CURDIR)
export TEST_DIRECTORY

View File

@@ -8,17 +8,12 @@
test_description='Test bidirectionality of remote-hg'
. ./test-lib.sh
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 not available'
test_done
fi
if ! python -c 'import mercurial'
then
skip_all='skipping remote-hg tests; mercurial not available'
skip_all='skipping remote-hg tests; python with mercurial not available'
test_done
fi
@@ -45,26 +40,26 @@ hg_push () {
git checkout -q -b tmp &&
git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git checkout -q @{-1} &&
git branch -q -D tmp 2>/dev/null || true
git branch -q -D tmp 2> /dev/null || true
)
}
hg_log () {
hg -R $1 log --graph --debug
hg -R $1 log --debug
}
setup () {
(
echo "[ui]"
echo "username = A U Thor <author@example.com>"
echo "[defaults]"
echo "backout = -d \"0 0\""
echo "commit = -d \"0 0\""
echo "debugrawcommit = -d \"0 0\""
echo "tag = -d \"0 0\""
echo "[extensions]"
echo "graphlog ="
) >>"$HOME"/.hgrc &&
cat > "$HOME"/.hgrc <<-EOF &&
[ui]
username = A U Thor <author@example.com>
[defaults]
backout = -d "0 0"
commit = -d "0 0"
debugrawcommit = -d "0 0"
tag = -d "0 0"
[extensions]"
graphlog =
EOF
git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches true
@@ -83,22 +78,22 @@ test_expect_success 'encoding' '
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add älphà" &&
GIT_AUTHOR_NAME="tést èncödîng" &&
export GIT_AUTHOR_NAME &&
echo beta >beta &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
echo gamma >gamma &&
echo gamma > gamma &&
git add gamma &&
git commit -m "add gämmâ" &&
: TODO git config i18n.commitencoding latin-1 &&
echo delta >delta &&
echo delta > delta &&
git add delta &&
git commit -m "add déltà"
) &&
@@ -107,8 +102,8 @@ test_expect_success 'encoding' '
git_clone hgrepo gitrepo2 &&
hg_clone gitrepo2 hgrepo2 &&
HGENCODING=utf-8 hg_log hgrepo >expected &&
HGENCODING=utf-8 hg_log hgrepo2 >actual &&
HGENCODING=utf-8 hg_log hgrepo > expected &&
HGENCODING=utf-8 hg_log hgrepo2 > actual &&
test_cmp expected actual
'
@@ -119,14 +114,14 @@ test_expect_success 'file removal' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
echo beta >beta &&
echo beta > beta &&
git add beta &&
git commit -m "add beta"
mkdir foo &&
echo blah >foo/bar &&
echo blah > foo/bar &&
git add foo &&
git commit -m "add foo" &&
git rm alpha &&
@@ -139,8 +134,8 @@ test_expect_success 'file removal' '
git_clone hgrepo gitrepo2 &&
hg_clone gitrepo2 hgrepo2 &&
hg_log hgrepo >expected &&
hg_log hgrepo2 >actual &&
hg_log hgrepo > expected &&
hg_log hgrepo2 > actual &&
test_cmp expected actual
'
@@ -152,12 +147,12 @@ test_expect_success 'git tags' '
git init -q gitrepo &&
cd gitrepo &&
git config receive.denyCurrentBranch ignore &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git tag alpha &&
echo beta >beta &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
git tag -a -m "added tag beta" beta
@@ -167,8 +162,8 @@ test_expect_success 'git tags' '
git_clone hgrepo gitrepo2 &&
hg_clone gitrepo2 hgrepo2 &&
hg_log hgrepo >expected &&
hg_log hgrepo2 >actual &&
hg_log hgrepo > expected &&
hg_log hgrepo2 > actual &&
test_cmp expected actual
'
@@ -180,7 +175,7 @@ test_expect_success 'hg branch' '
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -q -m "add alpha" &&
git checkout -q -b not-master
@@ -203,8 +198,9 @@ test_expect_success 'hg branch' '
: Back to the common revision &&
(cd hgrepo && hg checkout default) &&
hg_log hgrepo >expected &&
hg_log hgrepo2 >actual &&
# 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
'
@@ -216,7 +212,7 @@ test_expect_success 'hg tags' '
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
@@ -231,10 +227,50 @@ test_expect_success 'hg tags' '
) &&
hg_push hgrepo gitrepo &&
hg_clone gitrepo hgrepo2 &&
# pushing a fetched tag is a problem ...
{ hg_clone gitrepo hgrepo2 || true ; } &&
hg_log hgrepo >expected &&
hg_log hgrepo2 >actual &&
# 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 hgrepo2 > actual &&
test_cmp expected actual
'

541
test/helper.t Executable file
View 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

View File

@@ -8,22 +8,22 @@
test_description='Test remote-hg output compared to hg-git'
. ./test-lib.sh
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 not available'
skip_all='skipping remote-hg tests; python with mercurial not available'
test_done
fi
if ! python -c 'import mercurial'
if "$PYTHON" -c 'import hggit' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
if ! python -c 'import hggit'
hggit=hggit
elif "$PYTHON" -c 'import hgext.git' > /dev/null 2>&1
then
hggit=hgext.git
else
skip_all='skipping remote-hg tests; hg-git not available'
test_done
fi
@@ -69,7 +69,7 @@ hg_push_git () {
git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git branch -D default &&
git checkout -q @{-1} &&
git branch -q -D tmp 2>/dev/null || true
git branch -q -D tmp 2> /dev/null || true
)
}
@@ -82,7 +82,7 @@ hg_push_hg () {
}
hg_log () {
hg -R $1 log --graph --debug >log &&
hg -R $1 log --graph --debug > log &&
grep -v 'tag: *default/' log
}
@@ -91,22 +91,24 @@ git_log () {
}
setup () {
(
echo "[ui]"
echo "username = A U Thor <author@example.com>"
echo "[defaults]"
echo "backout = -d \"0 0\""
echo "commit = -d \"0 0\""
echo "debugrawcommit = -d \"0 0\""
echo "tag = -d \"0 0\""
echo "[extensions]"
echo "hgext.bookmarks ="
echo "hggit ="
echo "graphlog ="
) >>"$HOME"/.hgrc &&
cat > "$HOME"/.hgrc <<-EOF &&
[ui]
username = A U Thor <author@example.com>
[defaults]
backout = -d "0 0"
commit = -d "0 0"
debugrawcommit = -d "0 0"
tag = -d "0 0"
[extensions]
$hggit =
graphlog =
[git]
debugextrainmessage = 1
EOF
git config --global receive.denycurrentbranch warn
git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches false
git config --global remote-hg.shared-marks false
HGEDITOR=true
HGMERGE=true
@@ -118,13 +120,38 @@ 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_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
chmod 0644 alpha &&
git add alpha &&
git commit -m "add alpha" &&
@@ -144,10 +171,10 @@ test_expect_success 'executable bit' '
hg_log . &&
hg manifest -r 1 -v &&
hg manifest -v
) >"output-$x" &&
) > "output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
git_log gitrepo2-$x >"log-$x"
git_log gitrepo2-$x > "log-$x"
done &&
test_cmp output-hg output-git &&
@@ -160,7 +187,7 @@ test_expect_success 'symlink' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
ln -s alpha beta &&
@@ -175,10 +202,10 @@ test_expect_success 'symlink' '
cd hgrepo-$x &&
hg_log . &&
hg manifest -v
) >"output-$x" &&
) > "output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
git_log gitrepo2-$x >"log-$x"
git_log gitrepo2-$x > "log-$x"
done &&
test_cmp output-hg output-git &&
@@ -191,19 +218,19 @@ test_expect_success 'merge conflict 1' '
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A >afile &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B >afile &&
echo B > afile &&
hg ci -m "A->B" &&
hg up -r0 &&
echo C >afile &&
echo C > afile &&
hg ci -m "A->C" &&
hg merge -r1 &&
echo C >afile &&
echo C > afile &&
hg resolve -m afile &&
hg ci -m "merge to C"
) &&
@@ -212,8 +239,8 @@ test_expect_success 'merge conflict 1' '
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"
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
@@ -226,19 +253,19 @@ test_expect_success 'merge conflict 2' '
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A >afile &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B >afile &&
echo B > afile &&
hg ci -m "A->B" &&
hg up -r0 &&
echo C >afile &&
echo C > afile &&
hg ci -m "A->C" &&
hg merge -r1 || true &&
echo B >afile &&
echo B > afile &&
hg resolve -m afile &&
hg ci -m "merge to B"
) &&
@@ -247,8 +274,8 @@ test_expect_success 'merge conflict 2' '
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"
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
@@ -261,18 +288,18 @@ test_expect_success 'converged merge' '
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A >afile &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B >afile &&
echo B > afile &&
hg ci -m "A->B" &&
echo C >afile &&
echo C > afile &&
hg ci -m "B->C" &&
hg up -r0 &&
echo C >afile &&
echo C > afile &&
hg ci -m "A->C" &&
hg merge -r2 || true &&
@@ -283,8 +310,8 @@ test_expect_success 'converged merge' '
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"
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
@@ -298,22 +325,22 @@ test_expect_success 'encoding' '
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add älphà" &&
GIT_AUTHOR_NAME="tést èncödîng" &&
export GIT_AUTHOR_NAME &&
echo beta >beta &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
echo gamma >gamma &&
echo gamma > gamma &&
git add gamma &&
git commit -m "add gämmâ" &&
: TODO git config i18n.commitencoding latin-1 &&
echo delta >delta &&
echo delta > delta &&
git add delta &&
git commit -m "add déltà"
) &&
@@ -323,8 +350,8 @@ test_expect_success 'encoding' '
hg_clone_$x gitrepo hgrepo-$x &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
HGENCODING=utf-8 hg_log hgrepo-$x >"hg-log-$x" &&
git_log gitrepo2-$x >"git-log-$x"
HGENCODING=utf-8 hg_log hgrepo-$x > "hg-log-$x" &&
git_log gitrepo2-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
@@ -337,14 +364,14 @@ test_expect_success 'file removal' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
echo beta >beta &&
echo beta > beta &&
git add beta &&
git commit -m "add beta"
mkdir foo &&
echo blah >foo/bar &&
echo blah > foo/bar &&
git add foo &&
git commit -m "add foo" &&
git rm alpha &&
@@ -361,10 +388,10 @@ test_expect_success 'file removal' '
hg_log . &&
hg manifest -r 3 &&
hg manifest
) >"output-$x" &&
) > "output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
git_log gitrepo2-$x >"log-$x"
git_log gitrepo2-$x > "log-$x"
done &&
test_cmp output-hg output-git &&
@@ -378,12 +405,12 @@ test_expect_success 'git tags' '
git init -q gitrepo &&
cd gitrepo &&
git config receive.denyCurrentBranch ignore &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git tag alpha &&
echo beta >beta &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
git tag -a -m "added tag beta" beta
@@ -392,7 +419,7 @@ test_expect_success 'git tags' '
for x in hg git
do
hg_clone_$x gitrepo hgrepo-$x &&
hg_log hgrepo-$x >"log-$x"
hg_log hgrepo-$x > "log-$x"
done &&
test_cmp log-hg log-git
@@ -407,7 +434,7 @@ test_expect_success 'hg author' '
git init -q gitrepo-$x &&
cd gitrepo-$x &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
@@ -418,38 +445,38 @@ test_expect_success 'hg author' '
cd hgrepo-$x &&
hg co master &&
echo beta >beta &&
echo beta > beta &&
hg add beta &&
hg commit -u "test" -m "add beta" &&
echo gamma >>beta &&
echo gamma >> beta &&
hg commit -u "test <test@example.com> (comment)" -m "modify beta" &&
echo gamma >gamma &&
echo gamma > gamma &&
hg add gamma &&
hg commit -u "<test@example.com>" -m "add gamma" &&
echo delta >delta &&
echo delta > delta &&
hg add delta &&
hg commit -u "name<test@example.com>" -m "add delta" &&
echo epsilon >epsilon &&
echo epsilon > epsilon &&
hg add epsilon &&
hg commit -u "name <test@example.com" -m "add epsilon" &&
echo zeta >zeta &&
echo zeta > zeta &&
hg add zeta &&
hg commit -u " test " -m "add zeta" &&
echo eta >eta &&
echo eta > eta &&
hg add eta &&
hg commit -u "test < test@example.com >" -m "add eta" &&
echo theta >theta &&
echo theta > theta &&
hg add theta &&
hg commit -u "test >test@example.com>" -m "add theta" &&
echo iota >iota &&
echo iota > iota &&
hg add iota &&
hg commit -u "test <test <at> example <dot> com>" -m "add iota"
) &&
@@ -457,8 +484,8 @@ test_expect_success 'hg author' '
hg_push_$x hgrepo-$x gitrepo-$x &&
hg_clone_$x gitrepo-$x hgrepo2-$x &&
hg_log hgrepo2-$x >"hg-log-$x" &&
git_log gitrepo-$x >"git-log-$x"
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
@@ -474,7 +501,7 @@ test_expect_success 'hg branch' '
git init -q gitrepo-$x &&
cd gitrepo-$x &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -q -m "add alpha" &&
git checkout -q -b not-master
@@ -494,8 +521,8 @@ test_expect_success 'hg branch' '
hg_push_$x hgrepo-$x gitrepo-$x &&
hg_clone_$x gitrepo-$x hgrepo2-$x &&
hg_log hgrepo2-$x >"hg-log-$x" &&
git_log gitrepo-$x >"git-log-$x"
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
@@ -511,7 +538,7 @@ test_expect_success 'hg tags' '
git init -q gitrepo-$x &&
cd gitrepo-$x &&
echo alpha >alpha &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
@@ -532,7 +559,7 @@ test_expect_success 'hg tags' '
git --git-dir=gitrepo-$x/.git tag -l &&
hg_log hgrepo2-$x &&
cat hgrepo2-$x/.hgtags
) >"output-$x"
) > "output-$x"
done &&
test_cmp output-hg output-git

314
test/main-push.t Executable file
View 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

1334
test/main.t Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -18,33 +18,80 @@
# along with this program. If not, see http://www.gnu.org/licenses/ .
# Public: Current version of Sharness.
SHARNESS_VERSION="0.3.0"
SHARNESS_VERSION="1.1.0"
export SHARNESS_VERSION
# 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
# Keep the original TERM for say_color
ORIGINAL_TERM=$TERM
# Public: Root directory containing tests. Tests can override this variable,
# 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.
# TERM is sanitized below, after saving color control sequences.
LANG=C
LC_ALL=C
PAGER=cat
PAGER="cat"
TZ=UTC
TERM=dumb
EDITOR=:
export LANG LC_ALL PAGER TZ TERM EDITOR
export LANG LC_ALL PAGER TZ EDITOR
unset VISUAL CDPATH GREP_OPTIONS
# Line feed
LF='
'
[ "x$ORIGINAL_TERM" != "xdumb" ] && (
TERM=$ORIGINAL_TERM &&
export TERM &&
[ "x$TERM" != "xdumb" ] && (
[ -t 1 ] &&
tput bold >/dev/null 2>&1 &&
tput setaf 1 >/dev/null 2>&1 &&
@@ -60,6 +107,8 @@ while test "$#" -ne 0; do
immediate=t; shift ;;
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
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)
help=t; shift ;;
-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
# passed without the ok/not ok details is always an error.
test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
--chain-lint)
chain_lint=t; shift ;;
--no-chain-lint)
chain_lint=; shift ;;
--no-color)
color=; shift ;;
--tee)
shift ;; # was handled already
--root=*)
root=$(expr "z$1" : 'z[^=]*=\(.*\)')
shift ;;
--verbose-log)
verbose_log=t
shift ;;
*)
echo "error: unknown test option '$1'" >&2; exit 1 ;;
esac
done
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() {
(
TERM=$ORIGINAL_TERM
export TERM
test -z "$1" && test -n "$quiet" && return
case "$1" in
error)
tput bold; tput setaf 1;; # bold red
skip)
tput setaf 4;; # blue
warn)
tput setaf 3;; # brown/yellow
pass)
tput setaf 2;; # green
info)
tput setaf 6;; # cyan
*)
test -n "$quiet" && return;;
error) say_color_color=$say_color_error ;;
skip) say_color_color=$say_color_skip ;;
warn) say_color_color=$say_color_warn ;;
pass) say_color_color=$say_color_pass ;;
info) say_color_color=$say_color_info ;;
*) say_color_color=$say_color_raw ;;
esac
shift
printf "%s" "$*"
tput sgr0
echo
)
printf '%s%s%s\n' "$say_color_color" "$*" "$say_color_reset"
}
else
say_color() {
test -z "$1" && test -n "$quiet" && return
shift
printf "%s\n" "$*"
printf '%s\n' "$*"
}
fi
TERM=dumb
export TERM
error() {
say_color error "error: $*"
EXIT_OK=t
@@ -121,7 +190,7 @@ say() {
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
echo "$test_description"
@@ -130,7 +199,11 @@ fi
exec 5>&1
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
else
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
# 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
#
@@ -198,7 +271,7 @@ test_have_prereq() {
# prerequisites can be concatenated with ','
save_IFS=$IFS
IFS=,
set -- $*
set -- $@
IFS=$save_IFS
total_prereq=0
@@ -215,7 +288,7 @@ test_have_prereq() {
negative_prereq=
esac
total_prereq=$(($total_prereq + 1))
total_prereq=$((total_prereq + 1))
case "$satisfied_prereq" in
*" $prerequisite "*)
satisfied_this_prereq=t
@@ -226,7 +299,7 @@ test_have_prereq() {
case "$satisfied_this_prereq,$negative_prereq" in
t,|,t)
ok_prereq=$(($ok_prereq + 1))
ok_prereq=$((ok_prereq + 1))
;;
*)
# Keep a list of missing prerequisites; restore
@@ -247,12 +320,12 @@ test_have_prereq() {
# the text_expect_* functions instead.
test_ok_() {
test_success=$(($test_success + 1))
say_color "" "ok $test_count - $@"
test_success=$((test_success + 1))
say_color "" "ok $test_count - $*"
}
test_failure_() {
test_failure=$(($test_failure + 1))
test_failure=$((test_failure + 1))
say_color error "not ok $test_count - $1"
shift
echo "$@" | sed -e 's/^/# /'
@@ -260,13 +333,13 @@ test_failure_() {
}
test_known_broken_ok_() {
test_fixed=$(($test_fixed + 1))
say_color error "ok $test_count - $@ # TODO known breakage vanished"
test_fixed=$((test_fixed + 1))
say_color error "ok $test_count - $* # TODO known breakage vanished"
}
test_known_broken_failure_() {
test_broken=$(($test_broken + 1))
say_color warn "not ok $test_count - $@ # TODO known breakage"
test_broken=$((test_broken + 1))
say_color warn "not ok $test_count - $* # TODO known breakage"
}
# Public: Execute commands in debug mode.
@@ -287,10 +360,29 @@ test_debug() {
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_() {
# This is a separate function because some tests use
# "return" to end a test_expect_success block early.
eval </dev/null >&3 2>&4 "$*"
case ",$test_prereq," in
*,INTERACTIVE,*)
eval "$*"
;;
*)
eval </dev/null >&3 2>&4 "$*"
;;
esac
}
test_run_() {
@@ -299,6 +391,13 @@ test_run_() {
test_eval_ "$1"
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
test_eval_ "$test_cleanup"
fi
@@ -309,7 +408,7 @@ test_run_() {
}
test_skip_() {
test_count=$(($test_count + 1))
test_count=$((test_count + 1))
to_skip=
for skp in $SKIP_TESTS; do
case $this_test.$test_count in
@@ -328,7 +427,7 @@ test_skip_() {
of_prereq=" of $test_prereq"
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})"
: true
;;
@@ -426,6 +525,44 @@ test_expect_failure() {
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.
#
# Use it instead of "! <command>". For example, when <command> dies due to a
@@ -518,7 +655,7 @@ test_expect_code() {
shift
"$@"
exit_code=$?
if test $exit_code = $want_code; then
if test "$exit_code" = "$want_code"; then
return 0
fi
@@ -528,7 +665,7 @@ test_expect_code() {
# 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,
# will the command's output, the diff, be printed to the standard output.
#
@@ -551,6 +688,79 @@ test_cmp() {
${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
# test.
#
@@ -576,6 +786,23 @@ test_when_finished() {
} && (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.
#
# Must be called at the end of each test script.
@@ -600,9 +827,9 @@ test_done() {
EXIT_OK=t
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"
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
total $test_count
@@ -621,7 +848,7 @@ test_done() {
say_color warn "# still have $test_broken known breakage(s)"
fi
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)"
else
test_remaining=$test_count
@@ -641,6 +868,8 @@ test_done() {
fi
say "1..$test_count$skip_all"
test_eval_ "$final_cleanup"
test -d "$remove_trash" &&
cd "$(dirname "$remove_trash")" &&
rm -rf "$(basename "$remove_trash")"
@@ -656,14 +885,15 @@ test_done() {
esac
}
# Public: Root directory containing tests. Tests can override this variable,
# e.g. for testing Sharness itself.
: ${SHARNESS_TEST_DIRECTORY:=$(pwd)}
export SHARNESS_TEST_DIRECTORY
# Public: Source directory of test code and sharness library.
# This directory may be different from the directory in which tests are
# being run.
: "${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
# the parent directory of SHARNESS_TEST_DIRECTORY.
: ${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}
: "${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}"
PATH="$SHARNESS_BUILD_DIRECTORY:$PATH"
export PATH SHARNESS_BUILD_DIRECTORY
@@ -672,19 +902,43 @@ SHARNESS_TEST_FILE="$0"
export SHARNESS_TEST_FILE
# Prepare test area.
test_dir="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
test -n "$root" && test_dir="$root/$test_dir"
case "$test_dir" in
/*) SHARNESS_TRASH_DIRECTORY="$test_dir" ;;
*) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$test_dir" ;;
SHARNESS_TRASH_DIRECTORY="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY"
case "$SHARNESS_TRASH_DIRECTORY" in
/*) ;; # absolute path is good
*) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_OUTPUT_DIRECTORY/$SHARNESS_TRASH_DIRECTORY" ;;
esac
test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY"
rm -rf "$test_dir" || {
rm -rf "$SHARNESS_TRASH_DIRECTORY" || {
EXIT_OK=t
echo >&5 "FATAL: Cannot prepare test area"
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
# variable is set to that directory too.
export SHARNESS_TRASH_DIRECTORY
@@ -692,10 +946,10 @@ export SHARNESS_TRASH_DIRECTORY
HOME="$SHARNESS_TRASH_DIRECTORY"
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
# 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=${this_test%.$SHARNESS_TEST_EXTENSION}
@@ -708,4 +962,10 @@ for skp in $SKIP_TESTS; do
esac
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 :

View File

@@ -1,8 +1,55 @@
#!/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 [ -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
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
@@ -10,3 +57,6 @@ GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
# maintain backwards compatible default
# (as used in remote helper)
git config --global init.defaultBranch master

1
tools/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
results.txt

303
tools/check-versions Executable file
View 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

View 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()

View 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
View 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