gitconfig-man 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +69 -0
- package/EXAMPLES.md +274 -0
- package/LICENSE +16 -0
- package/README.md +309 -0
- package/index.js +3 -0
- package/package.json +102 -0
- package/src/cli.js +15 -0
- package/src/cliOptions.js +55 -0
- package/src/commands.js +351 -0
- package/src/constants.js +17 -0
- package/src/extendConfig.js +109 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Contributing to gitconfig-man
|
|
2
|
+
|
|
3
|
+
Thank you for considering contributing to gitconfig-man! We welcome contributions from everyone.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Clone your fork: `git clone https://github.com/yourusername/gitconfig-man.git`
|
|
9
|
+
3. Create a new branch: `git checkout -b feature/your-feature-name`
|
|
10
|
+
4. Make your changes
|
|
11
|
+
5. Test your changes
|
|
12
|
+
6. Commit your changes: `git commit -m 'Add some feature'`
|
|
13
|
+
7. Push to the branch: `git push origin feature/your-feature-name`
|
|
14
|
+
8. Submit a pull request
|
|
15
|
+
|
|
16
|
+
## Development Setup
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install dependencies
|
|
20
|
+
npm install
|
|
21
|
+
|
|
22
|
+
# Run tests
|
|
23
|
+
npm test
|
|
24
|
+
|
|
25
|
+
# Run tests in watch mode
|
|
26
|
+
npm run test:watch
|
|
27
|
+
|
|
28
|
+
# Run tests with coverage
|
|
29
|
+
npm run test:ci
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Code Style
|
|
33
|
+
|
|
34
|
+
- Use consistent indentation (2 spaces)
|
|
35
|
+
- Follow the existing code style
|
|
36
|
+
- Write clear, descriptive commit messages
|
|
37
|
+
- Add comments for complex logic
|
|
38
|
+
- Keep functions small and focused
|
|
39
|
+
|
|
40
|
+
## Testing
|
|
41
|
+
|
|
42
|
+
- Write tests for new features
|
|
43
|
+
- Ensure all tests pass before submitting PR
|
|
44
|
+
- Maintain or improve code coverage
|
|
45
|
+
|
|
46
|
+
## Reporting Issues
|
|
47
|
+
|
|
48
|
+
When reporting issues, please include:
|
|
49
|
+
|
|
50
|
+
- Your OS and Node.js version
|
|
51
|
+
- Steps to reproduce the issue
|
|
52
|
+
- Expected behavior
|
|
53
|
+
- Actual behavior
|
|
54
|
+
- Any error messages or logs
|
|
55
|
+
|
|
56
|
+
## Pull Request Guidelines
|
|
57
|
+
|
|
58
|
+
- Keep PRs focused on a single feature or fix
|
|
59
|
+
- Update documentation as needed
|
|
60
|
+
- Add tests for new features
|
|
61
|
+
- Ensure all tests pass
|
|
62
|
+
- Keep commit history clean
|
|
63
|
+
|
|
64
|
+
## Questions?
|
|
65
|
+
|
|
66
|
+
Feel free to open an issue for any questions or clarifications.
|
|
67
|
+
|
|
68
|
+
Thank you for contributing! 🎉
|
|
69
|
+
|
package/EXAMPLES.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# gitconfig-man Examples
|
|
2
|
+
|
|
3
|
+
This document provides practical examples of using gitconfig-man in different scenarios.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Installation and Initialization
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install globally
|
|
11
|
+
npm install -g gitconfig-man
|
|
12
|
+
|
|
13
|
+
# Initialize (saves your current git config as 'default' profile)
|
|
14
|
+
gitconfig-man -i
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Example 1: Personal and Work Profiles
|
|
18
|
+
|
|
19
|
+
### Setup
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Initialize with current config as default
|
|
23
|
+
gitconfig-man -i
|
|
24
|
+
|
|
25
|
+
# Create work profile
|
|
26
|
+
gitconfig-man -c work
|
|
27
|
+
|
|
28
|
+
# Configure work settings
|
|
29
|
+
git config --global user.name "John Doe"
|
|
30
|
+
git config --global user.email "john.doe@company.com"
|
|
31
|
+
git config --global core.editor "code"
|
|
32
|
+
|
|
33
|
+
# Create personal profile
|
|
34
|
+
gitconfig-man -c personal
|
|
35
|
+
|
|
36
|
+
# Configure personal settings
|
|
37
|
+
git config --global user.name "John"
|
|
38
|
+
git config --global user.email "john@personal.com"
|
|
39
|
+
git config --global core.editor "vim"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Daily Usage
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Switch to work profile
|
|
46
|
+
gitconfig-man -s work
|
|
47
|
+
|
|
48
|
+
# Work on company projects...
|
|
49
|
+
git clone git@github.com:company/project.git
|
|
50
|
+
cd project
|
|
51
|
+
git commit -m "Work commit" # Uses work email
|
|
52
|
+
|
|
53
|
+
# Switch to personal profile
|
|
54
|
+
gitconfig-man -s personal
|
|
55
|
+
|
|
56
|
+
# Work on personal projects...
|
|
57
|
+
git clone git@github.com:john/personal-project.git
|
|
58
|
+
cd personal-project
|
|
59
|
+
git commit -m "Personal commit" # Uses personal email
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Example 2: Multiple Client Projects
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Client A configuration
|
|
66
|
+
gitconfig-man -c client-a
|
|
67
|
+
git config --global user.name "Your Name"
|
|
68
|
+
git config --global user.email "you@clienta.com"
|
|
69
|
+
git config --global commit.gpgsign true
|
|
70
|
+
|
|
71
|
+
# Client B configuration
|
|
72
|
+
gitconfig-man -c client-b
|
|
73
|
+
git config --global user.name "Your Name"
|
|
74
|
+
git config --global user.email "you@clientb.com"
|
|
75
|
+
git config --global commit.gpgsign false
|
|
76
|
+
|
|
77
|
+
# Switch between clients
|
|
78
|
+
gitconfig-man -s client-a # When working on Client A projects
|
|
79
|
+
gitconfig-man -s client-b # When working on Client B projects
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Example 3: Different Development Environments
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Production-like config
|
|
86
|
+
gitconfig-man -c production
|
|
87
|
+
git config --global core.autocrlf false
|
|
88
|
+
git config --global core.editor "nano"
|
|
89
|
+
git config --global pull.rebase true
|
|
90
|
+
|
|
91
|
+
# Development config
|
|
92
|
+
gitconfig-man -c development
|
|
93
|
+
git config --global core.autocrlf true
|
|
94
|
+
git config --global core.editor "code --wait"
|
|
95
|
+
git config --global pull.rebase false
|
|
96
|
+
git config --global alias.st status
|
|
97
|
+
git config --global alias.co checkout
|
|
98
|
+
git config --global alias.br branch
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Example 4: Open Source vs Private Projects
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Open source profile
|
|
105
|
+
gitconfig-man -c opensource
|
|
106
|
+
git config --global user.name "Your Public Name"
|
|
107
|
+
git config --global user.email "public@email.com"
|
|
108
|
+
git config --global commit.gpgsign true
|
|
109
|
+
git config --global user.signingkey ABC123DEF
|
|
110
|
+
|
|
111
|
+
# Private/Corporate profile
|
|
112
|
+
gitconfig-man -c corporate
|
|
113
|
+
git config --global user.name "Your Corporate Name"
|
|
114
|
+
git config --global user.email "name@company.com"
|
|
115
|
+
git config --global commit.gpgsign false
|
|
116
|
+
git config --global http.sslVerify true
|
|
117
|
+
git config --global http.proxy http://corporate-proxy:8080
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Example 5: Interactive Mode
|
|
121
|
+
|
|
122
|
+
### Create Profile Interactively
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
gitconfig-man -c
|
|
126
|
+
# ? Enter name for the new profile: staging
|
|
127
|
+
# ✓ Saved current git config to 'work' profile
|
|
128
|
+
# ✓ Created new profile: staging
|
|
129
|
+
# ? Do you want to switch to newly created profile (staging)? Yes
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Switch Profile Interactively
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
gitconfig-man -s
|
|
136
|
+
# ? Select profile to switch to: (Use arrow keys or type to search)
|
|
137
|
+
# ❯ default
|
|
138
|
+
# work
|
|
139
|
+
# personal
|
|
140
|
+
# staging
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Delete Profile Interactively
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
gitconfig-man -d
|
|
147
|
+
# ? Select profile to delete: (Use arrow keys or type to search)
|
|
148
|
+
# ❯ staging
|
|
149
|
+
# testing
|
|
150
|
+
# ? Are you sure you want to delete profile 'staging'? Yes
|
|
151
|
+
# ✓ Successfully deleted profile 'staging'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Example 6: List All Profiles
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
gitconfig-man -ls
|
|
158
|
+
|
|
159
|
+
# Available profiles:
|
|
160
|
+
# • default
|
|
161
|
+
# ✓ work (active)
|
|
162
|
+
# • personal
|
|
163
|
+
# • client-a
|
|
164
|
+
# • client-b
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Example 7: Complex Git Configuration
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Create a profile with extensive configuration
|
|
171
|
+
gitconfig-man -c advanced
|
|
172
|
+
|
|
173
|
+
# User settings
|
|
174
|
+
git config --global user.name "Developer Name"
|
|
175
|
+
git config --global user.email "dev@example.com"
|
|
176
|
+
|
|
177
|
+
# Core settings
|
|
178
|
+
git config --global core.editor "vim"
|
|
179
|
+
git config --global core.autocrlf input
|
|
180
|
+
git config --global core.whitespace trailing-space,space-before-tab
|
|
181
|
+
|
|
182
|
+
# Color settings
|
|
183
|
+
git config --global color.ui true
|
|
184
|
+
git config --global color.status auto
|
|
185
|
+
git config --global color.branch auto
|
|
186
|
+
|
|
187
|
+
# Aliases
|
|
188
|
+
git config --global alias.st status
|
|
189
|
+
git config --global alias.co checkout
|
|
190
|
+
git config --global alias.br branch
|
|
191
|
+
git config --global alias.ci commit
|
|
192
|
+
git config --global alias.unstage 'reset HEAD --'
|
|
193
|
+
git config --global alias.last 'log -1 HEAD'
|
|
194
|
+
git config --global alias.visual '!gitk'
|
|
195
|
+
|
|
196
|
+
# Merge and diff tools
|
|
197
|
+
git config --global merge.tool vimdiff
|
|
198
|
+
git config --global diff.tool vimdiff
|
|
199
|
+
|
|
200
|
+
# Push settings
|
|
201
|
+
git config --global push.default simple
|
|
202
|
+
|
|
203
|
+
# Pull settings
|
|
204
|
+
git config --global pull.rebase true
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Tips and Tricks
|
|
208
|
+
|
|
209
|
+
### Verify Current Configuration
|
|
210
|
+
|
|
211
|
+
After switching profiles, verify your settings:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
gitconfig-man -s work
|
|
215
|
+
git config --global --list
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Backup Profiles
|
|
219
|
+
|
|
220
|
+
The profiles are stored as JSON files in `~/.gitconfigman/`. You can backup this directory:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
cp -r ~/.gitconfigman ~/gitconfig-backup
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Restore from Backup
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
cp -r ~/gitconfig-backup ~/.gitconfigman
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Reset to Default
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
gitconfig-man -s default
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### View Specific Settings
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
git config --global user.name
|
|
242
|
+
git config --global user.email
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Troubleshooting
|
|
246
|
+
|
|
247
|
+
### Check Active Profile
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
gitconfig-man -ls
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The active profile is marked with ✓
|
|
254
|
+
|
|
255
|
+
### Verify Git Config Location
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
git config --list --show-origin
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
This shows where each setting is coming from.
|
|
262
|
+
|
|
263
|
+
### Manual Profile Editing
|
|
264
|
+
|
|
265
|
+
Profiles are stored in `~/.gitconfigman/` as JSON files. You can edit them manually if needed:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
cat ~/.gitconfigman/work.json
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
For more information, see the [README.md](README.md) or run `gitconfig-man -h`.
|
|
274
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, gitconfig-man contributors
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
gitconfig-man
|
|
2
|
+
=============
|
|
3
|
+
|
|
4
|
+
<!-- Build & Test Status -->
|
|
5
|
+
[](https://github.com/yourusername/gitconfig-man/actions/workflows/ci.yml)
|
|
6
|
+
[](https://github.com/yourusername/gitconfig-man/actions/workflows/ci.yml)
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
<!-- Package Info -->
|
|
11
|
+
[](https://www.npmjs.com/package/gitconfig-man)
|
|
12
|
+
[](https://www.npmjs.com/package/gitconfig-man)
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
<!-- Platform & Standards -->
|
|
16
|
+
[](https://opensource.org/licenses/ISC)
|
|
17
|
+
[](https://github.com/yourusername/gitconfig-man/graphs/commit-activity)
|
|
18
|
+
[](CONTRIBUTING.md)
|
|
19
|
+
|
|
20
|
+
<!-- Repository Stats (activate after first push) -->
|
|
21
|
+
[](https://github.com/yourusername/gitconfig-man/commits)
|
|
22
|
+
[](https://github.com/yourusername/gitconfig-man/issues)
|
|
23
|
+
[](https://github.com/yourusername/gitconfig-man/pulls)
|
|
24
|
+
[](https://github.com/yourusername/gitconfig-man/stargazers)
|
|
25
|
+
|
|
26
|
+
A sophisticated CLI tool to manage multiple git config profiles and switch between different git configurations with ease & grace.
|
|
27
|
+
|
|
28
|
+
## CI/CD Status
|
|
29
|
+
|
|
30
|
+
| Workflow | Status |
|
|
31
|
+
|----------|--------|
|
|
32
|
+
| **Build & Test** | [](https://github.com/yourusername/gitconfig-man/actions/workflows/ci.yml) |
|
|
33
|
+
| **Test Coverage** |  |
|
|
34
|
+
| **NPM Publish** |  |
|
|
35
|
+
|
|
36
|
+
> 📊 **Note:** Some badges will activate after first push to GitHub. GitHub Actions badges will work after setting up CI/CD workflows.
|
|
37
|
+
|
|
38
|
+
### Platform Support
|
|
39
|
+
|
|
40
|
+
Tests run automatically on:
|
|
41
|
+
- ✅ **Ubuntu** (Linux) - Node.js 16.x, 18.x, 20.x
|
|
42
|
+
- ✅ **macOS** - Node.js 16.x, 18.x, 20.x
|
|
43
|
+
- ✅ **Windows** - Node.js 16.x, 18.x, 20.x
|
|
44
|
+
|
|
45
|
+
**19 Tests** | **19%+ Coverage** | **All Tests Passing**
|
|
46
|
+
|
|
47
|
+
## Overview
|
|
48
|
+
-----------
|
|
49
|
+
|
|
50
|
+
Managing different git configurations for different projects or accounts can be tedious. This package makes your life easier by creating different git config profiles and managing them for you. Perfect for developers who need to switch between personal and work accounts, or manage multiple git identities.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
----------------
|
|
54
|
+
|
|
55
|
+
``` sh
|
|
56
|
+
npm install -g gitconfig-man
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
--------
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
➜ ~ gitconfig-man -h
|
|
64
|
+
|
|
65
|
+
Git Config Man - Git Config Profile Manager
|
|
66
|
+
|
|
67
|
+
Usage: gitconfig-man <command> [options]
|
|
68
|
+
|
|
69
|
+
Commands:
|
|
70
|
+
-i Initialize gitconfig-man and create default profile
|
|
71
|
+
-c [name] Create new git config profile (interactive if no name)
|
|
72
|
+
-s [name] Switch to another git config profile (interactive if no name)
|
|
73
|
+
-d [name] Delete git config profile (interactive if no name)
|
|
74
|
+
-ls List all profiles
|
|
75
|
+
-h Show help
|
|
76
|
+
-v Show version
|
|
77
|
+
|
|
78
|
+
Tip: Run commands without arguments for interactive mode
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### ✨ Interactive Features
|
|
82
|
+
|
|
83
|
+
gitconfig-man supports **interactive mode with autocomplete**! Simply run commands without arguments to get an enhanced interactive experience:
|
|
84
|
+
|
|
85
|
+
- **`gitconfig-man -s`** - Interactive profile switcher with autocomplete
|
|
86
|
+
- **`gitconfig-man -c`** - Interactive profile creator with validation
|
|
87
|
+
- **`gitconfig-man -d`** - Interactive profile deletion with confirmation
|
|
88
|
+
|
|
89
|
+
### Initialization
|
|
90
|
+
|
|
91
|
+
Calling `gitconfig-man -i` creates a `~/.gitconfigman/` directory if it doesn't exist, and saves your current global git config as the 'default' profile.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
➜ ~ gitconfig-man -i
|
|
95
|
+
|
|
96
|
+
⚙️ Initializing Git Config Man...
|
|
97
|
+
|
|
98
|
+
✓ Created gitconfig-man directory: /Users/username/.gitconfigman
|
|
99
|
+
✓ Created default profile
|
|
100
|
+
✓ Activated 'default' profile
|
|
101
|
+
|
|
102
|
+
✨ Git Config Man initialized successfully!
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Create a new git config profile
|
|
106
|
+
|
|
107
|
+
With profile name:
|
|
108
|
+
```
|
|
109
|
+
➜ ~ gitconfig-man -c work
|
|
110
|
+
✓ Saved current git config to 'default' profile
|
|
111
|
+
✓ Created new profile: work
|
|
112
|
+
? Do you want to switch to newly created profile (work)? (Y/n) y
|
|
113
|
+
✓ Activated profile 'work'
|
|
114
|
+
Current git config has been cleared. Configure it using 'git config --global' commands.
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Interactive mode** (just run without name):
|
|
118
|
+
```
|
|
119
|
+
➜ ~ gitconfig-man -c
|
|
120
|
+
? Enter name for the new profile: personal
|
|
121
|
+
✓ Saved current git config to 'default' profile
|
|
122
|
+
✓ Created new profile: personal
|
|
123
|
+
? Do you want to switch to newly created profile (personal)? (Y/n)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
After creating a new profile and switching to it, your global git config will be cleared. You can then configure it using standard git commands:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
git config --global user.name "Your Name"
|
|
130
|
+
git config --global user.email "your.email@example.com"
|
|
131
|
+
git config --global core.editor "vim"
|
|
132
|
+
# ... any other git config settings you need
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### List available git config profiles
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
➜ ~ gitconfig-man -ls
|
|
139
|
+
|
|
140
|
+
Available profiles:
|
|
141
|
+
• default
|
|
142
|
+
✓ work (active)
|
|
143
|
+
• personal
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Switch to a specific git config profile
|
|
147
|
+
|
|
148
|
+
With profile name:
|
|
149
|
+
```
|
|
150
|
+
➜ ~ gitconfig-man -s default
|
|
151
|
+
✓ Saved current git config to 'work' profile
|
|
152
|
+
✓ Activated profile 'default'
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Interactive mode with autocomplete** (just run without name):
|
|
156
|
+
```
|
|
157
|
+
➜ ~ gitconfig-man -s
|
|
158
|
+
? Select profile to switch to: (Use arrow keys or type to search)
|
|
159
|
+
❯ default
|
|
160
|
+
personal
|
|
161
|
+
```
|
|
162
|
+
Start typing to filter profiles with autocomplete!
|
|
163
|
+
|
|
164
|
+
### Delete a specific git config profile
|
|
165
|
+
|
|
166
|
+
With profile name:
|
|
167
|
+
```
|
|
168
|
+
➜ ~ gitconfig-man -d work
|
|
169
|
+
✓ Successfully deleted profile 'work'
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Interactive mode with autocomplete and confirmation** (just run without name):
|
|
173
|
+
```
|
|
174
|
+
➜ ~ gitconfig-man -d
|
|
175
|
+
? Select profile to delete: (Use arrow keys or type to search)
|
|
176
|
+
❯ work
|
|
177
|
+
staging
|
|
178
|
+
? Are you sure you want to delete profile 'work'? (y/N) y
|
|
179
|
+
✓ Successfully deleted profile 'work'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Get the current gitconfig-man version
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
➜ ~ gitconfig-man -v
|
|
186
|
+
gitconfig-man version 1.0.0
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## How It Works
|
|
190
|
+
----------------
|
|
191
|
+
|
|
192
|
+
gitconfig-man works by:
|
|
193
|
+
|
|
194
|
+
1. Storing your git global configurations as JSON files in `~/.gitconfigman/`
|
|
195
|
+
2. Each profile is saved as `profilename.json`
|
|
196
|
+
3. When you switch profiles, it:
|
|
197
|
+
- Saves your current git config to the active profile
|
|
198
|
+
- Clears all global git config settings
|
|
199
|
+
- Applies the settings from the new profile
|
|
200
|
+
|
|
201
|
+
This means all your `git config --global` settings are preserved and can be switched instantly!
|
|
202
|
+
|
|
203
|
+
## Common Use Cases
|
|
204
|
+
--------------------
|
|
205
|
+
|
|
206
|
+
### Personal and Work Accounts
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Initialize
|
|
210
|
+
gitconfig-man -i
|
|
211
|
+
|
|
212
|
+
# Create work profile
|
|
213
|
+
gitconfig-man -c work
|
|
214
|
+
git config --global user.name "Work Name"
|
|
215
|
+
git config --global user.email "work@company.com"
|
|
216
|
+
|
|
217
|
+
# Create personal profile
|
|
218
|
+
gitconfig-man -c personal
|
|
219
|
+
git config --global user.name "Personal Name"
|
|
220
|
+
git config --global user.email "personal@email.com"
|
|
221
|
+
|
|
222
|
+
# Switch between them
|
|
223
|
+
gitconfig-man -s work
|
|
224
|
+
gitconfig-man -s personal
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Different Project Configurations
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Profile for open source projects
|
|
231
|
+
gitconfig-man -c opensource
|
|
232
|
+
git config --global user.name "Your Name"
|
|
233
|
+
git config --global user.email "opensource@email.com"
|
|
234
|
+
git config --global core.editor "vim"
|
|
235
|
+
|
|
236
|
+
# Profile for client projects
|
|
237
|
+
gitconfig-man -c client
|
|
238
|
+
git config --global user.name "Professional Name"
|
|
239
|
+
git config --global user.email "client@company.com"
|
|
240
|
+
git config --global core.editor "nano"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Requirements
|
|
244
|
+
---------------
|
|
245
|
+
|
|
246
|
+
- Node.js >= 16.0.0
|
|
247
|
+
- npm >= 7.0.0
|
|
248
|
+
- Git installed and accessible via command line
|
|
249
|
+
|
|
250
|
+
## Development
|
|
251
|
+
-----------
|
|
252
|
+
|
|
253
|
+
### Running Tests
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Run all tests
|
|
257
|
+
npm test
|
|
258
|
+
|
|
259
|
+
# Run tests in watch mode
|
|
260
|
+
npm run test:watch
|
|
261
|
+
|
|
262
|
+
# Run tests with coverage
|
|
263
|
+
npm run test:ci
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Project Structure
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
gitconfig-man/
|
|
270
|
+
├── src/
|
|
271
|
+
│ ├── __tests__/ # Test files
|
|
272
|
+
│ ├── cli.js # CLI entry point
|
|
273
|
+
│ ├── cliOptions.js # CLI argument parsing
|
|
274
|
+
│ ├── commands.js # Command implementations
|
|
275
|
+
│ ├── constants.js # Constants and configuration
|
|
276
|
+
│ └── extendConfig.js # Git config utilities
|
|
277
|
+
├── .github/
|
|
278
|
+
│ └── workflows/ # GitHub Actions CI/CD
|
|
279
|
+
├── index.js # Main entry point
|
|
280
|
+
└── package.json
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Contributing
|
|
284
|
+
|
|
285
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
286
|
+
|
|
287
|
+
1. Fork the repository
|
|
288
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
289
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
290
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
291
|
+
5. Open a Pull Request
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
----------
|
|
295
|
+
|
|
296
|
+
ISC, a permissive free software license published by the Internet Software Consortium.
|
|
297
|
+
|
|
298
|
+
## Notes
|
|
299
|
+
--------
|
|
300
|
+
|
|
301
|
+
- The 'default' profile cannot be deleted
|
|
302
|
+
- You cannot delete the currently active profile
|
|
303
|
+
- All git config changes are saved automatically when switching profiles
|
|
304
|
+
- Profile files are stored in `~/.gitconfigman/` directory
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
Made with ❤️ for developers who manage multiple git identities.
|
|
309
|
+
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gitconfig-man",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A cli tool to manage multiple git config profiles and switch between different git configurations with ease & grace.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": "index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "jest --coverage",
|
|
9
|
+
"test:watch": "jest --watch",
|
|
10
|
+
"test:ci": "jest --coverage --ci --maxWorkers=2"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/yourusername/gitconfig-man.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"git",
|
|
18
|
+
"config",
|
|
19
|
+
"gitconfig",
|
|
20
|
+
"profile",
|
|
21
|
+
"manage",
|
|
22
|
+
"git config",
|
|
23
|
+
"git profiles",
|
|
24
|
+
"git user",
|
|
25
|
+
"git email",
|
|
26
|
+
"multiple accounts",
|
|
27
|
+
"config manager",
|
|
28
|
+
"gitconfig-man"
|
|
29
|
+
],
|
|
30
|
+
"author": "Your Name",
|
|
31
|
+
"license": "ISC",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/yourusername/gitconfig-man/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/yourusername/gitconfig-man#readme",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=16.0.0",
|
|
38
|
+
"npm": ">=7.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"chalk": "^4.1.2",
|
|
42
|
+
"fs-extra": "^10.0.0",
|
|
43
|
+
"inquirer": "^8.2.5",
|
|
44
|
+
"inquirer-autocomplete-prompt": "^2.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"jest": "^29.7.0",
|
|
48
|
+
"jest-junit": "^16.0.0",
|
|
49
|
+
"@types/jest": "^29.5.11"
|
|
50
|
+
},
|
|
51
|
+
"jest": {
|
|
52
|
+
"testEnvironment": "node",
|
|
53
|
+
"coverageDirectory": "coverage",
|
|
54
|
+
"collectCoverageFrom": [
|
|
55
|
+
"src/**/*.js",
|
|
56
|
+
"!src/**/*.test.js",
|
|
57
|
+
"!src/**/*.spec.js",
|
|
58
|
+
"!src/__tests__/helpers.js",
|
|
59
|
+
"!src/__tests__/testUtils.js",
|
|
60
|
+
"!**/node_modules/**",
|
|
61
|
+
"!**/coverage/**"
|
|
62
|
+
],
|
|
63
|
+
"testMatch": [
|
|
64
|
+
"**/__tests__/**/*.test.js",
|
|
65
|
+
"**/?(*.)+(spec|test).js"
|
|
66
|
+
],
|
|
67
|
+
"testPathIgnorePatterns": [
|
|
68
|
+
"/node_modules/",
|
|
69
|
+
"helpers.js",
|
|
70
|
+
"testUtils.js"
|
|
71
|
+
],
|
|
72
|
+
"coveragePathIgnorePatterns": [
|
|
73
|
+
"/node_modules/",
|
|
74
|
+
"/coverage/",
|
|
75
|
+
"/__tests__/helpers.js",
|
|
76
|
+
"/__tests__/testUtils.js"
|
|
77
|
+
],
|
|
78
|
+
"coverageThreshold": {
|
|
79
|
+
"global": {
|
|
80
|
+
"branches": 0,
|
|
81
|
+
"functions": 0,
|
|
82
|
+
"lines": 0,
|
|
83
|
+
"statements": 0
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"reporters": [
|
|
87
|
+
"default",
|
|
88
|
+
[
|
|
89
|
+
"jest-junit",
|
|
90
|
+
{
|
|
91
|
+
"outputDirectory": "coverage",
|
|
92
|
+
"outputName": "junit.xml",
|
|
93
|
+
"classNameTemplate": "{classname}",
|
|
94
|
+
"titleTemplate": "{title}",
|
|
95
|
+
"ancestorSeparator": " › ",
|
|
96
|
+
"usePathForSuiteName": "true"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { init, run, prepareArgs, getName } = require("./cliOptions");
|
|
2
|
+
|
|
3
|
+
async function gitConfigCli() {
|
|
4
|
+
let args = prepareArgs(process.argv);
|
|
5
|
+
let name = getName(process.argv);
|
|
6
|
+
if (name === 'ls') {
|
|
7
|
+
name = '';
|
|
8
|
+
args.push('ls');
|
|
9
|
+
}
|
|
10
|
+
init();
|
|
11
|
+
await run(args, name);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = gitConfigCli;
|
|
15
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const commands = require("./commands");
|
|
2
|
+
const { cliOptions, options } = require("./constants");
|
|
3
|
+
|
|
4
|
+
const generateOption = function (option, name, help) {
|
|
5
|
+
options.push({
|
|
6
|
+
option,
|
|
7
|
+
name,
|
|
8
|
+
method: name,
|
|
9
|
+
help,
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const generateOptions = function () {
|
|
14
|
+
cliOptions.forEach((op) => generateOption(...op));
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const init = function () {
|
|
18
|
+
generateOptions();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const run = async function (args, name) {
|
|
22
|
+
if (!args.length) {
|
|
23
|
+
commands.help(options);
|
|
24
|
+
return process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
for (let arg of args) {
|
|
27
|
+
const command = options.find((op) => op.name === arg || op.option === arg);
|
|
28
|
+
if (!command) {
|
|
29
|
+
commands.help(options);
|
|
30
|
+
return process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
const fn = commands[command.method];
|
|
33
|
+
await fn(name);
|
|
34
|
+
}
|
|
35
|
+
process.exit();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const prepareArgs = function (argv) {
|
|
39
|
+
return argv
|
|
40
|
+
.slice(2, argv.length)
|
|
41
|
+
.filter((arg) => arg.charAt(0) === "-")
|
|
42
|
+
.map((arg) => arg.replace(/\-/g, ""));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const getName = function (argv) {
|
|
46
|
+
return argv.slice(2).find((arg) => arg.charAt(0) !== "-");
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
prepareArgs,
|
|
51
|
+
getName,
|
|
52
|
+
init,
|
|
53
|
+
run,
|
|
54
|
+
};
|
|
55
|
+
|
package/src/commands.js
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
const fs = require("fs-extra");
|
|
2
|
+
const os = require("os");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const inquirer = require("inquirer");
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const autocompletePrompt = require("inquirer-autocomplete-prompt");
|
|
7
|
+
const { options } = require("./constants");
|
|
8
|
+
const {
|
|
9
|
+
getGlobalConfig,
|
|
10
|
+
clearGlobalConfig,
|
|
11
|
+
applyGlobalConfig,
|
|
12
|
+
saveConfigToFile,
|
|
13
|
+
loadConfigFromFile,
|
|
14
|
+
} = require("./extendConfig");
|
|
15
|
+
|
|
16
|
+
// Register autocomplete prompt
|
|
17
|
+
inquirer.registerPrompt("autocomplete", autocompletePrompt);
|
|
18
|
+
|
|
19
|
+
const CONFIGMAN_DIR_PATH = path.join(os.homedir(), ".gitconfigman");
|
|
20
|
+
const CONFIGMAN_PATH = path.join(CONFIGMAN_DIR_PATH, ".gitconfigman");
|
|
21
|
+
const IS_INITIALIZED = fs.existsSync(CONFIGMAN_DIR_PATH);
|
|
22
|
+
let CONFIGMAN_CONTENT = IS_INITIALIZED
|
|
23
|
+
? JSON.parse(fs.readFileSync(CONFIGMAN_PATH))
|
|
24
|
+
: undefined;
|
|
25
|
+
|
|
26
|
+
const logger = (type, message) => {
|
|
27
|
+
if (Array.isArray(message)) {
|
|
28
|
+
message = message.join(" ");
|
|
29
|
+
}
|
|
30
|
+
switch (type) {
|
|
31
|
+
case "success":
|
|
32
|
+
console.log(chalk.green(message ? message : ""));
|
|
33
|
+
break;
|
|
34
|
+
case "error":
|
|
35
|
+
console.log(chalk.red(message ? message : ""));
|
|
36
|
+
break;
|
|
37
|
+
case "warning":
|
|
38
|
+
console.log(chalk.yellow(message ? message : ""));
|
|
39
|
+
break;
|
|
40
|
+
case "info":
|
|
41
|
+
console.log(chalk.cyan(message ? message : ""));
|
|
42
|
+
break;
|
|
43
|
+
default:
|
|
44
|
+
console.log(message ? message : "");
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const help = function () {
|
|
50
|
+
console.log();
|
|
51
|
+
console.log(chalk.bold.cyan("Git Config Man") + chalk.gray(" - Git Config Profile Manager"));
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(chalk.bold("Usage:") + " gitconfig-man <command> [options]");
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(chalk.bold("Commands:"));
|
|
56
|
+
for (let option of options) {
|
|
57
|
+
console.log(chalk.gray(option.help));
|
|
58
|
+
}
|
|
59
|
+
console.log();
|
|
60
|
+
console.log(chalk.dim("Tip: Run commands without arguments for interactive mode"));
|
|
61
|
+
console.log();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const init = function () {
|
|
65
|
+
if (!fs.existsSync(CONFIGMAN_DIR_PATH)) {
|
|
66
|
+
console.log(chalk.cyan("\n⚙️ Initializing Git Config Man...\n"));
|
|
67
|
+
fs.mkdirSync(CONFIGMAN_DIR_PATH);
|
|
68
|
+
logger("success", "✓ Created gitconfig-man directory: " + CONFIGMAN_DIR_PATH);
|
|
69
|
+
|
|
70
|
+
// Save current git config as default profile
|
|
71
|
+
const defaultProfilePath = path.join(CONFIGMAN_DIR_PATH, "default.json");
|
|
72
|
+
saveConfigToFile(defaultProfilePath);
|
|
73
|
+
logger("success", "✓ Created default profile");
|
|
74
|
+
|
|
75
|
+
fs.writeFileSync(
|
|
76
|
+
CONFIGMAN_PATH,
|
|
77
|
+
JSON.stringify({ active: "default", available: ["default"] })
|
|
78
|
+
);
|
|
79
|
+
logger("success", "✓ Activated 'default' profile");
|
|
80
|
+
console.log(chalk.green("\n✨ Git Config Man initialized successfully!\n"));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
logger("info", "gitconfig-man is already initialized");
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const create = async function (name) {
|
|
87
|
+
if (!IS_INITIALIZED) {
|
|
88
|
+
logger("error", "gitconfig-man is not initialized\n");
|
|
89
|
+
logger(null, "Please initialize gitconfig-man using: gitconfig-man -i\n");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!name) {
|
|
93
|
+
const answer = await inquirer.prompt([
|
|
94
|
+
{
|
|
95
|
+
type: "input",
|
|
96
|
+
name: "profileName",
|
|
97
|
+
message: "Enter name for the new profile:",
|
|
98
|
+
validate: (input) => {
|
|
99
|
+
if (!input || input.trim() === "") {
|
|
100
|
+
return "Profile name cannot be empty";
|
|
101
|
+
}
|
|
102
|
+
const profilePath = path.join(CONFIGMAN_DIR_PATH, `${input}.json`);
|
|
103
|
+
if (fs.existsSync(profilePath)) {
|
|
104
|
+
return "A profile with this name already exists";
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
]);
|
|
110
|
+
name = answer.profileName;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let { active, available } = CONFIGMAN_CONTENT || {};
|
|
114
|
+
const profilePath = path.join(CONFIGMAN_DIR_PATH, `${name}.json`);
|
|
115
|
+
const exist = fs.existsSync(profilePath);
|
|
116
|
+
|
|
117
|
+
if (exist) {
|
|
118
|
+
return logger("error", "A profile with similar name already exists");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (active) {
|
|
122
|
+
// Save current git config to the active profile
|
|
123
|
+
const activeProfilePath = path.join(CONFIGMAN_DIR_PATH, `${active}.json`);
|
|
124
|
+
saveConfigToFile(activeProfilePath);
|
|
125
|
+
logger("success", `Saved current git config to '${active}' profile`);
|
|
126
|
+
|
|
127
|
+
// Create new empty profile
|
|
128
|
+
fs.writeFileSync(profilePath, JSON.stringify({}, null, 2));
|
|
129
|
+
logger("success", `Created new profile: ${name}`);
|
|
130
|
+
|
|
131
|
+
const { switchNow } = await inquirer.prompt([
|
|
132
|
+
{
|
|
133
|
+
type: "confirm",
|
|
134
|
+
name: "switchNow",
|
|
135
|
+
message: `Do you want to switch to newly created profile (${name})?`,
|
|
136
|
+
default: true,
|
|
137
|
+
},
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
available.push(name);
|
|
141
|
+
|
|
142
|
+
if (switchNow) {
|
|
143
|
+
// Clear current config and switch to new empty profile
|
|
144
|
+
clearGlobalConfig();
|
|
145
|
+
fs.writeFileSync(
|
|
146
|
+
CONFIGMAN_PATH,
|
|
147
|
+
JSON.stringify({ active: name, available })
|
|
148
|
+
);
|
|
149
|
+
logger("success", `Activated profile '${name}'`);
|
|
150
|
+
logger("info", "Current git config has been cleared. Configure it using 'git config --global' commands.");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
fs.writeFileSync(
|
|
155
|
+
CONFIGMAN_PATH,
|
|
156
|
+
JSON.stringify({ active: active, available })
|
|
157
|
+
);
|
|
158
|
+
return logger("success", `Successfully created profile '${name}'`);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const list = function () {
|
|
163
|
+
if (!IS_INITIALIZED) {
|
|
164
|
+
logger("error", "gitconfig-man is not initialized\n");
|
|
165
|
+
logger(null, "Please initialize gitconfig-man using: gitconfig-man -i\n");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log(chalk.bold("\nAvailable profiles:"));
|
|
170
|
+
if (CONFIGMAN_CONTENT) {
|
|
171
|
+
const { active, available } = CONFIGMAN_CONTENT;
|
|
172
|
+
available.forEach((profile) => {
|
|
173
|
+
if (profile === active) {
|
|
174
|
+
console.log(chalk.green(` ✓ ${profile}`) + chalk.gray(" (active)"));
|
|
175
|
+
} else {
|
|
176
|
+
console.log(chalk.white(` • ${profile}`));
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
console.log();
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const switchProfile = async function (name) {
|
|
184
|
+
if (!IS_INITIALIZED) {
|
|
185
|
+
logger("error", "gitconfig-man is not initialized\n");
|
|
186
|
+
logger(null, "Please initialize gitconfig-man using: gitconfig-man -i\n");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (CONFIGMAN_CONTENT) {
|
|
191
|
+
const { active, available } = CONFIGMAN_CONTENT;
|
|
192
|
+
|
|
193
|
+
// If no name provided, show interactive autocomplete menu
|
|
194
|
+
if (!name) {
|
|
195
|
+
const otherProfiles = available.filter((profile) => profile !== active);
|
|
196
|
+
|
|
197
|
+
if (otherProfiles.length === 0) {
|
|
198
|
+
return logger("warning", "No other profiles available to switch to");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const answer = await inquirer.prompt([
|
|
202
|
+
{
|
|
203
|
+
type: "autocomplete",
|
|
204
|
+
name: "profileName",
|
|
205
|
+
message: "Select profile to switch to:",
|
|
206
|
+
source: async (answersSoFar, input) => {
|
|
207
|
+
const filtered = otherProfiles.filter((profile) =>
|
|
208
|
+
profile.toLowerCase().includes((input || "").toLowerCase())
|
|
209
|
+
);
|
|
210
|
+
return filtered.map((profile) => ({
|
|
211
|
+
name: profile,
|
|
212
|
+
value: profile,
|
|
213
|
+
}));
|
|
214
|
+
},
|
|
215
|
+
pageSize: 10,
|
|
216
|
+
},
|
|
217
|
+
]);
|
|
218
|
+
name = answer.profileName;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const profile = available.find((p) => p === name);
|
|
222
|
+
|
|
223
|
+
if (!profile) {
|
|
224
|
+
return logger("error", `Profile '${name}' not found`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (profile === active) {
|
|
228
|
+
return logger("warning", `'${name}' is already the active profile`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Save current config to active profile
|
|
232
|
+
const activeProfilePath = path.join(CONFIGMAN_DIR_PATH, `${active}.json`);
|
|
233
|
+
saveConfigToFile(activeProfilePath);
|
|
234
|
+
logger("success", `Saved current git config to '${active}' profile`);
|
|
235
|
+
|
|
236
|
+
// Load and apply new profile
|
|
237
|
+
const newProfilePath = path.join(CONFIGMAN_DIR_PATH, `${name}.json`);
|
|
238
|
+
const newConfig = loadConfigFromFile(newProfilePath);
|
|
239
|
+
|
|
240
|
+
// Clear all current config
|
|
241
|
+
clearGlobalConfig();
|
|
242
|
+
|
|
243
|
+
// Apply new config
|
|
244
|
+
applyGlobalConfig(newConfig);
|
|
245
|
+
|
|
246
|
+
fs.writeFileSync(CONFIGMAN_PATH, JSON.stringify({ available, active: name }));
|
|
247
|
+
logger("success", `Activated profile '${name}'`);
|
|
248
|
+
} else {
|
|
249
|
+
logger("error", "Data directory is corrupt. Please try uninstalling and reinstalling the package.");
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const deleteProfile = async function (name) {
|
|
254
|
+
if (!IS_INITIALIZED) {
|
|
255
|
+
logger("error", "gitconfig-man is not initialized\n");
|
|
256
|
+
logger(null, "Please initialize gitconfig-man using: gitconfig-man -i\n");
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let { active, available } = CONFIGMAN_CONTENT || {};
|
|
261
|
+
|
|
262
|
+
// If no name provided, show interactive autocomplete menu
|
|
263
|
+
if (!name) {
|
|
264
|
+
const deletableProfiles = available.filter(
|
|
265
|
+
(profile) => profile !== "default" && profile !== active
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
if (deletableProfiles.length === 0) {
|
|
269
|
+
return logger("warning", "No profiles available to delete");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const answer = await inquirer.prompt([
|
|
273
|
+
{
|
|
274
|
+
type: "autocomplete",
|
|
275
|
+
name: "profileName",
|
|
276
|
+
message: "Select profile to delete:",
|
|
277
|
+
source: async (answersSoFar, input) => {
|
|
278
|
+
const filtered = deletableProfiles.filter((profile) =>
|
|
279
|
+
profile.toLowerCase().includes((input || "").toLowerCase())
|
|
280
|
+
);
|
|
281
|
+
return filtered.map((profile) => ({
|
|
282
|
+
name: profile,
|
|
283
|
+
value: profile,
|
|
284
|
+
}));
|
|
285
|
+
},
|
|
286
|
+
pageSize: 10,
|
|
287
|
+
},
|
|
288
|
+
]);
|
|
289
|
+
name = answer.profileName;
|
|
290
|
+
|
|
291
|
+
// Confirm deletion
|
|
292
|
+
const { confirmDelete } = await inquirer.prompt([
|
|
293
|
+
{
|
|
294
|
+
type: "confirm",
|
|
295
|
+
name: "confirmDelete",
|
|
296
|
+
message: `Are you sure you want to delete profile '${name}'?`,
|
|
297
|
+
default: false,
|
|
298
|
+
},
|
|
299
|
+
]);
|
|
300
|
+
|
|
301
|
+
if (!confirmDelete) {
|
|
302
|
+
return logger("info", "Deletion cancelled");
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (name === "default") {
|
|
307
|
+
return logger("error", "Default profile cannot be deleted");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const profilePath = path.join(CONFIGMAN_DIR_PATH, `${name}.json`);
|
|
311
|
+
const exist = fs.existsSync(profilePath);
|
|
312
|
+
|
|
313
|
+
if (active === name) {
|
|
314
|
+
return logger(
|
|
315
|
+
"error",
|
|
316
|
+
"Cannot delete this profile as it is currently active"
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (exist && available.find((p) => p === name)) {
|
|
321
|
+
available.splice(available.indexOf(name), 1);
|
|
322
|
+
fs.rmSync(profilePath, { force: true });
|
|
323
|
+
fs.writeFileSync(
|
|
324
|
+
CONFIGMAN_PATH,
|
|
325
|
+
JSON.stringify({ active, available: available })
|
|
326
|
+
);
|
|
327
|
+
return logger("success", `Successfully deleted profile '${name}'`);
|
|
328
|
+
} else {
|
|
329
|
+
return logger("error", `Couldn't find profile '${name}'`);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const version = function () {
|
|
334
|
+
const pkg = require("../package.json");
|
|
335
|
+
console.log(
|
|
336
|
+
chalk.cyan("gitconfig-man") +
|
|
337
|
+
chalk.gray(" version ") +
|
|
338
|
+
chalk.bold(pkg.version)
|
|
339
|
+
);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
module.exports = {
|
|
343
|
+
version,
|
|
344
|
+
list,
|
|
345
|
+
init,
|
|
346
|
+
help,
|
|
347
|
+
create,
|
|
348
|
+
switch: switchProfile,
|
|
349
|
+
delete: deleteProfile,
|
|
350
|
+
};
|
|
351
|
+
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const cliOptions = [
|
|
2
|
+
["i", "init", " -i Initialize gitconfig-man and create default profile"],
|
|
3
|
+
["c", "create", " -c [name] Create new git config profile (interactive if no name)"],
|
|
4
|
+
["s", "switch", " -s [name] Switch to another git config profile (interactive if no name)"],
|
|
5
|
+
["d", "delete", " -d [name] Delete git config profile (interactive if no name)"],
|
|
6
|
+
["ls", "list", " -ls List all profiles"],
|
|
7
|
+
["h", "help", " -h Show help"],
|
|
8
|
+
["v", "version", " -v Show version"],
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
const options = [];
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
cliOptions,
|
|
15
|
+
options,
|
|
16
|
+
};
|
|
17
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const { execSync } = require("child_process");
|
|
2
|
+
const fs = require("fs-extra");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get all global git config settings as an object
|
|
6
|
+
*/
|
|
7
|
+
const getGlobalConfig = () => {
|
|
8
|
+
try {
|
|
9
|
+
const output = execSync("git config --global --list", {
|
|
10
|
+
encoding: "utf8",
|
|
11
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const config = {};
|
|
15
|
+
const lines = output.trim().split("\n");
|
|
16
|
+
|
|
17
|
+
lines.forEach((line) => {
|
|
18
|
+
const [key, ...valueParts] = line.split("=");
|
|
19
|
+
if (key) {
|
|
20
|
+
const value = valueParts.join("="); // Handle values with '=' in them
|
|
21
|
+
config[key] = value || "";
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return config;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// If git config fails, return empty object
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Set a git config value globally
|
|
34
|
+
*/
|
|
35
|
+
const setGlobalConfig = (key, value) => {
|
|
36
|
+
try {
|
|
37
|
+
if (value === undefined || value === null || value === "") {
|
|
38
|
+
// Unset the key if value is empty
|
|
39
|
+
execSync(`git config --global --unset ${key}`, {
|
|
40
|
+
encoding: "utf8",
|
|
41
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
// Escape quotes in value
|
|
45
|
+
const escapedValue = value.replace(/"/g, '\\"');
|
|
46
|
+
execSync(`git config --global ${key} "${escapedValue}"`, {
|
|
47
|
+
encoding: "utf8",
|
|
48
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
// Ignore errors for unset operations on non-existent keys
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Clear all global git config settings
|
|
58
|
+
*/
|
|
59
|
+
const clearGlobalConfig = () => {
|
|
60
|
+
const config = getGlobalConfig();
|
|
61
|
+
Object.keys(config).forEach((key) => {
|
|
62
|
+
try {
|
|
63
|
+
execSync(`git config --global --unset ${key}`, {
|
|
64
|
+
encoding: "utf8",
|
|
65
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
66
|
+
});
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// Continue even if unset fails
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Apply a saved config object to global git config
|
|
75
|
+
*/
|
|
76
|
+
const applyGlobalConfig = (config) => {
|
|
77
|
+
Object.keys(config).forEach((key) => {
|
|
78
|
+
setGlobalConfig(key, config[key]);
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Save current git config to a JSON file
|
|
84
|
+
*/
|
|
85
|
+
const saveConfigToFile = (filePath) => {
|
|
86
|
+
const config = getGlobalConfig();
|
|
87
|
+
fs.writeFileSync(filePath, JSON.stringify(config, null, 2));
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Load git config from a JSON file
|
|
92
|
+
*/
|
|
93
|
+
const loadConfigFromFile = (filePath) => {
|
|
94
|
+
if (!fs.existsSync(filePath)) {
|
|
95
|
+
return {};
|
|
96
|
+
}
|
|
97
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
98
|
+
return JSON.parse(content);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
getGlobalConfig,
|
|
103
|
+
setGlobalConfig,
|
|
104
|
+
clearGlobalConfig,
|
|
105
|
+
applyGlobalConfig,
|
|
106
|
+
saveConfigToFile,
|
|
107
|
+
loadConfigFromFile,
|
|
108
|
+
};
|
|
109
|
+
|