Guest?
 
  • Showing issue #? of ? found
Back to Search
Project
SubGit
Priority
Normal
Type
Bug
State
Fixed
Assignee
Semyon Vadishev
Subsystem
Translator Core
Affected versions
Miai EAP5 (build 1096)
Fix versions
1.0.0 (build 1696), Miai EAP6 (build 1381)
Fixed in build
No Fixed in build
  • Created by   Jean Helou
    14 months ago (21 Mar 2012 11:35)
  • Updated by   Semyon Vadishev
    13 months ago (25 Apr 2012 18:12)
0
Issue is visible to: All Users
  The issue is visible to the selected user group only
You don't have permissions to view 2 more attachments to this issue
Here is what I did :
I did a first subgit install of an svn repo
because of some problems in my custom pre/post commit hooks, I lost sync between both repos.
I subgit uninstalled the svn repo, deleted the git repo and subgit installed again and fixed my scripts

I had a local clone of the previous repo, when I git pulled it did "something" I haven't identified yet but when I git pushed afterwards I got a message in my log with "merge from master" or something approaching and it created a shelf with my name in svn.

I deleted the root/shelves/myshelf in tortoise svn, and it generated the attached sync error (it is attached as developpers only as it contains information on a private repository).

I have since deleted the git repo again, regenerated it with subgit install and recloned it to avoid the issue.
I have also disabled shelves mapping by using
shelves = shelves/*
As the shelves configuration.

I am unclear what shelves are and how they are generated and why, but I don't want them synced between git and svn. hopefully my configuration won't blow up when trying to translate them.
Comments (17)
 
History
 
Linked Issues (?)
 
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 18:15
14 months ago
Here is the possible explanation of what happened, correct me please if I missed something:

I did a first subgit install of an svn repo


At this moment you have:

REMOTE_SVN_REPO — original svn repository
REMOTE_GIT_REPO — git repository synchronized
LOCAL_GIT_REPO — git repository you've cloned from REMOTE_GIT_REPO.

Everything is up-to-date, i.e. every svn revision represents corresponding git commit and vice versa.

because of some problems in my custom pre/post commit hooks, I lost sync between both repos.


You have some commits which present in LOCAL_GIT_REPO and REMOTE_GIT_REPO, but there are no corresponding revisions in REMOTE_SVN_REPO, since synchronization didn't start due to hooks misconfiguration.

Probably, you also have some revisions in REMOTE_SVN_REPO which are not yet synchronized with REMOTE_GIT_REPOSITORY, so they don't present in LOCAL_GIT_REPO.

I subgit uninstalled the svn repo, deleted the git repo and subgit installed again and fixed my scripts


After that your REMOTE_GIT_REPO contains commits converted from those revisions committed into REMOTE_SVN_REPO after the very first 'subgit install'.
At this moment you have REMOTE_SVN_REPO and REMOTE_GIT_REPO up-to-date, but REMOTE_GIT_REPO and LOCAL_GIT_REPO are not up-to-date.

I had a local clone of the previous repo, when I git pulled it did "something" I haven't identified yet but when I git pushed afterwards I got a message in my log with "merge from master" or something approaching and it created a shelf with my name in svn.


Your LOCAL_GIT_REPO contains those commits which are neither in REMOTE_GIT_REPO nor in REMOTE_SVN_REPO, at the same time REMOTE_GIT_REPO has some commits converted from those revisions committed after the very first install, and these commits are not in LOCAL_GIT_REPO. In git terms you have a diverged history.

When you run 'git pull', git created a merge commit with the "merge from master" message. This situation is typical when one uses 'git pull' instead of 'git pull –rebase'.

So, what SubGit sees: there is a merge commit referenced by 'master' ref, it has two parents from REMOTE_GIT_REPO and LOCAL_GIT_REPO. SubGit has nothing to do but send first parent into ^/trunk, which correspondes to master branch in Git. The second parent goes into a artificial branch, or "shelf" as we call it, so you get this temporary branch ^/shelves/myshelf.

We introduced shelves exactly for this case — when we can say nothing about what branch these commits belongs to.

I deleted the root/shelves/myshelf in tortoise svn, and it generated the attached sync error (it is attached as developpers only as it contains information on a private repository).


That's pretty strange, ^/shelves/mushelf exists only for those revisions when SubGit was translating the diverged history. SubGit always deletes all the shelves as soon as it converts the merge commit which joins the diverged commits.

From the log you've provided I can say that translation was in progress, hence SubGit should not allow you to commit the branch deletion. Did this commit actually happen. Is there corresponding revision entry in 'svn log -v ^/' output?

If I'm right, the failure you hit is not related to the deleted shelf, but is something more generic.
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 18:22
14 months ago
I have since deleted the git repo again, regenerated it with subgit install and recloned it to avoid the issue.
I have also disabled shelves mapping by using
shelves = shelves/*
As the shelves configuration.


'subgit install' must exit with error if you have no git.*.shelves config options.

As I described in my previous comment:

  • if you convert svn revisions into git commits, you will never get shelves in your history
  • if you convert git commits into svn revisions and always use 'git pull –rebase' to keep the history linear, you will never get any shelves in svn.
  • if you convert git commits into svn revisions and always use default merge messages like "Merge master into foo", SubGit will understand what is master and what is foo, it won't create any shelves and send commits to ^/trunk and ^/branches/foo.

SubGit creates shelves only when it fails to find a good name for some branch in Git.
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 18:47
14 months ago
well, subgit install works just fine with my
shelves = shelves/*
apping, most likely it will explode in a bad way if it ever tries to actually create a shelve.


I'm sorry, I misunderstood that. "shelves = shelves/*" is a just a shortcut for "shelves = shelves/*:refs/shelves/*", so technically you'll get the same behavior with such configuration.
guest
  guest
21 Mar 2012 18:52
14 months ago
Hmmm ok.
Will you consider a conf switch to disable shelves entirely ?
I guess i could be extremely careful with my git usage but i would much prefer having sugit block any shelve creating attempt :( event at the cost of having to clone my local repo again and manually recover my changes.
Jean Helou
  Jean Helou
21 Mar 2012 18:55
14 months ago
Oups, somehow wasn't logged on for the last comment
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 19:06
14 months ago
I would prefer a message telling me that my git repo is corrupted and I have to clone again and/or a way for subgit to silently ignore the merge source when commiting to svn and simply apply the patch as if it were a normal commit. Could this happen ?


AFAIU, you suggest the following:

1. In case some user pushes a piece of Git history with shelves to be created in svn, we reject such push operation and asks user to linearize the history.

  • The history may be extremely complex, so linearizing such a history may become a torture.

  • Currently SubGit translates commits in the background. In order to implement shelves check we have to block push operation for a while until we understand whether the history is fine or not.

2. If SubGit fails to determine a branch for one of parents of a merge commit, throw away the history of this parent.

  • It's really hard to understand, what branch to throw away. User may wonder how that comes that they did a bunch of commits but in Subversion history they created has squashed into a single revision.

  • If SubGit throw away a certain parent and its subhistory, and then someone creates a tag or a new branch from some commit of this subhistory, we have to translate corresponding commits.

Formerly we had discussion on these issues and decided that the shelves approach has much more benefits comparing to its alternatives. So, we decided to hold this way. Sure, we understand that a special branches namespace may confuse some users, but we believe that proper usage of rebase instead of merge fix the problem in general.
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 19:13
14 months ago
As a quick and dirty workaround for the shelves problem you can add a special hook, which traverses the pushed history and detect commit messages typical for those merge commits which lead to shelves creation.

Here is the pattern we use to detect such merge commits:
merge (remote-tracking )?branch ['"]?({branch}/)*({branch})['"]? of .+
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 19:19
14 months ago
Will you consider a conf switch to disable shelves entirely ?
I guess i could be extremely careful with my git usage but i would much prefer having sugit block any shelve creating attempt :( event at the cost of having to clone my local repo again and manually recover my changes.


I doubt we'll do that in near future. But if at some moment we will decide to do that, we'll stick the option 2 from my previous comment:
If SubGit fails to determine a branch for one of parents of a merge commit, throw away the history of this parent.


May I ask you what exactly disturbs you? Having shelves directory in repository root or having shelves in log output?

We have plans to delete shelves directory every time it's empty. This way, most of the time repository root won't have this directory, it will present only for those revisions when one of shelves actually was added by SubGit.
Jean Helou
  Jean Helou
21 Mar 2012 19:48
14 months ago
Here is what I want to do :
Be able to use the full git power to create branches merge them and share them with some other advanced users, while keeping it completly transparent for the svn users.

That is why I configured my namespace so that branches from svn are a subset of git branches (see SGT-436). I want to be able to create branches (feature branches most likely) in git, push them in the central repository to be able to share them easily with other developers and NOT have them appear in SVN at all, then merge them in master or in one of the svn branch and push that to svn. On the svn side I would like it to appear as a normal commit, possibly with a weird message, but I don't want to replicate the full branch

If I want the feature branch history, either I branch it off to the svn namespace and push it on the server where it will be published in svn, or I rebase it onto master and push that. In the rebase case, I still don't want the git feature branch to be pushed to svn.



I am not sure the regex pre commit hook is a solution actually, and if you are able to determine which branch to shelve, you are also able to determine which history to drop : the history for the branch you would have shleved, the history for the git ref which does not exist in svn.

edit
After pondering this some more:

2. If SubGit fails to determine a branch for one of parents of a merge commit, throw away the history of this parent.

It's really hard to understand, what branch to throw away. User may wonder how that comes that they did a bunch of commits but in Subversion history they created has squashed into a single revision.


Isn't this is exactly what happens in git history ... if you only consider the branch which received the merge you will only see merge branch 'whatever' and not the commit history, unless you did a rebase ...

If SubGit throw away a certain parent and its subhistory, and then someone creates a tag or a new branch from some >commit of this subhistory, we have to translate corresponding commits.


Only if the ref created is mapped in the svn repo, and then yes it makes sense to translate the corresponding commits, but not before that ...
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 21:06
14 months ago
Be able to use the full git power to create branches merge them and share them with some other advanced users, while keeping it completly transparent for the svn users.

I got your point, thank you.

The use case you're describing is definitely interesting. But there are another not less important scenarios we have to think about:

Just imagine you're translating the history of 10 000 git commits into Subversion. The first one is a merge commit, the only reference available refers to this commit. And, yes, this is something one can find in the wild github jungles.

So, you have to decide which part of the history won't be ever available to any svn user. That means, say, 5 000 commits of history will disappear completely from Subversion. And what if soon someone adds a tag on the commit you just dropped?

As I already mentioned, in our team we discussed the behavior you're describing. At the end of the day we found that using additional ^/shelves/* namespace significantly decreases the possible risks for SubGit users. And all that by the price most svn users will never notice.

I mean, really, for an average Subversion user the difference between the current behavior and your suggestion is just a single line in svn:mergeinfo property one gets on svn update.

And I'm not saying we will never implement what you've suggested. Probably, we will. But it's definitely not for SubGit 1.0. We need to gather more feedback, understand which edge cases we have to consider, etc.
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 21:45
14 months ago
Isn't this is exactly what happens in git history ... if you only consider the branch which received the merge you will only see merge branch 'whatever' and not the commit history, unless you did a rebase ...


I doubt that.

$ git log master
commit 27fcd3db59b0fbeea27bb25fd39a81cc83111b21
Merge: ae5171a c498aab
Merge branch 'foo' into 'master'

commit ae5171a6e2fb5ce358c48ea368f27d7e61624783
Commit on master branch.

commit c498aab18c7315b445417304bb99b51d3e410274
Commit on foo branch.

commit bc65b202d094a3bf111fb076c55e75f7e2e7af95
initial
Semyon Vadishev
  Semyon Vadishev
21 Mar 2012 21:51
14 months ago
Only if the ref created is mapped in the svn repo, and then yes it makes sense to translate the corresponding commits, but not before that ...

Yes, that makes sense. I put some random thoughts on every option there.
Jean Helou
  Jean Helou
21 Mar 2012 21:52
14 months ago
On the history thing : yeah I mixed things up with git merge –squash
Jean Helou
  Jean Helou
21 Mar 2012 21:54
14 months ago
I should rename and requalify this issue as what we discussed is mostly the feature switch I requested.
I will open another bug somewhere since the repo sync was lost when I deleted the shelve and the shelves root from svn when I shouldn't have been able to.
Semyon Vadishev
  Semyon Vadishev
27 Mar 2012 21:59
14 months ago
From the debug log you've provided it seems Subversion hooks were not installed at the Subversion repository. As result shelves deletion was not blocked by svn pre-commit hook, after that SubGit failed to handle missing shelves directory. Could that be possible?
Jean Helou
  Jean Helou
27 Mar 2012 22:11
14 months ago
I guess it is but it is unlikely as I was testing subgit sync, I don't remember uninstalling before deleting the shelves but it's been a few days.
As far as I remember I pushed from git then, svn updated on the other side, then visually checked the svn repo. I tried to get some info on what shelves where then I removed the inner folder then the shelve root (which is why there are 2 commits) and didn't get any errors. I noticed the problem after cloning fresh starting to work on it and not getting one of the modifications from a co-worker ... that's when I saw the sync error zip file.
Semyon Vadishev
  Semyon Vadishev
25 Apr 2012 18:12
13 months ago
Since r1307 of trunk we've introduce losless processing of svn branches and tags. This modification fixes the failure described in this issue.
Related Changes
Resolved Date
13 months ago (25 Apr 2012 18:12)
State
SubmittedFixed
Apply Command

Command Preview: