-
Notifications
You must be signed in to change notification settings - Fork 1
Add git_analytics dashboard generator and generated artifacts #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| #!/usr/bin/env python3 | ||
| """Build a professional dashboard for pull-request and merge activity.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import csv | ||
| import json | ||
| import re | ||
| import subprocess | ||
| from collections import Counter | ||
| from datetime import datetime | ||
| from pathlib import Path | ||
|
|
||
| ROOT = Path(__file__).resolve().parent | ||
| OUT_CSV = ROOT / "merge_pr_activity.csv" | ||
| OUT_HTML = ROOT / "merge_pr_activity.html" | ||
| OUT_MD = ROOT / "merge_pr_summary.md" | ||
|
|
||
| LOG_FORMAT = "%H|%ad|%s" | ||
| DATE_FORMAT = "%Y-%m-%d" | ||
| PR_RE = re.compile(r"Merge pull request #(\d+)", re.IGNORECASE) | ||
| FROM_RE = re.compile(r"\sfrom\s([^/\s]+)/?([^\s]*)", re.IGNORECASE) | ||
|
|
||
|
|
||
| def run_git_log() -> list[str]: | ||
| cmd = ["git", "log", "--merges", "--date=short", f"--pretty=format:{LOG_FORMAT}"] | ||
| result = subprocess.run(cmd, check=True, text=True, capture_output=True) | ||
| return [line.strip() for line in result.stdout.splitlines() if line.strip()] | ||
|
|
||
|
|
||
| def parse_lines(lines: list[str]) -> list[dict[str, str | int | None]]: | ||
| rows = [] | ||
| for line in lines: | ||
| commit, date, subject = line.split("|", 2) | ||
| pr_match = PR_RE.search(subject) | ||
| from_match = FROM_RE.search(subject) | ||
| author = from_match.group(1) if from_match else "unknown" | ||
| source_branch = from_match.group(2) if from_match else "unknown" | ||
| pr_number = int(pr_match.group(1)) if pr_match else None | ||
| dt = datetime.strptime(date, DATE_FORMAT) | ||
| rows.append( | ||
| { | ||
| "commit": commit, | ||
| "date": date, | ||
| "month": dt.strftime("%Y-%m"), | ||
| "weekday": dt.strftime("%A"), | ||
| "subject": subject, | ||
| "pr_number": pr_number, | ||
| "is_pr_merge": int(pr_number is not None), | ||
| "author": author, | ||
| "source_branch": source_branch, | ||
| } | ||
| ) | ||
| return rows | ||
|
|
||
|
|
||
| def write_csv(rows: list[dict[str, str | int | None]]) -> None: | ||
| fields = ["commit", "date", "month", "weekday", "subject", "pr_number", "is_pr_merge", "author", "source_branch"] | ||
| with OUT_CSV.open("w", newline="", encoding="utf-8") as f: | ||
| writer = csv.DictWriter(f, fieldnames=fields) | ||
| writer.writeheader() | ||
| writer.writerows(rows) | ||
|
|
||
|
|
||
| def write_html(rows: list[dict[str, str | int | None]]) -> None: | ||
| merges_by_month = Counter(str(r["month"]) for r in rows) | ||
| pr_by_month = Counter(str(r["month"]) for r in rows if r["is_pr_merge"]) | ||
| weekday_order = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] | ||
| merges_by_weekday = Counter(str(r["weekday"]) for r in rows) | ||
| top_authors = Counter(str(r["author"]) for r in rows if str(r["author"]) != "unknown") | ||
|
|
||
| months = sorted(set(merges_by_month) | set(pr_by_month)) | ||
| total_merges = len(rows) | ||
| total_pr_merges = sum(int(r["is_pr_merge"]) for r in rows) | ||
| pr_numbers = sorted(int(r["pr_number"]) for r in rows if r["pr_number"] is not None) | ||
| first_pr, last_pr = (pr_numbers[0], pr_numbers[-1]) if pr_numbers else (None, None) | ||
|
|
||
| table_rows = rows[:100] | ||
|
|
||
| html = f"""<!doctype html> | ||
| <html> | ||
| <head> | ||
| <meta charset='utf-8'> | ||
| <title>Professional Pull Request Dashboard</title> | ||
| <script src='https://cdn.plot.ly/plotly-2.35.2.min.js'></script> | ||
| <style> | ||
| body{{font-family:Inter,Segoe UI,Arial,sans-serif;background:#0b1020;color:#e9eefc;margin:0;padding:24px;}} | ||
| h1{{margin:0 0 12px 0;}} | ||
| .sub{{color:#a8b2d1;margin-bottom:18px}} | ||
| .kpi{{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin:16px 0 24px;}} | ||
| .card{{background:#151b31;border:1px solid #2a3358;border-radius:12px;padding:14px;}} | ||
| .k{{font-size:12px;color:#a8b2d1}} .v{{font-size:28px;font-weight:700;margin-top:6px}} | ||
| .charts{{display:grid;grid-template-columns:2fr 1fr;gap:12px;}} | ||
| .charts2{{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:12px;}} | ||
| #prTable{{width:100%;border-collapse:collapse;font-size:12px}} | ||
| #prTable th,#prTable td{{border-bottom:1px solid #2a3358;padding:8px;text-align:left}} | ||
| #prTable th{{color:#a8b2d1}} | ||
| input{{background:#0f1428;color:#e9eefc;border:1px solid #2a3358;border-radius:8px;padding:8px 10px;min-width:260px;margin:8px 0 12px;}} | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <h1>Professional Pull Request Dashboard</h1> | ||
| <div class='sub'>Generated from merge history (`git log --merges`) • Interactive analysis for PR trends.</div> | ||
|
|
||
| <div class='kpi'> | ||
| <div class='card'><div class='k'>Total Merge Commits</div><div class='v'>{total_merges}</div></div> | ||
| <div class='card'><div class='k'>PR Merge Commits</div><div class='v'>{total_pr_merges}</div></div> | ||
| <div class='card'><div class='k'>First PR Number</div><div class='v'>{first_pr if first_pr is not None else 'N/A'}</div></div> | ||
| <div class='card'><div class='k'>Latest PR Number</div><div class='v'>{last_pr if last_pr is not None else 'N/A'}</div></div> | ||
| </div> | ||
|
|
||
| <div class='charts'> | ||
| <div class='card'><div id='monthChart'></div></div> | ||
| <div class='card'><div id='typeChart'></div></div> | ||
| </div> | ||
| <div class='charts2'> | ||
| <div class='card'><div id='weekdayChart'></div></div> | ||
| <div class='card'><div id='authorChart'></div></div> | ||
| </div> | ||
|
|
||
| <div class='card' style='margin-top:12px'> | ||
| <h3 style='margin-top:0'>Recent Merge/PR Records (Top 100)</h3> | ||
| <input id='search' placeholder='Filter by PR number, commit, branch, author, or subject...' onkeyup='filterTable()' /> | ||
| <table id='prTable'> | ||
| <thead><tr><th>Date</th><th>PR</th><th>Author</th><th>Branch</th><th>Commit</th><th>Subject</th></tr></thead> | ||
| <tbody></tbody> | ||
| </table> | ||
| </div> | ||
|
|
||
| <script> | ||
| const months = {json.dumps(months)}; | ||
| const monthMerge = {json.dumps([merges_by_month[m] for m in months])}; | ||
| const monthPR = {json.dumps([pr_by_month.get(m, 0) for m in months])}; | ||
| const weekday = {json.dumps(weekday_order)}; | ||
| const weekdayVals = {json.dumps([merges_by_weekday.get(d, 0) for d in weekday_order])}; | ||
| const authorNames = {json.dumps([k for k, _ in top_authors.most_common(10)])}; | ||
| const authorVals = {json.dumps([v for _, v in top_authors.most_common(10)])}; | ||
| const tableData = {json.dumps(table_rows)}; | ||
|
|
||
| const commonLayout = {{paper_bgcolor:'#151b31', plot_bgcolor:'#151b31', font:{{color:'#e9eefc'}}}}; | ||
| Plotly.newPlot('monthChart', [ | ||
| {{x: months, y: monthMerge, name:'All merges', type:'scatter', mode:'lines+markers'}}, | ||
| {{x: months, y: monthPR, name:'PR merges', type:'scatter', mode:'lines+markers'}} | ||
| ], {{...commonLayout, title:'Monthly Pull/Merge Trend', xaxis:{{title:'Month'}}, yaxis:{{title:'Count'}}}}); | ||
|
|
||
| Plotly.newPlot('typeChart', [{{type:'pie', labels:['PR merges','Other merges'], values:[{total_pr_merges},{total_merges-total_pr_merges}], hole:0.48}}], {{...commonLayout, title:'Merge Type Split'}}); | ||
| Plotly.newPlot('weekdayChart', [{{x:weekday, y:weekdayVals, type:'bar', marker:{{color:'#53a7ff'}}}}], {{...commonLayout, title:'Merge Activity by Weekday', yaxis:{{title:'Count'}}}}); | ||
| Plotly.newPlot('authorChart', [{{x:authorVals, y:authorNames, type:'bar', orientation:'h', marker:{{color:'#7bd88f'}}}}], {{...commonLayout, title:'Top PR Sources (from merge text)', xaxis:{{title:'Merge count'}}}}); | ||
|
|
||
| function renderTable(rows) {{ | ||
| const tbody = document.querySelector('#prTable tbody'); | ||
| tbody.innerHTML = rows.map(r => `<tr><td>${{r.date}}</td><td>${{r.pr_number ?? ''}}</td><td>${{r.author}}</td><td>${{r.source_branch}}</td><td><code>${{r.commit.slice(0,8)}}</code></td><td>${{r.subject}}</td></tr>`).join(''); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The dashboard renders commit-derived strings ( Useful? React with 👍 / 👎. |
||
| }} | ||
|
Comment on lines
+138
to
+153
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prevent script/HTML injection from git metadata before rendering Git-derived fields (notably 🔐 Suggested hardening patch@@
- table_rows = rows[:100]
+ table_rows = rows[:100]
+ safe_table_json = json.dumps(table_rows).replace("</", "<\\/")
@@
-const tableData = {json.dumps(table_rows)};
+const tableData = {safe_table_json};
@@
function renderTable(rows) {{
const tbody = document.querySelector('`#prTable` tbody');
- tbody.innerHTML = rows.map(r => `<tr><td>${{r.date}}</td><td>${{r.pr_number ?? ''}}</td><td>${{r.author}}</td><td>${{r.source_branch}}</td><td><code>${{r.commit.slice(0,8)}}</code></td><td>${{r.subject}}</td></tr>`).join('');
+ tbody.textContent = '';
+ for (const r of rows) {{
+ const tr = document.createElement('tr');
+ const values = [r.date, r.pr_number ?? '', r.author, r.source_branch, r.commit.slice(0, 8), r.subject];
+ values.forEach((value, idx) => {{
+ const td = document.createElement('td');
+ if (idx === 4) {{
+ const code = document.createElement('code');
+ code.textContent = String(value);
+ td.appendChild(code);
+ }} else {{
+ td.textContent = String(value);
+ }}
+ tr.appendChild(td);
+ }});
+ tbody.appendChild(tr);
+ }}
}}🤖 Prompt for AI Agents |
||
|
|
||
| function filterTable() {{ | ||
| const q = document.getElementById('search').value.toLowerCase(); | ||
| const rows = tableData.filter(r => JSON.stringify(r).toLowerCase().includes(q)); | ||
| renderTable(rows); | ||
| }} | ||
|
|
||
| renderTable(tableData); | ||
| </script> | ||
| </body></html>""" | ||
|
|
||
| OUT_HTML.write_text(html, encoding="utf-8") | ||
|
|
||
|
|
||
| def write_markdown(rows: list[dict[str, str | int | None]]) -> None: | ||
| merges_by_month = Counter(str(r["month"]) for r in rows) | ||
| top_month = max(merges_by_month.items(), key=lambda x: x[1]) if merges_by_month else ("N/A", 0) | ||
| top_author = Counter(str(r["author"]) for r in rows if str(r["author"]) != "unknown").most_common(1) | ||
| total_merges = len(rows) | ||
| total_pr = sum(int(r["is_pr_merge"]) for r in rows) | ||
| pr_numbers = [int(r["pr_number"]) for r in rows if r["pr_number"] is not None] | ||
|
|
||
| lines = [ | ||
| "# Professional Git Pull/Merge Dashboard Summary", | ||
| "", | ||
| f"- Total merge commits: **{total_merges}**", | ||
| f"- PR merge commits: **{total_pr}**", | ||
| f"- Non-PR merges: **{total_merges - total_pr}**", | ||
| f"- PR range: **#{min(pr_numbers)} to #{max(pr_numbers)}**" if pr_numbers else "- PR range: N/A", | ||
| f"- Peak month: **{top_month[0]}** ({top_month[1]} merges)", | ||
| f"- Top source author in merge text: **{top_author[0][0]}** ({top_author[0][1]} merges)" if top_author else "- Top source author: N/A", | ||
| "", | ||
| "Open `git_analytics/merge_pr_activity.html` for the full professional dashboard.", | ||
| ] | ||
| OUT_MD.write_text("\n".join(lines), encoding="utf-8") | ||
|
|
||
|
|
||
| def main() -> None: | ||
| rows = parse_lines(run_git_log()) | ||
| write_csv(rows) | ||
| write_html(rows) | ||
| write_markdown(rows) | ||
| print(f"Processed {len(rows)} merge commits into professional dashboard artifacts.") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| commit,date,month,weekday,subject,pr_number,is_pr_merge,author,source_branch | ||
| b8f962e242f4fe7e4f754b0189410104d24eb9ff,2026-05-25,2026-05,Monday,Merge pull request #76 from Ritik574-coder/dbt_branch,76,1,Ritik574-coder,dbt_branch | ||
| d6bfa79a5c738de07c68f093eb077562fb08712e,2026-05-25,2026-05,Monday,Merge pull request #75 from Ritik574-coder/dbt_branch,75,1,Ritik574-coder,dbt_branch | ||
| f55e9dcfd026227588a6fd188d47a058b97b18ad,2026-05-24,2026-05,Sunday,Merge pull request #74 from Ritik574-coder/dbt_branch,74,1,Ritik574-coder,dbt_branch | ||
| 11dfff130115df45de1d1e2089a54dcb6c44f863,2026-05-23,2026-05,Saturday,Merge pull request #73 from Ritik574-coder/dbt_branch,73,1,Ritik574-coder,dbt_branch | ||
| 044418bae08c3e9f1ab4387af3abd4568473cc1a,2026-05-23,2026-05,Saturday,Merge pull request #72 from Ritik574-coder/dbt_branch,72,1,Ritik574-coder,dbt_branch | ||
| a5b8dd149488771fbc4b2e73c1d484a69e02d270,2026-05-22,2026-05,Friday,Merge pull request #71 from Ritik574-coder/dbt_branch,71,1,Ritik574-coder,dbt_branch | ||
| 036421b56e0075a924316a52c8bb307cec621fc4,2026-05-21,2026-05,Thursday,Merge pull request #70 from Ritik574-coder/dbt_branch,70,1,Ritik574-coder,dbt_branch | ||
| 34e749b0ce566e8e9c808dc62329eb0e7348e940,2026-05-21,2026-05,Thursday,Merge pull request #69 from Ritik574-coder/dbt_branch,69,1,Ritik574-coder,dbt_branch | ||
| ea8f002b57aec7d280cbe68803c801b8c45c0d92,2026-05-21,2026-05,Thursday,Merge pull request #68 from Ritik574-coder/dbt_branch,68,1,Ritik574-coder,dbt_branch | ||
| ce5f4857bd890253d7304a1e6a4f0246cc1a8087,2026-05-20,2026-05,Wednesday,Merge pull request #67 from Ritik574-coder/dbt_branch,67,1,Ritik574-coder,dbt_branch | ||
| 7ccf2a710300526f65aa83df9d956128c2fbad52,2026-05-20,2026-05,Wednesday,Merge pull request #66 from Ritik574-coder/dbt_branch,66,1,Ritik574-coder,dbt_branch | ||
| 3f98986ffeb5f94eceeea2888ba7e0a1dabeb7e0,2026-05-20,2026-05,Wednesday,Merge pull request #65 from Ritik574-coder/dbt_branch,65,1,Ritik574-coder,dbt_branch | ||
| b296a101e99b7e594fb149c38d0ec14b7e7d2119,2026-05-19,2026-05,Tuesday,Merge pull request #64 from Ritik574-coder/dbt_branch,64,1,Ritik574-coder,dbt_branch | ||
| 96f1e480b24936c93d9d67ad04d5de0c18465166,2026-05-18,2026-05,Monday,Merge pull request #63 from Ritik574-coder/dbt_branch,63,1,Ritik574-coder,dbt_branch | ||
| 116ec9451d86d023b2883af7e26b5f5fccbaffd9,2026-05-18,2026-05,Monday,Merge pull request #62 from Ritik574-coder/dbt_branch,62,1,Ritik574-coder,dbt_branch | ||
| 76e73c5b9eec4ab8f14e681b0aa130ee3ab8b2be,2026-05-17,2026-05,Sunday,Merge pull request #61 from Ritik574-coder/dbt_branch,61,1,Ritik574-coder,dbt_branch | ||
| afe17e6bc3dfc90c0c82872c4a772d66c33baeab,2026-05-17,2026-05,Sunday,Merge pull request #60 from Ritik574-coder/dbt_branch,60,1,Ritik574-coder,dbt_branch | ||
| ef07904295bda741bbfe7fa83b2584b3523e059a,2026-05-17,2026-05,Sunday,Merge pull request #59 from Ritik574-coder/dbt_branch,59,1,Ritik574-coder,dbt_branch | ||
| 4287da02eae902c0f29bad1a9398c8871dc142c7,2026-05-16,2026-05,Saturday,Merge pull request #58 from Ritik574-coder/dbt_branch,58,1,Ritik574-coder,dbt_branch | ||
| 674d9d37f5583e1873488d3b9e1ba38dc8765c10,2026-05-16,2026-05,Saturday,Merge pull request #57 from Ritik574-coder/dbt_branch,57,1,Ritik574-coder,dbt_branch | ||
| 54975ff6f77b9bef4d05d9fc73124eca239f9c62,2026-05-16,2026-05,Saturday,Merge pull request #56 from Ritik574-coder/dbt_branch,56,1,Ritik574-coder,dbt_branch | ||
| e11915a343fb859a721592403805115f0314b7a0,2026-05-15,2026-05,Friday,Merge pull request #55 from Ritik574-coder/dbt_branch,55,1,Ritik574-coder,dbt_branch | ||
| 711f5afb901528657fec260c33d7f37cfb594e19,2026-05-15,2026-05,Friday,Merge pull request #54 from Ritik574-coder/dbt_branch,54,1,Ritik574-coder,dbt_branch | ||
| 3a50b0c083334cf91a19a232c34f7ce5dacf7d16,2026-05-15,2026-05,Friday,Merge pull request #53 from Ritik574-coder/dbt_branch,53,1,Ritik574-coder,dbt_branch | ||
| 750595f11b41145e53470be4a68f52c43e0f6acf,2026-05-14,2026-05,Thursday,Merge pull request #52 from Ritik574-coder/dbt_branch,52,1,Ritik574-coder,dbt_branch | ||
| ff4ae559841c22c5696214d4f7dc13ee84ceab69,2026-05-14,2026-05,Thursday,Merge pull request #51 from Ritik574-coder/dbt_branch,51,1,Ritik574-coder,dbt_branch | ||
| d5ae3cc9a1563ddddbfa3c583542bb9719dd1833,2026-05-14,2026-05,Thursday,Merge pull request #48 from Ritik574-coder/dbt_branch,48,1,Ritik574-coder,dbt_branch | ||
| d130178e0a416009313743250a36c47ac988af1b,2026-05-13,2026-05,Wednesday,Merge pull request #47 from Ritik574-coder/dbt_branch,47,1,Ritik574-coder,dbt_branch | ||
| fe5952b488bb1164c2ae8250feb735c283242396,2026-05-13,2026-05,Wednesday,Merge pull request #46 from Ritik574-coder/dbt_branch,46,1,Ritik574-coder,dbt_branch | ||
| 692b559fd7f411351442081867814a00594d7cd4,2026-05-13,2026-05,Wednesday,Merge pull request #45 from Ritik574-coder/dbt_branch,45,1,Ritik574-coder,dbt_branch | ||
| 7ab4485da27ef58cdeba261cc548f77d562d0fa1,2026-05-12,2026-05,Tuesday,Merge pull request #44 from Ritik574-coder/dbt_branch,44,1,Ritik574-coder,dbt_branch | ||
| 2211c9ed8904147f2fa3b302c1f19d959efa59c8,2026-05-12,2026-05,Tuesday,Merge pull request #43 from Ritik574-coder/dbt_branch,43,1,Ritik574-coder,dbt_branch | ||
| ac7363bf731af71cc376ef51f907be5432963a07,2026-05-11,2026-05,Monday,Merge pull request #42 from Ritik574-coder/dbt_branch,42,1,Ritik574-coder,dbt_branch | ||
| 2d18b65257b7177b0b01c98585fd7378002ea7fd,2026-05-11,2026-05,Monday,Merge pull request #41 from Ritik574-coder/dbt_branch,41,1,Ritik574-coder,dbt_branch | ||
| f485e706e5c650c6dacfd38e310c3d1ddaeef58a,2026-05-11,2026-05,Monday,Merge pull request #40 from Ritik574-coder/dbt_branch,40,1,Ritik574-coder,dbt_branch | ||
| ea8bde836ad8790ff3e32c82ed4c6a41bab7114d,2026-05-11,2026-05,Monday,Merge pull request #39 from Ritik574-coder/dbt_branch,39,1,Ritik574-coder,dbt_branch | ||
| 4442793431d72b6cbeef1eaa40f5c0ecab138bf9,2026-05-11,2026-05,Monday,Merge pull request #38 from Ritik574-coder/dbt_branch,38,1,Ritik574-coder,dbt_branch | ||
| 812d76dd6c221eb8eb3ab63b39142378bbb7323a,2026-05-10,2026-05,Sunday,Merge pull request #37 from Ritik574-coder/dbt_branch,37,1,Ritik574-coder,dbt_branch | ||
| c600a0903e3380a55960075e7c01e186108a1aa4,2026-05-10,2026-05,Sunday,Merge pull request #36 from Ritik574-coder/dbt_branch,36,1,Ritik574-coder,dbt_branch | ||
| a7151576694df6e6bfa45efd8bdea44d05db3885,2026-05-10,2026-05,Sunday,Merge pull request #35 from Ritik574-coder/dbt_branch,35,1,Ritik574-coder,dbt_branch | ||
| 282ddf9f1dbcc306b1228e87d24d4025c20a4846,2026-05-10,2026-05,Sunday,Merge pull request #34 from Ritik574-coder/dbt_branch,34,1,Ritik574-coder,dbt_branch | ||
| f07675e61d3356d40ec74542b65d10ee685d87ed,2026-05-09,2026-05,Saturday,Merge pull request #27 from Ritik574-coder/dbt_branch,27,1,Ritik574-coder,dbt_branch | ||
| 893be9a3df972c9d8b421e03e1a8c0418ac76f41,2026-05-09,2026-05,Saturday,Merge pull request #26 from Ritik574-coder/dbt_branch,26,1,Ritik574-coder,dbt_branch | ||
| 78f131d9a28f1726d261455a643545e2104d558f,2026-05-09,2026-05,Saturday,Merge pull request #25 from Ritik574-coder/dbt_branch,25,1,Ritik574-coder,dbt_branch | ||
| 6a287e91655849d74a20019b5facde4c1cbbe62f,2026-05-09,2026-05,Saturday,Merge pull request #24 from Ritik574-coder/dbt_branch,24,1,Ritik574-coder,dbt_branch | ||
| e952a20385a1307f47a5bad463c27aaf8db08f43,2026-05-08,2026-05,Friday,Merge pull request #23 from Ritik574-coder/dbt_branch,23,1,Ritik574-coder,dbt_branch | ||
| 0c8bd0be3ba72a88a986100b655dd85cafc7de89,2026-05-07,2026-05,Thursday,Merge pull request #22 from Ritik574-coder/dbt_branch,22,1,Ritik574-coder,dbt_branch | ||
| ac383a3c20f1a52a2ee0059c3a78d86f78fe08da,2026-05-07,2026-05,Thursday,Merge pull request #20 from Ritik574-coder/dbt_branch,20,1,Ritik574-coder,dbt_branch | ||
| ac50486918198ae7c8470d8a865c437adc895975,2026-05-06,2026-05,Wednesday,Merge pull request #19 from Ritik574-coder/dbt_branch,19,1,Ritik574-coder,dbt_branch | ||
| 1d31a646da1c53f389a821341873207253d8638c,2026-05-06,2026-05,Wednesday,Merge pull request #18 from Ritik574-coder/dbt_branch,18,1,Ritik574-coder,dbt_branch | ||
| 83cb669e02c47317eea99682b272ad7b2d2cedd9,2026-05-06,2026-05,Wednesday,Merge pull request #17 from Ritik574-coder/dbt_branch,17,1,Ritik574-coder,dbt_branch | ||
| 940075ec99381b029283193829d753f821333764,2026-05-05,2026-05,Tuesday,Merge pull request #16 from Ritik574-coder/dbt_branch,16,1,Ritik574-coder,dbt_branch | ||
| afe2642426eb4ed29525b6e5ee5993fbd1c0144b,2026-05-05,2026-05,Tuesday,Merge pull request #15 from Ritik574-coder/main,15,1,Ritik574-coder,main | ||
| a04b75442a245d1a30d54c501fbb8d339d8be5c2,2026-05-05,2026-05,Tuesday,Merge pull request #14 from Ritik574-coder/dbt_branch,14,1,Ritik574-coder,dbt_branch | ||
| a1467117388a7525a8202b821a3945bc3237af95,2026-05-05,2026-05,Tuesday,Merge pull request #13 from Ritik574-coder/dbt_branch,13,1,Ritik574-coder,dbt_branch | ||
| 3798cac3191b240755c7dc2eb7938cdf262cc426,2026-05-04,2026-05,Monday,Merge pull request #12 from Ritik574-coder/dbt_branch,12,1,Ritik574-coder,dbt_branch | ||
| 897dbfb0ef7a373eae84c4e4417e501cd7130b67,2026-05-04,2026-05,Monday,Merge pull request #11 from Ritik574-coder/dbt_branch,11,1,Ritik574-coder,dbt_branch | ||
| 755ab5ab731c0e6de5512c381bd6c7512555797e,2026-05-04,2026-05,Monday,Merge pull request #10 from Ritik574-coder/dbt_branch,10,1,Ritik574-coder,dbt_branch | ||
| 39cb160a198e188dbf2cf4c206c8cc57928ac798,2026-05-03,2026-05,Sunday,Merge pull request #9 from Ritik574-coder/dbt_branch,9,1,Ritik574-coder,dbt_branch | ||
| eb2bd106995782a3f1f184dbae7c91f630820b2a,2026-05-03,2026-05,Sunday,Merge pull request #8 from Ritik574-coder/dbt_branch,8,1,Ritik574-coder,dbt_branch | ||
| cb939cd240dada445e72dae5ce13653107c76225,2026-05-02,2026-05,Saturday,Merge pull request #7 from Ritik574-coder/dbt_branch,7,1,Ritik574-coder,dbt_branch | ||
| 2f2bcbe7599268689594c3aa685aac1d1cd96c2e,2026-05-01,2026-05,Friday,Merge pull request #6 from Ritik574-coder/dbt_branch,6,1,Ritik574-coder,dbt_branch | ||
| 11e6c003d1d248b02e3b6df1e6f54072401abdda,2026-05-01,2026-05,Friday,Merge pull request #5 from Ritik574-coder/dbt_branch,5,1,Ritik574-coder,dbt_branch | ||
| af2eeb060234abfc9bfdd6e8b541f5fa64b7eba4,2026-05-01,2026-05,Friday,Merge pull request #4 from Ritik574-coder/dbt_branch,4,1,Ritik574-coder,dbt_branch | ||
| 78eb7d44d5a70673b4968bc0a18d29aba06f5b56,2026-05-01,2026-05,Friday,Merge pull request #3 from Ritik574-coder/dbt_branch,3,1,Ritik574-coder,dbt_branch | ||
| aa5c6d7494b16882cc5cc0292cc72cfa07b05e54,2026-05-01,2026-05,Friday,Merge pull request #2 from Ritik574-coder/dbt_branch,2,1,Ritik574-coder,dbt_branch | ||
| d11350b1302c3d0293013303a09701354ef2ac6e,2026-05-01,2026-05,Friday,Merge pull request #1 from Ritik574-coder/dbt_branch,1,1,Ritik574-coder,dbt_branch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
git log --mergeswithout--first-parentwalks all parents, so merges that happened on side/topic branches are included in the dataset and can distort totals and trends for the main integration branch. In repos where teams regularly merge upstream into feature branches, this will inflate merge counts and make the monthly/weekday metrics report activity that was never merged directly into the target branch.Useful? React with 👍 / 👎.