השוואת טקסטים
השוו שני טקסטים צד לצד או בתצוגה מאוחדת, עם הדגשות ברמת מילה, אפשרויות רווחים ורישיות, ו-patch להעתקה.
הדביקו שתי גרסאות של טקסט להשוואה
מה הכלי הזה עושה
diff עונה על שאלה אחת במדויק: מה צריך להשתנות כדי להפוך טקסט אחד לאחר? הדביקו את המקור בחלון «מקור» ואת הגרסה החדשה בחלון «מתוקן», והכלי מציג כל שורה שנמחקה, כל שורה שנוספה, ובתוך שורה ששונתה — את המילים המדויקות שהשתנו, מודגשות. זו אותה שאלה ש-git עונה עליה בכל commit, מחושבת עם אותה משפחת אלגוריתמים, כולה בדפדפן שלכם.
החלק האחרון חשוב בכלי diff יותר מברוב הכלים: הדברים שאנשים משווים נוטים להיות פרטיים — שתי גרסאות של קונפיג פרודקשן, שאילתה לפני ואחרי אופטימיזציה, גוף התשובה שעבד אתמול מול זה שנכשל היום. כאן הם לעולם לא עוזבים את המכשיר.
צד לצד או מאוחדת
שתי התצוגות מציגות את אותה השוואה בסידור שונה. צד לצד מציבה את המקור ואת המתוקן זה מול זה — עמודת המקור מתחת לחלון «מקור» — עם שורות תואמות מיושרות, הדרך הטבעית לקרוא גרסה חדשה של מסמך. מאוחדת שוזרת אותם בעמודה אחת: מחיקות עם מינוס בתחילת השורה והוספות עם פלוס — הפורמט של git log ושל סקירות קוד, קומפקטי יותר וטוב יותר כשהשינויים מפוזרים. שתי התצוגות מסמנות את מספרי השורות המקוריים בשוליים, כך שממצא כאן ממופה ישר חזרה לקובץ שלכם.
איך ה-diff מחושב
הכלי מממש את אלגוריתם ההבדלים של Myers, שפורסם ב-1986 ועדיין ברירת המחדל של git היום. הוא מוצא סקריפט עריכה קצר ביותר: המספר המינימלי של מחיקות והוספות שורות שהופך טקסט אחד לאחר. המינימליות הזאת היא מה שהופך diff לקריא — השוואה נאיבית שמסתנכרנת מחדש בצורה גרועה אחרי שינוי מדווחת על בלוקים שלמים כמוחלפים, בעוד Myers מצביע בדיוק על שתי השורות שבאמת זזו.
ההשוואה נעשית קודם ברמת שורות, ואז כל זוג שורות ששונו מושווה שוב ברמת מילים כדי להפיק את ההדגשות. מגבלה אחת ביושר: כששני טקסטים כמעט לא חולקים דבר, חיפוש הסקריפט המינימלי היה עולה יותר זיכרון ממה שראוי ללשונית דפדפן, ולכן מעבר למרחק עריכה של אלפיים הכלי נסוג להצגת הכול כמוחלף — ואומר את זה בהודעה, במקום בשקט.
אפשרויות הרווחים והרישיות
הרבה הבדלים הם אמיתיים אבל לא רלוונטיים. קובץ שהוזח מחדש מטאבים לרווחים, רווח סופי שעורך הוסיף, מילת מפתח שאותיותיה הוגדלו — כולם שינויים אמיתיים, כולם רעש כשמה שרוצים לדעת הוא אם הלוגיקה השתנתה. שתי תיבות הסימון מטפלות במקרים הנפוצים: אחת מנטרלת רווחים בקצוות כל שורה, השנייה מנטרלת רישיות. הן משפיעות רק על מה שנחשב שינוי — התצוגה תמיד מציגה כל שורה בדיוק כפי שהודבקה.
- התעלם מרווחי קצה — רווחים וטאבים בתחילת ובסוף שורה נזרקים לפני ההשוואה, כך ששינוי הזחה בלבד מפסיק להופיע כשורה ששונתה. רווחים בתוך השורה עדיין נספרים.
- התעלם מרישיות — שורות ומילים שנבדלות רק בגודל אותיות נחשבות שוות. שימושי למילות מפתח של SQL, שמות כותרות HTTP והקשרים אחרים שאינם רגישים לרישיות.
ה-patch שאפשר להעתיק
כפתור ההעתקה מפיק את ההשוואה בפורמט unified diff — השפה המשותפת של שינויי קוד. כל בלוק שינוי (hunk) נפתח בכותרת @@ שמציינת את מספרי השורות שהוא מכסה, שורות שנמחקו מתחילות במינוס, שורות שנוספו בפלוס, וכמה שורות הקשר לא-משתנות עוטפות כל בלוק כדי שאפשר יהיה לאתר את השינוי גם אם הקובץ זז מעט.
--- a +++ b @@ -1,3 +1,3 @@ server: - port: 8080 + port: 9090 timeout: 30
את הטקסט הזה אפשר להדביק בכרטיס משימה או בסקירת קוד, לשלוח לעמית, או להחיל מכנית: שמרו לקובץ, ו-git apply או פקודת patch של יוניקס ישחזרו את השינוי על המקור. פרט ששווה להכיר: קובץ שלא מסתיים ב-newline מקבל ב-patch את הסימון \ No newline at end of file — הכלי משחזר את ההתנהגות הזאת, כי newline סופי חסר הוא הבדל אמיתי, והעמדת פנים אחרת מייצרת patches שלא חלים.
שאלות נפוצות
- למה מדווח שינוי כששני הטקסטים נראים אותו דבר?
- ההבדל כנראה בלתי-נראה: רווחים בסוף שורה, טאבים מול רווחים, או newline חסר אחרי השורה האחרונה. הפעילו «התעלם מרווחי קצה» כדי לשלול את השניים הראשונים. הבדל של newline סופי עדיין ידווח — גם git מדווח עליו, עם סימון ה-no-newline שלו — כי הבדל ברמת הבייטים אמיתי גם כשאף תו לא מציג אותו.
- למה טקסטים שונים מאוד מוצגים כהחלפה אחת גדולה?
- מציאת ה-diff המינימלי עולה זיכרון ביחס לריבוע של מידת השוני בין הטקסטים. מעבר למרחק עריכה של כאלפיים שינויי שורות הכלי עובר לתצוגה גסה של הכול-הוחלף ומציג הודעה. עם שתי גרסאות של אותו מסמך לעולם לא תגיעו לזה; השוואת שני קבצים לא קשורים — כן.
- איך מחילים את ה-patch שהועתק?
- שמרו אותו לקובץ, ואז הריצו git apply thefile.patch בתוך המאגר, או patch original.txt thefile.patch עם הכלי הקלאסי של יוניקס. ה-patch נוצר מול הטקסט המקורי המדויק, ולכן הוא חל נקי כל עוד היעד לא זז.
- האם משהו מהטקסט שלי מועלה לשרת?
- לא. ההשוואה רצה כולה בדפדפן — אין שרת שיכול לראות את שני הטקסטים. זו בדיוק הנקודה של חישוב בצד הלקוח: קונפיגים, סיסמאות ונתוני פרודקשן מושווים בלי לעזוב את המחשב.