164 Commits
test ... v1.0.2

Author SHA1 Message Date
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
19 changed files with 4509 additions and 578 deletions

View File

@@ -1,26 +1,20 @@
language: python
dist: xenial
language: minimal
install:
- if [ "$HG_VERSION" != "dev" ];
then pip install -q Mercurial${HG_VERSION+==$HG_VERSION};
else pip install -q http://selenic.com/repo/hg/archive/tip.tar.gz;
fi
- pip install -q dulwich hg-git || true
before_script:
- hg --version || true
- pip show hg-git dulwich
cache:
directories:
- $HOME/.cache/git-remote-hg
script:
- export TEST_OPTS='-v'
- make test
- ./tools/check-versions hg:$HG_VERSION
matrix:
include:
- env: HG_VERSION=2.9.1
- env: HG_VERSION=2.8.2
- env: HG_VERSION=2.7.2
- env: HG_VERSION=3.0
- env: HG_VERSION=dev
- python: 2.7
- python: 2.6
- 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

@@ -26,4 +26,16 @@ install-doc: doc
install -d -m 755 $(D)$(mandir)/
install -m 644 doc/git-remote-hg.1 $(D)$(mandir)/git-remote-hg.1
.PHONY: all test install install-doc clean
pypi:
version=`git describe --tags ${REV}` && \
sed -i "s/version = .*/version = '$$version'[1:]/" setup.py
-rm -rf dist build
python setup.py sdist bdist_wheel
pypi-upload:
twine upload dist/*
pypi-test:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
.PHONY: all test install install-doc clean pypy pypy-upload

View File

@@ -9,12 +9,38 @@ git clone "hg::http://selenic.com/repo/hello"
To enable this, simply add the 'git-remote-hg' script anywhere in your `$PATH`:
--------------------------------------
wget https://raw.github.com/felipec/git-remote-hg/master/git-remote-hg -O ~/bin/git-remote-hg
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:
@@ -89,6 +115,23 @@ However, some of these features require very new versions of 'git-remote-hg',
so you might have better luck simply specifying the username and password in
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
@@ -105,17 +148,31 @@ Closed branches are not supported; they are not shown and you can't close or
reopen. Additionally in certain rare situations a synchronization issue can
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`
* `git push origin old:new` (it will push 'old') (patches available)
* `git push --dry-run origin branch` (it will push) (patches available)
****
Another limitation is that if `git log` reports a rename, this will not survive
the push and Mercurial will not be aware of a rename (and similarly so for copy).
Though Mercurial would know about it if you *manually* ran `git-format-patch`
followed by a `hg apply -s`, which is not the nice way to go obviously.
Actually, scratch the limitations above ascribed to the remote-helpers framework.
They are not limitations of the framework, but are due to how the original
implementation of 'git-remote-hg' interacts with it.
Using the remote-helpers framework in only a slightly different way has none
of the above limitations. See the <<no-limitations, relevant section>>
below for more details.
****
== Other projects ==
There are other 'git-remote-hg' projects out there, do not confuse this one,
this is the one distributed officially by the Git project:
this is the one distributed officially by the Git project
(_though actually no longer so nowadays_):
* https://github.com/msysgit/msysgit/wiki/Guide-to-git-remote-hg[msysgit's git-remote-hg]
* https://github.com/rfk/git-remote-hg[rfk's git-remote-hg]
@@ -123,7 +180,240 @@ this is the one distributed officially by the Git project:
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 ==
Send your patches to the mailing list git-fc@googlegroups.com (no need to
subscribe).
Please file an issue with some patches or a pull-request.

View File

@@ -58,6 +58,50 @@ If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly
% git config --global remote-hg.hg-git-compat true
--------------------------------------
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
-----
@@ -119,3 +163,49 @@ would only see the latest head.
Closed branches are not supported; they are not shown and you can't close or
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

46
setup.py Normal file
View File

@@ -0,0 +1,46 @@
# git-remote-hg setuptools script
import setuptools
import subprocess
import sys
import os
# strip leading v
version = 'v1.0.2'[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",
"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,6 +1,6 @@
RM ?= rm -f
T = $(wildcard *.t)
T = main.t main-push.t bidi.t helper.t
TEST_DIRECTORY := $(CURDIR)
export TEST_DIRECTORY

View File

@@ -17,7 +17,7 @@ then
test_done
fi
if ! python2 -c 'import mercurial' > /dev/null 2>&1
if ! python -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
@@ -51,7 +51,7 @@ hg_push () {
}
hg_log () {
hg -R $1 log --graph --debug
hg -R $1 log --debug
}
setup () {
@@ -204,8 +204,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
'
@@ -232,7 +233,47 @@ 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 ; } &&
# 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 &&

547
test/helper.t Executable file
View File

@@ -0,0 +1,547 @@
#!/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 not available'
test_done
fi
if ! python -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; 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

@@ -17,16 +17,16 @@ then
test_done
fi
if ! python2 -c 'import mercurial' > /dev/null 2>&1
if ! python -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
if python2 -c 'import hggit' > /dev/null 2>&1
if python -c 'import hggit' > /dev/null 2>&1
then
hggit=hggit
elif python2 -c 'import hgext.git' > /dev/null 2>&1
elif python -c 'import hgext.git' > /dev/null 2>&1
then
hggit=hgext.git
else
@@ -34,17 +34,6 @@ else
test_done
fi
hg_version=$(python2 -c 'from mercurial import util; print util.version()')
echo "hg_version: $hg_version"
case $hg_version in
3.0*+*)
skip_all='skipping remote-hg tests; unsuported version of hg by hg-git'
test_done
;;
esac
# clone to a git repo with git
git_clone_git () {
git clone -q "hg::$1" $2 &&
@@ -117,13 +106,15 @@ setup () {
debugrawcommit = -d "0 0"
tag = -d "0 0"
[extensions]
hgext.bookmarks =
$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
@@ -135,6 +126,31 @@ 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*" &&

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
) &&
(
cd hgrepo &&
hg update &&
stat content2 >expected &&
# umask mileage might vary
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

View File

@@ -11,13 +11,22 @@ test_description='Test remote-hg'
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
. "$TEST_DIRECTORY"/test-lib.sh
if test "$CAPABILITY_PUSH" = "t"
then
git config --global remote-hg.capability-push true
git config --global remote-hg.push-updates-notes true
git config --global remote-hg.fast-export-options '-C -C -M'
else
git config --global remote-hg.capability-push false
fi
if ! test_have_prereq PYTHON
then
skip_all='skipping remote-hg tests; python not available'
test_done
fi
if ! python2 -c 'import mercurial' > /dev/null 2>&1
if ! python -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
@@ -81,23 +90,20 @@ check_push () {
'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
;;
*)
echo "BUG: wrong kind '$kind'" && return 3
;;
esac
test $ref_ret -ne 0 && echo "match for '$branch' failed" && break
test $ref_ret -ne 0 && echo "match for '$branch' failed" && return 2
done
if test $expected_ret -ne $ret || test $ref_ret -ne 0
then
return 1
fi
test $expected_ret -ne $ret && return 1
return 0
}
@@ -176,7 +182,7 @@ test_expect_success 'update bookmark' '
git checkout --quiet devel &&
echo devel > content &&
git commit -a -m devel &&
git push --quiet
git push --quiet origin devel
) &&
check_bookmark hgrepo devel devel
@@ -442,7 +448,7 @@ test_expect_success 'remote update bookmark diverge' '
echo diverge > content &&
git commit -a -m diverge &&
check_push 1 <<-\EOF
diverge:fetch-first
diverge:non-fast-forward
EOF
) &&
@@ -467,10 +473,56 @@ test_expect_success 'remote new bookmark multiple branch head' '
# cleanup previous stuff
rm -rf hgrepo
testcopyrenamedesc='push commits with copy and rename'
testcopyrename='
test_when_finished "rm -rf gitrepo hgrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
cp content content-copy &&
# recent git-fast-export is (too) picky in recognizing copies
# although git-log is not as picky;
# since https://github.com/git/git/commit/8096e1d385660c159d9d47e69b2be63cf22e4f31
# a copy is only marked if source filed not modified as well
# (though destination file can be modified)
echo one >> content-copy &&
git add content content-copy &&
git commit -m copy &&
git mv content-copy content-moved
git commit -m moved &&
git push origin master
) &&
(
hg -R hgrepo update &&
test_cmp gitrepo/content hgrepo/content
test_cmp gitrepo/content-moved hgrepo/content-moved
cd hgrepo &&
test `hg log -f content-moved | grep -c changeset` -eq 3
)
'
if test "$CAPABILITY_PUSH" = "t"
then
test_expect_success "$testcopyrenamedesc" "$testcopyrename"
else
test_expect_failure "$testcopyrenamedesc" "$testcopyrename"
fi
test_expect_success 'fetch special filenames' '
test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
LC_ALL=C.UTF-8
LC_ALL=en_US.UTF-8
export LC_ALL
(
@@ -503,7 +555,7 @@ test_expect_success 'push special filenames' '
mkdir -p tmp && cd tmp &&
LC_ALL=C.UTF-8
LC_ALL=en_US.UTF-8
export LC_ALL
(
@@ -618,17 +670,31 @@ test_expect_success 'remote big push' '
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 ''
if test "$CAPABILITY_PUSH" = "t"
then
# cap push handles refs one by one
# so it will push all requested it can
check_branch hgrepo default six &&
check_branch hgrepo good_branch eight &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch ten &&
check_bookmark hgrepo good_bmark three &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark six
else
check_branch hgrepo default one &&
check_branch hgrepo 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
fi
'
test_expect_success 'remote big push fetch first' '
test_expect_success 'remote big push non fast forward' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
(
@@ -677,22 +743,33 @@ test_expect_success 'remote big push fetch first' '
check_push 1 --all <<-\EOF &&
master
good_bmark
bad_bmark:fetch-first
branches/bad_branch:festch-first
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
git fetch &&
check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
if test "$CAPABILITY_PUSH" = "t"
then
# cap push handles refs one by one
# so it will already have pushed some above previously
# (and master is a fake one that jumps around a bit)
check_push 1 --all <<-\EOF
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
else
check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
fi
)
'
test_expect_failure 'remote big push force' '
test_expect_success 'remote big push force' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
@@ -700,16 +777,30 @@ test_expect_failure 'remote big push force' '
(
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
if test "$CAPABILITY_PUSH" = "t"
then
check_push 0 --force --all <<-\EOF
master:forced-update
good_bmark:forced-update
branches/good_branch:forced-update
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
else
check_push 0 --force --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
fi
) &&
check_branch hgrepo default six &&
@@ -722,7 +813,7 @@ test_expect_failure 'remote big push force' '
check_bookmark hgrepo new_bmark six
'
test_expect_failure 'remote big push dry-run' '
test_expect_success 'remote big push dry-run' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
@@ -753,11 +844,55 @@ test_expect_failure 'remote big push dry-run' '
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_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 ''
check_bookmark hgrepo new_bmark
'
test_expect_success 'remote big push force dry-run' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
if test "$CAPABILITY_PUSH" = "t"
then
check_push 0 --force --dry-run --all <<-\EOF
master:forced-update
good_bmark:forced-update
branches/good_branch:forced-update
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
else
check_push 0 --force --dry-run --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
fi
) &&
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch &&
check_bookmark hgrepo good_bmark one &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark
'
test_expect_success 'remote double failed push' '
@@ -783,6 +918,78 @@ test_expect_success 'remote double failed push' '
test_expect_code 1 git push
)
'
test_expect_success 'fetch prune' '
test_when_finished "rm -rf gitrepo hgrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
echo feature-a > content &&
hg commit -m feature-a
hg bookmark feature-a
) &&
git clone "hg::hgrepo" gitrepo &&
check gitrepo origin/feature-a feature-a &&
(
cd hgrepo &&
hg bookmark -d feature-a
) &&
(
cd gitrepo &&
git fetch --prune origin
git branch -a > out &&
! grep feature-a out
)
'
test_expect_success 'fetch multiple independent histories' '
test_when_finished "rm -rf gitrepo hgrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
hg up -r null &&
echo another > ocontent &&
hg add ocontent &&
hg commit -m one
) &&
# -r 1 acts as master
(
git init --bare gitrepo && cd gitrepo &&
git remote add origin hg::../hgrepo &&
git fetch origin refs/heads/*:refs/heads/*
) &&
(
cd hgrepo &&
hg up 0 &&
echo two > content &&
hg commit -m two
) &&
# now master already exists
# -r 2 becomes master head which has rev 0 as ancestor
# so when importing (parentless) rev 0, a reset is needed
# (to ensure rev 0 is not given a parent commit)
(
cd gitrepo &&
git fetch origin &&
git log --format="%s" origin/master > ../actual
) &&
hg -R hgrepo log -r . -f --template "{desc}\n" > expected &&
test_cmp actual expected
'
test_expect_success 'clone remote with null bookmark, then push' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
@@ -828,7 +1035,8 @@ test_expect_success 'notes' '
test_cmp expected actual
'
test_expect_failure 'push updates notes' '
testpushupdatesnotesdesc='push updates notes'
testpushupdatesnotes='
test_when_finished "rm -rf hgrepo gitrepo" &&
(
@@ -844,7 +1052,7 @@ test_expect_failure 'push updates notes' '
(
cd gitrepo &&
echo two > content &&
git commit -a -m two
git commit -a -m two &&
git push
) &&
@@ -853,7 +1061,39 @@ test_expect_failure 'push updates notes' '
test_cmp expected actual
'
test_expect_success 'pull tags' '
if test "$CAPABILITY_PUSH" = "t"
then
test_expect_success "$testpushupdatesnotesdesc" "$testpushupdatesnotes"
else
test_expect_failure "$testpushupdatesnotesdesc" "$testpushupdatesnotes"
fi
test_expect_success 'push bookmark without changesets' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo one > content &&
hg add content &&
hg commit -m one
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
echo two > content &&
git commit -a -m two &&
git push origin master &&
git branch feature-a &&
git push origin feature-a
) &&
check_bookmark hgrepo feature-a two
'
test_expect_unstable 'pull tags' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
@@ -898,7 +1138,7 @@ test_expect_success 'push merged named branch' '
git push
) &&
cat > expected <<-EOF
cat > expected <<-EOF &&
Merge
three
two
@@ -939,7 +1179,7 @@ test_expect_success 'push tag different branch' '
cd hgrepo &&
echo one > content &&
hg add content &&
hg commit -m one
hg commit -m one &&
hg branch feature &&
echo two > content &&
hg commit -m two
@@ -1024,4 +1264,78 @@ test_expect_success 'clone replace directory with a file' '
check_files gitrepo "dir_or_file"
'
test_expect_success 'clone can ignore invalid refnames' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
touch test.txt &&
hg add test.txt &&
hg commit -m master &&
hg branch parent &&
echo test >test.txt &&
hg commit -m test &&
hg branch parent/child &&
echo test1 >test.txt &&
hg commit -m test1
) &&
git clone -c remote-hg.ignore-name=child "hg::hgrepo" gitrepo &&
check_files gitrepo "test.txt"
'
test_expect_success 'push annotated tag' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo one > content &&
hg add content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git tag -m "Version 1.0" v1.0 &&
git push --tags
) &&
cat > expected <<-\EOF &&
tip:Version 1.0:C O Mitter <committer@example.com>
v1.0:one:H G Wells <wells@example.com>
EOF
hg -R hgrepo log --template "{tags}:{desc}:{author}\n" > actual &&
test_cmp expected actual
'
test_expect_success 'timezone issues with negative offsets' '
test_when_finished "rm -rf hgrepo gitrepo1 gitrepo2" &&
hg init hgrepo &&
(
git clone "hg::hgrepo" gitrepo1 &&
cd gitrepo1 &&
echo two >> content &&
git add content &&
git commit -m two --date="2016-09-26 00:00:00 -0230" &&
git push
) &&
git clone "hg::hgrepo" gitrepo2 &&
git --git-dir=gitrepo1/.git log -1 --format="%ai" > expected &&
git --git-dir=gitrepo2/.git log -1 --format="%ai" > actual &&
test_cmp expected actual
'
if test "$CAPABILITY_PUSH" != "t"
then
test_done
fi

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 :

1
tools/.gitignore vendored Normal file
View File

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

297
tools/check-versions Executable file
View File

@@ -0,0 +1,297 @@
#!/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'
$tests = %w[main.t bidi.t hg-git.t]
$workdir = "#{Dir.home}/.cache/git-remote-hg"
$builddir = "/tmp/git-remote-hg-build"
$testoutdir = "/tmp/git-remote-hg-tests"
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