Automatic removal of .git directories from Composer dependencies

If you've adopted a Composer-based Drupal 8 workflow (hopefully using the Drupal Composer/Drupal Project template) where you're keeping dependencies in your project's repository, then you've no-doubt experienced the annoyance of a rouge .git directory ending up in one of your project's dependencies. This will always happen when you're using the -dev version of a Drupal module. 

For example, as of the authoring of this Quicktip, the Field Redirection module does not yet have a stable release for Drupal 8. When added to a project using Composer, the results look like this:

Michaels-MacBook-Pro:dcoweek5 michael$ ddev composer require drupal/field_redirection
Executing [composer require drupal/field_redirection] at the project root (/var/www/html in the container, /Users/michael/sites/dcoweek5 on the host)
Using version 2.x-dev for drupal/field_redirection
./composer.json has been updated > DrupalProject\composer\ScriptHandler::checkComposerVersion
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing drupal/field_redirection (dev-2.x e1c30f2): Cloning e1c30f24f9 from cache
Writing lock file

Git directory

Notice on the "Installing drupal/field_redirection..." line, it indicates that the project is cloned, not downloaded. This means that a .git directory has been created in the Field Redirection directory.

Note that I'm calling Composer as "ddev composer ..." - this is because I use DDEV as my local development environment and am utilizing its built-in Composer command.

If this goes unnoticed, and you attempt to do a normal "git add/commit" workflow for the new module, you'll end up with a somewhat-friendly Git message indicating that you now have a Git submodule.

Unfortunately, Git submodules aren't normally necessary nor wanted when you are committing dependencies to the project repository. So, the typical solution is to delete the .git directory of the dependency prior to performing the "git add/commit".

Luckily, there's an easier way! Travis Neilans recently pointed me in the direction of the Composer Cleanup VCS Directories project. By adding this as a dependency of your project, any .git directories that result from adding project dependencies will be automatically removed! First, install the Composer Cleanup VCS Directories project using:

composer require topfloor/composer-cleanup-vcs-dirs

Then, anytime you use "composer require" to install a project dependency, if there's a .git directory, you'll see a message indicating that it has been automatically removed.

Deleting .git directory from /var/www/html/web/modules/contrib/field_redirection/.git

Comments

Thanks a lot for this tip, exactly what I was looking for. However, when those .git directories got deleted, the next time this module should be updated, the composer process stops with the message "Update failed (The .git directory is missing". I can confirm that I want to reinstall and all is like before.

To avoid this message I tried the option "--no-interaction" but that simply stops the process and doesn't install anything.

Any idea if any other command line option would prevent that from happening?

Here's another way to do the same thing that doesn't involve adding a new dependency. You can add a line (first one below) to the "scripts" section of the composer.json:


"scripts": {
"remove-git-submodules" : "find . -mindepth 2 -type d -name .git | xargs rm -rf",
"pre-install-cmd": [
"DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
],
"pre-update-cmd": [
"DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
],
"post-install-cmd": [
"DrupalProject\\composer\\ScriptHandler::createRequiredFiles",
"@remove-git-submodules"
],
"post-update-cmd": [
"DrupalProject\\composer\\ScriptHandler::createRequiredFiles",
"@remove-git-submodules"
]
},

Good tip for that scenario, but I'd add a note about committing dependencies to your repository is bad practice.

Submitted by johnzzon (not verified) on Thu, 12/13/2018 - 09:03

Just to add more information to the previous comment, the only thing that needs to be committed when adding a new module is the new line in composer.json (and possibly changes made to the lock file after a rebuild).

The whole point of using Composer is that it manages dependencies for you. You don't need to commit them, and you can avoid this whole problem with submodules altogether. When you deploy, you run a composer install command, which builds everything needed.

Agreed, we never commit dependencies ourselves. But still the .git directories in sub-directories can get into your way: one sample is PhpStorm which wants to manage those repositories when available and I have to disable them each and every time a new one gets recognised. Another example is caching in CI/CD with GitLab where you could easily tell that all untracked files should be cached but that's ignoring those that come with .git directories themselves.

Both scenarios might be bugs or glitches with those other tools but I can also imagine when I why their current behavior could make sense in other contexts.

Build workflows are not the only game in town.

Git workflows are simple, still work well, and fit the majority of small development needs. The development snobbery around the whole build vs git workflow thing is really quite unfortunate.

No, I'm not going to stand up learn an entire chain of build tools for a simple one developer website development workflow just because a bunch of enterprise and big shop developers decided it was 'best practice'.

And composer doesn't belong on a production site.

The Git workflow still works well for plenty of use cases.

Ideally there should be a simple way to tell the parent repo to simply ignore and .git folders in subdirectories.

Submitted by just-passin-thru (not verified) on Thu, 01/24/2019 - 14:32

Add new comment

The content of this field is kept private and will not be shown publicly.