Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions extensions/git-commands/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Git Commands Changelog

## [Beginner-friendly descriptions and keywords] - {2026-04-30}

- Rewrite alias descriptions for beginners with examples, pitfalls, and why.
- Add search keywords for every alias to improve matching.

## [Maintenance] - 2026-01-01

- Add copy and paste command to the action panel.
Expand Down
2 changes: 1 addition & 1 deletion extensions/git-commands/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h1 align="center">Git Commands</h1>

<h3 align="center">
Quickly use and learn Git commands and Oh My Zsh alias.
Quickly use and learn Git commands and Oh My Zsh aliases.
</h3>

<p align="center">
Expand Down
7 changes: 0 additions & 7 deletions extensions/git-commands/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions extensions/git-commands/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
"$schema": "https://www.raycast.com/schemas/extension.json",
"name": "git-commands",
"title": "Git Commands",
"description": "Quickly use and learn Git commands and Oh My Zsh alias.",
"description": "Quickly use and learn Git commands and Oh My Zsh aliases.",
"icon": "icon.png",
"author": "manumorante",
"contributors": [
"ridemountainpig"
"ridemountainpig",
"chizitere_david"
],
"categories": [
"Documentation",
Expand Down
890 changes: 610 additions & 280 deletions extensions/git-commands/src/alias.json

Large diffs are not rendered by default.

47 changes: 43 additions & 4 deletions extensions/git-commands/src/search-commands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import {
openCommandPreferences,
} from "@raycast/api";
import { useCachedPromise, useCachedState } from "@raycast/utils";
import { useMemo, useState } from "react";
import { Alias, Data } from "./types";
import aliasesJSON from "./alias.json";

const cache = new Cache();

export default function Command() {
const [showDetails, setShowDetails] = useCachedState("show-details", false);
const [searchText, setSearchText] = useState("");

// Preferences
const preferences = getPreferenceValues();
Expand Down Expand Up @@ -88,6 +90,42 @@ export default function Command() {

return [...new Set([clean, clean.replace(/--/g, "")])];
};

const normalize = (value: string) => value.toLowerCase().trim();
const tokenize = (value: string) => normalize(value).split(/\s+/).filter(Boolean);
const scoreAlias = (alias: Alias, query: string) => {
if (!query) return 0;
const terms = tokenize(query);
if (terms.length === 0) return 0;

const name = normalize(alias.name);
const command = normalize(alias.command);
const description = normalize(alias.description || "");
const keywords = (alias.keywords || []).map(normalize);

let score = 0;
for (const term of terms) {
if (name === term) score += 60;
if (name.startsWith(term)) score += 25;
if (command.startsWith(`git ${term}`)) score += 40;
if (command.includes(` ${term}`)) score += 10;
if (keywords.includes(term)) score += 20;
if (description.includes(term)) score += 5;
}
// Prefer shorter aliases (base commands) when scores are close.
score += Math.max(0, 10 - name.length);
return score;
};

const sortBySearch = (aliases: Alias[]) => {
if (!searchText.trim()) return aliases;
const query = searchText;
return aliases.slice().sort((a, b) => scoreAlias(b, query) - scoreAlias(a, query) || a.name.localeCompare(b.name));
};

const sortedPins = useMemo(() => sortBySearch(data.pins), [data.pins, searchText]);
const sortedRecent = useMemo(() => sortBySearch(data.recent), [data.recent, searchText]);
const sortedAliases = useMemo(() => sortBySearch(data.aliases), [data.aliases, searchText]);
const Item = ({ alias, hidePin }: { alias: Alias; hidePin?: boolean }) => {
const { name, command, type, description, pin = false, recent = false } = alias;

Expand All @@ -104,7 +142,7 @@ export default function Command() {
title={name}
subtitle={{ value: command, tooltip: command }}
detail={<List.Item.Detail markdown={detail} />}
keywords={[...description.split(" "), ...command.split(" ").map(toKeyword).flat()]}
keywords={[...(alias.keywords || []), ...command.split(" ").map(toKeyword).flat(), name]}
accessories={[
...(pin && !hidePin
? [{ icon: { source: Icon.Tack, ...(isPinColored && { tintColor: Color.Yellow }) } }]
Expand Down Expand Up @@ -167,21 +205,22 @@ export default function Command() {
isLoading={isLoading}
searchBarPlaceholder="Search command, description or alias"
isShowingDetail={showDetails}
onSearchTextChange={setSearchText}
>
<List.Section title="Pinned" subtitle={data.pins.length > maxPins ? `${data.pins.length}` : ""}>
{data.pins.slice(0, maxPins).map((alias) => (
{sortedPins.slice(0, maxPins).map((alias) => (
<Item key={alias.name} alias={alias} hidePin />
))}
</List.Section>

<List.Section title="Recent" subtitle={data.recent.length > maxRecent ? `${data.recent.length}` : ""}>
{data.recent.slice(0, maxRecent).map((alias) => (
{sortedRecent.slice(0, maxRecent).map((alias) => (
<Item key={alias.name} alias={alias} />
))}
</List.Section>

<List.Section title="All aliases" subtitle={`${data.aliases.length}`}>
{data.aliases.map((alias) => (
{sortedAliases.map((alias) => (
<Item key={alias.name} alias={alias} />
))}
</List.Section>
Expand Down
1 change: 1 addition & 0 deletions extensions/git-commands/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type Alias = {
description: string;
pin?: boolean;
recent?: boolean;
keywords?: string[];
};

/**
Expand Down