能控制subgit对git地址只读吗

subgit,能控制subgit对git地址只读吗,当前希望用subgit实现git同步到svn,但svn的操作不同步到git,想了解subgit能否对git地址只读不写

Dear greysonjo,

Unfortunately, we can not provide support in Chinese. From what I understood via automatic translation, you are trying to synchronize read-only Git to SVN. In this case, it’s natural that changes in SVN are not transmitted to Git. If I got it wrong, please describe your case in English with more details.

yes, I would like to know how subgit makes changes to Git itself, because I have another requirement that after using subgit, changes on SVN will not be synchronized back to Git, while writing on git will be synchronized to SVN, so I would like to know how subgit can read only git without writing

SubGit uses filesystem-level access to Git, so there’s no hook or something like that that could enforce that. If something is changed in SVN, it gets to Git.

But on the other hand, you can use branches mapping to choose which SVN trunk/branches/tags will or will not be synchronized with Git. For example, you can have a dedicated branch ‘branches/git’ that would be synchronized with Git. You can protect changes to it at SVN level using path-based authorization to forbid everybody to change ‘branches/git’ except the SVN user on behalf of which Git works. Alternatively you could use pre-commit hook but this would be trickier, path-based authorization is much simpler.

If you make sure that nobody can change ‘branches/git’ except the SVN user on behalf of which SubGit works and setup SubGit to only synchronize ‘branches/git’, e.g. using:

[svn]
...
trunk = branches/git:refs/heads/master
# branches unset
# tags unset

then you’ll make sure SubGit won’t translate changes from ‘branches/git’ in SVN to Git (just because there will be no changes).

On SVN side you can merge ‘branches/git’ to other SVN branches manually to get changes from Git unidirectionally or just have it as read-only mirror. This setup is the closest to what you describe.

Some our users ask about a possibility to have some SVN branch that would receive changes from Git via SubGit and directly from other users, but such that SVN changes to it would not get to Git. Unfortunately, this setup is technically impossible. Imagine a scenario that you have some ‘file’ in such branch with content:

some content

in both Git and SVN. Then you change this line from Git (e.g. to “some content changed from Git”), commit and push. Both SVN and Git will have this file with content:

some content changed from Git

Until now everything is ok. But what if it gets changed from SVN by some user (e.g. to “some content changed from SVN”). If this change doesn’t get translated to Git there would be 2 versions of the file:

some content changed from SVN

in SVN and

some content changed from Git

in Git. If somebody changes this ‘file’ from Git again, e.g. to “some content changed from Git again”, there’s a question whether such change should be translated to SVN.

  • If yes, it will silently overwrite someone else’s change done in SVN leading to an unexpected/inconsistent result;
  • If no, the synchronization would stop for this file and this could break compilation.

So as you can see unidirectional synchronization quickly leads to problems and the only kind of the synchronization that is possible is bidirectional. But you can make it effectively unidirectional by forbidding to commit to certain branch in SVN for everyone except SubGit using path-based authorization.

Thank you very much for your answer. Another question is whether Subgit supports synchronizing the existing Git repository to the newly created SVN address, because the deployment steps of Subgit are all about how to synchronize a SVN address to a new git or overwrite a git. We want to leave the Git repository unchanged and synchronize with a new SVN successfully. Is there any way to do this?

SubGit allows that only if none the branches in the existing Git repository are configured to be synchronized using branches mapping. Otherwise SubGit will fail with

Subversion and Git repositories are out of sync and can not be synchronized

error. You might run into the same error if you 1) disable synchronization for a while using “subgit uninstall”; 2) commit to both SVN and Git; 3) enable synchronization back with “subgit install”.

So to the moment of enabling synchronization only one side (Git or SVN) is allowed to have changes but not both.

So in your case I would suggest to 1) setup ‘subgit/config’ to synchronize SVN with some not yet existing branch in Git, e.g.

trunk = branches/git:refs/heads/svn

Then 2) merge into to that branch Git changes you want to send to SVN.

Alternatively (and maybe better for your case) you can use not-yet-existing branch in SVN, with existing branch in Git:

trunk = branches/git:refs/heads/master

In this case you can enable synchronization, it will create ‘branches/git’ and send ‘refs/heads/master’ content to it and will do that continuously.

In either case to the moment of enabling synchronization either SVN branches or Git branches configured for synchronization shouldn’t exist, i.e. “SVN branches do not exist, Git branches do”, or “Git branches do not exist, SVN branches do”, or “neither of them exist”.

Thank you very much for this method, which solved my problem very effectively. In addition, I would like to confirm:

“SVN branches do not exist, Git branches do” or “Git branches do not exist, SVN branches do”, Or neither of them exist.

I understand that subgit will automatically determine which side of SVN or GIT is empty, and then automatically identify and synchronize the one with data to the one without data. For example, if git has data but SVN has no data, then subgit will automatically identify and synchronize git to SVN, or IF SVN has data, Git has no data, when subgit is started, it will automatically identify and synchronize SVN’s data to Git, is that right?

If this is the case, will subgit mistakenly synchronize the data from the non-data side to the data side, causing the data on the data side to be erased?

You’re absolutely right, the synchronization always goes from “data” to “no data”. It will not mistakenly synchronize the “no data” → “data”.

But let’s consider the final case: “data” - “data”. Normally, when SubGit is active this cannot happen because SubGit actively prevents that. But if you turn it off (with “subgit uninstall” command) for a while, commit to both SVN and Git and then turn it on (using “subgit install” ) turning on will fails because of conflict. In order not to leave the user in such a state, we’ve introduced “subgit install --recover” for recovering from conflicting situation. In this case SubGit always resolves conflicts in the same way:

  • moves Git branch to refs/subgit/unsynced/... namespace;
  • replaces it with data from SVN (always from SVN);
  • generates conflict resolution instructions (commands to run) to incorporate Git changes back to that conflicting branch (until then there’s only SVN data).

This cannot happen accidentally but only upon deliberate run of “subgit install --recover” command and conflicts can only happen if you explicitly turning SubGit off and commit to both SVN and Git. If you never commit to SVN, you’ll never get conflicts.

Finally I would like to note that there’s a common mistake: “empty branch” is not “no data” situation. I mean that if you create an empty branch in SVN and a corresponding branch with some data in Git, it’s “data” - “data” situation. “no data” situation is the absence of a branch in SVN (or Git).

I hope this information helps.

Thank you very much for your help. Every bit of advice was very useful

I was annoyed because I encountered the common mistakes you mentioned.

  1. We want to create a new directory in an existing SVN address to synchronize with git repository, but this can’t be implemented, right?
  2. In addition, is there any way to use “subgit install – revocer ” always from git to override the CONTENTS of SVN
  1. If you just want to create a new directory but haven’t done it yet, it would be better if you don’t create such a directory yourself but let SubGit create it. If you set svn.url to a non-existent URL and then synchronize it to existing Git repository, “subgit install” will create a directory at that URL itself. Thus you could avoid any problems.

This note is true for “trunk=:refs/heads/master” configuration (mapping an SVN directory to Git master, without branches or tags). But if you’re using standard trunk/branches/tags structure, it doesn’t matter if you create the project root directory on your own or let SubGit do that. This is because project root doesn’t map to any Git branch, only trunk/branches/tags inside it do. But it’s important not to create SVN trunk or branches yourself in this case.

  1. No, it always works in SVN → Git direction. So for your case it’s important not to make changes to SVN side directly to prevent any need in “subgit install --recover”.

Thank you very much again. This solves another problem for me.
Now the data is being synchronized, but the data is large. During the data synchronization process of “subgit install”, what will be the impact if users are reading and writing in the Git repository? Or can the user read and write in this process?

Hello,
Pulling (reading), is possible at any time.

Until the moment “subgit install” finishes you can’t push to the Git repository. During “subgit install” SubGit creates hooks that reject any updates to the Git repository.

Interestingly, there’s no real reason to have such hooks if translation direction is Git → SVN but they make perfect sense for SVN → Git translation. And as SVN → Git case is 99% of all the cases of our users, we’ve just forgotten about the situation of 1) Git → SVN + 2) someone wanting to push during initial “subgit install”.

So if you really need to push to the Git repository during initial Git → SVN subgit install, I think, you can just manually remove these blocking hooks as a work-around, but I have to check that this doesn’t lead to any problems.

Thank you very much.
In fact, we hope that during the “subgit install” period, the user can not read and write in both Git and SVN. As you said, subgit creates a hook in git, so we can do it, but there is no such method in SVN, so we know to find another method to deal with this problem.

In addition, according to the scenario you mentioned before, I have started “subgit install” for a period of time. If the data of Git and SVN are inconsistent when the subgit process is stopped, what will happen when I start “subgit install”? How to solve this problem?

Up to this point, we have successfully started Subgit through the method you provided, and our needs are met. The next is more about some follow-up maintenance issues

SVN has path-based authorization mechanism to prevent changing certain paths. But it requires admin rights to the SVN, so SubGit can’t setup that but you can do that manually.

I’m not sure I understand the question about data

The only reason for them to become inconsistent is committing to SVN repository (to be more precise, the SVN branch you’ve configured to be synchronized) during Git → SVN translation. In this case you’ll have “data” - “data” conflict with “subgit install --recover” as the main solution (which - I understand - you don’t like). So it’s better to forbid changing of that SVN branch to anyone except the SVN user on behalf of which SubGit acts.

Ok, thank you very much again for your patience in answering all my questions. If there are new questions in the future, I may need your help.

I am in China, welcome to China to take you to try Chinese food, nice to have this dialogue, bye

1.Why do you delete branches on Git and then synchronize them back from SVN? How do I cancel this operation and make sure git prevails

  1. Subgit only synchronizes master, not branch and tag , how to do this

Hello Greysonjo,

  • I’m afraid I don’t understand your first question to the very end. If a branch is deleted in Git, then this change is being propagated to SVN, the counterpart SVN branch is then being removed too. Same for the opposite direction, removing a mirrored SVN branch will be removed in Git, too.

  • if only one branch is synchronized, then most probably the rest branches are not included in SubGit mapping configuration. To make those branches and tags synchronized, the branches and tags should be added to the mapping.

  1. Because I have encountered a problem in deleting branches on Git, the corresponding branches are not deleted on SVN, and the branches on Git are restored

  2. I want subgit to synchronize only the master trunk for me and not the other branches, In this case, how to configure ?

Hello Greysonjo,

  1. This should not normally happen, something definitely was wrong with this mirror. My assumption is that the SVN user SubGit used was not allowed to remove those branches in SVN and that’s why that happened. This is only an assumption, however, a deeper investigation is needed to say for sure, could you please share all the SubGit logs from that repository?

  2. To synchronize only the trunk to masterleave only that particular mapping in the configuration:

    trunk = trunk:refs/heads/master
    

    and remove all the rest mapping lines so that only trunk is mapped. Note, that such a mapping configuration change cannot be applied to the working mirror on the fly, so if the initial replication already finished in the repository, then this change should be applied with rebuild:

    subgit install --rebuild <REPO>
    

    With the rebuild option, SubGit will backup the current repository and perform the initial import once again, but this time following the new (trunk-only) mapping configuration, so the Git repository will contain only master after the import finishes.

OK, thank you very much