gitifyhg
gitifyhg copied to clipboard
Branches do not properly track
I am not sure if the following is a bug, or a missing feature, or perhaps even intentional; to me it feels like the first, but, well.. Here ya go: The following script fails with an error:
#!/bin/sh -ex
NAME=named-branches
rm -rf $NAME
mkdir $NAME
cd $NAME
mkdir repo_orig
cd repo_orig
hg init
echo a > a
hg add a
hg commit -m a
hg branch x
echo b > b
hg add b
hg commit -m b
hg update default
echo A > a
hg commit -m A a
cd ..
git clone gitifyhg::`pwd`/repo_orig repo_clone
cd repo_clone
#git co -b branches/x origin/branches/x # <-- this works
git co -b x origin/branches/x # <-- this does not work
echo B2 > b
git commit -m B2-x b
git push
The error I get is this:
Traceback (most recent call last):
File "/sw/bin/git-remote-gitifyhg", line 9, in <module>
load_entry_point('gitifyhg==0.6.3', 'console_scripts', 'git-remote-gitifyhg')()
File "/sw/lib/python2.7/site-packages/gitifyhg-0.6.3-py2.7.egg/gitifyhg.py", line 701, in main
HGRemote(*[x.decode('utf-8') for x in sys.argv[1:3]]).process()
File "/sw/lib/python2.7/site-packages/gitifyhg-0.6.3-py2.7.egg/gitifyhg.py", line 277, in process
getattr(self, 'do_%s' % command)(parser)
File "/sw/lib/python2.7/site-packages/gitifyhg-0.6.3-py2.7.egg/gitifyhg.py", line 351, in do_export
GitExporter(self, parser).process()
File "/sw/lib/python2.7/site-packages/gitifyhg-0.6.3-py2.7.egg/gitifyhg.py", line 530, in process
getattr(self, 'do_%s' % command)()
File "/sw/lib/python2.7/site-packages/gitifyhg-0.6.3-py2.7.egg/gitifyhg.py", line 602, in do_commit
tip = listbookmarks(self.repo)[git_to_hg_spaces(bookmark)]
KeyError: 'x'
The problem to me seems that gitifyhg looks at the local branch name. But what it really should do is look at the remote merge branch. I.e. I have this in my config:
[branch "x"]
remote = origin
merge = refs/heads/branches/x
so I would expect gitifyhg to figure out where to push, in particular that the commits should end up on the hg branch "x".
All of this works if I name the local git branch "branches/x". But this seems like a needless and irritating restriction, and should be relatively simple to fix.
Definitely a bug. I'm not sure when I'll have a chance to look at it, I'm crossing the atlantic and dealing with jet lag this weekend.
We have a discussion going on in the other issue about heads/BRANCH vs heads/branches/BRANCH, and I just wanted to chime in here that this isn't a problem after I switched to heads/BRANCH in my fork. Git seems to deal with branches much better when they're placed directly under heads/. I recall seeing some other strange behavior as well with tracking and pushing, although can't remember what as this point, and all of that is what led me to make that switch. Maybe something to consider...
Git does not at all care whether branches are "placed directly under heads". The reason why it works in your code is that my test code above uses the local branch name "x", and it just so happens that when you drop the "branches/" prefix, then the remote and local branch name match again. I.e. before your changes these two lines behave differently
#git co -b branches/x origin/branches/x # <-- this works
git co -b x origin/branches/x # <-- this does not work
but afterwards, they are changed to the same, working
git co -b x origin/x
But it is trivial to make it fail (albeit differently) in your version of the code, too; just name the local branch "foo" instead of "x". It doesn't throw an exception then, though, but instead prints the not very reassuring message
warning: helper reported unexpected status of refs/heads/foo
and ends up creating a new hg branch "foo".
The bug is the same in both cases: the helper should not care about the name of the local branch, but rather the name of the remote branch it is tracking.
Note that using the push
remote-helper commands instead of export
could be used to avoid this, as push gets told both the remote and the local ref. But of course it is more work to implement this protocol variant.
I just discovered the existence of the push
command this weekend. I definitely think it would improve stability to support it, but I haven't looked into the amount of work. So I'm tentatively for it (which is to say: I'm all for it if somebody submits a pull request ;) )
Yesterday I wasted three quarters of an hour to resolve the mess caused by how branch names are handled and translated, and things were made seriously worse by the fact that we use hg revisions and not hashes (see issue #16).
What happened was that on the git side, I created a new (properly named) feature branch A , made some commits on them, pushed it -- so far all was good. Then I made some work on my feature branch A (no push this time -- the big mistake), then switched to another (already existing) remote branch B. And then I merged my branch A into B. And then I pushed B. Kaboom, and suddenly my recent commits on branch A were put on branch B in Mercurial. Luckily, I always push to a local hg clone (to shield the real repos from mistakes like this, and also bugs in gitifyhg). So I set about to fixing this (that was necessary since branch B is a throw-away branch for integration tests only, so a commit there is useless). For this, I had to hg strip
both the internal hg clone of gitifyg, and my own manual clone; manually edit our marks files, removing references to the bad commits; and finally update the git branch refs.
This cleanup would have been a bit easier if we were tracking sha1s instead of hg revisions (as the "hg strip" changes the revisions, of course). Also, it showed me that our branch tracking heuristics are somewhat dangerous in this particular case.
I am not quite sure what, if anything, we could do about this, though. :-/
One small idea, though: gitifyhg could have noticed that a new commit was about to be pushed which is contained in more than one remote-tracking branch, and that it thus cannot necessarily decide which is the "right" hg branch. It could then print a warning and either error out, telling the user how to resolve this; or prompt the user for instructions on how to resolve this (yes, this is difficult to achieve with the remote-helper API right now, but that API could perhaps be changed etc. -- I don't want to prematurely limit brainstorming on ways how to resolve this).
It could also attempt better heuristics. In my case, the new commit was on two branches, A and B, but A was "more special" than B, in particular it was merged into B. Hence, it would be logical to assume that the new commit belongs to A, not B.
I don't know, man. Named branches are bad, bad, bad. There are plenty of other sequences that can result in the refs for A and B being in the same place as your example, but with the commits made differently so that hg-like named branch semantics would not be honored by your proposal.
It looks like that, to have the behavior you'd like, the order of the operations has to be taken into account. Indeed, you could have commited these changes to B and then branched from there to create branch A. In this case, the final Git repo would be the same but you would expect the commits to go to branch B. Wouldn't the better be to add some hooks to "checkout" and "merge" to prevent these problems (or at least warn the user, telling him what to do?).
Yeah, I do and did realize that no heuristic can possible catch the general case, although for me the branches usual interact in a very trivial way, so a heuristic would be possible... but indeed, that would be very narrow and only would work for my workflow, but not for most other people.
I would already be happy if gitifyhg would somehow detect that there is an ambiguity, then refuse pushing my changes, and provide me with a way to manually set for each commit to which commit it "belongs". But that, too, is problematic.
In any case: In the current scenario, it is very easy to screw up, and any kinds of safety net we can (optionally) offer users seems like an improvement to me.
I wonder how Kiln Harmony solves this -- if it solves this at all.
http://blog.fogcreek.com/announcing-kiln-harmony-the-future-of-dvcs/ may provide some partial answers (and not specifically on this issue).
No it doesn't; but perhaps the article series they announce will. See also our mailing list
For now I remain sceptical... especially about Joel Spolsky's claim that Everything maps. Everything round-trips. But if they really came up with a magic way to do that, hats off to them!
This is actually already fixed.