@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.
Files changed (3) hide show
  1. package/README.md +67 -0
  2. package/index.js +108 -0
  3. 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
+ [![npm version](https://badge.fury.io/js/git-time-machine.svg)](https://www.npmjs.com/package/git-time-machine)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
+ }