Search code examples
gitsvnversion-controlmercurial

Version Control For One File Across Multiple Directories, Avoiding Conflict With Existing Git Repos


I'm working on a style file for latex that can be used in multiple scenarios. For each scenario, I have a test case in a directory that includes a copy of the style file.

The style file and the test cases have separate repositories on Git:

  • Git repository 1: style, i.e. the style file.
  • Git repository 2: examples, i.e. the test cases.
    • /A: one of the test cases and a copy of style
    • /B: another test case and a copy of style

For ease of testing and for end users it is muuuch easier if the style file is in the same directory as the scenario. This all gives me many opportunities for getting out of sync.

Currently I sync each style file by hand, but would like to do this with the support of some kind of diff / versioning tool.

I have tried setting up another repository and placing the style file in there, and syncing using mercurial so that I have another directory...

  • Mercurial repo 1: style file

... but mercurial also works using the concept of syncing whole directories and so when I attempt to clone the style file in the mercurial repo into the directory where the test cases are, I end up with mercurial then trying to pull the examples into the style file repository.

Question: how can I version control one file in an directory where I am already using git for a different repository?

(I will accept constructive "you're doing it all wrong - try this" answers with gratitude!)


Solution

  • Okay, to check my understanding:

    There's four types of content to consider here: the small-utility-library code (which happens to fit in just one file here), production/external users of the utility, and tests and examples. You're providing the library and the test and example cases and want to fit your payload into the external users' workflows.

    If this were compiled code it would be perfectly ordinary: build and test your utility, ship the product, production users use the shipped library or if they're into it a bit more build it themselves as a submodule and send or carry patches.

    When there's no compile-and-build step, and especially when the payload is a single file as it is here, the boundaries start to irk a bit, the natural desire is "can't I just get the one file?".

    Yes? Assuming I got close enough to run with:


    The thing to understand is that the only really important structure in Git is ancestry linkage. Any repository can contain any number of distinct histories.

    In particular, people using your style library can bring in your published histories and work with them however they like.

    All users:

    git remote add acstyle u://r/l
    git fetch acstyle
    

    just-gimme-the-content users can then do

    git checkout acstyle/payload -- .
    

    and now their checkout has the most recent payload.

    Users more familiar with Git might want it to keep records for them, they can

    git merge acstyle/payload    # initially with `--allow-unrelated-histories`
    

    and their checkouts have the same additional content but also record its ancestry.

    You can offer multiple branches in your published repo, and e.g. merge the bare payload into the testcase/example scenarios. It's easy to do.

    Say you've got a development "master" branch with all your test cases and examples handy, but you want to construct payload branches as above that won't litter other people's repositories.

    Initial construction of the minimal payload branch:

    # from any clean checkout
    git checkout --orphan payload
    git reset --hard
    git checkout master -- acstyle.sty
    git commit -m "acstyle-payload-v1.0"
    

    When it's time to publish a new payload version, do that again but omit the orphan and reset bits, or to publish full history behind the tip so it's there but won't litter the checkout, you could do

    git checkout payload
    git merge -s ours --no-commit master    # add `--allow-unrelated-histories` the first time
    git checkout master -- acstyle.sty      
    git commit -m "acstyle-payload-v1.1"
    

    I don't know how to predict whether users will like having the full development history behind a -s ours merge this way, maintaining both is easy.

    You can maintain payload-plus-examples branches and whatever other flavors seem good the same way, users simply fetch what they want and combine it into their own histories however they want.

    If you're going this route, don't use tags in your published repository, Git by default copies all tags from every repository it fetches from and they'd litter your users' histories. Instead, just use the commit messages, users can use the :/ syntax to refer to commits by message content if they want something other than the most recent,

    git checkout :/^acstyle-payload-v0.9a -- acstyle.sty
    

    and they can see the log of published versions with

    git log --oneline ---first-parent acstyle/payload