194 Commits

Author SHA1 Message Date
Mark Nauwelaerts
88b2756e43 t: post-merge adjust of test-lib.sh 2025-08-30 20:31:47 +02:00
Mark Nauwelaerts
d000a0b5e6 t: post-merge align of main-push test 2025-08-23 18:12:41 +02:00
Mark Nauwelaerts
4e119d9ea6 t: post-merge align of helper test 2025-08-23 18:12:41 +02:00
Mark Nauwelaerts
e31f83cbc5 Merge branch 'felipec' 2025-08-23 15:39:32 +02:00
Mark Nauwelaerts
5e1aa3a8e0 Merge commit 'bad0a3e5e5dd8352b3ea67d6efa8584ebde5311e' into felipec 2025-08-23 15:30:30 +02:00
Mark Nauwelaerts
ce7ddae09a Merge commit 'f4cdd20cb106c9e0ba57bc63b4231f9da6e72513' into felipec 2025-08-23 15:27:12 +02:00
Felipe Contreras
bad0a3e5e5 check-versions: test hg 7.0 2025-08-02 03:54:13 -06:00
Felipe Contreras
705f9ecaec github: enable windows test 2025-08-02 03:49:15 -06:00
Felipe Contreras
7c3eccdb93 t: cleanup win check 2025-08-02 03:44:52 -06:00
Felipe Contreras
44d09e7d37 t: check for MinGW32 2025-08-02 03:44:52 -06:00
Felipe Contreras
f87d0bc1a1 github: update python version 2025-08-02 03:44:28 -06:00
Felipe Contreras
54804bc402 github: update actions 2025-08-02 03:44:28 -06:00
Felipe Contreras
99c02f49df github: cleanup 2025-08-02 03:44:28 -06:00
Felipe Contreras
39960e1ae8 github: use prove 2025-08-02 03:44:28 -06:00
Felipe Contreras
5353a87001 t: allow execution from other dirs 2025-08-02 03:44:28 -06:00
Felipe Contreras
9a80e68234 t: update to sharness 1.2.1 2025-08-02 03:44:28 -06:00
Felipe Contreras
f4cdd20cb1 t: rename directory 2025-08-01 19:05:51 -06:00
Mark Nauwelaerts
16b33919e4 Release v1.0.5 2025-06-29 21:34:12 +02:00
Mark Nauwelaerts
9813797360 Transform invalid reserved pathname components
Fixes mnauw/git-remote-hg#58
2025-05-04 12:45:41 +02:00
Mark Nauwelaerts
e1a9c3e91b Update loading source file as module 2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
a8f6d92613 helper: add mapfile subcommand
Fixes mnauw/git-remote-hg#55
2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
4b8a307400 helper: use proper variable in error message 2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
6d75435eab helper: align update of reference to shared hg repo
... to use a relative path where possible
2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
d47a4abdae Always ensure reference to shared hg repo is up to date 2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
afdb8943ea ci: disable trigger on push 2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
dc1be060d1 README: drop mention of supported version
... as the intention is always to support the latest anyway
2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
13781788eb README: add a note about broken hg-git compatibility mode 2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
5061e6a322 README: minor note on notes 2025-05-04 12:19:35 +02:00
Mark Nauwelaerts
587099b968 Disable a hg-git mimic attempt
This essentially mostly reverts b029ac0500,
as we have no way to properly decide on those extra pieces.

hg-git uses commit extra metadata, which is not supported by fast-import
or fast-export, and until/unless that changes there is no way to match
hg-git.  Trying to do so in contorted ways only adds confusion.
2025-05-04 12:17:27 +02:00
Mark Nauwelaerts
b5f104364f test: ensure original behaviour in hg-git test 2025-05-03 12:18:25 +02:00
Mark Nauwelaerts
a48d4fd7fb test: post-merge align of main-push test 2025-05-03 12:18:25 +02:00
Mark Nauwelaerts
301552278a test: post-merge align of helper test 2025-05-02 16:13:19 +02:00
Mark Nauwelaerts
fddbbfe990 Merge branch 'felipec'
Integrate changes from felipec where appropriate and still relevant.
2025-05-01 20:18:03 +02:00
Mark Nauwelaerts
c329c9690a Merge commit '408333afca931970d19c57bb697cdf83f6abcbef' into felipec
These changes can be merged with limited conflict resolution.
2025-05-01 20:00:37 +02:00
Mark Nauwelaerts
6c36268028 Merge commit '474cacd81d0f34717aebc6df473406285d5868ad' into felipec
These changes can be merged with limited conflict resolution.
2025-05-01 19:48:36 +02:00
Mark Nauwelaerts
893dd9434f Merge commit '7713b7ecefea9f0df2970079086fe318e3d26311' into felipec
These changes have been discarded.

While it may involve ancient API, there is limited gain wrt complexity,
so might as well leave in place.
2025-05-01 19:38:27 +02:00
Mark Nauwelaerts
4ddbfeb9c8 Merge commit '463f397ba49b9f5f416c1cf85c1104c3939be224' into felipec
Discard change, which now follows a similar approach to what was
introduced long ago in c3f02d39ad.
Caution is also required in subsequent imports as considered in
a59e1246a2.
2025-05-01 16:20:56 +02:00
Mark Nauwelaerts
93271a4e1b Merge commit 'e774ad2d96ae27e23c8ede88384bb1c085d631e8' into felipec
Accept trivial change.
2025-05-01 16:20:16 +02:00
Mark Nauwelaerts
36706dffe6 Merge commit '086ca235076d7450d3e46e8f80f483b895856777' into felipec
Discard superfluous cleanup.
2025-05-01 16:07:24 +02:00
Mark Nauwelaerts
da532bf6f4 Merge commit '7c373be665ebcf794a297b3c98afd9d94365d9f9' into felipec
These changes can be merged and accepted with limited conflict resolution.
2025-05-01 16:05:05 +02:00
Mark Nauwelaerts
aa1d0bc152 Merge commit '7908c70efbd0420e21c2b0b7841b61e3b933be51' into felipec
These changes can be merged with limited conflict resolution.
2025-05-01 16:02:47 +02:00
Mark Nauwelaerts
bdbe62256a Merge commit '8025945a62d16ef078299ad5903081f250d762ed' into felipec
These changes can be merged with some adjustments.
That is, only conditionally prefer some newer API, but otherwise
prefer current code paths, which have been tried and tested for a
long time through various version (both python and hg).
2025-04-30 20:55:24 +02:00
Mark Nauwelaerts
8acf139e44 Merge commit 'b8b9a2f571c322bb3fe8a19c102a0f75fe9f3a9a' into felipec
These changes can be merged with limited to no conflict resolution.
2025-04-30 20:31:41 +02:00
Mark Nauwelaerts
1df692295c Merge commit 'f032d3617bb47585f20006abee83d7309498c17d' into felipec
This change is part of port to python v3 and can as such be discarded.
2025-04-30 20:18:32 +02:00
Mark Nauwelaerts
027e1a16f0 Merge commit '60a1d7ae7a60988f122d8d9ba9ad3c693c5141ae' into felipec
These changes can be merged with limited conflict resolution.
2025-04-30 19:16:33 +02:00
Mark Nauwelaerts
723e6c76fc Merge commit '9b54c626bcf25d390861b430145e96af3ec8459c' into felipec
The removal of support for older version can reduce clutter and ease
maintenance, but in this case such gains are marginal, and there would
then only be loss (of older functionality).

As such, this change is discarded, and older version support is kept.
2025-04-30 18:34:29 +02:00
Mark Nauwelaerts
2529c986c2 Merge commit 'd51f508916d543f987868dd6f7072c72e8f692b2' into felipec
These changes can be merged with limited to no conflict resolution.
2025-04-30 18:30:58 +02:00
Mark Nauwelaerts
ab398ade1d Merge commit '7196dac02d94105586305462be5c15a812c6f7de' into felipec
These changes can be mostly accepted and merged with limited resolution,
especially since hg-git testing is mostly disabled and discarded in
future commits.
2025-04-29 21:56:56 +02:00
Mark Nauwelaerts
e1d25cf97c Merge commit 'b4c3277f72f995cc0babcdc5bc6f6d0e2254acc3' into felipec
These changes can be merged with limited conflict resolution.
2025-04-29 21:18:04 +02:00
Mark Nauwelaerts
0fe1e359ec Merge commit '7394fc890e76ec3919fa30048338a9cbb59ce899' into felipec
This commit can be discarded as it is not relevant; revwalk() is used
in stead of gitrange().  The latter is based on recorded tips, which
are also no longer in use, as that approach is not quite robust.
It is also inefficient when fetching large number of new bookmarks
(for which there can be no pre-tracked tip).
2025-04-29 20:53:25 +02:00
Mark Nauwelaerts
498c615051 Merge commit '22229dd738ae3d0752b293cca1cf948c1d154cfa' into felipec
These changes can be merged with limited to no conflict resolution.
2025-04-29 20:48:13 +02:00
Mark Nauwelaerts
6b6aa9deaa Merge tag 'v0.6' into felipec
These changes involve a port to python3.  These can mostly be discarded,
as such port has already been done in an alternative way, which supports
both v2 and v3.
2025-04-28 18:53:34 +02:00
Mark Nauwelaerts
2685f56c7c Merge tag 'v0.5' into felipec
These changes can be merged with limited to no conflict resolution.
2025-04-28 18:37:33 +02:00
Mark Nauwelaerts
3314ce3dda Makefile: use lighter asciidoctor iso asciidoc 2025-04-28 17:24:22 +02:00
Felipe Contreras
408333afca github: use newer hg versions 2025-03-08 08:48:47 -06:00
Felipe Contreras
c861db6add check-versions: add newer versions 2025-03-08 08:32:03 -06:00
Felipe Contreras
d2a3a646af test: unset user some config 2025-03-08 08:30:24 -06:00
Felipe Contreras
f00911668a Avoid decoding some binary stuff 2025-03-08 02:01:54 -06:00
Felipe Contreras
474cacd81d check-versions: fix for newer ruby versions 2025-03-07 23:53:09 -06:00
Mark Nauwelaerts
e4d87d5e2c Use raw literals for some regexps
Fixes mnauw/git-remote-hg#57
2025-02-08 21:19:29 +01:00
Felipe Contreras
615cc7fe04 github: disable windows tests
It's not working. Probably related to actions/runner-images#7253.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2024-03-07 01:07:07 -06:00
Dan Rose
79e75991ab Use raw strings for regexes
Fixes #94.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2024-03-07 00:28:50 -06:00
Mark Nauwelaerts
b029ac0500 Improve hg-git compatibility mode
... by adjusting to some hg-git changes

See mnauw/git-remote-hg#55
2023-05-07 13:21:45 +02:00
Felipe Contreras
7713b7ecef Remove push_unsafe()
It's not needed anymore.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-05 12:29:28 -06:00
Felipe Contreras
b274b8057e Don't force public pushes
This is something that needs to explicitly happen.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-05 12:29:28 -06:00
Felipe Contreras
451e31022a Restrict common discovery
This was added in hg 4.5.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-05 12:29:28 -06:00
Felipe Contreras
9c61c09ebf Remove support for lock-based unbundling
This was deprecated in 0.9.1 and support for those servers dropped in
4.4.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-05 12:29:23 -06:00
Felipe Contreras
463f397ba4 Remove last-note
We can take advantage of `ref^0` and let `git fast-import` figure out
the most recent commit.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-04 15:07:19 -06:00
Felipe Contreras
e774ad2d96 Fix initial marks version
[no ci]

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-04 09:40:10 -06:00
Felipe Contreras
086ca23507 Trivial cleanups
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-04 07:45:58 -06:00
Felipe Contreras
7c373be665 test: test against hg 6.4
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-05-04 07:20:51 -06:00
Felipe Contreras
3bfec5fc6f github: give a name to the action
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-22 18:17:20 -06:00
Felipe Contreras
7908c70efb Trivial simplifications
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 02:09:17 -06:00
Felipe Contreras
7cff2c6adb Simplify export_file args
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 02:07:45 -06:00
Felipe Contreras
9c5b8835f4 Get rid of export_files
It's not necessary.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 02:02:11 -06:00
Felipe Contreras
537e5a4735 Reorganize export_files
No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 01:58:42 -06:00
Felipe Contreras
8025945a62 Simpler get_filechanges algorithm
The status method achieves the same thing as the current code.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 01:54:10 -06:00
Felipe Contreras
33dccdfab0 Simplify get_filechanges
No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 01:47:48 -06:00
Felipe Contreras
4ad9c8d70c Reorganize get_filechanges
So it's more extensible.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 01:44:31 -06:00
Felipe Contreras
740c681c1d Trivial style change
More idiomatic.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 01:39:33 -06:00
Felipe Contreras
995179444c Trivial simplification
When there's no parents the files are the same as the manifest.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-20 01:37:49 -06:00
Felipe Contreras
e6c479c136 Cleanup timezone stuff
No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-14 04:10:54 -06:00
Felipe Contreras
b8b9a2f571 Use relative option to hg.share
When available.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 22:48:07 -06:00
Felipe Contreras
4c50223dba remote-hg: remove shared repo upgrade
We are not in 2013 anymore.

This reverts commit 8f9a87c (remote-hg: add shared repo upgrade,
2013-08-09).

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 22:47:53 -06:00
Felipe Contreras
35d32d5a75 Remove ancient marks upgrade path
It's safe to safe everyone already moved on since 2013.

This reverts d379f37 (remote-hg: upgrade version 1 marks, 2013-05-24).

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 21:49:05 -06:00
Felipe Contreras
7f6a843f0d github: add windows job
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 18:46:30 -06:00
Felipe Contreras
63cf2780ba test: fixes for Windows
It's not clear if these tests can't work, or don't work at the moment,
but at least some seem to be the fault of hg, not us.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 18:45:17 -06:00
Felipe Contreras
f032d3617b Improve output writing
Let's avoid all python weirdness and just write directly.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 11:52:05 -06:00
Mark Nauwelaerts
60a1d7ae7a Fix for paths in Windows
Rewritten-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 11:52:05 -06:00
Felipe Contreras
10aec96d88 Simplify absolute path fix
This actually works on Windows.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-07 11:33:30 -06:00
Felipe Contreras
9b54c626bc Remove support for hg < 4.0
2016 is ancient anyway.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
d51f508916 check-versions: trivial results cleanup 2023-03-06 15:40:44 -06:00
Felipe Contreras
9916fead46 github: trivial update
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
09c4726083 check-versions: simplify for a single component
No need for all the extra complexity just for hg.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
bb663c032f github: use standard hg packages
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
b590aec106 check-versions: remove code for other tools
Only support hg.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
4496af4a5c check-versions: remove hg hack
It was only needed for hg-git tests.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
890080673b check-versions: remove hg-git stuff
It's not worth it to keep trying to run this.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
5e6ef0a1d5 test: properly check for mercurial
We want to fail if it's not present, not skip the tests.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
a1e2c4acc9 test: remove pointless prereq checks
The prereq check was necessary in upstream git, not here where it's a
noop.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:40:44 -06:00
Felipe Contreras
7196dac02d Merge branch 'hg-git-revamp'
* hg-git-revamp:
  test: enable hg-git tests
  test: hg-git: trivial cleanup
  test: hg-git: general cleanup
  test: hg-git: fetch output from expected dir
  test: add expected output
  test: hg-git: add test_cmp_expected helper
  test: hg-git: add helper functions
  test: switch to bash
  test: hg-git: add main helper
  test: hg-git: simplify hg log filter
  test: relax hg-git checks
  test: hg-git: cleanup
2023-03-06 15:39:23 -06:00
Felipe Contreras
a8bb2a28a3 test: enable hg-git tests
They have been working for a long time but the standard packages needed
to be patched with check-versions to run them successfully.

Now that the expected output is stored we don't need to patch anything
and they can just be run.

This reverts commit b022367aef.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:18:53 -06:00
Felipe Contreras
ffcb41cc52 test: hg-git: trivial cleanup
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:18:53 -06:00
Felipe Contreras
9949745533 test: hg-git: general cleanup
Now that we don't have to run hg-git the code is much simpler.

No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:18:52 -06:00
Felipe Contreras
83620648ab test: hg-git: fetch output from expected dir
So we don't actually have to run hg-git every time (it's broken most of
the time anyway).

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:09:02 -06:00
Felipe Contreras
30a2d61bdf test: add expected output
Generated with: hg:6.3 hggit:1.0.1 dulwich:0.20.50

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:09:02 -06:00
Felipe Contreras
2fdb786fc4 test: hg-git: add test_cmp_expected helper
No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:09:02 -06:00
Felipe Contreras
79797918ff test: hg-git: add helper functions
It's tedious to do almost exactly the same thing over and over.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:09:02 -06:00
Felipe Contreras
d45d5cde50 test: switch to bash
We are using some bash-specific tricks.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 15:09:02 -06:00
Felipe Contreras
7078666c77 test: hg-git: add main helper
Simplifies current code and will be useful later.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 09:55:03 -06:00
Felipe Contreras
08e453f8db test: hg-git: simplify hg log filter
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 09:55:03 -06:00
Felipe Contreras
ec7119d0ef test: relax hg-git checks
We don't care about the revision number of the commits, only the
topology.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 09:55:03 -06:00
Felipe Contreras
6ae5e3961e test: hg-git: cleanup
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 09:55:03 -06:00
Felipe Contreras
b4c3277f72 github: trigger actions on all branches
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-06 09:42:51 -06:00
Felipe Contreras
de9bf35388 test: include sharness properly
So that it can be overridden.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-05 22:40:09 -06:00
Felipe Contreras
857d68708b test: trivial cleanups
TEST_DIRECTORY doesn't even exist in sharness.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-05 22:32:27 -06:00
Felipe Contreras
7394fc890e Simplify gitrange
The internal function for `a %% b` is marginally faster, and much
simpler.

Nowadays most versions of hg should have it.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-02 16:54:33 -06:00
Felipe Contreras
22229dd738 Only report success after successful push
Otherwise git core will update the namespaced refs, and show success to
the user, even in the case of a crash.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-01 11:38:29 -06:00
Felipe Contreras
5cd03ad0fd github: update python version
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-01 11:08:56 -06:00
Felipe Contreras
bf7ad934d7 check-versions: update
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2023-03-01 11:08:27 -06:00
Mark Nauwelaerts
426ed618b2 Release v1.0.4 2022-12-07 19:10:40 +01:00
Mark Nauwelaerts
5f34d049b9 test: adjust configuration to recent git
... to allow file protocol

Fixes mnauw/git-remote-hg#53
2022-12-06 22:57:29 +01:00
Mark Nauwelaerts
ea7e9bf31a helper: align getenv compatibility helper 2022-10-22 18:46:52 +02:00
Mark Nauwelaerts
a3a36883c5 Ensure fallback getenvb returns bytes 2022-10-22 18:46:47 +02:00
Jeremiah Blanchard
0fdd28319a Fixes bug where compat.getenv fails on Windows due to bytes type (when string expected) (tested on Python 3.10) 2022-10-22 18:28:04 +02:00
Felipe Contreras
a5bc03d4d6 doc: use asdiidoctor
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-19 18:41:53 -05:00
Felipe Contreras
104e8895d6 doc: update and cleanup
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-19 18:37:24 -05:00
Felipe Contreras
30f31c13ce Skip close check for non-local branches
Apparently nowadays some remotes contain a bunch of topic branches which
are not pulled by default.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-10 23:53:45 -05:00
Felipe Contreras
485806e1e3 Dump data contents as-is
We don't care if it's valid utf-8 or not, just dump it.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-10 21:13:02 -05:00
Felipe Contreras
6e13c1c818 github: run tests with python3
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-08 00:33:10 -05:00
Felipe Contreras
ce38d52ce5 check-versions: add latest version
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-08 00:01:41 -05:00
Felipe Contreras
6b8ee2f1b6 check-versions: update version list
All these work with python3, and finally we are up-to-date.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-08 00:01:41 -05:00
Felipe Contreras
b3b9b5de39 Enable python3 support
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-08 00:01:41 -05:00
Felipe Contreras
34ba087896 Use unicode_escape
Seems to work in both python2 and python3.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
4aec2fe3cc Properly print binary data
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
e892cb6ce3 Decode commit data
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
59ad50c6d0 Encode more stuff
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
b8c8b1fd00 Encode hg literals
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
0cf8b2c20a Encode more hg stuff
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
8c3cde6be7 Encode hg urls
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
ccee8909ff Encode hg rev and hex stuff
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
dd6b72df21 Encode and decode {hg,git}ref
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
01d619ad3c Encode hg tag stuff
In preparation for python3.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
9d45e70fce Encode hg branch stuff
In preparation for python3.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
055cec1aa7 Encode hg bookmark stuff
In preparation for python3.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
7d50fa42c1 Decode and encode parsed strings
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:21 -05:00
Felipe Contreras
f6676e6d86 Avoid python2 iteritems()
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:58:19 -05:00
Felipe Contreras
cac075744d Use python3 print syntax
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:30:38 -05:00
Felipe Contreras
19633eaf36 Improve urllib imports
So it's more extensible for when we move to python3.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:30:38 -05:00
Felipe Contreras
900a55e974 Use more standard python3 idioms
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:30:38 -05:00
Felipe Contreras
d1f60c445e readme: general updates
[no ci]

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 23:18:16 -05:00
Felipe Contreras
bd3f404d34 readme: python3 support is ready
[no ci]

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-07 22:33:46 -05:00
Felipe Contreras
dcf96f31db readme: more description about mnauw's fork
[no ci]

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-05 23:27:09 -05:00
Felipe Contreras
795b88e16c readme: minor improvements
[no ci]

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-05 23:22:48 -05:00
Felipe Contreras
20366b4b20 Trivial cleanup
rev_marks and tips are already strings.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-05 20:31:16 -05:00
Felipe Contreras
1f5134062e Add debug helper
It's kind of tedious to always add something like this.

[no ci]

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-05 17:33:37 -05:00
Felipe Contreras
2313dc2ca0 readme: update
[no ci]

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-05 02:58:51 -05:00
Felipe Contreras
0e52a6c883 check-versions: add last python2 combination
Mercurial 5.8 does keep working with python 2.7, but hggit 0.10.1
doesn't, and neither does dulwich 0.20.0.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-05 02:22:33 -05:00
Felipe Contreras
e24a713dc9 check-versions: add hack for hg 5.7
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-08-05 01:29:05 -05:00
Felipe Contreras
122b7f5da2 Remove annoying warning
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 05:16:36 -05:00
Felipe Contreras
98c1c9263e github: update hg versions
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 04:23:14 -05:00
Felipe Contreras
85293dcf69 check-versions: add 2020 versions
Also, update the hggit patch for 0.9.0.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 04:23:14 -05:00
Felipe Contreras
970883c46c check-versions: add more versions
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 01:25:14 -05:00
Felipe Contreras
ad77f125b7 travis: remove crap
No longer open.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 01:25:14 -05:00
Felipe Contreras
5dcd6df3c8 github: cache check-versions stuff
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 00:59:58 -05:00
Felipe Contreras
ed80437db4 github: use a matrix of hg versions
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 00:48:57 -05:00
Felipe Contreras
0a1e8ecbc7 github: add simple workflow
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 00:38:40 -05:00
Felipe Contreras
6d6504d1fd test: fix for latest versions of git
Since git 2.34 the big push with force test is broken thanks to:

726a228dfb (fast-export: fix surprising behavior with --first-parent, 2021-12-16)

Since this only affects pushing multiple heads to the same branch, it
probably is not that important.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 00:38:40 -05:00
Felipe Contreras
237ff083af check-versions: update versions
These combinations seem to work.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 00:19:44 -05:00
Felipe Contreras
0c8f8571c7 check-versions: update hggit url
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 00:19:44 -05:00
Felipe Contreras
1442c29d39 check-versions: fix variable
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2022-07-30 00:19:38 -05:00
Julien Cristau
dfa3ad5fca helper: adjust for hg 6.1
mercurial.util.url became mercurial.utils.urlutil.url in 5.8.
2022-03-28 22:48:55 +02:00
Mark Nauwelaerts
ebd5bdb111 Release v1.0.3.2 2022-02-23 23:16:12 +01:00
Paul Wise
00ac711fb2 Fix syntax error caused by extra semicolon
Fixes: commit 4d38bff053
2022-02-23 23:15:30 +01:00
Mark Nauwelaerts
aadc899982 Release v1.0.3.1 2022-02-22 22:00:48 +01:00
Paul Wise
4d38bff053 Fail the build when Python with Mercurial is not available 2022-02-22 21:58:51 +01:00
Paul Wise
a8cd6a92b3 Do not overwrite found python executable with 'python' 2022-02-22 21:58:51 +01:00
Paul Wise
a08ad9d2b4 Add an option to test the pre-installed scripts
This is useful for distros like Debian that do tests on installed packages.

See-also: https://ci.debian.net/
2022-02-22 21:58:51 +01:00
Mark Nauwelaerts
8c08b6de21 Release v1.0.3 2022-02-21 22:55:11 +01:00
Mark Nauwelaerts
949345fb11 test: drop check on default
... since default branch is updated semi-random (implementation defined) from
the last non-branch push.

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

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

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

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

The Python setuptools based build system already modifies shebangs.

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

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

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

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

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

Ubuntu 21.04 will change the default umask to 027.
2021-04-03 10:00:58 +02:00
Paul Wise
1796289df3 Remove unused Python imports in the setuptools build system
Suggested-by: vulture
2021-04-03 10:00:18 +02:00
45 changed files with 2610 additions and 1462 deletions

44
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: CI
# on: [push]
on:
# save cycles; disable on push, enable manual trigger
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
hg: [ '6.0', '6.1', '6.2', '6.3', '6.4', '6.5', '6.6', '6.7', '6.8', '6.9', '7.0' ]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- uses: actions/cache@v4
id: cache-pip
with:
path: ~/.cache/pip
key: pip
- name: Install hg
run:
pip install mercurial==${{ matrix.hg }}
- run: prove -j4
test-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- uses: actions/cache@v4
id: cache-pip
with:
path: ~/appdata/local/pip/cache
key: pip-windows
- name: Install hg
run:
pip install mercurial
- name: Run all tests
run: prove -j4 --exec bash.exe

3
.gitignore vendored Normal file
View File

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

View File

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

View File

@@ -3,24 +3,47 @@ prefix := $(HOME)
bindir := $(prefix)/bin
mandir := $(prefix)/share/man/man1
all: doc
all: build doc
build:
if [ -n "$$PYTHON" ] && "$$PYTHON" -c 'import mercurial' 2> /dev/null ; then \
: Use chosen Python version ; \
elif python3 -c 'import mercurial' 2> /dev/null ; then \
PYTHON=python3 ; \
elif python2 -c 'import mercurial' 2> /dev/null ; then \
PYTHON=python2 ; \
elif python -c 'import mercurial' 2> /dev/null ; then \
PYTHON=python ; \
else \
echo 'Python with Mercurial not available' >&2 ; \
exit 1 ; \
fi ; \
mkdir -p bin ; \
for s in git-remote-hg git-hg-helper ; do \
printf "%s\n" "#!/usr/bin/env $$PYTHON" > "bin/$$s" ; \
tail -n +2 "./$$s" >> "bin/$$s" ; \
chmod 755 "bin/$$s" ; \
touch -r "./$$s" "bin/$$s" ; \
done
doc: doc/git-remote-hg.1
test:
$(MAKE) -C test
$(MAKE) -C t
doc/git-remote-hg.1: doc/git-remote-hg.txt
a2x -d manpage -f manpage $<
asciidoctor -d manpage -b manpage $<
clean:
$(RM) doc/git-remote-hg.1
$(RM) -r bin/
D = $(DESTDIR)
install:
install: build
install -d -m 755 $(D)$(bindir)/
install -m 755 git-remote-hg $(D)$(bindir)/git-remote-hg
install -m 755 bin/git-remote-hg $(D)$(bindir)/git-remote-hg
install -m 755 bin/git-hg-helper $(D)$(bindir)/git-hg-helper
install-doc: doc
install -d -m 755 $(D)$(mandir)/
@@ -38,4 +61,4 @@ pypi-upload:
pypi-test:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
.PHONY: all test install install-doc clean pypy pypy-upload
.PHONY: all build test install install-doc clean pypy pypy-upload

View File

@@ -1,4 +1,4 @@
'git-remote-hg' is the semi-official Mercurial bridge from Git project, once
`git-remote-hg` is the semi-official Mercurial bridge from the Git project, once
installed, it allows you to clone, fetch and push to and from Mercurial
repositories as if they were Git ones:
@@ -6,10 +6,10 @@ repositories as if they were Git ones:
git clone "hg::http://selenic.com/repo/hello"
--------------------------------------
To enable this, simply add the 'git-remote-hg' script anywhere in your `$PATH`:
To enable this, simply add the `git-remote-hg` script anywhere in your `$PATH`:
--------------------------------------
wget https://raw.github.com/mnauw/git-remote-hg/master/git-remote-hg -O ~/bin/git-remote-hg
wget https://raw.githubusercontent.com/mnauw/git-remote-hg/master/git-remote-hg -O ~/bin/git-remote-hg
chmod +x ~/bin/git-remote-hg
--------------------------------------
@@ -49,7 +49,8 @@ If you want to see Mercurial revisions as Git commit notes:
% git config core.notesRef refs/notes/hg
--------------------------------------
If you are not interested in Mercurial permanent and global branches (aka. commit labels):
If you are not interested in Mercurial permanent and global branches (aka.
commit labels):
--------------------------------------
% git config --global remote-hg.track-branches false
@@ -57,29 +58,47 @@ If you are not interested in Mercurial permanent and global branches (aka. commi
With this configuration, the 'branches/foo' refs won't appear.
If you want the equivalent of 'hg clone --insecure':
If you want the equivalent of `hg clone --insecure`:
--------------------------------------
% git config --global remote-hg.insecure true
--------------------------------------
If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly the same commits:
If you want `git-remote-hg` to be compatible with `hg-git`, and generate exactly
the same commits:
--------------------------------------
% git config --global remote-hg.hg-git-compat true
--------------------------------------
****
mnauw's note; The above is not quite the case, it only ever has been (somewhat)
if an undocumented debug mode (`debugextrainmessage` setting) was enabled
in (likely somewhat patched) `hg-git`. And as of `hg-git` v1.2.0 the latter is
no longer considered. In fact, `hg-git` creates git commits with additional hg
metadata stored in so-called "extra commit headers". The latter might be seen by
`git log --format=raw` or `git cat-file -p <commitid>`, but are otherwise mostly
only used internally by the git suite (for signatures). While they are supported
by `dulwich`'s API (which is a python git implementation), there is, however,
limited to no support for those in git "porcelain or plumbing" commands. In
particular, `git fast-export` and `git fast-import` do not consider these, so a
`gitremote-helpers` tool is then also out of luck. Incidentally, it also
follows that a `git fast-export | git fast-import` "clone" approach would also
lose such extra metadata, and likewise so for e.g. `git filter-repo`.
All in all, this mode is not quite recommended.
If the concern here is not so much `hg-git` compatibility but rather "hg-git-hg
round-trip fidelity", then see the discussion below on `check-hg-commits` setting.
****
== Notes ==
Remember to run `git gc --aggressive` after cloning a repository, specially if
Remember to run `git gc --aggressive` after cloning a repository, especially if
it's a big one. Otherwise lots of space will be wasted.
The oldest version of mercurial supported is 1.9. For the most part 1.8 works,
but you might experience some issues.
=== Pushing branches ===
To push a branch, you need to use the "branches/" prefix:
To push a branch, you need to use the 'branches/' prefix:
--------------------------------------
% git checkout branches/next
@@ -89,7 +108,7 @@ To push a branch, you need to use the "branches/" prefix:
All the pushed commits will receive the "next" Mercurial named branch.
*Note*: Make sure you don't have +remote-hg.track-branches+ disabled.
*Note*: Make sure you don't have `remote-hg.track-branches` disabled.
=== Cloning HTTPS ===
@@ -99,7 +118,7 @@ The simplest way is to specify the user and password in the URL:
git clone hg::https://user:password@bitbucket.org/user/repo
--------------------------------------
You can also use the http://mercurial.selenic.com/wiki/SchemesExtension[schemes extension]:
You can also use the https://mercurial-scm.org/wiki/SchemesExtension[schemes extension]:
--------------------------------------
[auth]
@@ -109,11 +128,7 @@ bb.password = password
--------------------------------------
Finally, you can also use the
https://pypi.python.org/pypi/mercurial_keyring[keyring extension].
However, some of these features require very new versions of 'git-remote-hg',
so you might have better luck simply specifying the username and password in
the URL.
https://pypi.org/project/mercurial_keyring[keyring extension].
=== Submodules ===
@@ -141,10 +156,10 @@ Mercurial branches and bookmarks have some limitations of Git branches: you
can't have both 'dev/feature' and 'dev' (as Git uses files and directories to
store them).
Multiple anonymous heads (which are useless anyway) are not supported; you
Multiple anonymous heads (which are useless anyway) are not supported: you
would only see the latest head.
Closed branches are not supported; they are not shown and you can't close or
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]).
@@ -170,16 +185,27 @@ below for more details.
== Other projects ==
There are other 'git-remote-hg' projects out there, do not confuse this one,
this is the one distributed officially by the Git project
(_though actually no longer so nowadays_):
There are other `git-remote-hg` projects out there, but this is the original,
which was distributed officially in the Git project.
* https://github.com/msysgit/msysgit/wiki/Guide-to-git-remote-hg[msysgit's git-remote-hg]
* https://github.com/rfk/git-remote-hg[rfk's git-remote-hg]
Over the years many similar tools have died out, the only actively maintained
alternative is mnauw's fork of this project:
https://github.com/mnauw/git-remote-hg[mnauw/git-remote-hg]. I've merged some of
his patches, and he has merged some of my patches, so the projects are mostly in
sync, but not quite. In particular Nauwelaerts' fork has many administrative
extensions, which although useful to some people, I don't believe they belong
in the core.
For a comparison between these and other projects go
https://github.com/felipec/git/wiki/Comparison-of-git-remote-hg-alternatives[here].
****
mnauw's note; I do not know what "the core" means?
However, the "extensions" provide useful and possibly
critical maintenance wrt git-remote-hg's internal data, so it belongs as close
to the latter one as possible.
****
[[no-limitations]]
== Limitations (or not) ==
@@ -361,7 +387,8 @@ 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).
git-to-git fetch (or clone) (as that is only automatically so for `refs/heads/`,
though it could be pushed manually).
As such (and as said), this approach aims for plain-and-simple safety, but only
within a local scope (git repo).

View File

@@ -38,7 +38,8 @@ If you want to see Mercurial revisions as Git commit notes:
% git config core.notesRef refs/notes/hg
--------------------------------------
If you are not interested in Mercurial permanent and global branches (aka. commit labels):
If you are not interested in Mercurial permanent and global branches (aka.
commit labels):
--------------------------------------
% git config --global remote-hg.track-branches false
@@ -52,7 +53,8 @@ If you want the equivalent of `hg clone --insecure`:
% git config --global remote-hg.insecure true
--------------------------------------
If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly the same commits:
If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly
the same commits:
--------------------------------------
% git config --global remote-hg.hg-git-compat true
@@ -102,19 +104,32 @@ the invalid '~'
% git config --global remote-hg.ignore-name ~
--------------------------------------
Even though the "gitdir" is configurable (using `GIT_DIR`), git does not accept
certain pathname components, e.g. `.git` or `.gitmodules` (case-insensitive).
Problems arise if the hg repo contains such pathnames, and recent git versions
will reject this in a very hard way. So these pathnames are now mapped
from "hg space" to "git space" in a one-to-one way, where (e.g.)
`.git[0 or more suffix]` is mapped to `.git[1 or more suffix]` (obviously by
appending or removing a suffix). The "suffix" in question defaults to `_`,
but can be configured using
--------------------------------------
% git config --global remote-hg.dotfile-suffix _
--------------------------------------
NOTES
-----
Remember to run `git gc --aggressive` after cloning a repository, specially if
Remember to run `git gc --aggressive` after cloning a repository, especially if
it's a big one. Otherwise lots of space will be wasted.
The oldest version of Mercurial supported is 1.9. For the most part 1.8 works,
but you might experience some issues.
The newest supported version of Mercurial is 6.2, the oldest one is 2.4.
Pushing branches
~~~~~~~~~~~~~~~~
To push a Mercurial named branch, you need to use the "branches/" prefix:
To push a branch, you need to use the "branches/" prefix:
--------------------------------------
% git checkout branches/next
@@ -135,7 +150,7 @@ The simplest way is to specify the user and password in the URL:
git clone hg::https://user:password@bitbucket.org/user/repo
--------------------------------------
You can also use the http://mercurial.selenic.com/wiki/SchemesExtension[schemes extension]:
You can also use the https://mercurial-scm.org/wiki/SchemesExtension[schemes extension]:
--------------------------------------
[auth]
@@ -145,7 +160,7 @@ bb.password = password
--------------------------------------
Finally, you can also use the
https://pypi.python.org/pypi/mercurial_keyring[keyring extension].
https://pypi.org/project/mercurial_keyring[keyring extension].
CAVEATS
-------
@@ -157,10 +172,10 @@ Mercurial branches and bookmarks have some limitations of Git branches: you
can't have both 'dev/feature' and 'dev' (as Git uses files and directories to
store them).
Multiple anonymous heads (which are useless anyway) are not supported; you
Multiple anonymous heads (which are useless anyway) are not supported: you
would only see the latest head.
Closed branches are not supported; they are not shown and you can't close or
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]).

View File

@@ -5,6 +5,11 @@
from mercurial import hg, ui, commands, util
from mercurial import context, subrepo
try:
# hg >= 5.8
from mercurial.utils import urlutil
except ImportError:
from mercurial import util as urlutil
import re
import sys
@@ -51,7 +56,13 @@ if sys.version_info[0] == 3:
stdout = sys.stdout.buffer
stderr = sys.stderr.buffer
getcwd = os.getcwdb
getenv = os.getenvb if os.supports_bytes_environ else os.getenv
@staticmethod
def getenvb(val, default):
result = os.getenv(val.decode(), default.decode() if hasattr(default, 'decode') else default)
# if result is a string, get bytes instead
result = result.encode() if hasattr(result, 'encode') else result
return result
getenv = os.getenvb if os.supports_bytes_environ else getenvb
else:
class compat(basecompat):
# life was simple in those days ...
@@ -86,11 +97,27 @@ def debug(msg, *args):
def log(msg, *args):
logger.log(logging.LOG, msg, *args)
# new style way to import a source file
def _imp_load_source(module_name, file_path):
import importlib.util
loader = importlib.machinery.SourceFileLoader(module_name, file_path)
spec = importlib.util.spec_from_loader(module_name, loader)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module
def import_sibling(mod, filename):
import imp
mydir = os.path.dirname(__file__)
sys.dont_write_bytecode = True
return imp.load_source(mod, os.path.join(mydir, filename))
vi = sys.version_info
ff = os.path.join(mydir, filename)
if vi.major >= 3 and vi.minor >= 5:
return _imp_load_source(mod, ff)
else:
import imp
return imp.load_source(mod, ff)
class GitHgRepo:
@@ -135,7 +162,7 @@ class GitHgRepo:
process = self.start_cmd(args, **kwargs)
output = process.communicate()[0]
if check and process.returncode != 0:
die(b'command failed: %s' % b' '.join([compat.to_b(a) for a in cmd]))
die(b'git command failed: %s' % b' '.join([compat.to_b(a) for a in args]))
return output
def get_config(self, config, getall=False):
@@ -216,9 +243,12 @@ class GitHgRepo:
warn(b'failed to find local hg for remote %s' % (r))
continue
else:
npath = os.path.abspath(hg_path)
# use relative path if possible
if check_version(4, 2):
npath = os.path.join(b'..', b'..', b'..', b'.hg')
# make sure the shared path is always up-to-date
util.writefile(os.path.join(local_hg, b'sharedpath'),
os.path.abspath(hg_path))
util.writefile(os.path.join(local_hg, b'sharedpath'), npath)
self.hg_repos[r] = os.path.join(local_path)
log('%s determined hg_repos %s', self.identity(), self.hg_repos)
@@ -308,11 +338,11 @@ class GitHgRepo:
if not kind in (b'hg', b'git'):
warn('skipping unsupported subrepo type %s' % kind)
continue
if not util.url(src).isabs():
if not urlutil.url(src).isabs():
parent = self.get_hg_repo_url(remote)
if not parent:
die(b'could not determine repo url of %s' % remote)
parent = util.url(parent)
parent = urlutil.url(parent)
parent.path = posixpath.join(parent.path or b'', src)
parent.path = posixpath.normpath(parent.path)
src = bytes(parent)
@@ -544,6 +574,43 @@ class GcCommand(SubCommand):
gm.store()
class MapFileCommand(SubCommand):
def argumentparser(self):
usage = '%%(prog)s %s [options] <remote>' % (self.subcommand)
p = argparse.ArgumentParser(usage=usage)
p.add_argument('--output', required=True,
help='mapfile to write')
p.epilog = textwrap.dedent("""\
Writes a so-called git-mapfile, as used internally by hg-git.
This files consists of lines of format `<githexsha> <hghexsha>`.
As such, the result could be used to coax hg-git in some manner.
However, as git-remote-hg and hg-git may (likely) produce different
commits (either git or hg), mixed use of both tools is not recommended.
""")
return p
def do(self, options, args):
remotehg = import_sibling('remotehg', 'git-remote-hg')
if not args or len(args) != 1:
self.usage('expect 1 remote')
remote = args[0]
hgpath = remotehg.select_marks_dir(remote, self.githgrepo.gitdir, False)
puts(b"Loading hg marks ...")
hgm = remotehg.Marks(os.path.join(hgpath, b'marks-hg'), None)
puts(b"Loading git marks ...")
gm = GitMarks(os.path.join(hgpath, b'marks-git'))
puts(b"Writing mapfile ...")
with open(options.output, 'wb') as f:
for c, m in gm.marks.items():
hgc = hgm.rev_marks.get(m, None)
if hgc:
f.write(b'%s %s\n' % (c, hgc))
class SubRepoCommand(SubCommand):
def writestate(repo, state):
@@ -910,6 +977,7 @@ def get_subcommands():
b'repo': RepoCommand,
b'gc': GcCommand,
b'sub': SubRepoCommand,
b'mapfile': MapFileCommand,
b'help' : HelpCommand
}
# add remote named subcommands
@@ -932,6 +1000,7 @@ def do_usage():
gc \t perform maintenance and consistency cleanup on repo tracking marks
sub \t manage subrepos
repo \t show local hg repo backing a remote
mapfile \t dump a hg-git git-mapfile
If the subcommand is the name of a remote hg repo, then any remaining arguments
are considered a "hg command", e.g. hg heads, or thg, and it is then executed

View File

@@ -86,7 +86,13 @@ if sys.version_info[0] == 3:
stdout = sys.stdout.buffer
stderr = sys.stderr.buffer
getcwd = os.getcwdb
getenv = os.getenvb if os.supports_bytes_environ else os.getenv
@staticmethod
def getenvb(val, default):
result = os.getenv(val.decode(), default.decode() if hasattr(default, 'decode') else default)
# if result is a string, get bytes instead
result = result.encode() if hasattr(result, 'encode') else result
return result
getenv = os.getenvb if os.supports_bytes_environ else getenvb
urlparse = urllib.parse.urlparse
urljoin = urllib.parse.urljoin
else:
@@ -116,6 +122,27 @@ else:
urlparse = staticmethod(_urlparse)
urljoin = staticmethod(_urljoin)
# new style way to import a source file
def _imp_load_source(module_name, file_path):
import importlib.util
loader = importlib.machinery.SourceFileLoader(module_name, file_path)
spec = importlib.util.spec_from_loader(module_name, loader)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module
def import_sibling(mod, filename):
mydir = os.path.dirname(__file__)
sys.dont_write_bytecode = True
vi = sys.version_info
ff = os.path.join(mydir, filename)
if vi.major >= 3 and vi.minor >= 5:
return _imp_load_source(mod, ff)
else:
import imp
return imp.load_source(mod, ff)
#
# If you want to see Mercurial revisions as Git commit notes:
# git config core.notesRef refs/notes/hg
@@ -141,11 +168,11 @@ else:
# Commits are modified to preserve hg information and allow bidirectionality.
#
NAME_RE = re.compile(b'^([^<>]+)')
AUTHOR_RE = re.compile(b'^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
NAME_RE = re.compile(br'^([^<>]+)')
AUTHOR_RE = re.compile(br'^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
EMAIL_RE = re.compile(br'([^ \t<>]+@[^ \t<>]+)')
AUTHOR_HG_RE = re.compile(b'^(.*?) ?<(.*?)(?:>(.*))?$')
RAW_AUTHOR_RE = re.compile(b'^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
AUTHOR_HG_RE = re.compile(br'^(.*?) ?<(.*?)(?:>(.*))?$')
RAW_AUTHOR_RE = re.compile(br'^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
VERSION = 2
@@ -153,6 +180,9 @@ def die(msg):
compat.stderr.write(b'ERROR: %s\n' % compat.to_b(msg, 'utf-8'))
sys.exit(1)
def debug(*args):
compat.stderr.write(b'DEBUG: %s\n' % compat.to_b(repr(args)))
def warn(msg):
compat.stderr.write(b'WARNING: %s\n' % compat.to_b(msg, 'utf-8'))
compat.stderr.flush()
@@ -193,7 +223,9 @@ def gitref(ref):
# standard url percentage encoding with a (legacy) twist:
# ' ' -> '___'
# '___' also percentage encoded
return compat.urlquote(ref).replace(b'___', b'%5F%5F%5F').replace(b'%20', b'___')
# python 3.6 considers ~ reserved, whereas python 3.7 no longer
return compat.urlquote(ref).replace(b'___', b'%5F%5F%5F'). \
replace(b'%20', b'___').replace(b'~', b'%7E')
def check_version(*check):
if not hg_version:
@@ -229,27 +261,17 @@ def get_rev_hg(commit):
class Marks:
def __init__(self, path, repo):
def __init__(self, path, _repo=None):
self.path = path
self.repo = repo
self.clear()
self.load()
if self.version < VERSION:
if self.version == 1:
self.upgrade_one()
# upgraded?
if self.version < VERSION:
self.clear()
self.version = VERSION
def clear(self):
self.tips = {}
self.marks = {}
self.rev_marks = {}
self.last_mark = 0
self.version = 0
self.version = VERSION
self.last_note = 0
def load(self):
@@ -265,20 +287,12 @@ class Marks:
self.tips = []
self.marks = marks
self.last_mark = tmp['last-mark']
self.version = tmp.get('version', 1)
self.version = tmp['version']
self.last_note = 0
for rev, mark in compat.iteritems(self.marks):
self.rev_marks[mark] = rev
def upgrade_one(self):
def get_id(rev):
return hghex(self.repo.changelog.node(int(rev)))
self.tips = dict((name, get_id(rev)) for name, rev in compat.iteritems(self.tips))
self.marks = dict((get_id(rev), mark) for rev, mark in compat.iteritems(self.marks))
self.rev_marks = dict((mark, get_id(rev)) for mark, rev in compat.iteritems(self.rev_marks))
self.version = 2
def dict(self):
return { 'tips': self.tips, 'marks': self.marks,
'last-mark': self.last_mark, 'version': self.version,
@@ -381,7 +395,7 @@ class Parser:
return None
_, name, email, date, tz = m.groups()
if name and b'ext:' in name:
m = re.match(b'^(.+?) ext:\((.+)\)$', name)
m = re.match(br'^(.+?) ext:\((.+)\)$', name)
if m:
name = m.group(1)
ex = compat.urlunquote(m.group(2))
@@ -400,40 +414,38 @@ class Parser:
return (user, int(date), hgtz(tz))
def fix_file_path(path):
def posix_path(path):
if os.sep == '/':
return path
# even Git for Windows expects forward
return path.replace(compat.to_b(os.sep), b'/')
# also converts forward slash to backwards slash on Win
path = os.path.normpath(path)
if not os.path.isabs(path):
return posix_path(path)
return posix_path(os.path.relpath(path, b'/'))
if os.path.isabs(path):
path = os.path.relpath(path, b'/')
if os.sep == '/':
return path
# even Git for Windows expects forward
return path.replace(compat.to_b(os.sep), b'/')
def export_files(files):
final = []
for f in files:
fid = node.hex(f.filenode())
def export_file(ctx, fname):
f = ctx.filectx(fname)
fid = node.hex(f.filenode())
if fid in filenodes:
mark = filenodes[fid]
else:
mark = marks.next_mark()
filenodes[fid] = mark
d = f.data()
if fid in filenodes:
mark = filenodes[fid]
else:
mark = marks.next_mark()
filenodes[fid] = mark
d = f.data()
puts(b"blob")
puts(b"mark :%u" % mark)
puts(b"data %d" % len(d))
puts(d)
puts(b"blob")
puts(b"mark :%u" % mark)
puts(b"data %d" % len(d))
puts(f.data())
path = fix_file_path(f.path())
final.append((gitmode(f.flags()), mark, path))
return final
path = fixup_path_to_git(fix_file_path(f.path()))
return (gitmode(f.flags()), mark, path)
def get_filechanges(repo, ctx, parent):
if hasattr(parent, 'status'):
stat = parent.status(ctx)
return stat.modified + stat.added, stat.removed
modified = set()
added = set()
removed = set()
@@ -475,7 +487,7 @@ def fixup_user_git(user):
def fixup_user_hg(user):
def sanitize(name):
# stole this from hg-git
return re.sub(b'[<>\n]', b'?', name.lstrip(b'< ').rstrip(b'> '))
return re.sub(br'[<>\n]', b'?', name.lstrip(b'< ').rstrip(b'> '))
m = AUTHOR_HG_RE.match(user)
if m:
@@ -506,6 +518,51 @@ def fixup_user(user):
return b'%s <%s>' % (name, mail)
# (recent) git fast-import does not accept .git or .gitmodule component names
# (anywhere, case-insensitive)
# in any case, surprising things may happen, so add some front-end replacement magic;
# transform of (hg) .git(0 or more suffix) to (git) .git(1 or more suffix)
# (likewise so for any invalid git keyword)
def fixup_dotfile_path(path, suffix, add):
def subst(part):
if (not part) or part[0] != ord(b'.'):
return part
for prefix in (b'.git', b'.gitmodules'):
pl = len(prefix)
tail = len(part) - pl
if tail < 0:
continue
if part[0:pl].lower() == prefix and part[pl:] == suffix * tail:
if add:
return part + suffix
elif tail == 0:
# .git should not occur in git space
# so complain
if pl == 3:
die('invalid path component %s' % part)
else:
# but .gitmodules might
# leave as-is, it is handled/ignored elsewhere
return part
else:
return part[0:-1]
return part
# quick optimization check;
if (not path) or (path[0] != ord(b'.') and path.find(b'/.') < 0):
return path
sep = b'/'
return sep.join((subst(part) for part in path.split(sep)))
def fixup_path_to_git(path):
if not dotfile_suffix:
return path
return fixup_dotfile_path(path, dotfile_suffix, True)
def fixup_path_from_git(path):
if not dotfile_suffix:
return path
return fixup_dotfile_path(path, dotfile_suffix, False)
def updatebookmarks(repo, peer):
remotemarks = peer.listkeys(b'bookmarks')
@@ -577,18 +634,6 @@ def get_repo(url, alias):
else:
shared_path = os.path.join(gitdir, b'hg')
# check and upgrade old organization
hg_path = os.path.join(shared_path, b'.hg')
if os.path.exists(shared_path) and not os.path.exists(hg_path):
repos = os.listdir(shared_path)
for x in repos:
local_hg = os.path.join(shared_path, x, b'clone', b'.hg')
if not os.path.exists(local_hg):
continue
if not os.path.exists(hg_path):
shutil.move(local_hg, hg_path)
shutil.rmtree(os.path.join(shared_path, x, b'clone'))
# setup shared repo (if not there)
try:
hg.peer(myui, {}, shared_path, create=True)
@@ -599,8 +644,13 @@ def get_repo(url, alias):
os.makedirs(dirname)
local_path = os.path.join(dirname, b'clone')
kwargs = {}
hg_path = os.path.join(shared_path, b'.hg')
if check_version(4, 2):
kwargs = {'relative': True}
hg_path = os.path.join(b'..', b'..', b'..', b'.hg')
if not os.path.exists(local_path):
hg.share(myui, shared_path, local_path, update=False)
hg.share(myui, shared_path, local_path, update=False, **kwargs)
else:
# make sure the shared path is always up-to-date
util.writefile(os.path.join(local_path, b'.hg', b'sharedpath'), hg_path)
@@ -709,11 +759,16 @@ def export_ref(repo, name, kind, head):
if rename:
renames.append((rename[0], f))
# NOTE no longer used in hg-git, a HG:rename extra header is used
for e in renames:
extra_msg += b"rename : %s => %s\n" % e
for key, value in compat.iteritems(extra):
if key in (b'author', b'committer', b'encoding', b'message', b'branch', b'hg-git'):
if key in (b'author', b'committer', b'encoding', b'message', b'branch', b'hg-git', b'transplant_source'):
continue
elif key == b'hg-git-rename-source' and value == b'git':
# extra data that hg-git might put there unconditionally
# or that we put in there to be compatible
continue
else:
extra_msg += b"extra : %s : %s\n" % (key, compat.urlquote(value))
@@ -724,7 +779,7 @@ def export_ref(repo, name, kind, head):
if len(parents) == 0:
puts(b'reset %s/%s' % (prefix, ename))
modified_final = export_files(c.filectx(f) for f in modified)
modified_final = [export_file(c, fname) for fname in modified]
puts(b"commit %s/%s" % (prefix, ename))
puts(b"mark :%d" % (marks.get_mark(c.hex())))
@@ -739,7 +794,7 @@ def export_ref(repo, name, kind, head):
puts(b"merge :%u" % (rev_to_mark(parents[1])))
for f in removed:
puts(b"D %s" % (fix_file_path(f)))
puts(b"D %s" % fixup_path_to_git(fix_file_path(f)))
for f in modified_final:
puts(b"M %s :%u %s" % f)
puts()
@@ -837,8 +892,11 @@ def do_list(parser, branchmap):
for branch, heads in compat.iteritems(branchmap):
# only open heads
heads = [h for h in heads if b'close' not in repo.changelog.read(h)[5]]
if heads:
try:
heads = [h for h in heads if b'close' not in repo.changelog.read(h)[5]]
if heads:
branches[branch] = heads
except error.LookupError:
branches[branch] = heads
list_head(repo, cur)
@@ -1029,6 +1087,7 @@ def parse_commit(parser):
else:
die(b'Unknown file command: %s' % line)
path = c_style_unescape(path)
path = fixup_path_from_git(path)
files[path] = files.get(path, {})
files[path].update(f)
@@ -1133,10 +1192,20 @@ def parse_commit(parser):
extra[b'branch'] = hgref(branch)
if mode == 'hg':
# add some extra that hg-git adds (almost) unconditionally
# see also https://foss.heptapod.net/mercurial/hg-git/-/merge_requests/211
# NOTE it could be changed to another value below
# actually, it is *almost* unconditionally, and only done if the commit
# is deduced to originate in git. However, the latter is based on
# presence/absence of HG markers in commit "extra headers".
# The latter can not be handled here, and so this can not be correctly
# reproduced.
# extra[b'hg-git-rename-source'] = b'git'
i = data.find(b'\n--HG--\n')
if i >= 0:
tmp = data[i + len(b'\n--HG--\n'):].strip()
for k, v in [e.split(b' : ', 1) for e in tmp.split(b'\n')]:
# NOTE no longer used in hg-git, a HG:rename extra header is used
if k == b'rename':
old, new = v.split(b' => ', 1)
files[new]['rename'] = old
@@ -1324,7 +1393,10 @@ def checkheads(repo, remote, p_revs, force):
def push_unsafe(repo, remote, p_revs, force):
fci = discovery.findcommonincoming
commoninc = fci(repo, remote, force=force)
if check_version(4, 5):
commoninc = fci(repo, remote, force=force, ancestorsof=list(p_revs))
else:
commoninc = fci(repo, remote, force=force)
common, _, remoteheads = commoninc
fco = discovery.findcommonoutgoing
outgoing = fco(repo, remote, onlyheads=list(p_revs), commoninc=commoninc, force=force)
@@ -1355,12 +1427,6 @@ def push_unsafe(repo, remote, p_revs, force):
else:
ret = remote.addchangegroup(cg, b'push', repo.url())
phases = remote.listkeys(b'phases')
if phases:
for head in p_revs:
# update to public
remote.pushkey(b'phases', hghex(head), b'1', b'0')
return ret
def push(repo, remote, p_revs, force):
@@ -1395,6 +1461,7 @@ def do_push_hg(parser):
global parsed_refs, parsed_tags
p_bmarks = []
p_revs = {}
ok_refs = []
parsed_refs = {}
parsed_tags = {}
@@ -1441,7 +1508,7 @@ def do_push_hg(parser):
continue
p_revs[bnode] = ref
puts(b"ok %s" % ref)
ok_refs.append(ref)
elif ref.startswith(b'refs/heads/'):
bmark = ref[len(b'refs/heads/'):]
new = node
@@ -1451,14 +1518,14 @@ def do_push_hg(parser):
puts(b"ok %s up to date" % ref)
continue
puts(b"ok %s" % ref)
ok_refs.append(ref)
if not bookmark_is_fake(bmark, parser.repo._bookmarks):
p_bmarks.append((ref, bmark, old, new))
p_revs[bnode] = ref
elif ref.startswith(b'refs/tags/'):
if dry_run:
puts(b"ok %s" % ref)
ok_refs.append(ref)
continue
tag = ref[len(b'refs/tags/'):]
tag = hgref(tag)
@@ -1485,14 +1552,15 @@ def do_push_hg(parser):
fp.write(b'%s %s\n' % (node, tag))
fp.close()
p_revs[bnode] = ref
puts(b"ok %s" % ref)
ok_refs.append(ref)
else:
# transport-helper/fast-export bugs
continue
if dry_run:
if peer:
checkheads(parser.repo, peer, p_revs, force_push)
if not peer or checkheads(parser.repo, peer, p_revs, force_push):
for ref in ok_refs:
puts(b"ok %s" % ref)
return
success = True
@@ -1513,12 +1581,18 @@ def do_push_hg(parser):
if not peer.pushkey(b'bookmarks', bmark, old, new):
success = False
puts(b"error %s" % ref)
ok_refs.remove(ref)
else:
# update local bookmarks
for ref, bmark, old, new in p_bmarks:
if not bookmarks.pushbookmark(parser.repo, bmark, old, new):
success = False
puts(b"error %s" % ref)
ok_refs.remove(ref)
# update rest of the refs
for ref in ok_refs:
puts(b"ok %s" % ref)
return success
@@ -1602,10 +1676,7 @@ def do_push_refspec(parser, refspec, revs):
tmpfastexport = open(os.path.join(marksdir, b'git-fast-export-%d' % (os.getpid())), 'w+b')
subprocess.check_call(cmd, stdin=None, stdout=tmpfastexport)
try:
import imp
sys.dont_write_bytecode = True
ctx.hghelper = imp.load_source('hghelper', \
os.path.join(os.path.dirname(__file__), 'git-hg-helper'))
ctx.hghelper = import_sibling('hghelper', 'git-hg-helper')
ctx.hghelper.init_git(gitdir)
ctx.gitmarks = ctx.hghelper.GitMarks(tmpmarks)
# let processing know it should not bother pushing if not requested
@@ -1727,8 +1798,7 @@ def fix_path(alias, repo, orig_url):
url = compat.urlparse(orig_url, b'file')
if url.scheme != b'file' or os.path.isabs(os.path.expanduser(url.path)):
return
abs_url = compat.urljoin(b"%s/" % compat.getcwd(), orig_url)
cmd = ['git', 'config', b'remote.%s.url' % alias, b"hg::%s" % abs_url]
cmd = ['git', 'config', b'remote.%s.url' % alias, b"hg::%s" % os.path.abspath(orig_url)]
subprocess.call(cmd)
def select_private_refs(alias):
@@ -1843,6 +1913,7 @@ def main(args):
global capability_push
global remove_username_quotes
global marksdir
global dotfile_suffix
marks = None
is_tmp = False
@@ -1862,6 +1933,7 @@ def main(args):
track_branches = get_config_bool('remote-hg.track-branches', True)
capability_push = get_config_bool('remote-hg.capability-push', True)
remove_username_quotes = get_config_bool('remote-hg.remove-username-quotes', True)
dotfile_suffix = get_config('remote-hg.dotfile-suffix').strip() or b'_'
force_push = False
if hg_git_compat:
@@ -1906,7 +1978,7 @@ def main(args):
fix_path(alias, peer or repo, url)
marks_path = os.path.join(marksdir, b'marks-hg')
marks = Marks(marks_path, repo)
marks = Marks(marks_path)
if sys.platform == 'win32':
import msvcrt

View File

@@ -1,12 +1,9 @@
# git-remote-hg setuptools script
import setuptools
import subprocess
import sys
import os
# strip leading v
version = 'v1.0.2.1'[1:]
version = 'v1.0.5'[1:]
# check for released version
assert (len(version) > 0)

View File

View File

@@ -1,9 +1,9 @@
RM ?= rm -f
T = main.t main-push.t bidi.t helper.t
TEST_DIRECTORY := $(CURDIR)
SHARNESS_TEST_DIRECTORY := $(CURDIR)
export TEST_DIRECTORY
export SHARNESS_TEST_DIRECTORY
all: test
@@ -11,7 +11,7 @@ test: $(T)
$(MAKE) clean
$(T):
$(SHELL) $@ $(TEST_OPTS)
./$@ $(TEST_OPTS)
clean:
$(RM) -r 'trash directory'.* test-results

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
# Copyright (c) 2012 Felipe Contreras
#
@@ -8,20 +8,7 @@
test_description='Test bidirectionality of remote-hg'
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
. "$(dirname "$0")"/test-lib.sh
# clone to a git repo
git_clone () {

View File

@@ -0,0 +1,60 @@
blob
mark :1
data 2
A
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 0 +0000
committer A U Thor <author@example.com> 0 +0000
data 7
origin
M 100644 :1 afile
blob
mark :3
data 2
C
commit refs/heads/master
mark :4
author A U Thor <author@example.com> 3 +0000
committer A U Thor <author@example.com> 3 +0000
data 5
A->C
from :2
M 100644 :3 afile
blob
mark :5
data 2
B
commit refs/heads/master
mark :6
author A U Thor <author@example.com> 1 +0000
committer A U Thor <author@example.com> 1 +0000
data 5
A->B
from :2
M 100644 :5 afile
commit refs/heads/master
mark :7
author A U Thor <author@example.com> 2 +0000
committer A U Thor <author@example.com> 2 +0000
data 5
B->C
from :6
M 100644 :3 afile
commit refs/heads/master
mark :8
author A U Thor <author@example.com> 4 +0000
committer A U Thor <author@example.com> 4 +0000
data 6
merge
from :4
merge :7

View File

@@ -0,0 +1,67 @@
changeset: 9a6668f453c3003b71e11bb8d7572af57a7ce891
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 331ac2e605f2e6092ccb3802244a65b71f3be726
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: afile
extra: branch=default
description:
origin
changeset: ead35d346ecb18ce9d9d54604ff62b41caa196ce
phase: draft
parent: 9a6668f453c3003b71e11bb8d7572af57a7ce891
parent: -0000000000000000000000000000000000000000
manifest: 894f8ad9a84f743d52747963d0b9f4e9cf37d489
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:01 1970 +0000
files: afile
extra: branch=default
description:
A->B
changeset: 541c7bc8b2d01c8bf71b2298d17edcda120e49bf
phase: draft
parent: ead35d346ecb18ce9d9d54604ff62b41caa196ce
parent: -0000000000000000000000000000000000000000
manifest: 04dae4001cb1fb2384111589720617c4b742044c
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:02 1970 +0000
files: afile
extra: branch=default
description:
B->C
changeset: 5694aadcd7171ecb9768b13e29d027e22a360d44
phase: draft
parent: 9a6668f453c3003b71e11bb8d7572af57a7ce891
parent: -0000000000000000000000000000000000000000
manifest: 6efc6bb8e097947aa212887bdb01fb89dfa3de13
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:03 1970 +0000
files: afile
extra: branch=default
description:
A->C
changeset: 9ee75b4362cc15f9110d6538b2f1c9f0cf14825a
bookmark: master
tag: tip
phase: draft
parent: 5694aadcd7171ecb9768b13e29d027e22a360d44
parent: 541c7bc8b2d01c8bf71b2298d17edcda120e49bf
manifest: eb9f4687448653e876d787cd6f2e59140680ff09
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:04 1970 +0000
files: afile
extra: branch=default
description:
merge

View File

@@ -0,0 +1,56 @@
blob
mark :1
data 6
alpha
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 12
add älphà
M 100644 :1 alpha
blob
mark :3
data 5
beta
commit refs/heads/master
mark :4
author tést èncödîng <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 9
add beta
from :2
M 100644 :3 beta
blob
mark :5
data 6
gamma
commit refs/heads/master
mark :6
author tést èncödîng <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 12
add gämmâ
from :4
M 100644 :5 gamma
blob
mark :7
data 6
delta
commit refs/heads/master
mark :8
author tést èncödîng <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 12
add déltà
from :6
M 100644 :7 delta

View File

@@ -0,0 +1,58 @@
changeset: 6674f1c866b5c428db4acde16404c14077889646
bookmark: master
tag: tip
phase: draft
parent: 7e9fd3fd2f75d7de4bf3d77c47f192a51927ac28
parent: -0000000000000000000000000000000000000000
manifest: ea49f93388380ead5601c8fcbfa187516e7c2ed8
user: tést èncödîng <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: delta
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add déltà
changeset: 7e9fd3fd2f75d7de4bf3d77c47f192a51927ac28
phase: draft
parent: 99c5adad03b9a9935e181f4be91ff7693a790110
parent: -0000000000000000000000000000000000000000
manifest: f580e7da3673c137370da2b931a1dee83590d7b4
user: tést èncödîng <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: gamma
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add gämmâ
changeset: 99c5adad03b9a9935e181f4be91ff7693a790110
phase: draft
parent: 1e3e49d2cc8feaad4942d100108f20f207742d3a
parent: -0000000000000000000000000000000000000000
manifest: f0bd6fbafbaebe4bb59c35108428f6fce152431d
user: tést èncödîng <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: beta
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add beta
changeset: 1e3e49d2cc8feaad4942d100108f20f207742d3a
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add älphà

View File

@@ -0,0 +1,32 @@
blob
mark :1
data 6
alpha
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 10
add alpha
M 100644 :1 alpha
commit refs/heads/master
mark :3
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 19
set executable bit
from :2
M 100755 :1 alpha
commit refs/heads/master
mark :4
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 21
clear executable bit
from :3
M 100644 :1 alpha

View File

@@ -0,0 +1,46 @@
changeset: 1efb93106a36bf71352ab04e769a3422522cf946
bookmark: master
tag: tip
phase: draft
parent: d7cae8b1fdab97568ba5eca44ca2bf5a44d7c394
parent: -0000000000000000000000000000000000000000
manifest: 51e6255d794f794a8c4e0f03edf264444e3c5ce7
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
clear executable bit
changeset: d7cae8b1fdab97568ba5eca44ca2bf5a44d7c394
phase: draft
parent: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
parent: -0000000000000000000000000000000000000000
manifest: e4bf4ef5e9aea7a6a57573e533a5519bd062f144
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
set executable bit
changeset: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add alpha
644 alpha
644 alpha

View File

@@ -0,0 +1,60 @@
blob
mark :1
data 6
alpha
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 10
add alpha
M 100644 :1 alpha
blob
mark :3
data 5
beta
commit refs/heads/master
mark :4
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 9
add beta
from :2
M 100644 :3 beta
blob
mark :5
data 5
blah
commit refs/heads/master
mark :6
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 8
add foo
from :4
M 100644 :5 foo/bar
commit refs/heads/master
mark :7
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 13
remove alpha
from :6
D alpha
commit refs/heads/master
mark :8
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 15
remove foo/bar
from :7
D foo/bar

View File

@@ -0,0 +1,75 @@
changeset: 54f595cbdf1f516dc3b2b25faa6f051aae712f5d
bookmark: master
tag: tip
phase: draft
parent: 7fe32a9185c6d37db430ee5248cdb2ae66582478
parent: -0000000000000000000000000000000000000000
manifest: 3f83f42fa00fb0cac14a83aa48baac2f287a9329
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files-: foo/bar
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
remove foo/bar
changeset: 7fe32a9185c6d37db430ee5248cdb2ae66582478
phase: draft
parent: a21fd0b26a555427c2ea72f8ed37190f6216f705
parent: -0000000000000000000000000000000000000000
manifest: cd10925837609b99d345c44c85bd1f73d742cbbc
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files-: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
remove alpha
changeset: a21fd0b26a555427c2ea72f8ed37190f6216f705
phase: draft
parent: 7cd99375c843931bd8959b766a94e050f428512b
parent: -0000000000000000000000000000000000000000
manifest: a6ee442a94bfc6fb0b7d717183bb8b4534ca4ccd
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: foo/bar
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add foo
changeset: 7cd99375c843931bd8959b766a94e050f428512b
phase: draft
parent: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
parent: -0000000000000000000000000000000000000000
manifest: f0bd6fbafbaebe4bb59c35108428f6fce152431d
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: beta
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add beta
changeset: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add alpha
beta
foo/bar
beta

32
t/expected/git tags/log Normal file
View File

@@ -0,0 +1,32 @@
changeset: 7cd99375c843931bd8959b766a94e050f428512b
bookmark: master
tag: beta
tag: tip
phase: draft
parent: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
parent: -0000000000000000000000000000000000000000
manifest: f0bd6fbafbaebe4bb59c35108428f6fce152431d
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: beta
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add beta
changeset: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
tag: alpha
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add alpha

View File

@@ -0,0 +1,141 @@
blob
mark :1
data 6
alpha
reset refs/heads/not-master
commit refs/heads/not-master
mark :2
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 10
add alpha
M 100644 :1 alpha
blob
mark :3
data 5
beta
commit refs/heads/master
mark :4
author test <none@none> 0 +0000
committer test <none@none> 0 +0000
data 9
add beta
from :2
M 100644 :3 beta
blob
mark :5
data 11
beta
gamma
commit refs/heads/master
mark :6
author test ext:(%20%28comment%29) <test@example.com> 0 +0000
committer test ext:(%20%28comment%29) <test@example.com> 0 +0000
data 12
modify beta
from :4
M 100644 :5 beta
blob
mark :7
data 6
gamma
commit refs/heads/master
mark :8
author <test@example.com> 0 +0000
committer <test@example.com> 0 +0000
data 10
add gamma
from :6
M 100644 :7 gamma
blob
mark :9
data 6
delta
commit refs/heads/master
mark :10
author name <test@example.com> 0 +0000
committer name <test@example.com> 0 +0000
data 10
add delta
from :8
M 100644 :9 delta
blob
mark :11
data 8
epsilon
commit refs/heads/master
mark :12
author name <test@example.com> 0 +0000
committer name <test@example.com> 0 +0000
data 12
add epsilon
from :10
M 100644 :11 epsilon
blob
mark :13
data 5
zeta
commit refs/heads/master
mark :14
author test <none@none> 0 +0000
committer test <none@none> 0 +0000
data 9
add zeta
from :12
M 100644 :13 zeta
blob
mark :15
data 4
eta
commit refs/heads/master
mark :16
author test <test@example.com> 0 +0000
committer test <test@example.com> 0 +0000
data 8
add eta
from :14
M 100644 :15 eta
blob
mark :17
data 6
theta
commit refs/heads/master
mark :18
author test ?test@example.com <test ?test@example.com> 0 +0000
committer test ?test@example.com <test ?test@example.com> 0 +0000
data 10
add theta
from :16
M 100644 :17 theta
blob
mark :19
data 5
iota
commit refs/heads/master
mark :20
author test ext:(%20example%20%3Cdot%3E%20com%3E) <test ?at> 0 +0000
committer test ext:(%20example%20%3Cdot%3E%20com%3E) <test ?at> 0 +0000
data 9
add iota
from :18
M 100644 :19 iota

134
t/expected/hg author/hg-log Normal file
View File

@@ -0,0 +1,134 @@
changeset: 307c03466a07cccafaafc991f36d695d6ad595f3
bookmark: master
tag: tip
phase: draft
parent: 5832614d351449a2f8d6f7ccbef4877c2b18cbe0
parent: -0000000000000000000000000000000000000000
manifest: e8f1b3ae088bdd25e3570a4953ccb6b948524473
user: test <test ?at> example <dot> com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: iota
extra: branch=default
description:
add iota
changeset: 5832614d351449a2f8d6f7ccbef4877c2b18cbe0
phase: draft
parent: e52ded4aca5d210ed58c63158d64fb911876f345
parent: -0000000000000000000000000000000000000000
manifest: 7e4875db7e2970c529f462520121d333e514bf4d
user: test ?test@example.com <test ?test@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: theta
extra: branch=default
description:
add theta
changeset: e52ded4aca5d210ed58c63158d64fb911876f345
phase: draft
parent: 9a34ba7d552e8b73ad306baf1d1eb83de0f74c12
parent: -0000000000000000000000000000000000000000
manifest: ef03e54a9916ac3158c9686503dd4f609c26b3ec
user: test <test@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: eta
extra: branch=default
description:
add eta
changeset: 9a34ba7d552e8b73ad306baf1d1eb83de0f74c12
phase: draft
parent: 6281edc25b9fe9538407726f044a9a61ac7ba5bc
parent: -0000000000000000000000000000000000000000
manifest: 616201b85baf7ed02d41f6a7deb04c52009d8483
user: test
date: Thu Jan 01 00:00:00 1970 +0000
files+: zeta
extra: branch=default
description:
add zeta
changeset: 6281edc25b9fe9538407726f044a9a61ac7ba5bc
phase: draft
parent: 4c7841053c633cb51f8375555d08b6bea54fc4cb
parent: -0000000000000000000000000000000000000000
manifest: c703b3d7be8a0638047142f57ff83d4e94b5d1fa
user: name <test@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: epsilon
extra: branch=default
description:
add epsilon
changeset: 4c7841053c633cb51f8375555d08b6bea54fc4cb
phase: draft
parent: fa8f26586397dd4797842e9300c8db221fe5514d
parent: -0000000000000000000000000000000000000000
manifest: 300b54001cbfa5d027b4bccdb594ccb463adb55d
user: name <test@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: delta
extra: branch=default
description:
add delta
changeset: fa8f26586397dd4797842e9300c8db221fe5514d
phase: draft
parent: 2708ff417fb7e2c0a4f9596286c0a398553fa793
parent: -0000000000000000000000000000000000000000
manifest: 45b0c483a79307d14f7e234feb78776478f828ec
user: <test@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: gamma
extra: branch=default
description:
add gamma
changeset: 2708ff417fb7e2c0a4f9596286c0a398553fa793
phase: draft
parent: 8c51e5fe974fe1cc63a56bbfad343f9ede6bed30
parent: -0000000000000000000000000000000000000000
manifest: c305998040b12e956b998318982c9eb92d2d7b28
user: test <test@example.com> (comment)
date: Thu Jan 01 00:00:00 1970 +0000
files: beta
extra: branch=default
description:
modify beta
changeset: 8c51e5fe974fe1cc63a56bbfad343f9ede6bed30
phase: draft
parent: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
parent: -0000000000000000000000000000000000000000
manifest: f0bd6fbafbaebe4bb59c35108428f6fce152431d
user: test
date: Thu Jan 01 00:00:00 1970 +0000
files+: beta
extra: branch=default
description:
add beta
changeset: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
bookmark: not-master
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add alpha

View File

@@ -0,0 +1,38 @@
blob
mark :1
data 6
alpha
reset refs/heads/not-master
commit refs/heads/not-master
mark :2
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 10
add alpha
M 100644 :1 alpha
commit refs/heads/master
mark :3
author A U Thor <author@example.com> 0 +0000
committer A U Thor <author@example.com> 0 +0000
data 52
rename alpha to beta
--HG--
rename : alpha => beta
from :2
D alpha
M 100644 :1 beta
commit refs/heads/master
mark :4
author A U Thor <author@example.com> 0 +0000
committer A U Thor <author@example.com> 0 +0000
data 44
started branch gamma
--HG--
branch : gamma
from :3

View File

@@ -0,0 +1,44 @@
changeset: 3320583a8de0b31511f499a4ab3426bee1a7f478
branch: gamma
bookmark: master
tag: tip
phase: draft
parent: 5889597089fea2d144989baa9427d1a080293fdb
parent: -0000000000000000000000000000000000000000
manifest: e353b4d5282d044ad738398fd32d0b684d04a14b
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
extra: branch=gamma
description:
started branch gamma
changeset: 5889597089fea2d144989baa9427d1a080293fdb
phase: draft
parent: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
parent: -0000000000000000000000000000000000000000
manifest: e353b4d5282d044ad738398fd32d0b684d04a14b
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: beta
files-: alpha
extra: branch=default
description:
rename alpha to beta
changeset: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
bookmark: not-master
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add alpha

33
t/expected/hg tags/output Normal file
View File

@@ -0,0 +1,33 @@
alpha
changeset: 16869bbe54be9f8082a8aec346de09f6c05cf1de
bookmark: master
tag: tip
phase: draft
parent: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
parent: -0000000000000000000000000000000000000000
manifest: 26f8145fb5b20cc6f70dd131b646f95ab79738c0
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: .hgtags
extra: branch=default
description:
Added tag alpha for changeset 362b656574c3
changeset: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
bookmark: not-master
tag: alpha
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add alpha
362b656574c3c9e89fa7f2d7a943091dc93bce4d alpha

View File

@@ -0,0 +1,51 @@
blob
mark :1
data 2
A
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 0 +0000
committer A U Thor <author@example.com> 0 +0000
data 7
origin
M 100644 :1 afile
blob
mark :3
data 2
C
commit refs/heads/master
mark :4
author A U Thor <author@example.com> 2 +0000
committer A U Thor <author@example.com> 2 +0000
data 5
A->C
from :2
M 100644 :3 afile
blob
mark :5
data 2
B
commit refs/heads/master
mark :6
author A U Thor <author@example.com> 1 +0000
committer A U Thor <author@example.com> 1 +0000
data 5
A->B
from :2
M 100644 :5 afile
commit refs/heads/master
mark :7
author A U Thor <author@example.com> 3 +0000
committer A U Thor <author@example.com> 3 +0000
data 11
merge to C
from :4
merge :6

View File

@@ -0,0 +1,54 @@
changeset: 9a6668f453c3003b71e11bb8d7572af57a7ce891
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 331ac2e605f2e6092ccb3802244a65b71f3be726
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: afile
extra: branch=default
description:
origin
changeset: ead35d346ecb18ce9d9d54604ff62b41caa196ce
phase: draft
parent: 9a6668f453c3003b71e11bb8d7572af57a7ce891
parent: -0000000000000000000000000000000000000000
manifest: 894f8ad9a84f743d52747963d0b9f4e9cf37d489
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:01 1970 +0000
files: afile
extra: branch=default
description:
A->B
changeset: d585ac55494928500f510b965b878d47f9ee60f6
phase: draft
parent: 9a6668f453c3003b71e11bb8d7572af57a7ce891
parent: -0000000000000000000000000000000000000000
manifest: 6efc6bb8e097947aa212887bdb01fb89dfa3de13
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:02 1970 +0000
files: afile
extra: branch=default
description:
A->C
changeset: c6ab734e24c39948e5a25713b48f4972c960ff8b
bookmark: master
tag: tip
phase: draft
parent: d585ac55494928500f510b965b878d47f9ee60f6
parent: ead35d346ecb18ce9d9d54604ff62b41caa196ce
manifest: 96bedb13781f1b9d729a2210a530f0c5c68f42e6
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:03 1970 +0000
files: afile
extra: branch=default
description:
merge to C

View File

@@ -0,0 +1,52 @@
blob
mark :1
data 2
A
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 0 +0000
committer A U Thor <author@example.com> 0 +0000
data 7
origin
M 100644 :1 afile
blob
mark :3
data 2
C
commit refs/heads/master
mark :4
author A U Thor <author@example.com> 2 +0000
committer A U Thor <author@example.com> 2 +0000
data 5
A->C
from :2
M 100644 :3 afile
blob
mark :5
data 2
B
commit refs/heads/master
mark :6
author A U Thor <author@example.com> 1 +0000
committer A U Thor <author@example.com> 1 +0000
data 5
A->B
from :2
M 100644 :5 afile
commit refs/heads/master
mark :7
author A U Thor <author@example.com> 3 +0000
committer A U Thor <author@example.com> 3 +0000
data 11
merge to B
from :4
merge :6
M 100644 :5 afile

View File

@@ -0,0 +1,54 @@
changeset: 9a6668f453c3003b71e11bb8d7572af57a7ce891
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 331ac2e605f2e6092ccb3802244a65b71f3be726
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: afile
extra: branch=default
description:
origin
changeset: ead35d346ecb18ce9d9d54604ff62b41caa196ce
phase: draft
parent: 9a6668f453c3003b71e11bb8d7572af57a7ce891
parent: -0000000000000000000000000000000000000000
manifest: 894f8ad9a84f743d52747963d0b9f4e9cf37d489
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:01 1970 +0000
files: afile
extra: branch=default
description:
A->B
changeset: d585ac55494928500f510b965b878d47f9ee60f6
phase: draft
parent: 9a6668f453c3003b71e11bb8d7572af57a7ce891
parent: -0000000000000000000000000000000000000000
manifest: 6efc6bb8e097947aa212887bdb01fb89dfa3de13
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:02 1970 +0000
files: afile
extra: branch=default
description:
A->C
changeset: 542b187b70e70dc759631d1065794f3c2c5a3e7b
bookmark: master
tag: tip
phase: draft
parent: d585ac55494928500f510b965b878d47f9ee60f6
parent: ead35d346ecb18ce9d9d54604ff62b41caa196ce
manifest: 0907d7dbc98790102fa6cb91b68b271ef0bc5b64
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:03 1970 +0000
files: afile
extra: branch=default
description:
merge to B

27
t/expected/rename/git-log Normal file
View File

@@ -0,0 +1,27 @@
blob
mark :1
data 6
alpha
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 0 +0000
committer A U Thor <author@example.com> 0 +0000
data 10
add alpha
M 100644 :1 alpha
commit refs/heads/master
mark :3
author A U Thor <author@example.com> 0 +0000
committer A U Thor <author@example.com> 0 +0000
data 52
rename alpha to beta
--HG--
rename : alpha => beta
from :2
D alpha
M 100644 :1 beta

29
t/expected/rename/hg-log Normal file
View File

@@ -0,0 +1,29 @@
changeset: a985b184598fd779e53576c65c5dd1d274736c73
bookmark: master
tag: tip
phase: draft
parent: 0558a161e3ca0d59f5f165e3182402d9f1e574a8
parent: -0000000000000000000000000000000000000000
manifest: e353b4d5282d044ad738398fd32d0b684d04a14b
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: beta
files-: alpha
extra: branch=default
description:
rename alpha to beta
changeset: 0558a161e3ca0d59f5f165e3182402d9f1e574a8
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
files+: alpha
extra: branch=default
description:
add alpha

27
t/expected/symlink/log Normal file
View File

@@ -0,0 +1,27 @@
blob
mark :1
data 6
alpha
reset refs/heads/master
commit refs/heads/master
mark :2
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 10
add alpha
M 100644 :1 alpha
blob
mark :3
data 5
alpha
commit refs/heads/master
mark :4
author A U Thor <author@example.com> 1167600600 +0230
committer C O Mitter <committer@example.com> 1167600600 +0230
data 9
add beta
from :2
M 120000 :3 beta

32
t/expected/symlink/output Normal file
View File

@@ -0,0 +1,32 @@
changeset: 87cbc97576079d3dfef04c678bfc8ab69999ebdf
bookmark: master
tag: tip
phase: draft
parent: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
parent: -0000000000000000000000000000000000000000
manifest: 4950f48a7f5b0ce6f31c2f4307e296dbac652026
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: beta
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add beta
changeset: 362b656574c3c9e89fa7f2d7a943091dc93bce4d
phase: draft
parent: -0000000000000000000000000000000000000000
parent: -0000000000000000000000000000000000000000
manifest: 8b8a0e87dfd7a0706c0524afa8ba67e20544cbf0
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
files+: alpha
extra: branch=default
extra: committer=C O Mitter <committer@example.com> 1167600600 -9000
description:
add alpha
644 alpha
644 @ beta

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
# Copyright (c) 2016 Mark Nauwelaerts
#
@@ -8,18 +8,11 @@
test_description='Test git-hg-helper'
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
. "$TEST_DIRECTORY"/test-lib.sh
. "$(dirname "$0")"/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'
skip_all='skipping remote-hg tests; python with mercurial not available'
test_done
fi
@@ -106,7 +99,7 @@ test_expect_success 'subcommand repo - with local proxy' '
test_cmp expected actual
'
test_expect_success 'subcommands hg-rev and git-rev' '
test_expect_success 'subcommands hg-rev and git-rev and mapfile' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repos &&
@@ -117,7 +110,9 @@ test_expect_success 'subcommands hg-rev and git-rev' '
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
git-hg-helper mapfile --output mapfile origin &&
test_cmp rev-HEAD git-HEAD &&
grep "`cat rev-HEAD` `cat hg-HEAD`" mapfile
)
'
@@ -544,4 +539,4 @@ test_expect_success 'subcommand sub status' '
)
'
test_done
test_done

446
t/hg-git.t Executable file
View File

@@ -0,0 +1,446 @@
#!/bin/bash
#
# Copyright (c) 2012 Felipe Contreras
#
# Base commands from hg-git tests:
# https://bitbucket.org/durin42/hg-git/src
#
# shellcheck disable=SC2016,SC2034,SC2086,SC2164,SC1091
test_description='Test remote-hg output compared to hg-git'
. "$(dirname "$0")"/test-lib.sh
export EXPECTED_DIR="$SHARNESS_TEST_DIRECTORY/expected"
git_clone () {
git clone -q "hg::$1" $2 &&
(
cd $2 &&
git checkout master &&
{ git branch -D default || true ;}
)
}
hg_clone () {
(
hg init $2 &&
hg -R $2 bookmark -i master &&
cd $1 &&
git push -q "hg::../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
) &&
(cd $2 && hg -q update)
}
hg_push () {
(
cd $2
git checkout -q -b tmp &&
git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git branch -D default &&
git checkout -q '@{-1}' &&
{ git branch -q -D tmp 2> /dev/null || true ;}
)
}
hg_log () {
hg -R $1 log --debug -r 'sort(tip:0, date)' |
sed -e '/tag: *default/d' -e 's/[0-9]\+:\([0-9a-f]\{40\}\)/\1/'
}
git_log () {
git -C $1 fast-export --branches
}
test_cmp_expected () {
test_cmp "$EXPECTED_DIR/$test_id/$1" "$1"
}
cmp_hg_to_git_log () {
hg_log hgrepo2 > hg-log &&
git_log gitrepo > git-log &&
test_cmp_expected hg-log &&
test_cmp_expected git-log
}
cmp_hg_to_git_log_hgrepo1 () {
git_clone hgrepo1 gitrepo &&
hg_clone gitrepo hgrepo2 &&
cmp_hg_to_git_log
}
cmp_hg_to_git_manifest () {
(
hg_clone gitrepo hgrepo &&
cd hgrepo &&
hg_log . &&
eval "$1"
) > output &&
git_clone hgrepo gitrepo2 &&
git_log gitrepo2 > log &&
test_cmp_expected output &&
test_cmp_expected log
}
setup () {
cat > "$HOME"/.hgrc <<-EOF
[ui]
username = A U Thor <author@example.com>
[defaults]
commit = -d "0 0"
tag = -d "0 0"
EOF
cat > "$HOME"/.gitconfig <<-EOF
[remote-hg]
hg-git-compat = true
track-branches = false
# directly use local repo to avoid push (and hence phase issues)
shared-marks = false
EOF
export HGEDITOR=true
export HGMERGE=true
export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
}
setup
# save old function
eval "old_$(declare -f test_expect_success)"
test_expect_success () {
local req
test "$#" = 3 && { req=$1; shift; } || req=
test_id="$1"
old_test_expect_success "$req" "$1" "
test_when_finished \"rm -rf gitrepo* hgrepo*\" && $2"
}
test_expect_success 'rename' '
(
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"
) &&
cmp_hg_to_git_log_hgrepo1
'
test_expect_success !WIN 'executable bit' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
chmod 0644 alpha &&
git add alpha &&
git commit -m "add alpha" &&
chmod 0755 alpha &&
git add alpha &&
git commit -m "set executable bit" &&
chmod 0644 alpha &&
git add alpha &&
git commit -m "clear executable bit"
) &&
cmp_hg_to_git_manifest "hg manifest -v -r -1; hg manifest -v"
'
test_expect_success !WIN 'symlink' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
ln -s alpha beta &&
git add beta &&
git commit -m "add beta"
) &&
cmp_hg_to_git_manifest "hg manifest -v"
'
test_expect_success 'merge conflict 1' '
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B > afile &&
hg ci -m "A->B" -d "1 0" &&
hg up -r0 &&
echo C > afile &&
hg ci -m "A->C" -d "2 0" &&
hg merge -r1 &&
echo C > afile &&
hg resolve -m afile &&
hg ci -m "merge to C" -d "3 0"
) &&
cmp_hg_to_git_log_hgrepo1
'
test_expect_success 'merge conflict 2' '
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B > afile &&
hg ci -m "A->B" -d "1 0" &&
hg up -r0 &&
echo C > afile &&
hg ci -m "A->C" -d "2 0" &&
hg merge -r1 || true &&
echo B > afile &&
hg resolve -m afile &&
hg ci -m "merge to B" -d "3 0"
) &&
cmp_hg_to_git_log_hgrepo1
'
test_expect_success 'converged merge' '
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B > afile &&
hg ci -m "A->B" -d "1 0" &&
echo C > afile &&
hg ci -m "B->C" -d "2 0" &&
hg up -r0 &&
echo C > afile &&
hg ci -m "A->C" -d "3 0" &&
hg merge -r2 || true &&
hg ci -m "merge" -d "4 0"
) &&
cmp_hg_to_git_log_hgrepo1
'
test_expect_success 'encoding' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add älphà" &&
GIT_AUTHOR_NAME="tést èncödîng" &&
export GIT_AUTHOR_NAME &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
echo gamma > gamma &&
git add gamma &&
git commit -m "add gämmâ" &&
: TODO git config i18n.commitencoding latin-1 &&
echo delta > delta &&
git add delta &&
git commit -m "add déltà"
) &&
hg_clone gitrepo hgrepo &&
git_clone hgrepo gitrepo2 &&
HGENCODING=utf-8 hg_log hgrepo > hg-log &&
git_log gitrepo2 > git-log &&
test_cmp_expected hg-log &&
test_cmp_expected git-log
'
test_expect_success 'file removal' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
echo beta > beta &&
git add beta &&
git commit -m "add beta"
mkdir foo &&
echo blah > foo/bar &&
git add foo &&
git commit -m "add foo" &&
git rm alpha &&
git commit -m "remove alpha" &&
git rm foo/bar &&
git commit -m "remove foo/bar"
) &&
cmp_hg_to_git_manifest "hg manifest -r 3; hg manifest"
'
test_expect_success 'git tags' '
(
git init -q gitrepo &&
cd gitrepo &&
git config receive.denyCurrentBranch ignore &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git tag alpha &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
git tag -a -m "added tag beta" beta
) &&
hg_clone gitrepo hgrepo &&
hg_log hgrepo > log &&
test_cmp_expected log
'
test_expect_success 'hg author' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
) &&
(
hg_clone gitrepo hgrepo &&
cd hgrepo &&
hg co master &&
echo beta > beta &&
hg add beta &&
hg commit -u "test" -m "add beta" &&
echo gamma >> beta &&
hg commit -u "test <test@example.com> (comment)" -m "modify beta" &&
echo gamma > gamma &&
hg add gamma &&
hg commit -u "<test@example.com>" -m "add gamma" &&
echo delta > delta &&
hg add delta &&
hg commit -u "name<test@example.com>" -m "add delta" &&
echo epsilon > epsilon &&
hg add epsilon &&
hg commit -u "name <test@example.com" -m "add epsilon" &&
echo zeta > zeta &&
hg add zeta &&
hg commit -u " test " -m "add zeta" &&
echo eta > eta &&
hg add eta &&
hg commit -u "test < test@example.com >" -m "add eta" &&
echo theta > theta &&
hg add theta &&
hg commit -u "test >test@example.com>" -m "add theta" &&
echo iota > iota &&
hg add iota &&
hg commit -u "test <test <at> example <dot> com>" -m "add iota"
) &&
hg_push hgrepo gitrepo &&
hg_clone gitrepo hgrepo2 &&
cmp_hg_to_git_log
'
test_expect_success 'hg branch' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -q -m "add alpha" &&
git checkout -q -b not-master
) &&
(
hg_clone gitrepo hgrepo &&
cd hgrepo &&
hg -q co master &&
hg mv alpha beta &&
hg -q commit -m "rename alpha to beta" &&
hg branch gamma | grep -v "permanent and global" &&
hg -q commit -m "started branch gamma"
) &&
hg_push hgrepo gitrepo &&
hg_clone gitrepo hgrepo2 &&
cmp_hg_to_git_log
'
test_expect_success 'hg tags' '
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
) &&
(
hg_clone gitrepo hgrepo &&
cd hgrepo &&
hg co master &&
hg tag alpha
) &&
hg_push hgrepo gitrepo &&
hg_clone gitrepo hgrepo2 &&
(
git -C gitrepo tag -l &&
hg_log hgrepo2 &&
cat hgrepo2/.hgtags
) > output &&
test_cmp_expected output
'
test_done

View File

@@ -1,8 +1,8 @@
#!/bin/bash
CAPABILITY_PUSH=t
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
. "$TEST_DIRECTORY"/main.t
. "$(dirname "$0")"/main.t
# .. and some push mode only specific tests
@@ -270,10 +270,10 @@ test_expect_success 'push with renamed executable preserves executable bit' '
) &&
(
umask 0 &&
cd hgrepo &&
hg update &&
stat content2 >expected &&
# umask mileage might vary
grep -- -r.xr.xr.x expected
)
'

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
# Copyright (c) 2012 Felipe Contreras
#
@@ -8,8 +8,7 @@
test_description='Test remote-hg'
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
. "$TEST_DIRECTORY"/test-lib.sh
. "$(dirname "$0")"/test-lib.sh
if test "$CAPABILITY_PUSH" = "t"
then
@@ -20,18 +19,6 @@ 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 ! python -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
check () {
echo $3 > expected &&
git --git-dir=$1/.git log --format='%s' -1 $2 > actual &&
@@ -281,6 +268,41 @@ test_expect_success 'strip' '
test_cmp actual expected
'
test_expect_success 'dotfiles' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo one >.git &&
echo ONE >.GIT &&
mkdir a && echo two > a/.gitmodules &&
hg add .git .GIT a/.gitmodules &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
test_cmp gitrepo/.git_ hgrepo/.git &&
test_cmp gitrepo/.GIT_ hgrepo/.GIT &&
test_cmp gitrepo/a/.gitmodules_ hgrepo/a/.gitmodules &&
(
cd gitrepo &&
echo three >.git_ &&
echo THREE >.GIT &&
echo four >a/.gitmodules_ &&
git add .git_ .GIT_ a/.gitmodules_ &&
git commit -m one &&
git push
) &&
hg -R hgrepo update &&
test_cmp gitrepo/.git_ hgrepo/.git &&
test_cmp gitrepo/.GIT_ hgrepo/.GIT &&
test_cmp gitrepo/a/.gitmodules_ hgrepo/a/.gitmodules
'
test_expect_success 'remote push with master bookmark' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
@@ -519,7 +541,7 @@ else
test_expect_failure "$testcopyrenamedesc" "$testcopyrename"
fi
test_expect_success 'fetch special filenames' '
test_expect_success !WIN 'fetch special filenames' '
test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
LC_ALL=en_US.UTF-8
@@ -658,16 +680,27 @@ test_expect_success 'remote big push' '
(
cd gitrepo &&
check_push 1 --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
if test "$CAPABILITY_PUSH" = "t"
then
# cap push handles refs one by one
# so it will still correctly report several ok
check_push 1 --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
else
check_push 1 --all <<-\EOF
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
fi
) &&
if test "$CAPABILITY_PUSH" = "t"
@@ -681,7 +714,8 @@ test_expect_success 'remote big push' '
check_bookmark hgrepo good_bmark three &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark six
check_bookmark hgrepo new_bmark six &&
check gitrepo origin/master two
else
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
@@ -690,7 +724,8 @@ test_expect_success 'remote big push' '
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 &&
check gitrepo origin/master one
fi
'
@@ -740,12 +775,21 @@ test_expect_success 'remote big push non fast forward' '
echo five > content &&
git commit -q -a -m five &&
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
check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
else
# cap export now only report error cases
check_push 1 --all <<-\EOF
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
fi &&
git fetch &&
@@ -759,9 +803,8 @@ test_expect_success 'remote big push non fast forward' '
branches/bad_branch:non-fast-forward
EOF
else
# cap export now only report error cases
check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
@@ -803,7 +846,7 @@ test_expect_success 'remote big push force' '
fi
) &&
check_branch hgrepo default six &&
check gitrepo origin/master two &&
check_branch hgrepo good_branch eight &&
check_branch hgrepo bad_branch nine &&
check_branch hgrepo new_branch ten &&
@@ -821,16 +864,27 @@ test_expect_success 'remote big push dry-run' '
(
cd gitrepo &&
check_push 1 --dry-run --all <<-\EOF &&
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
if test "$CAPABILITY_PUSH" = "t"
then
# cap push handles refs one by one
# so it will still correctly report several ok
check_push 1 --dry-run --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
else
check_push 1 --dry-run --all <<-\EOF
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
fi &&
check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-\EOF
master
@@ -841,6 +895,7 @@ test_expect_success 'remote big push dry-run' '
EOF
) &&
check gitrepo origin/master one &&
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
@@ -885,6 +940,7 @@ test_expect_success 'remote big push force dry-run' '
fi
) &&
check gitrepo origin/master one &&
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
@@ -1093,7 +1149,7 @@ test_expect_success 'push bookmark without changesets' '
check_bookmark hgrepo feature-a two
'
test_expect_unstable 'pull tags' '
test_expect_success 'pull tags' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(

View File

@@ -1,8 +1,9 @@
#!/bin/sh
# Sharness test framework.
#
# Copyright (c) 2011-2012 Mathias Lafeldt
# Copyright (c) 2005-2012 Git project
# Copyright (c) 2005-2012 Junio C Hamano
# Copyright (c) 2019-2023 Felipe Contreras
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -17,42 +18,52 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/ .
if test -n "${ZSH_VERSION-}"
then
# shellcheck disable=SC2296
SHARNESS_SOURCE=${(%):-%x}
emulate sh -o POSIX_ARGZERO
else
# shellcheck disable=SC3028
SHARNESS_SOURCE=${BASH_SOURCE-$0}
fi
# Public: Current version of Sharness.
SHARNESS_VERSION="1.1.0"
SHARNESS_VERSION="1.2.1"
export SHARNESS_VERSION
# Public: The file extension for tests. By default, it is set to "t".
: "${SHARNESS_TEST_EXTENSION:=t}"
# Public: The file extension for tests. By default, it is set to "t".
export SHARNESS_TEST_EXTENSION
: "${SHARNESS_TEST_DIRECTORY:=$(dirname "$0")}"
# 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
# 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
: "${SHARNESS_TEST_SRCDIR:=$(cd "$(dirname "$SHARNESS_SOURCE")" && pwd)}"
# Public: Source directory of test code and sharness library.
# This directory may be different from the directory in which tests are
# being run.
export SHARNESS_TEST_SRCDIR
: "${SHARNESS_TEST_OUTDIR:=$SHARNESS_TEST_DIRECTORY}"
# Public: Directory where the output of the tests should be stored (i.e.
# trash directories).
export SHARNESS_TEST_OUTDIR
# Reset TERM to original terminal if found, otherwise save original TERM
[ "x" = "x$SHARNESS_ORIG_TERM" ] &&
[ -z "$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}"
: "${SHELL_PATH:=/bin/sh}"
export SHELL_PATH
# if --tee was passed, write the output not only to the terminal, but
@@ -62,8 +73,8 @@ 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")"
mkdir -p "$SHARNESS_TEST_OUTDIR/test-results"
BASE="$SHARNESS_TEST_OUTDIR/test-results/$(basename "$0" ".$SHARNESS_TEST_EXTENSION")"
# Make this filename available to the sub-process in case it is using
# --verbose-log.
@@ -128,6 +139,9 @@ while test "$#" -ne 0; do
--root=*)
root=$(expr "z$1" : 'z[^=]*=\(.*\)')
shift ;;
-x)
trace=t
shift ;;
--verbose-log)
verbose_log=t
shift ;;
@@ -177,6 +191,40 @@ else
}
fi
: "${test_untraceable:=}"
# Public: When set to a non-empty value, the current test will not be
# traced, unless it's run with a Bash version supporting
# BASH_XTRACEFD, i.e. v4.1 or later.
export test_untraceable
if test -n "$trace" && test -n "$test_untraceable"
then
# '-x' tracing requested, but this test script can't be reliably
# traced, unless it is run with a Bash version supporting
# BASH_XTRACEFD (introduced in Bash v4.1).
#
# Perform this version check _after_ the test script was
# potentially re-executed with $TEST_SHELL_PATH for '--tee' or
# '--verbose-log', so the right shell is checked and the
# warning is issued only once.
if test -n "$BASH_VERSION" && eval '
test ${BASH_VERSINFO[0]} -gt 4 || {
test ${BASH_VERSINFO[0]} -eq 4 &&
test ${BASH_VERSINFO[1]} -ge 1
}
'
then
: Executed by a Bash version supporting BASH_XTRACEFD. Good.
else
echo >&2 "warning: ignoring -x; '$0' is untraceable without BASH_XTRACEFD"
trace=
fi
fi
if test -n "$trace" && test -z "$verbose_log"
then
verbose=t
fi
TERM=dumb
export TERM
@@ -209,11 +257,22 @@ else
exec 4>/dev/null 3>/dev/null
fi
test_failure=0
test_count=0
test_fixed=0
test_broken=0
test_success=0
# Send any "-x" output directly to stderr to avoid polluting tests
# which capture stderr. We can do this unconditionally since it
# has no effect if tracing isn't turned on.
#
# Note that this sets up the trace fd as soon as we assign the variable, so it
# must come after the creation of descriptor 4 above. Likewise, we must never
# unset this, as it has the side effect of closing descriptor 4, which we
# use to show verbose tests to the user.
#
# Note also that we don't need or want to export it. The tracing is local to
# this shell, and we would not want to influence any shells we exec.
BASH_XTRACEFD=4
# Public: The current test number, starting at 0.
SHARNESS_TEST_NB=0
export SHARNESS_TEST_NB
die() {
code=$?
@@ -228,105 +287,30 @@ die() {
EXIT_OK=
trap 'die' EXIT
# Public: Define that a test prerequisite is available.
#
# The prerequisite can later be checked explicitly using test_have_prereq or
# implicitly by specifying the prerequisite name in calls to test_expect_success
# or test_expect_failure.
#
# $1 - Name of prerequisite (a simple word, in all capital letters by convention)
#
# Examples
#
# # Set PYTHON prerequisite if interpreter is available.
# command -v python >/dev/null && test_set_prereq PYTHON
#
# # Set prerequisite depending on some variable.
# test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
#
# Returns nothing.
test_set_prereq() {
satisfied_prereq="$satisfied_prereq$1 "
}
satisfied_prereq=" "
test_prereq=
missing_prereq=
# Public: Check if one or more test prerequisites are defined.
#
# The prerequisites must have previously been set with test_set_prereq.
# The most common use of this is to skip all the tests if some essential
# prerequisite is missing.
#
# $1 - Comma-separated list of test prerequisites.
#
# Examples
#
# # Skip all remaining tests if prerequisite is not set.
# if ! test_have_prereq PERL; then
# skip_all='skipping perl interface tests, perl not available'
# test_done
# fi
#
# Returns 0 if all prerequisites are defined or 1 otherwise.
test_have_prereq() {
# prerequisites can be concatenated with ','
save_IFS=$IFS
IFS=,
set -- $@
IFS=$save_IFS
test_failure=0
test_fixed=0
test_broken=0
test_success=0
total_prereq=0
ok_prereq=0
missing_prereq=
for prerequisite; do
case "$prerequisite" in
!*)
negative_prereq=t
prerequisite=${prerequisite#!}
;;
*)
negative_prereq=
esac
total_prereq=$((total_prereq + 1))
case "$satisfied_prereq" in
*" $prerequisite "*)
satisfied_this_prereq=t
;;
*)
satisfied_this_prereq=
esac
case "$satisfied_this_prereq,$negative_prereq" in
t,|,t)
ok_prereq=$((ok_prereq + 1))
;;
*)
# Keep a list of missing prerequisites; restore
# the negative marker if necessary.
prerequisite=${negative_prereq:+!}$prerequisite
if test -z "$missing_prereq"; then
missing_prereq=$prerequisite
else
missing_prereq="$prerequisite,$missing_prereq"
fi
esac
done
test $total_prereq = $ok_prereq
}
if test -e "$SHARNESS_TEST_SRCDIR/lib-sharness/functions.sh"
then
. "$SHARNESS_TEST_SRCDIR/lib-sharness/functions.sh"
fi
# You are not expected to call test_ok_ and test_failure_ directly, use
# the text_expect_* functions instead.
test_ok_() {
test_success=$((test_success + 1))
say_color "" "ok $test_count - $*"
say_color "" "ok $SHARNESS_TEST_NB - $*"
}
test_failure_() {
test_failure=$((test_failure + 1))
say_color error "not ok $test_count - $1"
say_color error "not ok $SHARNESS_TEST_NB - $1"
shift
echo "$@" | sed -e 's/^/# /'
test "$immediate" = "" || { EXIT_OK=t; exit 1; }
@@ -334,53 +318,76 @@ test_failure_() {
test_known_broken_ok_() {
test_fixed=$((test_fixed + 1))
say_color error "ok $test_count - $* # TODO known breakage vanished"
say_color error "ok $SHARNESS_TEST_NB - $* # TODO known breakage vanished"
}
test_known_broken_failure_() {
test_broken=$((test_broken + 1))
say_color warn "not ok $test_count - $* # TODO known breakage"
say_color warn "not ok $SHARNESS_TEST_NB - $* # TODO known breakage"
}
# Public: Execute commands in debug mode.
#
# Takes a single argument and evaluates it only when the test script is started
# with --debug. This is primarily meant for use during the development of test
# scripts.
#
# $1 - Commands to be executed.
#
# Examples
#
# test_debug "cat some_log_file"
#
# Returns the exit code of the last command executed in debug mode or 0
# otherwise.
test_debug() {
test "$debug" = "" || eval "$1"
want_trace () {
test "$trace" = t && {
test "$verbose" = t || test "$verbose_log" = t
}
}
# 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"
# This is a separate function because some tests use
# "return" to end a test_expect_success block early
# (and we want to make sure we run any cleanup like
# "set +x").
test_eval_inner_ () {
# Do not add anything extra (including LF) after '$*'
eval "
want_trace && set -x
$*"
}
test_eval_x_ () {
# If "-x" tracing is in effect, then we want to avoid polluting stderr
# with non-test commands. But once in "set -x" mode, we cannot prevent
# the shell from printing the "set +x" to turn it off (nor the saving
# of $? before that). But we can make sure that the output goes to
# /dev/null.
#
# There are a few subtleties here:
#
# - we have to redirect descriptor 4 in addition to 2, to cover
# BASH_XTRACEFD
#
# - the actual eval has to come before the redirection block (since
# it needs to see descriptor 4 to set up its stderr)
#
# - likewise, any error message we print must be outside the block to
# access descriptor 4
#
# - checking $? has to come immediately after the eval, but it must
# be _inside_ the block to avoid polluting the "set -x" output
#
test_eval_inner_ "$@" </dev/null >&3 2>&4
{
test_eval_ret_=$?
if want_trace
then
set +x
fi
} 2>/dev/null 4>&2
if test "$test_eval_ret_" != 0 && want_trace
then
say_color error >&4 "error: last command exited with \$?=$test_eval_ret_"
fi
return $test_eval_ret_
}
test_eval_() {
# This is a separate function because some tests use
# "return" to end a test_expect_success block early.
case ",$test_prereq," in
*,INTERACTIVE,*)
eval "$*"
;;
*)
eval </dev/null >&3 2>&4 "$*"
test_eval_x_ "$@"
;;
esac
}
@@ -392,13 +399,22 @@ test_run_() {
eval_ret=$?
if test "$chain_lint" = "t"; then
# turn off tracing for this test-eval, as it simply creates
# confusing noise in the "-x" output
trace_tmp=$trace
trace=
# 117 is magic because it is unlikely to match the exit
# code of other programs
test_eval_ "(exit 117) && $1"
if test "$?" != 117; then
error "bug in the test script: broken &&-chain: $1"
fi
trace=$trace_tmp
fi
if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then
if test -z "$immediate" || test $eval_ret = 0 ||
test -n "$expecting_failure" && test "$test_cleanup" != ":"
then
test_eval_ "$test_cleanup"
fi
if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
@@ -408,10 +424,11 @@ test_run_() {
}
test_skip_() {
test_count=$((test_count + 1))
SHARNESS_TEST_NB=$((SHARNESS_TEST_NB + 1))
to_skip=
for skp in $SKIP_TESTS; do
case $this_test.$test_count in
# shellcheck disable=SC2254
case $this_test.$SHARNESS_TEST_NB in
$skp)
to_skip=t
break
@@ -428,7 +445,7 @@ test_skip_() {
fi
say_color skip >&3 "skipping test: $*"
say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
say_color skip "ok $SHARNESS_TEST_NB # skip $1 (missing $missing_prereq${of_prereq})"
: true
;;
*)
@@ -437,6 +454,13 @@ test_skip_() {
esac
}
remove_trash_() {
test -d "$remove_trash" && (
cd "$(dirname "$remove_trash")" &&
rm -rf "$(basename "$remove_trash")"
)
}
# Public: Run test commands and expect them to succeed.
#
# When the test passed, an "ok" message is printed and the number of successful
@@ -563,246 +587,6 @@ test_expect_unstable() {
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
# segfault, test_must_fail diagnoses it as an error, while "! <command>" would
# mistakenly be treated as just another expected failure.
#
# This is one of the prefix functions to be used inside test_expect_success or
# test_expect_failure.
#
# $1.. - Command to be executed.
#
# Examples
#
# test_expect_success 'complain and die' '
# do something &&
# do something else &&
# test_must_fail git checkout ../outerspace
# '
#
# Returns 1 if the command succeeded (exit code 0).
# Returns 1 if the command died by signal (exit codes 130-192)
# Returns 1 if the command could not be found (exit code 127).
# Returns 0 otherwise.
test_must_fail() {
"$@"
exit_code=$?
if test $exit_code = 0; then
echo >&2 "test_must_fail: command succeeded: $*"
return 1
elif test $exit_code -gt 129 -a $exit_code -le 192; then
echo >&2 "test_must_fail: died by signal: $*"
return 1
elif test $exit_code = 127; then
echo >&2 "test_must_fail: command not found: $*"
return 1
fi
return 0
}
# Public: Run command and ensure that it succeeds or fails in a controlled way.
#
# Similar to test_must_fail, but tolerates success too. Use it instead of
# "<command> || :" to catch failures caused by a segfault, for instance.
#
# This is one of the prefix functions to be used inside test_expect_success or
# test_expect_failure.
#
# $1.. - Command to be executed.
#
# Examples
#
# test_expect_success 'some command works without configuration' '
# test_might_fail git config --unset all.configuration &&
# do something
# '
#
# Returns 1 if the command died by signal (exit codes 130-192)
# Returns 1 if the command could not be found (exit code 127).
# Returns 0 otherwise.
test_might_fail() {
"$@"
exit_code=$?
if test $exit_code -gt 129 -a $exit_code -le 192; then
echo >&2 "test_might_fail: died by signal: $*"
return 1
elif test $exit_code = 127; then
echo >&2 "test_might_fail: command not found: $*"
return 1
fi
return 0
}
# Public: Run command and ensure it exits with a given exit code.
#
# This is one of the prefix functions to be used inside test_expect_success or
# test_expect_failure.
#
# $1 - Expected exit code.
# $2.. - Command to be executed.
#
# Examples
#
# test_expect_success 'Merge with d/f conflicts' '
# test_expect_code 1 git merge "merge msg" B master
# '
#
# Returns 0 if the expected exit code is returned or 1 otherwise.
test_expect_code() {
want_code=$1
shift
"$@"
exit_code=$?
if test "$exit_code" = "$want_code"; then
return 0
fi
echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
return 1
}
# Public: Compare two files to see if expected output matches actual output.
#
# 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.
#
# This is one of the prefix functions to be used inside test_expect_success or
# test_expect_failure.
#
# $1 - Path to file with expected output.
# $2 - Path to file with actual output.
#
# Examples
#
# test_expect_success 'foo works' '
# echo expected >expected &&
# foo >actual &&
# test_cmp expected actual
# '
#
# Returns the exit code of the command set by TEST_CMP.
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.
#
# If some cleanup command fails, the test will not pass. With --immediate, no
# cleanup is done to help diagnose what went wrong.
#
# This is one of the prefix functions to be used inside test_expect_success or
# test_expect_failure.
#
# $1.. - Commands to prepend to the list of cleanup commands.
#
# Examples
#
# test_expect_success 'test core.capslock' '
# git config core.capslock true &&
# test_when_finished "git config --unset core.capslock" &&
# do_something
# '
#
# Returns the exit code of the last cleanup command executed.
test_when_finished() {
test_cleanup="{ $*
} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
}
# Public: Schedule cleanup commands to be run unconditionally when all tests
# have run.
#
# This can be used to clean up things like test databases. It is not needed to
# clean up temporary files, as test_done already does that.
#
# Examples:
#
# cleanup mysql -e "DROP DATABASE mytest"
#
# Returns the exit code of the last cleanup command executed.
final_cleanup=
cleanup() {
final_cleanup="{ $*
} && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup"
}
# Public: Summarize test results and exit with an appropriate error code.
#
# Must be called at the end of each test script.
@@ -823,16 +607,17 @@ cleanup() {
# fi
#
# Returns 0 if all tests passed or 1 if there was a failure.
# shellcheck disable=SC2154,SC2034
test_done() {
EXIT_OK=t
if test -z "$HARNESS_ACTIVE"; then
test_results_dir="$SHARNESS_TEST_OUTPUT_DIRECTORY/test-results"
test_results_dir="$SHARNESS_TEST_OUTDIR/test-results"
mkdir -p "$test_results_dir"
test_results_path="$test_results_dir/$this_test.$$.counts"
cat >>"$test_results_path" <<-EOF
total $test_count
total $SHARNESS_TEST_NB
success $test_success
fixed $test_fixed
broken $test_broken
@@ -848,54 +633,43 @@ 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=$((SHARNESS_TEST_NB - test_broken - test_fixed))
msg="remaining $test_remaining test(s)"
else
test_remaining=$test_count
msg="$test_count test(s)"
test_remaining=$SHARNESS_TEST_NB
msg="$SHARNESS_TEST_NB test(s)"
fi
case "$test_failure" in
0)
# Maybe print SKIP message
if test -n "$skip_all" && test $test_count -gt 0; then
error "Can't use skip_all after running some tests"
fi
[ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
if test $test_remaining -gt 0; then
check_skip_all_
if test "$test_remaining" -gt 0; then
say_color pass "# passed all $msg"
fi
say "1..$test_count$skip_all"
say "1..$SHARNESS_TEST_NB$skip_all"
test_eval_ "$final_cleanup"
test -d "$remove_trash" &&
cd "$(dirname "$remove_trash")" &&
rm -rf "$(basename "$remove_trash")"
remove_trash_
exit 0 ;;
*)
say_color error "# failed $test_failure among $msg"
say "1..$test_count"
say "1..$SHARNESS_TEST_NB"
exit 1 ;;
esac
}
# 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
: "${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}"
# 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/.."}"
export SHARNESS_BUILD_DIRECTORY
PATH="$SHARNESS_BUILD_DIRECTORY:$PATH"
export PATH SHARNESS_BUILD_DIRECTORY
export PATH
# Public: Path to test script currently executed.
SHARNESS_TEST_FILE="$0"
@@ -906,7 +680,7 @@ SHARNESS_TRASH_DIRECTORY="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SH
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" ;;
*) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_OUTDIR/$SHARNESS_TRASH_DIRECTORY" ;;
esac
test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY"
rm -rf "$SHARNESS_TRASH_DIRECTORY" || {
@@ -917,11 +691,11 @@ rm -rf "$SHARNESS_TRASH_DIRECTORY" || {
#
# Load any extensions in $srcdir/sharness.d/*.sh
# Load any extensions in $testdir/sharness.d/*.sh
#
if test -d "${SHARNESS_TEST_SRCDIR}/sharness.d"
if test -d "${SHARNESS_TEST_DIRECTORY}/sharness.d"
then
for file in "${SHARNESS_TEST_SRCDIR}"/sharness.d/*.sh
for file in "${SHARNESS_TEST_DIRECTORY}"/sharness.d/*.sh
do
# Ensure glob was not an empty match:
test -e "${file}" || break
@@ -930,6 +704,7 @@ then
then
echo >&5 "sharness: loading extensions from ${file}"
fi
# shellcheck disable=SC1090
. "${file}"
if test $? != 0
then
@@ -946,14 +721,28 @@ export SHARNESS_TRASH_DIRECTORY
HOME="$SHARNESS_TRASH_DIRECTORY"
export HOME
# shellcheck disable=SC3028
if [ "$OSTYPE" = msys ]; then
USERPROFILE="$SHARNESS_TRASH_DIRECTORY"
export USERPROFILE
fi
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 "$SHARNESS_TRASH_DIRECTORY" || exit 1
check_skip_all_() {
if test -n "$skip_all" && test $SHARNESS_TEST_NB -gt 0; then
error "Can't use skip_all after running some tests"
fi
[ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
}
this_test=${SHARNESS_TEST_FILE##*/}
this_test=${this_test%.$SHARNESS_TEST_EXTENSION}
this_test=${this_test%".$SHARNESS_TEST_EXTENSION"}
for skp in $SKIP_TESTS; do
# shellcheck disable=SC2254
case "$this_test" in
$skp)
say_color info >&3 "skipping test $this_test altogether"

136
t/test-lib.sh Normal file
View File

@@ -0,0 +1,136 @@
#!/bin/bash
: "${SHARNESS_TEST_SRCDIR:=$(cd "$(dirname "${BASH_SOURCE-$0}")" && pwd)}"
if [ -z "$SHARNESS" ] ; then
for d in \
"$SHARNESS_TEST_SRCDIR" \
"$HOME/share/sharness" \
"/usr/local/share/sharness" \
"/usr/share/sharness"
do
f="$d/sharness.sh"
if [ -f "$f" ] ; then
SHARNESS="$f"
fi
done
fi
if [ -z "$SHARNESS" ] || [ ! -f "$SHARNESS" ] ; then
echo "sharness.sh not found" >&2
exit 1
fi
# Prevent sharness from adding the source directory to PATH
# since the scripts use unversioned python for their shebang
# but tests should run under the python with mercurial support
# so create an empty directory and strip it from PATH afterwards
SHARNESS_BUILD_DIRECTORY="$(mktemp -d)"
. "$SHARNESS"
export PATH="${PATH#*:}"
rmdir "$SHARNESS_BUILD_DIRECTORY"
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
# maintain backwards compatible default
# (as used in remote helper)
git config --global init.defaultBranch master
git config --global protocol.file.allow always
unset XDG_CONFIG_HOME
test_set_prereq() {
satisfied_prereq="$satisfied_prereq$1 "
}
satisfied_prereq=" "
case "$(uname -s)" in
MSYS*|MINGW*)
test_set_prereq WIN
export TEST_CMP='diff --strip-trailing-cr -u'
;;
esac
test_cmp() {
${TEST_CMP:-diff -u} "$@"
}
test_when_finished() {
test_cleanup="{ $*
} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
}
test_expect_code() {
want_code=$1
shift
"$@"
exit_code=$?
if test "$exit_code" = "$want_code"; then
return 0
fi
echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
return 1
}
test_have_prereq() {
prerequisite=$1
case "$prerequisite" in
!*)
negative_prereq=t
prerequisite=${prerequisite#!}
;;
*)
negative_prereq=
esac
case "$satisfied_prereq" in
*" $prerequisite "*)
satisfied_this_prereq=t
;;
*)
satisfied_this_prereq=
esac
case "$satisfied_this_prereq,$negative_prereq" in
t,|,t)
return 0
;;
esac
return 1
}
if [ -z "$TEST_INSTALLED_SCRIPTS" ] ; then
if [ -n "$PYTHON" ] && "$PYTHON" -c 'import mercurial' 2> /dev/null ; then
: Use chosen Python version
elif python3 -c 'import mercurial' 2> /dev/null ; then
PYTHON=python3
elif python2 -c 'import mercurial' 2> /dev/null ; then
PYTHON=python2
elif python -c 'import mercurial' 2> /dev/null ; then
PYTHON=python
fi
if [ -n "$PYTHON" ] ; then
test_set_prereq PYTHON
# Change shebang on a copy of scripts to chosen Python version
TEST_BIN="$SHARNESS_TRASH_DIRECTORY/bin"
mkdir -p "$TEST_BIN"
for s in git-remote-hg git-hg-helper ; do
printf "%s\n" "#!/usr/bin/env $PYTHON" > "$TEST_BIN/$s"
tail -n +2 "$SHARNESS_TEST_DIRECTORY/../$s" >> "$TEST_BIN/$s"
chmod u+x "$TEST_BIN/$s"
done
export PATH="$TEST_BIN${PATH:+:$PATH}"
unset TEST_BIN
fi
else
# The build/install process ensures Python is available
test_set_prereq PYTHON
fi

View File

@@ -1,574 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2012 Felipe Contreras
#
# Base commands from hg-git tests:
# https://bitbucket.org/durin42/hg-git/src
#
test_description='Test remote-hg output compared to hg-git'
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
if python -c 'import hggit' > /dev/null 2>&1
then
hggit=hggit
elif python -c 'import hgext.git' > /dev/null 2>&1
then
hggit=hgext.git
else
skip_all='skipping remote-hg tests; hg-git not available'
test_done
fi
# clone to a git repo with git
git_clone_git () {
git clone -q "hg::$1" $2 &&
(cd $2 && git checkout master && git branch -D default)
}
# clone to an hg repo with git
hg_clone_git () {
(
hg init $2 &&
hg -R $2 bookmark -i master &&
cd $1 &&
git push -q "hg::../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
) &&
(cd $2 && hg -q update)
}
# clone to a git repo with hg
git_clone_hg () {
(
git init -q $2 &&
cd $1 &&
hg bookmark -i -f -r tip master &&
hg -q push -r master ../$2 || true
)
}
# clone to an hg repo with hg
hg_clone_hg () {
hg -q clone $1 $2
}
# push an hg repo with git
hg_push_git () {
(
cd $2
git checkout -q -b tmp &&
git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git branch -D default &&
git checkout -q @{-1} &&
git branch -q -D tmp 2> /dev/null || true
)
}
# push an hg git repo with hg
hg_push_hg () {
(
cd $1 &&
hg -q push ../$2 || true
)
}
hg_log () {
hg -R $1 log --graph --debug > log &&
grep -v 'tag: *default/' log
}
git_log () {
git --git-dir=$1/.git fast-export --branches
}
setup () {
cat > "$HOME"/.hgrc <<-EOF &&
[ui]
username = A U Thor <author@example.com>
[defaults]
backout = -d "0 0"
commit = -d "0 0"
debugrawcommit = -d "0 0"
tag = -d "0 0"
[extensions]
$hggit =
graphlog =
[git]
debugextrainmessage = 1
EOF
git config --global receive.denycurrentbranch warn
git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches false
git config --global remote-hg.shared-marks false
HGEDITOR=true
HGMERGE=true
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
export HGEDITOR HGMERGE GIT_AUTHOR_DATE GIT_COMMITTER_DATE
}
setup
test_expect_success 'rename' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo alpha > alpha &&
hg add alpha &&
hg commit -m "add alpha" &&
hg mv alpha beta &&
hg commit -m "rename alpha to beta"
) &&
for x in hg git
do
git_clone_$x hgrepo1 gitrepo-$x &&
hg_clone_$x gitrepo-$x hgrepo2-$x &&
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
test_cmp git-log-hg git-log-git
'
test_expect_success 'executable bit' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
chmod 0644 alpha &&
git add alpha &&
git commit -m "add alpha" &&
chmod 0755 alpha &&
git add alpha &&
git commit -m "set executable bit" &&
chmod 0644 alpha &&
git add alpha &&
git commit -m "clear executable bit"
) &&
for x in hg git
do
(
hg_clone_$x gitrepo hgrepo-$x &&
cd hgrepo-$x &&
hg_log . &&
hg manifest -r 1 -v &&
hg manifest -v
) > "output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
git_log gitrepo2-$x > "log-$x"
done &&
test_cmp output-hg output-git &&
test_cmp log-hg log-git
'
test_expect_success 'symlink' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
ln -s alpha beta &&
git add beta &&
git commit -m "add beta"
) &&
for x in hg git
do
(
hg_clone_$x gitrepo hgrepo-$x &&
cd hgrepo-$x &&
hg_log . &&
hg manifest -v
) > "output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
git_log gitrepo2-$x > "log-$x"
done &&
test_cmp output-hg output-git &&
test_cmp log-hg log-git
'
test_expect_success 'merge conflict 1' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B > afile &&
hg ci -m "A->B" &&
hg up -r0 &&
echo C > afile &&
hg ci -m "A->C" &&
hg merge -r1 &&
echo C > afile &&
hg resolve -m afile &&
hg ci -m "merge to C"
) &&
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 'merge conflict 2' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B > afile &&
hg ci -m "A->B" &&
hg up -r0 &&
echo C > afile &&
hg ci -m "A->C" &&
hg merge -r1 || true &&
echo B > afile &&
hg resolve -m afile &&
hg ci -m "merge to B"
) &&
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 'converged merge' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo A > afile &&
hg add afile &&
hg ci -m "origin" &&
echo B > afile &&
hg ci -m "A->B" &&
echo C > afile &&
hg ci -m "B->C" &&
hg up -r0 &&
echo C > afile &&
hg ci -m "A->C" &&
hg merge -r2 || true &&
hg ci -m "merge"
) &&
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 'encoding' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add älphà" &&
GIT_AUTHOR_NAME="tést èncödîng" &&
export GIT_AUTHOR_NAME &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
echo gamma > gamma &&
git add gamma &&
git commit -m "add gämmâ" &&
: TODO git config i18n.commitencoding latin-1 &&
echo delta > delta &&
git add delta &&
git commit -m "add déltà"
) &&
for x in hg git
do
hg_clone_$x gitrepo hgrepo-$x &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
HGENCODING=utf-8 hg_log hgrepo-$x > "hg-log-$x" &&
git_log gitrepo2-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
test_cmp git-log-hg git-log-git
'
test_expect_success 'file removal' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
echo beta > beta &&
git add beta &&
git commit -m "add beta"
mkdir foo &&
echo blah > foo/bar &&
git add foo &&
git commit -m "add foo" &&
git rm alpha &&
git commit -m "remove alpha" &&
git rm foo/bar &&
git commit -m "remove foo/bar"
) &&
for x in hg git
do
(
hg_clone_$x gitrepo hgrepo-$x &&
cd hgrepo-$x &&
hg_log . &&
hg manifest -r 3 &&
hg manifest
) > "output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
git_log gitrepo2-$x > "log-$x"
done &&
test_cmp output-hg output-git &&
test_cmp log-hg log-git
'
test_expect_success 'git tags' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
cd gitrepo &&
git config receive.denyCurrentBranch ignore &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git tag alpha &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
git tag -a -m "added tag beta" beta
) &&
for x in hg git
do
hg_clone_$x gitrepo hgrepo-$x &&
hg_log hgrepo-$x > "log-$x"
done &&
test_cmp log-hg log-git
'
test_expect_success 'hg author' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
for x in hg git
do
(
git init -q gitrepo-$x &&
cd gitrepo-$x &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
) &&
(
hg_clone_$x gitrepo-$x hgrepo-$x &&
cd hgrepo-$x &&
hg co master &&
echo beta > beta &&
hg add beta &&
hg commit -u "test" -m "add beta" &&
echo gamma >> beta &&
hg commit -u "test <test@example.com> (comment)" -m "modify beta" &&
echo gamma > gamma &&
hg add gamma &&
hg commit -u "<test@example.com>" -m "add gamma" &&
echo delta > delta &&
hg add delta &&
hg commit -u "name<test@example.com>" -m "add delta" &&
echo epsilon > epsilon &&
hg add epsilon &&
hg commit -u "name <test@example.com" -m "add epsilon" &&
echo zeta > zeta &&
hg add zeta &&
hg commit -u " test " -m "add zeta" &&
echo eta > eta &&
hg add eta &&
hg commit -u "test < test@example.com >" -m "add eta" &&
echo theta > theta &&
hg add theta &&
hg commit -u "test >test@example.com>" -m "add theta" &&
echo iota > iota &&
hg add iota &&
hg commit -u "test <test <at> example <dot> com>" -m "add iota"
) &&
hg_push_$x hgrepo-$x gitrepo-$x &&
hg_clone_$x gitrepo-$x hgrepo2-$x &&
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
test_cmp git-log-hg git-log-git
'
test_expect_success 'hg branch' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
for x in hg git
do
(
git init -q gitrepo-$x &&
cd gitrepo-$x &&
echo alpha > alpha &&
git add alpha &&
git commit -q -m "add alpha" &&
git checkout -q -b not-master
) &&
(
hg_clone_$x gitrepo-$x hgrepo-$x &&
cd hgrepo-$x &&
hg -q co master &&
hg mv alpha beta &&
hg -q commit -m "rename alpha to beta" &&
hg branch gamma | grep -v "permanent and global" &&
hg -q commit -m "started branch gamma"
) &&
hg_push_$x hgrepo-$x gitrepo-$x &&
hg_clone_$x gitrepo-$x hgrepo2-$x &&
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
test_cmp git-log-hg git-log-git
'
test_expect_success 'hg tags' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
for x in hg git
do
(
git init -q gitrepo-$x &&
cd gitrepo-$x &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
) &&
(
hg_clone_$x gitrepo-$x hgrepo-$x &&
cd hgrepo-$x &&
hg co master &&
hg tag alpha
) &&
hg_push_$x hgrepo-$x gitrepo-$x &&
hg_clone_$x gitrepo-$x hgrepo2-$x &&
(
git --git-dir=gitrepo-$x/.git tag -l &&
hg_log hgrepo2-$x &&
cat hgrepo2-$x/.hgtags
) > "output-$x"
done &&
test_cmp output-hg output-git
'
test_done

View File

@@ -1,12 +0,0 @@
#!/bin/sh
. ./sharness.sh
test_set_prereq PYTHON
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME

View File

@@ -1,30 +1,30 @@
#!/usr/bin/env ruby
#
# Copyright (c) 2019 Felipe Contreras
# Copyright (c) 2019-2023 Felipe Contreras
#
# This script runs the tests for all versions of the components:
# hg, hggit and dulwich
# This script runs the tests for all versions of hg.
#
# You can run it without arguments, in which case it reads the file
# 'versions.txt' and executes all those checks.
# You can run it without arguments, in which case it runs the tests for all
# versions in `versions.txt`.
#
# Or you can pass the versions to check manually, like:
# Or you can specify a single version manually:
#
# ./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
# ./check-versions 6.3
#
require 'fileutils'
require 'tmpdir'
$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"
$builddir = Dir.mktmpdir("git-remote-hg-build-")
$testoutdir = Dir.mktmpdir("git-remote-hg-tests-")
at_exit {
FileUtils.remove_entry($builddir)
FileUtils.remove_entry($testoutdir)
}
QUIET, LOW, HIGH = (1..3).to_a
$verbosity = LOW
@@ -56,46 +56,26 @@ def check_version(a, b)
(a <=> b) >= 0
end
# Component {{{1
# Hg {{{1
class Component
class Hg
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]
def initialize
@url = 'https://www.mercurial-scm.org/repo/hg'
end
def dir
"#{$workdir}/#{@id}"
end
def get_version(version)
return @kind == :hg ? 'tip' : '@' if version == '@'
@version_format ? @version_format % version : version
"#{$workdir}/hg"
end
def clone
run_cmd [@tool, 'clone', '-q', @url, dir]
run_cmd %w[hg 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
run_cmd %w[hg update --clean -q] << version
checkout_fix(version)
end
end
@@ -106,6 +86,18 @@ class Component
end
end
def checkout_fix(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
end
# Functions {{{1
@@ -115,16 +107,14 @@ def setup
FileUtils.mkdir_p(dirs.map { |e| "#{$builddir}/#{e}" })
FileUtils.mkdir_p($workdir)
$components.each do |id, component|
next if File.exists?(component.dir)
return if File.exist?($hg.dir)
if $verbosity < HIGH
puts "Cloning #{component.id}"
else
title "Cloning #{component.id}"
end
component.clone
if $verbosity < HIGH
puts "Cloning hg"
else
title "Cloning hg"
end
$hg.clone
end
def test_env(paths: nil)
@@ -157,31 +147,14 @@ def run_tests(tests)
end
end
def versions_to_s(versions)
versions.map { |k,v| "#{k}:#{v}" }.join(' ')
end
def check(version)
section version
def versions_from_args(args)
args.map { |e| k, v = e.split(':'); [k.to_sym, v] }.to_h
end
title "Checking out hg #{version}"
$hg.checkout(version)
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
title "Building hg"
$hg.build
paths = {
PATH: "#{$builddir}/bin",
@@ -194,103 +167,31 @@ def check(versions)
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
$hg = Hg.new()
# Main {{{1
setup
$checks = []
$results = []
$versions = versions_from_args(ARGV)
$version = ARGV.first
$checks = File.readlines(__dir__ + '/versions.txt', chomp: true)
$results = File.open(__dir__ + '/results.txt', 'w')
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
if $version
$verbosity = HIGH
exit check(versions) ? 0 : 1
exit check($version) ? 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)
$checks.each do |version|
result = check(version)
failures += 1 unless result
$results << [versions, result]
$results.puts '%s # %s' % [version, result ? 'OK' : 'FAIL']
end
exit 1 unless failures == 0

View File

@@ -1,22 +0,0 @@
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

View File

@@ -1,33 +1,47 @@
# 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
2.4
2.5
2.6
2.7
2.8
2.9
3.0
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
4.0
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
5.0
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
6.0
6.1
6.2
6.3
6.4
6.5
6.6
6.7
6.8
6.9
7.0