jwhitley / giternal

non-sucky git externals
MIT License
2 stars 0 forks source link

Reimplement `giternal freeze` via a version lock file #9

Open jwhitley opened 9 years ago

jwhitley commented 9 years ago

This fork removed the old freeze (and unfreeze) commands as they flattened the child repositories' content into the parent (or "meta") git repository. This proved highly undesirable for some projects that I've applied giternal to, so it was removed.

The proposed replacement is to follow the pattern of package managers such as Ruby's bundler, npm, and others by creating a version lockfile. The rough workflow would be:

If a specific config setting exists, e.g.:

giternal_settings:
  lockfile: true

Then giternal update will git pull in each child repo, and create/update a .giternal.lock file which specifies the specific refs in each of the child repos.

A new command giternal install will update each child repo to the ref in the lockfile. If the lockfile config is enabled and no lockfile is present, giternal install fails with an error. If lockfile is not enabled, it is a synonym for giternal update unless the --strict command line flag is present, in which case it fails. The --strict flag is to enforce a workflow where automated tooling expects to receive a blessed version set via a lockfile, and should be notified via error if this is not the case.

giternal update will likely also need extra options, e.g. to allow a specific named repository to be updated versus all repos in the config.

Air-Craft commented 9 years ago

I like the idea of syncing with bundler/npm etc as I'd imagine it'd reduce the friction for taking up this tool. Can I just confirm though that the actual code will be included in the parent repo? That's the whole point of this tool I believe but just to be sure...

Also one downside is that we'd no longer be able to work on the child repositories in place like we could via unfreeze before.

jwhitley commented 9 years ago

To answer your questions:

Can I just confirm though that the actual code will be included in the parent repo?

No, the implementation in this fork does not keep any child repo commits or code in the parent repository. The parent repo only contains "pointers" to the child repos, e.g. stored in a .giternal.lock file.

Also one downside is that we'd no longer be able to work on the child repositories in place like we could via unfreeze before.

The child repos' are stored under the parent repo, just like with the old unfreeze. Child repo working trees are in the locations specified in the giternal config, just like always. The difference is that (with the changes needed for this PR) that the "freeze" operation only writes a file in the parent repo marking the current git ref for each child repo.

Does that make sense?

Air-Craft commented 9 years ago

For me the whole point of giternal is that the child repo code is included in the parent repo (though not necessarily the entire git history), so if a vendor lib decided to go offline, you wouldn't be stuffed. How is new paradigm any different than git submodules?

jwhitley commented 9 years ago

@Club15CC Thanks for the feedback. For this fork, I'm likely to stay with this approach, but I definitely appreciate your desire to keep snapshots of the child repo's trees. For my part, I've almost always used full clones of dependencies' repos for that need.

To your question about git submodules, I find that they work poorly with collaboration on child repos. This fork is intended to help out with a workflow as follows:

  1. The parent repo and the child repos are managed by the same person/organization.
  2. The parent repo only contains the giternal config, and often some workflow tooling common across users of the child repos. E.g. a common pattern I've used includes a Vagrantfile, Chef or Puppet provisioning code, and often a Ruby-based top-level tool that wraps up the day-to-day uses of giternal/vagrant/etc. into a simple workflow.
  3. Almost all of the work occurs in the child repos

Particularly with number 3 above, submodules are not a good fit because they're a constant source of merge conflicts. With this giternal fork, child repos are easy to manage and there's no worry about conflicts. If/when I do add a lockfile, I expect it would be mostly updated and used on release branch(es) to record the specific versions of child repos used in that release.

Air-Craft commented 9 years ago

Definitely sympathise on the inadequacy of submodules: http://stackoverflow.com/questions/7702638/git-sub-repos-external-libs-for-web-development-best-strategy-once-and-for

It's interesting though as I'm doing more iOS dev at the moment where two things are drastically different than web:

Anyway, interesting to see your requirements. I do think a more bundler style approach would win giternal some traction.

jwhitley commented 9 years ago

I completely agree re: freezing external dependencies in-repo. I've managed that very problem in various ways over the years. This fork of giternal was very specifically conceived around a "we own all the repos" model. E.g. development shops with big SoA codebases, but where they own all of those services.

In your case of iOS development, vendoring libs directly into the repo is sensible. I've used git's subtree merge for that as well. Subtree merge is also similar to a setup I used to manage in Perforce years ago. In P4, we kept a whole //depot/3p tree for third-party dependencies. If we ever took a new drop, it would be updated and built under /3p, then the rebuilt libs were merged over to the relevant product branch. That kept the source code and its history well documented, and provided a nice paper trail if we ever hit an issue with a dependency.

Cheers!