Skip to content

[Feature]: Add a gitbun undo command that reverts the last commit created by Gitbun while preserving staged changes, with a confirmation prompt #76

Description

@divyanshim27

Summary

Gitbun's --auto flag commits immediately without preview. Even in interactive mode, a user can accidentally confirm and commit a generated message they didn't fully review. There is currently no recovery path — the user must manually run git reset HEAD~1 to undo the last commit. A gitbun undo command that wraps this operation with a safety confirmation and preserves staged changes would complete Gitbun's workflow loop.

Problem

  • When --auto is used in CI or by habit, a bad commit message cannot be corrected without knowing the git command to undo it.
  • git reset HEAD~1 --soft is not intuitive for newer developers — Gitbun's entire purpose is to abstract git workflow complexity.
  • There is no way inside Gitbun to regenerate a commit message after committing — the user must amend manually.
  • Gitbun tracks no metadata about commits it has created, so there's no way to verify what the "last Gitbun commit" was before undoing it.

Proposed Solution

1. Record Gitbun-created commits in a local metadata file:

// src/lib/commit-log.ts
import { join } from 'path';
import { readFileSync, writeFileSync, existsSync } from 'fs';

const GIT_DIR = join(process.cwd(), '.git');
const GITBUN_LOG = join(GIT_DIR, 'GITBUN_LAST_COMMIT');

export function recordCommit(sha: string, message: string) {
  writeFileSync(GITBUN_LOG, JSON.stringify({ sha, message, timestamp: Date.now() }));
}

export function getLastGitbunCommit(): { sha: string; message: string; timestamp: number } | null {
  if (!existsSync(GITBUN_LOG)) return null;
  try {
    return JSON.parse(readFileSync(GITBUN_LOG, 'utf-8'));
  } catch {
    return null;
  }
}

2. Add the undo subcommand:

// src/commands/undo.ts
import { execSync } from 'child_process';
import { getLastGitbunCommit } from '../lib/commit-log.js';
import chalk from 'chalk';
import inquirer from 'inquirer';

export async function undoLastCommit() {
  const lastCommit = getLastGitbunCommit();

  if (!lastCommit) {
    console.log(chalk.yellow('No Gitbun commit found to undo.'));
    return;
  }

  // Verify the last commit SHA still matches HEAD
  const headSha = execSync('git rev-parse HEAD').toString().trim();
  if (headSha !== lastCommit.sha) {
    console.log(chalk.red(
      `The last Gitbun commit (${lastCommit.sha.slice(0, 7)}) is no longer HEAD.\n` +
      `Cannot safely undo — run \`git reset HEAD~1 --soft\` manually if needed.`
    ));
    return;
  }

  console.log(chalk.cyan('Last Gitbun commit:'));
  console.log(chalk.white(`  ${lastCommit.message}`));
  console.log(chalk.gray(`  ${new Date(lastCommit.timestamp).toLocaleString()}`));
  console.log('');

  const { confirmed } = await inquirer.prompt([{
    type: 'confirm',
    name: 'confirmed',
    message: 'Undo this commit? (staged changes will be preserved)',
    default: false,
  }]);

  if (!confirmed) {
    console.log(chalk.gray('Undo cancelled.'));
    return;
  }

  execSync('git reset HEAD~1 --soft');
  console.log(chalk.green('✓ Commit undone. Your changes are still staged.'));
  console.log(chalk.cyan('Run `gitbun` to generate a new commit message.'));
}

3. Register the command in the CLI entry point:

// bin/gitbun.js (or src/index.ts)
program
  .command('undo')
  .description('Undo the last commit created by Gitbun (preserves staged changes)')
  .action(undoLastCommit);

Additional Notes

  • git reset HEAD~1 --soft is used (not --hard) — no changes are lost. All files return to the staged state.
  • The GITBUN_LAST_COMMIT file is stored inside .git/, which means it is gitignored by default and never committed.
  • If the last commit at HEAD is not a Gitbun commit (e.g., the user made a manual commit after), the undo is blocked with a clear error message.
  • I will add a unit test for commit-log.ts (record and retrieve) and a CLI integration test for the undo command flow.

Could you assign this issue to me?

Labels: enhancement, feature, cli, GSSoC 2026

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions