Coder Social home page Coder Social logo

Creating new branches? about git HOT 6 CLOSED

felipec avatar felipec commented on August 25, 2024
Creating new branches?

from git.

Comments (6)

fingolfin avatar fingolfin commented on August 25, 2024

[Disclaimer: I am not the author of git-remote-hg, just another user, so take this comment accordingly with a grain of salt.]

First off: I can reproduce this, too, but only when the hg repository is accessed over SSH. This is without remote-hg.hg-git-compat. However, it works fine when accessing a local hg repos, i.e. using
git clone hg::some/local/path gitclone

Thus, as a workaround, you could first make a local clone of the Mercurial repo, then git-clone that... Of course that's not that elegant and nice, and no excuse for anything, but I thought I should mention that there is at least a workaround.

As to the issue itself: This seems to be caused, ultimately, by the fundamental difference between git branches, and hg branches... In hg, the analog to git branches really are bookmarks (although hg bookmarks diverge in some subtle but important points in behavior from git branches, and in a way that I find most negative and dangerous... but I digress). Anyway, there is no direct analog hg branches in git at all. So when you push the new branch with git-remote-hg, it has to decide how to map this to a hg object, and at least in my setup, it opts to create a bookmark for a new head of the default branch. Which is a valid way to interpret this, but it may not be what you expect... it also creates a second head on a branch, something that is not possible (thankfully) in git; indeed, it is a quite dangerous thing in general, which is why Mercurial by default refuses to do it. Which is what we are seeing here. The very same error would pop up when trying to do such a thing with hg.

Now, one way to "solve" this would be to set Force=true in the repo.push() invocation. There seems to be no other way to stop that exception, as long as one is using a bookmark to implement that branch.

So one might want to use hg branches instead. But I think it is impossible to do this in a generic way that will always produce consistent and useful results; it would need to recreate information that simply is not there anymore. Sure, in the example given here, one could do this. But once the history becomes more complicated, it is no longer possible to decide for each commit uniquely to which branch it belongs. Example:

  A
 / \
B   C
| \ |
D   E

and "feature" points to D while "master" points to E. Now, when pushing this to hg, when hg only knows about commit A... then to which hg branch should commit B belong to? To "default" or to "feature" ?

Well, both are possible. So, git-remote-hg would have to make an arbitrary decision. E.g. it could start at the branch tips: D is in hg branch "feature" and "E" is in branch "default". Then it proceeds to parents: C has only children in "default", so we will assume it is in default. For B, there are children in both default and feature. We need a tie breaker. E.g.: "If any child of X is on default, assume that X is on default", or "count the number of children on each branch; choose one of the branches for which this number is maximal" or "choose the branch which comes first in the alphabet" or "choose the branch on which the youngest child commit is", or "choose one of the branches for which the child commit of X is not a merge commit", etc.

Whatever rule(s) one uses, the outcome may or may not be what the user expects. There will always be situations where the user will feel it is "wrong". This can't be helped, I guess... except by the user avoiding such situations in the first place. Indeed, I am hopeful that such situations as I described are relatively rare in practice. For if a push happened at any time before E was created, then at that time there would have been no ambiguity; or if E was there, but D not and "feature" pointed to B (or alternatively, if no branch "feature" was present), then again it would be clear to which branch B belongs.

from git.

dusty-phillips avatar dusty-phillips commented on August 25, 2024

I'm actually not able to clone local branches at all for some reason, as reported in #8. Since your comment suggests that is an issue local to my setup, I'll have to poke around this weekend to see what's going on.

The 'solution' you mention, to set force = True, is probably correct. I haven't looked at the code yet (I have taken two stabs at my own version, but they don't work well: https://github.com/buchuki/gitifyhg), but I don't think the creation of a new head is "dangerous" when it is being performed by git for the express purpose of creating new branch.

I think in the example you proposed actually could theoretically be determined unambiguously by comparing the timestamps of the commits, but it would be a painful process. It may be wiser to explicitly force the user to use a different command to create named upstream branches.

One workaround that would work fine for me is to create the named branches upstream first and then pull them into git and start committing. However, as I reported in #7, I haven't figured out how to do this, either. I suspect, once again, there may be something fishy in my environment:

Arch Linux
Kernel 3.6.9
Mercurial 2.4.1
python 2.7.3
git-remote-hg downloaded from the repo to ~/bin which is on PATH
remote-hg.hg-git-compat=true

I changed the first line of git-remote-hg to #!/usr/bin/python2 because /usr/bin/env python was picking up either python 3 or the version of python in my active virtualenv, which didn't have hg installed.

from git.

dusty-phillips avatar dusty-phillips commented on August 25, 2024

#7 has been solved, so this issue becomes less urgent for me.

from git.

fingolfin avatar fingolfin commented on August 25, 2024

Regarding the use of timestamps to recover the branch history: That is not really a viable approach, I think. First off, timestamps are inherently unsafe; e.g. clock time on different machines can very a lot, and you can easily reorder commits in git in such a way that a "newer" commit comes before an "older" one (e.g. using "git rebase -i"). And this does indeed happen in real-life, too.

Secondly, even if one were to trust the timestamps, then this still does not help in general: Sure, if D is older than E, then we can guess that B and D are on the same branch "feature". But if E is older than D, we again cannot decide to which branch B "belongs".

However, I guess one should not worry too much about it, and just make an arbitrary choice, e.g. always take the branch of the first parent commit. Personally, I consider the extra information provided by the "branch" property of hg commits to be useless, and all examples I saw so far which attempt to justify their use appeared to be quite contrived and silly :-). But that's just me... :-).

Fact is, though, there is no way to determine the "correct" mercurial branch for all commits in all cases. But I think it is fair to say that in such cases, people who really worry about each commit being in the right branch, should either not use git-remote-hg, or be very careful to always push all local changes whenever they switch between branches.

from git.

felipec avatar felipec commented on August 25, 2024

I believe the only sane approach for now is follow the git model; multiple bookmarks on the same branch. Which means we need to force the push.

I've implemented this in the hg-next branch, please give it a try:
https://raw.github.com/felipec/git/fc/remote/hg-next/contrib/remote-helpers/git-remote-hg

from git.

felipec avatar felipec commented on August 25, 2024

The proper fix is to implement our own checkheads() method, so we only check multiple heads in the branches, but not in the bookmarks: e1ae034.

With this, it's also possible to report non-fast-forward errors on the specific branches that triggered a failed push, and we can update the bookmarks only when the push succeeds, so everything is properly synchronized without the need of striping the commits of a failed push.

from git.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.