gin / env-merger
Smart, format-preserving .env merger with interactive conflict resolution and Laravel integration
Requires
- php: ^8.2
- laravel/prompts: ^0.1 || ^0.2 || ^0.3
- symfony/console: ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- pestphp/pest: ^2.0 || ^3.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Smart, format-preserving
.envmerger with interactive conflict resolution and Laravel Artisan integration.
gin/env-merger allows you to merge existing .env files with environment-specific files (e.g. .env.production, .env.staging, .env.local) via command-line switches or a rich interactive merge wizard.
✨ Features
- 🧠 Format & Comment Preservation: Retains all comments, section headers, blank lines, quotes, and inline comments in the base
.envfile. - ⚡ Framework-Agnostic Binary: Works out-of-the-box in any PHP project or globally via
vendor/bin/env-merge. - 🚀 Laravel Auto-Discovery: Automatically exposes
php artisan env:mergeinside Laravel applications. - 💬 Interactive Conflict Wizard: Powered by
laravel/promptsto inspect side-by-side diffs and choose between Base, Incoming, Custom values, or bulk accept. - 🔒 Secret Masking: Sensitive keys (
PASSWORD,SECRET,KEY,TOKEN,CREDENTIAL, etc.) are masked as••••••by default in terminal outputs and diffs for security. - 🛡️ Safety Backups: Automatically creates timestamped backup copies (
.env.backup.YYYYMMDD_His) before modifying files. - 🔍 Dry-Run Preview: Inspect diffs and affected keys without altering any files on disk.
📦 Installation
In an existing project (Laravel, Symfony, or Generic PHP)
composer require gin/env-merger --dev
Globally via Composer
composer global require gin/env-merger
🚀 Usage
Quick Start
Merge .env.production into .env:
./vendor/bin/env-merge .env .env.production
Or inside Laravel:
php artisan env:merge .env .env.production
If you run without arguments, env-merge automatically scans for available .env.* files in the current directory and lets you pick one.
Interactive Mode
Run the step-by-step interactive resolution wizard when conflicts exist:
./vendor/bin/env-merge -i
Or:
./vendor/bin/env-merge .env .env.staging --interactive
For each differing key, you will see a prompt:
Conflict [1/3] for key: DB_PASSWORD
Base value: ••••••••••
Incoming value: ••••••••••
Select resolution for DB_PASSWORD:
❯ Use Incoming [••••••••••]
Keep Base [••••••••••]
Enter Custom Value...
Accept All Remaining Incoming
Keep All Remaining Base
Dry-Run Preview
Preview all changes without touching any files:
./vendor/bin/env-merge .env .env.production --dry-run
Revealing Secrets in Output
By default, sensitive credentials are obfuscated. To display plain-text values:
./vendor/bin/env-merge .env .env.production --show-secrets
Specifying Output File
Write the merged result to a new file instead of updating in-place:
./vendor/bin/env-merge .env .env.production --output=.env.deploy
Non-Interactive Conflict Strategies
Configure how conflicts are resolved in CI/CD pipelines:
incoming(default): Target/incoming file overwrites base values.keep-base: Retains base values; only appends new keys from target.fail: Aborts with an error code if any conflicting values exist.
./vendor/bin/env-merge .env .env.production --strategy=keep-base
🛠 Command Reference
env-merge [base] [target] [options]
| Argument / Option | Default | Description |
|---|---|---|
base |
.env |
Path to the base environment file |
target |
auto | Path to incoming environment file (e.g. .env.production) |
-o, --output=PATH |
in-place | Destination file path for merged output |
-i, --interactive |
false |
Launch interactive conflict resolution wizard |
-s, --strategy=NAME |
incoming |
Conflict strategy: incoming, keep-base, fail |
--dry-run |
false |
Preview changes and diff without modifying files |
--backup / --no-backup |
true |
Create timestamped backup file before overwriting |
--show-secrets |
false |
Display unmasked secret values in diffs and prompts |
🧪 Testing
Run the test suite using Pest PHP:
./vendor/bin/pest
📄 License
This package is open-source software licensed under the MIT license.