git-visualizer / index.html
Ben-S's picture
A visual and interactive representation of the core features of git. Branch, merge, rebase, detached head, blame, commits, issues, pull requests, etc. Should be beautiful and easy to understand
ec7b4bb verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Git Visualizer — Interactive Git Core Concepts</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24' fill='none' stroke='%236366f1' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8.5 7.5a3.5 3.5 0 0 1 4.5 3.9V14a3 3 0 1 1-1.5-2.6'/%3E%3Cpath d='M6 3a5 5 0 0 0 5 5h3'/%3E%3Cpath d='M2 3v5.5A3.5 3.5 0 0 0 5.5 12H8'/%3E%3Cpath d='M2 12h3a5 5 0 0 1 5 5v3'/%3E%3Cpath d='M10 20v-3a5 5 0 0 1 5-5h3'/%3E%3C/svg%3E" />
<link rel="stylesheet" href="style.css" />
<script defer src="script.js"></script>
</head>
<body>
<header class="app-header">
<div class="brand">
<div class="logo"></div>
<div class="title">
<h1>Git Visualizer</h1>
<p>Explore commits, branches, merge, rebase, detached HEAD, blame, issues, and pull requests.</p>
</div>
</div>
<div class="customization">
<div class="chip">
<label for="primaryColor">Primary</label>
<input id="primaryColor" type="color" value="#6366f1" />
</div>
<div class="chip">
<label for="secondaryColor">Secondary</label>
<input id="secondaryColor" type="color" value="#22c55e" />
</div>
<div class="chip">
<label for="themeMode">Theme</label>
<select id="themeMode">
<option value="system">System</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
</div>
</header>
<main class="app">
<aside class="sidebar">
<section class="panel">
<h2>Repository</h2>
<div class="row">
<div>
<div class="label">Current HEAD</div>
<div id="currentHead" class="value">-</div>
</div>
<div>
<div class="label">Detached</div>
<div id="detachedState" class="value">No</div>
</div>
</div>
<div class="row">
<div>
<div class="label">Branches</div>
<ul id="branchList" class="list"></ul>
</div>
</div>
<div class="row">
<div>
<div class="label">Stash</div>
<ul id="stashList" class="list compact"></ul>
</div>
</div>
</section>
<section class="panel">
<h2>Actions</h2>
<div class="grid">
<div class="field">
<label for="commitMsg">Commit message</label>
<input id="commitMsg" type="text" placeholder="Describe your change" />
</div>
<button id="btnCommit" class="btn primary">Commit</button>
<button id="btnCommitAmend" class="btn ghost">Amend</button>
<button id="btnUndoCommit" class="btn ghost">Undo last commit</button>
</div>
<div class="grid">
<div class="field">
<label for="branchName">New branch name</label>
<input id="branchName" type="text" placeholder="feature/..." />
</div>
<button id="btnCreateBranch" class="btn">Create branch</button>
</div>
<div class="grid">
<div class="field">
<label for="switchBranch">Switch to branch</label>
<select id="switchBranch"></select>
</div>
<button id="btnCheckout" class="btn">Checkout</button>
</div>
<div class="grid">
<div class="field">
<label for="checkoutCommit">Checkout commit</label>
<select id="checkoutCommit"></select>
</div>
<button id="btnDetach" class="btn warn">Detach HEAD</button>
</div>
<div class="grid">
<button id="btnMerge" class="btn">Merge selected into current</button>
<button id="btnRebase" class="btn">Rebase current on selected</button>
</div>
<div class="grid">
<div class="field">
<label for="mergeTarget">Merge target</label>
<select id="mergeTarget"></select>
</div>
<div class="field">
<label for="rebaseTarget">Rebase target</label>
<select id="rebaseTarget"></select>
</div>
</div>
<div class="grid">
<button id="btnStash" class="btn">Stash</button>
<button id="btnStashPop" class="btn">Stash pop</button>
</div>
<div class="grid">
<button id="btnResetHard" class="btn danger">Reset --hard (to selected)</button>
<select id="resetTarget"></select>
</div>
</section>
<section class="panel">
<h2>Issues & Pull Requests</h2>
<div class="grid">
<button id="btnNewIssue" class="btn">New Issue</button>
<button id="btnNewPR" class="btn">New Pull Request</button>
</div>
<div class="row">
<div>
<div class="label">Issues</div>
<ul id="issuesList" class="list"></ul>
</div>
</div>
<div class="row">
<div>
<div class="label">Pull Requests</div>
<ul id="prsList" class="list"></ul>
</div>
</div>
</section>
<section class="panel">
<h2>Blame</h2>
<div class="grid">
<div class="field">
<label for="blameCommit">Select commit</label>
<select id="blameCommit"></select>
</div>
<button id="btnBlame" class="btn ghost">Show blame</button>
</div>
<div id="blamePanel" class="code hidden"></div>
</section>
<section class="panel">
<h2>Demo Scenarios</h2>
<div class="grid">
<button id="btnDemoBasic" class="btn">Init demo</button>
<button id="btnDemoPR" class="btn">Open PR scenario</button>
</div>
</section>
</aside>
<section class="graph">
<div class="graph-toolbar">
<div class="left">
<button id="btnFit" class="btn ghost">Fit</button>
<button id="btnCenterMain" class="btn ghost">Center main</button>
<button id="btnCenterHead" class="btn ghost">Center HEAD</button>
</div>
<div class="right">
<span class="legend"><span class="legend-dot"></span> Commits</span>
<span class="legend"><span class="legend-branch"></span> Branch head</span>
<span class="legend"><span class="legend-head"></span> HEAD</span>
</div>
</div>
<div class="canvas-wrapper">
<svg id="graphSvg" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
</section>
</main>
<footer class="app-footer">
<div>Tip: Start with “Init demo”, create a branch, make commits, then try Merge and Rebase. Toggle theme and colors above.</div>
<div class="small">Built for interactive learning of core Git concepts.</div>
</footer>
<script>
// Configure CSS variables from inputs (supports "undefined" placeholder too)
const primaryInput = document.getElementById('primaryColor');
const secondaryInput = document.getElementById('secondaryColor');
const themeMode = document.getElementById('themeMode');
const applyVars = () => {
const getOrFallback = (v, fallback) => (!v || v === 'undefined') ? fallback : v;
document.documentElement.style.setProperty('--primary', getOrFallback(primaryInput.value, '#6366f1'));
document.documentElement.style.setProperty('--secondary', getOrFallback(secondaryInput.value, '#22c55e'));
};
primaryInput.addEventListener('input', applyVars);
secondaryInput.addEventListener('input', applyVars);
themeMode.addEventListener('change', () => {
const mode = themeMode.value;
if (mode === 'system') document.documentElement.removeAttribute('data-theme');
else document.documentElement.setAttribute('data-theme', mode);
});
applyVars();
</script>
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
</body>
</html>