0Pricing
AI Agents · درس

تحليل سجل الالتزامات والفروق

استعراض سجل الالتزامات، واستخراج الملفات المتغيرة، وتلخيص الفروق

تحليل سجل الالتزامات والفروق درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.

لماذا نحلل سجل عمليات commit؟

يُعد سجل عمليات commit منجمًا ثمينًا للوكلاء؛ إذ يكشف ما الذي تغيّر، ومتى تغيّر، ومن أجراه. ويستخدم الوكلاء سجل عمليات commit لإنشاء سجلات التغييرات، وتلخيصات مراجعة الشيفرة، وتقارير نشاط المطورين، واكتشاف المخاطر، مثل التغييرات الكبيرة القريبة من إصدارات البرنامج، وفهم تطور قاعدة الشيفرة.

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()}')

تصفية عمليات commit حسب النطاق الزمني

استخدم المعلمتين since وuntil للحصول على عمليات commit ضمن نطاق زمني محدد. تقبل كلتاهما كائنات Python من النوع datetime. وهذه هي الأداة الأساسية لإنشاء تقارير النشاط الأسبوعية أو الشهرية.

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
)

إحصاءات commit: الإضافات والحذف

يحتوي كل كائن commit على الخاصية stats، التي تتضمن أعداد التغييرات additions وdeletions وtotal عبر جميع الملفات التي تغيّرت. ويعطي ذلك فكرة سريعة عن حجم التغيير.

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')

عرض الملفات التي تغيّرت في commit

تضم commit.files قائمة بكائنات File، كائنًا لكل ملف تغيّر في commit. وتشمل الخصائص: filename وstatus (مضاف أو معدّل أو محذوف أو معاد تسميته) وadditions وdeletions وpatch (نص الفرق).

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)}')

تحليل نص الفرق (Patch)

يحتوي file.patch على فرق موحّد. فالأسطر التي تبدأ بالرمز + هي إضافات، والتي تبدأ بالرمز - هي عمليات حذف، أما أسطر السياق فلا تحمل بادئة. حلّل هذا النص لاستخراج الأسطر المضافة بهدف تحليلها، مثل البحث عن أسرار جديدة أو تعليقات TODO أو أنماط غير سليمة.

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)

تجميع النشاط حسب المؤلف

جمّع عمليات commit حسب المؤلف لإنشاء تقارير نشاط المطورين. احسب عدد عمليات commit والأسطر المضافة والمحذوفة والملفات التي عُدّلت لكل مؤلف ضمن فترة زمنية. ويفيد ذلك في جلسات استعراض أداء الفريق واتخاذ قرارات إسناد طلبات السحب.

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')

إنشاء سجل تغييرات من عمليات commit

يقرأ وكيل سجل التغييرات عمليات commit الواقعة بين وسمين أو تاريخين، ثم يجمعها حسب النوع (feat أو fix أو chore وفق تنسيق conventional commit)، وينشئ سجل تغييرات منسقًا. استخدم نموذج LLM لتحسين جودة وصف كل 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')

تحديد عمليات commit عالية المخاطر

تكون عمليات commit عالية المخاطر عندما تكون كبيرة الحجم، أو تمس ملفات مهمة مثل المصادقة أو الدفع أو الأمان، أو أُجريت قريبًا جدًا من إصدار. ويمكن لوكيل الإبلاغ عنها لإخضاعها لتدقيق إضافي قبل دمجها في main.

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}')

مقارنة عمليتي commit

استخدم repo.compare(base, head) للحصول على الفرق بين مرجعين، مثل فرعين أو وسمين أو قيمتي SHA لعمليتي commit. ويُرجع ذلك كائن Comparison يتضمن الإحصاءات المجمعة، وقائمة عمليات commit، وقائمة الملفات التي تغيّرت بين النقطتين.

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')

تلخيص عمليات commit باستخدام LLM

مرّر مجموعة من رسائل عمليات commit وأسماء الملفات إلى نموذج LLM لإنشاء ملخص مفهوم للبشر لما تغيّر خلال فترة زمنية. وهذا هو جوهر روبوت الملخص الهندسي الأسبوعي.

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].text

اكتشاف الملفات الحساسة في عمليات commit

يفحص وكيل تحليل عمليات commit المخصص للأمان عمليات commit التي تتضمن عن طريق الخطأ ملفات حساسة، مثل المفاتيح الخاصة أو ملفات .env أو ملفات الإعدادات التي تحتوي على بيانات اعتماد أو تفريغات قواعد البيانات. افحص commit.files بحثًا عن أسماء ملفات تطابق أنماطًا حساسة معروفة.

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}')

تحقق سريع: commit.files في مقابل pr.get_files()

اختبر مدى فهمك للوصول إلى فروق عمليات commit.

خلاصة تحليل سجل عمليات commit

يمكن لوكيلك الآن تحليل سجل عمليات commit تحليلًا شاملًا:

  • repo.get_commits(since, until, author, sha) — تصفية عمليات commit حسب الوقت أو المؤلف أو الفرع
  • commit.stats — الإضافات والحذف والإجمالي عبر جميع الملفات التي تغيّرت
  • commit.files — تفاصيل كل ملف، بما في ذلك الفرق (unified diff)
  • حلّل file.patch لفحص الأسطر المضافة بحثًا عن الأسرار أو TODO أو الأنماط غير السليمة
  • جمّع عمليات commit حسب المؤلف لإنشاء تقارير النشاط
  • repo.compare(base, head) — الفرق بين مرجعين، مثل الفروع أو الوسوم أو قيم SHA
  • استخدم نماذج LLM لإنشاء ملخصات مفهومة للبشر من قوائم رسائل عمليات commit
  • أبلغ عن عمليات commit عالية المخاطر: تغييرات كبيرة + ملفات مهمة + قربها من الإصدارات

الأسئلة الشائعة

هل درس «تحليل سجل الالتزامات والفروق» مجاني؟

نعم — نص درس «تحليل سجل الالتزامات والفروق» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.

ماذا ستتعلم في «تحليل سجل الالتزامات والفروق»؟

استعراض سجل الالتزامات، واستخراج الملفات المتغيرة، وتلخيص الفروق تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟

لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «تحليل سجل الالتزامات والفروق»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟

نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. نظرة عامة على GitHub REST API
  2. عرض المشكلات وإدارتها
  3. تعليقات المراجعة الآلية لـ PR
  4. تحليل سجل الالتزامات والفروق
← العودة إلى AI Agents