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
Raw
History Blame Contribute Delete
8.16 kB
<!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>