gitshift 2.1.1 → 2.2.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/README.md +73 -0
- package/package.json +1 -1
- package/src/commands/backup.js +29 -0
- package/src/commands/restore.js +33 -0
- package/src/server.js +18 -0
- package/src/services/profile.js +10 -0
package/README.md
CHANGED
|
@@ -39,6 +39,47 @@ gitshift --help
|
|
|
39
39
|
- `gitshift remove <profile>` - Delete a saved profile.
|
|
40
40
|
- `gitshift scan` - Scan your `~/.ssh` folder and import existing SSH keys into new profiles.
|
|
41
41
|
- `gitshift doctor` - Check whether Git, SSH, and GitHub CLI are installed.
|
|
42
|
+
- `gitshift backup [file]` - Export profiles, folder mappings, and current profile to a JSON backup file (default: `gitshift-backup.json`).
|
|
43
|
+
- `gitshift restore <file>` - Restore profiles and mappings from a previously created backup JSON file (prompts to confirm overwrite).
|
|
44
|
+
|
|
45
|
+
- `gitshift link <folder>` - Link a local folder to a profile (prompts to select or create a profile).
|
|
46
|
+
- `gitshift unlink <folder>` - Remove an existing folder mapping.
|
|
47
|
+
- `gitshift links` - List folder → profile mappings.
|
|
48
|
+
- `gitshift auto` - Auto-switch profile based on the current working directory and configured folder mappings.
|
|
49
|
+
|
|
50
|
+
### Add Command
|
|
51
|
+
|
|
52
|
+
- **Interactive prompts**: `Profile Name`, `GitHub Username`, `Email` (all required).
|
|
53
|
+
- **SSH key generation**: prompts `Generate SSH key automatically?` (default: **yes**). If accepted, an SSH key is generated and saved under `~/.ssh` with the pattern `gitshift-<profile-name>`.
|
|
54
|
+
- **Validation**: profile names must be unique; empty values for name, username, or email are rejected.
|
|
55
|
+
- **Cancelation**: pressing Ctrl+C during prompts exits gracefully and cancels creation.
|
|
56
|
+
|
|
57
|
+
### Folder mappings
|
|
58
|
+
|
|
59
|
+
- `gitshift link <folder>`: associates a local folder path with a profile. If no profiles exist, you'll be prompted to create one; otherwise you can pick an existing profile or create a new one. Linking stores an absolute path mapping so GitShift can detect and switch profiles when you `cd` into that folder.
|
|
60
|
+
- `gitshift unlink <folder>`: removes the mapping for the given folder path.
|
|
61
|
+
- `gitshift links`: prints all configured folder mappings in the form `profile → /absolute/path`.
|
|
62
|
+
|
|
63
|
+
Example linking a folder
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
$ gitshift link ~/projects/my-repo
|
|
67
|
+
Select Profile: personal
|
|
68
|
+
Linked /Users/akashs/projects/my-repo
|
|
69
|
+
Profile: personal
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Auto switching
|
|
73
|
+
|
|
74
|
+
- `gitshift auto` checks the current working directory against your configured folder mappings. If a matching mapping is found, GitShift will set the Git user (`user.name` and `user.email`) and mark the matched profile as current.
|
|
75
|
+
|
|
76
|
+
Run `gitshift auto` inside a linked folder (or any child path) to switch automatically:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
$ cd ~/projects/my-repo
|
|
80
|
+
$ gitshift auto
|
|
81
|
+
Switched to personal
|
|
82
|
+
```
|
|
42
83
|
|
|
43
84
|
## Example Workflow
|
|
44
85
|
|
|
@@ -46,6 +87,7 @@ gitshift --help
|
|
|
46
87
|
gitshift add
|
|
47
88
|
gitshift list
|
|
48
89
|
gitshift scan
|
|
90
|
+
gitshift backup
|
|
49
91
|
gitshift use personal
|
|
50
92
|
gitshift current
|
|
51
93
|
gitshift doctor
|
|
@@ -55,6 +97,37 @@ When you create a profile and choose SSH generation, GitShift creates a key unde
|
|
|
55
97
|
|
|
56
98
|
If you already have SSH keys on your machine, `gitshift scan` will list the available keys, let you pick one, and save it as a new imported profile.
|
|
57
99
|
|
|
100
|
+
Interactive `add` example
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
$ gitshift add
|
|
104
|
+
Profile Name: personal
|
|
105
|
+
GitHub Username: akash
|
|
106
|
+
Email: akash@example.com
|
|
107
|
+
Generate SSH key automatically? (Y/n) [Y]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Backup & Restore
|
|
111
|
+
|
|
112
|
+
- `gitshift backup [file]` writes a JSON file containing your saved profiles, folder mappings, and the currently selected profile. If no file is provided it defaults to `gitshift-backup.json` in your current directory.
|
|
113
|
+
|
|
114
|
+
Example backup:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
$ gitshift backup
|
|
118
|
+
Backup saved to /Users/akashs/gitshift-backup.json
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- `gitshift restore <file>` reads the JSON backup and restores profiles and mappings. It prompts to confirm overwriting existing data.
|
|
122
|
+
|
|
123
|
+
Example restore:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
$ gitshift restore gitshift-backup.json
|
|
127
|
+
This will overwrite current data. Continue? (y/N)
|
|
128
|
+
Backup restored
|
|
129
|
+
```
|
|
130
|
+
|
|
58
131
|
## How It Works
|
|
59
132
|
|
|
60
133
|
Profiles are saved locally on your machine using the app's configuration store. Switching profiles updates your global Git identity with:
|
package/package.json
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { getCurrentProfile, getFolderMappings, getProfiles } from "../services/profile.js";
|
|
4
|
+
import { error, success } from "../utils/logger.js";
|
|
5
|
+
|
|
6
|
+
export async function backupCommand(fileName = "gitshift-backup.json") {
|
|
7
|
+
try {
|
|
8
|
+
const backup = {
|
|
9
|
+
profiles: getProfiles(),
|
|
10
|
+
folderMappings: getFolderMappings(),
|
|
11
|
+
currentProfile: getCurrentProfile(),
|
|
12
|
+
createdAt: new Date().toISOString(),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const filePath = path.resolve(fileName);
|
|
16
|
+
|
|
17
|
+
await fs.writeJson(
|
|
18
|
+
filePath,
|
|
19
|
+
backup,
|
|
20
|
+
{
|
|
21
|
+
spaces: 2,
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
success(`Backup saved to ${filePath}`);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
error(err.message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { confirm } from "@inquirer/prompts";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { restoreData } from "../services/profile.js";
|
|
5
|
+
import { error, success } from "../utils/logger.js";
|
|
6
|
+
|
|
7
|
+
export async function restoreCommand(file) {
|
|
8
|
+
try {
|
|
9
|
+
const filePath = path.resolve(file);
|
|
10
|
+
const exists = await fs.pathExists(filePath);
|
|
11
|
+
|
|
12
|
+
if (!exists) {
|
|
13
|
+
error("Backup file not found");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const overwrite = await confirm({
|
|
18
|
+
message: "This will overwrite current data. Continue?",
|
|
19
|
+
default: false,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (!overwrite) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const backup = await fs.readJson(filePath);
|
|
27
|
+
restoreData(backup);
|
|
28
|
+
|
|
29
|
+
success("Backup restored");
|
|
30
|
+
} catch (err) {
|
|
31
|
+
error(err.message);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/server.js
CHANGED
|
@@ -6,12 +6,14 @@ import { Command } from "commander";
|
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { addCommand } from "./commands/add.js";
|
|
8
8
|
import { autoCommand } from "./commands/auto.js";
|
|
9
|
+
import { backupCommand } from "./commands/backup.js";
|
|
9
10
|
import { currentCommand } from "./commands/current.js";
|
|
10
11
|
import { doctorCommand } from "./commands/doctor.js";
|
|
11
12
|
import { linkCommand } from "./commands/link.js";
|
|
12
13
|
import { linksCommand } from "./commands/links.js";
|
|
13
14
|
import { listCommand } from "./commands/list.js";
|
|
14
15
|
import { removeCommand } from "./commands/remove.js";
|
|
16
|
+
import { restoreCommand } from "./commands/restore.js";
|
|
15
17
|
import { scanCommand } from "./commands/scan.js";
|
|
16
18
|
import { unlinkCommand } from "./commands/unlink.js";
|
|
17
19
|
import { useCommand } from "./commands/use.js";
|
|
@@ -163,6 +165,22 @@ async function main() {
|
|
|
163
165
|
)
|
|
164
166
|
.action(doctorCommand);
|
|
165
167
|
|
|
168
|
+
program
|
|
169
|
+
.command("backup")
|
|
170
|
+
.description(
|
|
171
|
+
"Backup profiles and mappings"
|
|
172
|
+
)
|
|
173
|
+
.argument("[file]")
|
|
174
|
+
.action(backupCommand);
|
|
175
|
+
|
|
176
|
+
program
|
|
177
|
+
.command("restore")
|
|
178
|
+
.description(
|
|
179
|
+
"Restore backup"
|
|
180
|
+
)
|
|
181
|
+
.argument("<file>")
|
|
182
|
+
.action(restoreCommand);
|
|
183
|
+
|
|
166
184
|
program.exitOverride();
|
|
167
185
|
|
|
168
186
|
try {
|
package/src/services/profile.js
CHANGED
|
@@ -83,4 +83,14 @@ export function addFolderMapping(profile, folderPath) {
|
|
|
83
83
|
export function removeFolderMapping(folderPath) {
|
|
84
84
|
const mappings = getFolderMappings();
|
|
85
85
|
config.set("folderMappings", mappings.filter((item) => item.path !== folderPath));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function restoreData(data) {
|
|
89
|
+
|
|
90
|
+
config.set("profiles", data.profiles || []);
|
|
91
|
+
config.set("folderMappings", data.folderMappings || []);
|
|
92
|
+
|
|
93
|
+
if (data.currentProfile) {
|
|
94
|
+
config.set("current", data.currentProfile);
|
|
95
|
+
}
|
|
86
96
|
}
|