Historique des commits et analyse des différences
Parcourez l’historique des commits, extrayez les fichiers modifiés et résumez les différences.
Historique des commits et analyse des différences est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.
Pourquoi analyser l’historique des commits ?
L’historique des commits est une véritable mine d’or pour les agents : il révèle ce qui a changé, quand et par qui. Les agents l’utilisent pour générer des journaux des modifications, produire des synthèses de revues de code, établir des rapports d’activité des développeurs, détecter les risques — comme les changements importants effectués juste avant une mise en production — et comprendre l’évolution d’une base de code.
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
# Get recent commits on the default branch
commits = repo.get_commits()
print(f'Total commits: {commits.totalCount}')
# Preview the last 5
for commit in commits[:5]:
print(f'{commit.sha[:8]} | {commit.commit.author.name}')
print(f' {commit.commit.message.split(chr(10))[0][:60]}')
print(f' {commit.commit.author.date.date()}')Filtrer les commits par période
Utilisez les paramètres since et until pour obtenir les commits compris dans une période précise. Ces deux paramètres acceptent des objets Python datetime. Il s’agit de l’outil principal pour générer des rapports d’activité hebdomadaires ou mensuels.
import datetime
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
# Last 7 days of commits
now = datetime.datetime.utcnow()
last_week = now - datetime.timedelta(days=7)
recent_commits = repo.get_commits(
since=last_week,
until=now
)
print(f'Commits in last 7 days: {recent_commits.totalCount}')
# By specific author
author_commits = repo.get_commits(
since=last_week,
author='alice' # GitHub username
)
print(f'Alice\'s commits last week: {author_commits.totalCount}')
# On a specific branch
branch_commits = repo.get_commits(
sha='feature/new-api',
since=last_week
)Statistiques des commits : ajouts et suppressions
Chaque objet commit possède une propriété stats contenant le nombre d’additions, de deletions et de changements total dans tous les fichiers modifiés. Cela permet d’évaluer rapidement l’ampleur d’un changement.
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
commit = repo.get_commit('abc12345sha')
# Overall stats
print(f'SHA: {commit.sha[:8]}')
print(f'Message: {commit.commit.message[:80]}')
print(f'Author: {commit.commit.author.name}')
print(f'Date: {commit.commit.author.date}')
print(f'Additions: +{commit.stats.additions}')
print(f'Deletions: -{commit.stats.deletions}')
print(f'Total changes: {commit.stats.total}')
# Large commit warning
if commit.stats.total > 500:
print('WARNING: Large commit — careful code review needed')Répertorier les fichiers modifiés dans un commit
commit.files est une liste d’objets File, un pour chaque fichier modifié dans le commit. Propriétés : filename, status (ajouté, modifié, supprimé ou renommé), additions, deletions et patch (le texte du diff).
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
commit = repo.get_commit('abc12345sha')
print(f'Files changed: {len(commit.files)}')
for f in commit.files:
print(f' [{f.status.upper():<8}] {f.filename}')
print(f' +{f.additions} -{f.deletions}')
if f.previous_filename: # for renamed files
print(f' Renamed from: {f.previous_filename}')
# Find changed Python files
python_changes = [
f for f in commit.files
if f.filename.endswith('.py')
]
print(f'\nPython files changed: {len(python_changes)}')Analyser le texte du diff (patch)
Le file.patch contient un diff unifié. Les lignes commençant par + correspondent aux ajouts, celles commençant par - aux suppressions, et les lignes de contexte n’ont aucun préfixe. Analysez-le pour extraire les lignes ajoutées, par exemple afin de rechercher de nouveaux secrets, des commentaires TODO ou des anti-modèles.
def extract_added_lines(patch):
if not patch:
return []
added = []
for line in patch.split('\n'):
if line.startswith('+') and not line.startswith('+++'):
added.append(line[1:]) # strip the '+' prefix
return added
def scan_for_secrets(added_lines):
import re
PATTERNS = [
(r'api[_-]?key\s*=\s*["\'][^"\']{20,}', 'potential API key'),
(r'password\s*=\s*["\'][^"\']{6,}', 'potential hardcoded password'),
(r'sk-[a-zA-Z0-9]{20,}', 'potential OpenAI key'),
(r'ghp_[a-zA-Z0-9]{36}', 'potential GitHub token'),
]
findings = []
for i, line in enumerate(added_lines, 1):
for pattern, label in PATTERNS:
if re.search(pattern, line, re.IGNORECASE):
findings.append({'line': i, 'type': label, 'preview': line[:80]})
return findings
# --- demo ---
patch = (
'@@ -1,2 +1,3 @@\n'
' def connect():\n'
'+ api_key = "sk-abcdefghijklmnopqrstuvwx"\n'
'+ password = "hunter2222"\n'
)
added = extract_added_lines(patch)
print('Added lines:', added)
for finding in scan_for_secrets(added):
print(finding)
Regrouper l’activité par auteur
Regroupez les commits par auteur pour produire des rapports d’activité des développeurs. Comptez, pour chaque auteur et sur une période donnée, les commits, les lignes ajoutées ou supprimées et les fichiers concernés. Cela est utile pour les rétrospectives d’équipe et les décisions d’attribution des PR.
import datetime
from collections import defaultdict
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
last_month = datetime.datetime.utcnow() - datetime.timedelta(days=30)
author_stats = defaultdict(lambda: {'commits': 0, 'additions': 0, 'deletions': 0, 'files': set()})
for commit in repo.get_commits(since=last_month):
author = commit.commit.author.name
author_stats[author]['commits'] += 1
author_stats[author]['additions'] += commit.stats.additions
author_stats[author]['deletions'] += commit.stats.deletions
for f in commit.files:
author_stats[author]['files'].add(f.filename)
print('Author Activity (last 30 days):')
for author, stats in sorted(author_stats.items(), key=lambda x: -x[1]['commits']):
print(f'{author}: {stats["commits"]} commits, +{stats["additions"]} -{stats["deletions"]}, {len(stats["files"])} files')Générer un journal des modifications à partir des commits
Un agent de génération de journal des modifications lit les commits compris entre deux étiquettes ou deux dates, les regroupe par type — fonctionnalité, correction ou tâche, selon le format des commits conventionnels — puis génère un journal des modifications mis en forme. Utilisez un LLM pour améliorer la qualité de la description de chaque commit.
import re
import datetime
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
def get_commits_since_tag(repo, tag_name):
try:
ref = repo.get_git_ref(f'tags/{tag_name}')
tag_sha = ref.object.sha
tag_commit = repo.get_commit(tag_sha)
since = tag_commit.commit.author.date
return list(repo.get_commits(since=since))[:-1] # exclude the tag commit
except Exception:
return []
def parse_conventional_commit(message):
match = re.match(r'^(feat|fix|chore|docs|test|refactor|perf|style)(\(.+?\))?: (.+)', message)
if match:
return match.group(1), match.group(3)
return 'other', message.split('\n')[0][:60]
commits = get_commits_since_tag(repo, 'v1.2.0')
by_type = {'feat': [], 'fix': [], 'other': []}
for c in commits:
msg = c.commit.message
ctype, desc = parse_conventional_commit(msg)
by_type.get(ctype, by_type['other']).append(desc)
print(f'Parsed {len(commits)} commits')Identifier les commits à haut risque
Les commits à haut risque sont volumineux, modifient des fichiers critiques — authentification, paiements ou sécurité — ou sont effectués très peu de temps avant une mise en production. Un agent peut les signaler pour qu’ils soient examinés plus attentivement avant leur fusion dans la branche principale.
import datetime
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
CRITICAL_PATHS = [
'src/auth', 'src/payment', 'src/security',
'config/', '.env', 'Dockerfile', 'requirements.txt'
]
def is_high_risk(commit):
reasons = []
# Large change
if commit.stats.total > 300:
reasons.append(f'Large change: {commit.stats.total} lines')
# Touches critical files
for f in commit.files:
for path in CRITICAL_PATHS:
if f.filename.startswith(path):
reasons.append(f'Touches critical: {f.filename}')
break
return reasons
now = datetime.datetime.utcnow()
for commit in repo.get_commits(since=now - datetime.timedelta(days=1)):
risks = is_high_risk(commit)
if risks:
print(f'HIGH RISK: {commit.sha[:8]} - {commit.commit.message[:50]}')
for r in risks:
print(f' - {r}')Comparer deux commits
Utilisez repo.compare(base, head) pour obtenir le diff entre deux références — branches, étiquettes ou identifiants SHA de commits. Cette opération renvoie un objet Comparison contenant les statistiques combinées, la liste des commits et la liste des fichiers modifiés entre ces deux points.
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
# Compare two branches
comparison = repo.compare('main', 'feature/new-api')
print(f'Commits ahead: {comparison.ahead_by}')
print(f'Commits behind: {comparison.behind_by}')
print(f'Status: {comparison.status}') # ahead/behind/identical/diverged
print(f'Total commits in diff: {len(comparison.commits)}')
print(f'Files changed: {len(comparison.files)}')
# Summary of what changed
for f in comparison.files:
print(f' {f.status}: {f.filename} +{f.additions} -{f.deletions}')
# Compare two tags
tag_comparison = repo.compare('v1.0.0', 'v1.1.0')
print(f'Changes between v1.0.0 and v1.1.0: {len(tag_comparison.commits)} commits')Synthèse de commits générée par un LLM
Fournissez à un LLM un lot de messages de commits et de noms de fichiers afin de générer une synthèse lisible par un humain des changements effectués au cours d’une période donnée. C’est le cœur d’un robot hebdomadaire de synthèse de l’activité d’ingénierie.
import anthropic
import os
client = anthropic.Anthropic(api_key=os.environ['ANTHROPIC_API_KEY'])
def summarize_commits(commits, time_period='last week'):
commit_data = []
for commit in commits[:30]: # limit to avoid context overflow
commit_data.append(
f'- {commit.commit.message.split(chr(10))[0][:80]} '
f'(+{commit.stats.additions}/-{commit.stats.deletions})'
)
commit_list = '\n'.join(commit_data)
prompt = (
f'Summarize what happened in this codebase {time_period} '
f'based on these commit messages. Be concise (3-5 bullet points). '
f'Focus on user-facing changes and significant technical work.\n\n'
f'Commits:\n{commit_list}'
)
response = client.messages.create(
model='claude-opus-4-5',
max_tokens=400,
messages=[{'role': 'user', 'content': prompt}]
)
return response.content[0].textDétecter les fichiers sensibles dans les commits
Un agent d’analyse des commits axé sur la sécurité recherche les commits qui incluent accidentellement des fichiers sensibles : clés privées, fichiers .env, configurations contenant des identifiants ou sauvegardes de bases de données. Vérifiez dans commit.files les noms de fichiers correspondant à des modèles sensibles connus.
import re
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
SENSITIVE_PATTERNS = [
r'\.env$', r'\.pem$', r'\.key$', r'id_rsa', r'credentials\.json',
r'secret', r'password', r'\.p12$', r'keystore', r'\btoken\b'
]
def is_sensitive_filename(filename):
for pattern in SENSITIVE_PATTERNS:
if re.search(pattern, filename, re.IGNORECASE):
return pattern
return None
import datetime
last_day = datetime.datetime.utcnow() - datetime.timedelta(days=1)
for commit in repo.get_commits(since=last_day):
for f in commit.files:
matched = is_sensitive_filename(f.filename)
if matched and f.status in ('added', 'modified'):
print(f'ALERT: Sensitive file in commit {commit.sha[:8]}')
print(f' File: {f.filename} (matched: {matched})')
print(f' Author: {commit.commit.author.name}')
print(f' Link: {commit.html_url}')Vérification rapide : commit.files et pr.get_files()
Vérifiez votre compréhension de l’accès aux diffs des commits.
Récapitulatif de l’analyse de l’historique des commits
Votre agent peut maintenant analyser l’historique des commits de manière exhaustive :
- repo.get_commits(since, until, author, sha) — filtrer les commits par période, auteur ou branche
- commit.stats — ajouts, suppressions et total pour tous les fichiers modifiés
- commit.files — détails de chaque fichier, notamment le patch (diff unifié)
- Analyser
file.patchpour rechercher des secrets, des TODO ou des anti-modèles dans les lignes ajoutées - Regrouper les commits par auteur pour les rapports d’activité
- repo.compare(base, head) — diff entre deux références (branches, étiquettes ou identifiants SHA)
- Utiliser des LLM pour générer des synthèses lisibles par un humain à partir de listes de messages de commits
- Signaler les commits à haut risque : changements importants, fichiers critiques et proximité d’une mise en production
Questions Fréquemment Posées
La leçon « Historique des commits et analyse des différences » est-elle gratuite ?
Oui — le texte complet de « Historique des commits et analyse des différences » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Historique des commits et analyse des différences » ?
Parcourez l’historique des commits, extrayez les fichiers modifiés et résumez les différences. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Agents ?
Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Historique des commits et analyse des différences » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?
Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Présentation de l’API REST GitHub
- Répertorier et gérer les problèmes
- Commentaires automatisés de revue de PR
- Historique des commits et analyse des différences