@lakshanmuruganandam/git-time-machine 1.0.8
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 +67 -0
- package/index.js +108 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ⏳ Git Time Machine
|
|
4
|
+
|
|
5
|
+
> **Interactively travel between your recent Git branches with a beautiful UI.**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/git-time-machine)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
██████╗ ██╗████████╗ ████████╗██╗███╗ ███╗███████╗
|
|
14
|
+
██╔════╝ ██║╚══██╔══╝ ╚══██╔══╝██║████╗ ████║██╔════╝
|
|
15
|
+
██║ ███╗██║ ██║ ██║ ██║██╔████╔██║█████╗
|
|
16
|
+
██║ ██║██║ ██║ ██║ ██║██║╚██╔╝██║██╔══╝
|
|
17
|
+
╚██████╔╝██║ ██║ ██║ ██║██║ ╚═╝ ██║███████╗
|
|
18
|
+
╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
|
|
19
|
+
███╗ ███╗ █████╗ ██████╗ ██╗ ██╗██╗███╗ ██╗███████╗
|
|
20
|
+
████╗ ████║██╔══██╗██╔════╝ ██║ ██║██║████╗ ██║██╔════╝
|
|
21
|
+
██╔████╔██║███████║██║ ███████║██║██╔██╗ ██║█████╗
|
|
22
|
+
██║╚██╔╝██║██╔══██║██║ ██╔══██║██║██║╚██╗██║██╔══╝
|
|
23
|
+
██║ ╚═╝ ██║██║ ██║╚██████╗ ██║ ██║██║██║ ╚████║███████╗
|
|
24
|
+
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Typing `git branch`, hunting for the branch you worked on yesterday, and then manually typing `git checkout ...` is a massive waste of time.
|
|
28
|
+
|
|
29
|
+
**Git Time Machine** completely reinvents your git workflow by giving you a beautiful, interactive list of your local branches, sorted chronologically by the last commit date, allowing you to seamlessly "time jump" to your desired branch.
|
|
30
|
+
|
|
31
|
+
## ✨ Features
|
|
32
|
+
|
|
33
|
+
- **🕒 Chronological Sorting:** Branches are automatically sorted so the ones you were just working on are at the very top.
|
|
34
|
+
- **📝 Context Aware:** Shows the last commit message and the exact time it was committed so you never forget what a branch was for.
|
|
35
|
+
- **⚡ Lightning Fast:** No typing required. Just use your arrow keys and hit Enter to travel.
|
|
36
|
+
- **🎨 Premium UX:** Built with `inquirer` for a buttery-smooth terminal experience, complete with custom ASCII art.
|
|
37
|
+
|
|
38
|
+
## 🚀 Installation
|
|
39
|
+
|
|
40
|
+
Run it instantly anywhere without installing:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx git-time-machine
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or install it globally to keep the time machine on your terminal dashboard:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install -g git-time-machine
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 🎮 Usage
|
|
53
|
+
|
|
54
|
+
Run the command inside any git repository:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git-time-machine
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Controls:
|
|
61
|
+
- **`↑ / ↓`** : Scroll through the timeline.
|
|
62
|
+
- **`Enter`** : Initiate the time jump.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### Architected by [@lakshanmuruganandam](https://github.com/lakshanmuruganandam)
|
|
67
|
+
*Because we shouldn't have to remember exact branch names in 2026.*
|
package/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import boxen from 'boxen';
|
|
8
|
+
|
|
9
|
+
const program = new Command();
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('git-time-machine')
|
|
13
|
+
.description('Interactively travel between your recent Git branches with a beautiful UI.')
|
|
14
|
+
.version('1.0.0')
|
|
15
|
+
.parse(process.argv);
|
|
16
|
+
|
|
17
|
+
const banner = `
|
|
18
|
+
██████╗ ██╗████████╗ ████████╗██╗███╗ ███╗███████╗
|
|
19
|
+
██╔════╝ ██║╚══██╔══╝ ╚══██╔══╝██║████╗ ████║██╔════╝
|
|
20
|
+
██║ ███╗██║ ██║ ██║ ██║██╔████╔██║█████╗
|
|
21
|
+
██║ ██║██║ ██║ ██║ ██║██║╚██╔╝██║██╔══╝
|
|
22
|
+
╚██████╔╝██║ ██║ ██║ ██║██║ ╚═╝ ██║███████╗
|
|
23
|
+
╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
|
|
24
|
+
███╗ ███╗ █████╗ ██████╗ ██╗ ██╗██╗███╗ ██╗███████╗
|
|
25
|
+
████╗ ████║██╔══██╗██╔════╝ ██║ ██║██║████╗ ██║██╔════╝
|
|
26
|
+
██╔████╔██║███████║██║ ███████║██║██╔██╗ ██║█████╗
|
|
27
|
+
██║╚██╔╝██║██╔══██║██║ ██╔══██║██║██║╚██╗██║██╔══╝
|
|
28
|
+
██║ ╚═╝ ██║██║ ██║╚██████╗ ██║ ██║██║██║ ╚████║███████╗
|
|
29
|
+
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
console.log(pc.magenta(banner));
|
|
33
|
+
console.log(pc.gray(' Where are we going today?'));
|
|
34
|
+
console.log(pc.dim(' Architected by @lakshanmuruganandam\n'));
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
// Check if we are in a git repo
|
|
38
|
+
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.log(pc.red('❌ You are not inside a Git repository. Exiting.'));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const currentBranch = execSync('git branch --show-current').toString().trim();
|
|
46
|
+
const rawBranches = execSync('git for-each-ref --sort=-committerdate refs/heads/ --format="%(refname:short)|%(committerdate:relative)|%(authorname)|%(subject)"').toString().trim();
|
|
47
|
+
|
|
48
|
+
if (!rawBranches) {
|
|
49
|
+
console.log(pc.green('✨ Your repository is completely empty. No branches found.'));
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const branches = rawBranches.split('\n').map(line => {
|
|
54
|
+
const [name, date, author, subject] = line.split('|');
|
|
55
|
+
return { name: name?.trim(), date: date?.trim(), author: author?.trim(), subject: subject?.trim() };
|
|
56
|
+
}).filter(b => b.name && b.name !== currentBranch);
|
|
57
|
+
|
|
58
|
+
if (branches.length === 0) {
|
|
59
|
+
console.log(pc.green(`✨ You only have the current branch (${currentBranch}). Nowhere to travel to.`));
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const choices = branches.map(b => {
|
|
64
|
+
let dateColored = pc.gray(b.date);
|
|
65
|
+
if (b.date.includes('minutes') || b.date.includes('hours')) {
|
|
66
|
+
dateColored = pc.green(b.date);
|
|
67
|
+
} else if (b.date.includes('days')) {
|
|
68
|
+
dateColored = pc.yellow(b.date);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Truncate subject if too long
|
|
72
|
+
let shortSubject = b.subject || '';
|
|
73
|
+
if (shortSubject.length > 40) shortSubject = shortSubject.substring(0, 37) + '...';
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
name: `${b.name.padEnd(25)} 🕒 ${dateColored.padEnd(25)} 📝 ${pc.gray(shortSubject)}`,
|
|
77
|
+
value: b.name,
|
|
78
|
+
short: b.name
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const { selected } = await inquirer.prompt([{
|
|
83
|
+
type: 'list',
|
|
84
|
+
name: 'selected',
|
|
85
|
+
message: `Select a timeline to travel to (Current: ${pc.cyan(currentBranch)}):`,
|
|
86
|
+
choices: choices,
|
|
87
|
+
pageSize: 12,
|
|
88
|
+
loop: false
|
|
89
|
+
}]);
|
|
90
|
+
|
|
91
|
+
console.log();
|
|
92
|
+
try {
|
|
93
|
+
const output = execSync(`git checkout ${selected}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
94
|
+
console.log(
|
|
95
|
+
boxen(
|
|
96
|
+
pc.green(`Time jump successful. 🌌\n`) + pc.white(`You are now in: ${pc.bold(selected)}`),
|
|
97
|
+
{ padding: 1, margin: { top: 1 }, borderStyle: 'round', borderColor: 'green' }
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
console.log(pc.red(`❌ Failed to travel to timeline: `) + pc.white(selected));
|
|
102
|
+
if (e.stderr) console.log(pc.gray(e.stderr.toString()));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(pc.red('\nAn unexpected error occurred:'), error.message);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lakshanmuruganandam/git-time-machine",
|
|
3
|
+
"version": "1.0.8",
|
|
4
|
+
"description": "Interactively travel between your recent Git branches with a beautiful UI.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"git",
|
|
11
|
+
"branch",
|
|
12
|
+
"checkout",
|
|
13
|
+
"cli",
|
|
14
|
+
"time-machine",
|
|
15
|
+
"interactive"
|
|
16
|
+
],
|
|
17
|
+
"author": "Lakshan Muruganandam <lakshan@example.com>",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"boxen": "^8.0.1",
|
|
21
|
+
"cli-spinners": "^3.4.0",
|
|
22
|
+
"commander": "^15.0.0",
|
|
23
|
+
"inquirer": "^8.2.6",
|
|
24
|
+
"log-update": "^8.0.0",
|
|
25
|
+
"picocolors": "^1.1.1"
|
|
26
|
+
},
|
|
27
|
+
"bin": {
|
|
28
|
+
"git-time-machine": "./index.js"
|
|
29
|
+
},
|
|
30
|
+
"type": "module"
|
|
31
|
+
}
|