כלי סביבת העבודה

מאפייני קבצים

.gitattributes הוא הקובץ בעל הערך הגבוה ביותר ב־git שכמעט אף אחד לא כותב. זו הדרך שבה מאגר מלמד את git על התוכן של עצמו: אילו קבצים בינאריים, אילו צריכים להשתרשר במקום להתנגש, אילו לעולם לא יוצאים בארכיון, ואילו סופי שורה כולם מקבלים.

החלק החשוב: הוא נכנס לקומיט. כלל שתוסיפו מתקן את הבעיה לכל מי שמשכפל, בכל מערכת הפעלה, לנצח — בניגוד להגדרה בתצורה שלכם, שמתקנת את זה עבורכם ומשאירה את העמיתים שלכם לגלות את זה בדרך הקשה.

⌘K ← מאפייני קבצים.

הכללים שמאגר כבר נושא, הערכות המוכנות, בודק הנתיבים ודרייברי הדיף

מה הכללים עושים

מאפיין מתקן
text=auto eol=lf סופי שורה שמתהפכים לפי מי עשה צ׳קאאוט לקובץ
binary git שמנסה להשוות או למזג תלת־כיוונית PSD, DOCX או נכס מהודר
merge=union יומן שינויים שכולם מוסיפים לו, וכולם מתנגשים עליו
-merge קבצים שבהם מיזוג תלת־כיווני מייצר שטויות — קובצי נעילה, קוד מחולל
export-ignore תצורת CI ופיקסצ׳רים שנשלחים בתוך tarball של ריליס
diff=<driver> דיפים בלתי קריאים לפורמטים שכן קריאים, בהינתן ממיר
filter=lfs קבצים גדולים שנשמרים דרך LFS
linguist-vendored קוד מוטמע שנספר כשלכם בסטטיסטיקת השפות

binary הוא קיצור ל־-diff -merge -text, שהוא שלוש תשובות ל״תפסיק לנחש לגבי הקובץ הזה״ במילה אחת.

עריכה

הערכות המוכנות ממלאות תבנית ואת המאפיינים שלה; ערכו את התבנית לפני ההוספה — CHANGELOG.md הוא הצעה, לא כלל על הפרויקט שלכם.

העריכות כירורגיות. הוספת כלל לתבנית שכבר יש לה אחד כותבת מחדש את השורה הזו במקומה, במקום לצרף כלל שני שמנצח בזכות היותו מאוחר יותר. ההערות בקובץ שורדות בלי שנוגעים בהן, כי ה״למה״ שליד כלל שווה בדרך כלל יותר מהכלל.

כל שמירה היא פעולת Gitcito רגילה: היא מציגה הודעה קופצת, וביטול משחזר את הקובץ בדיוק כפי שהיה.

למאגר יכולים להיות כמה קובצי מאפיינים. אחד בשורש, אחד בכל תת־תיקייה, ו־.git/info/attributes פרטי שלעולם אינו נכנס לקומיט וחל רק במחשב שלכם — המקום הנכון לכלל שנוגע לכם, לא לפרויקט. Gitcito מונה את כולם ואומר מי הוא מי.

מה חל על נתיב?

הכללים מגיעים מכמה קבצים, הספציפי יותר מנצח, וקריאה שלהם כדי לחשב את התשובה היא ניחוש. מה חל על נתיב? מריץ git check-attr ומראה למה git עצמו מגיע — התשובה היחידה שנחשבת.

דרייברי דיף: להפוך מסמך Word לקריא

.docx הוא zip. .pdf הוא גרף אובייקטים דחוס. git משווה אותם כמו שהם — רעש — ולכן ההיסטוריה של מסמך בלתי קריאה גם כשהמסמך עצמו אינו כזה.

דרייבר דיף מתקן את זה עם textconv: פקודה שהופכת את הקובץ לטקסט לצורכי השוואה בלבד. הקובץ בעץ העבודה שלכם אינו נגוע; git פשוט משווה את הטקסט שהומר.

שני חצאים, ושניהם נחוצים:

  1. diff.<name>.textconv בתצורת git — פקודת הממיר.
  2. *.docx diff=<name> ב־.gitattributes — על אילו קבצים זה חל.

הכפתורים כאן עושים את שניהם בבת אחת. עבור Word, Excel, JSON ו־.strings, Gitcito מגיע עם הממיר בעצמו — אותו ניתוח מסמכים שהתצוגות המקדימות שלו משתמשות בו, חשוף כפקודה קטנה בשם gitcito-textconv בתוך האפליקציה — כך שארבעת אלה עובדים בלי להתקין דבר. השאר עדיין זקוקים לכלי אמיתי ב־PATH שלכם: Gitcito בודק ומאפיר את מה שחסר, במקום לכתוב דרייבר שנכשל בדיף הראשון.

דרייבר דורש נותן לכם
word כלום — מגיע עם Gitcito דיפים של פרוזה ב־.docx
excel כלום — מגיע עם Gitcito דיפים של שורות (CSV לכל גיליון) ב־.xlsx/.xls
json כלום — מגיע עם Gitcito דיפים יציבים של JSON, ממוינים לפי מפתח
strings כלום — מגיע עם Gitcito הפרשים לפי שורות של .strings בקידוד UTF-16, ש-git קורא לו בינארי
pdf pdftotext (poppler) דיפים טקסטואליים של .pdf
exif exiftool מה השתנה בתמונה, כשהפיקסלים אטומים

זה שבאמת נושך פרויקטי iOS

‏Localizable.strings הוא UTF-16 לאורך רוב ההיסטוריה של Xcode, ו-UTF-16 מלא בבתי NUL — ולכן git קורא לו בינארי ולא מציג כלום:

diff --git a/Localizable.strings b/Localizable.strings
Binary files a/Localizable.strings and b/Localizable.strings differ

וזה בדיוק הקובץ שבו הכי חשוב לראות איזו מחרוזת מישהו הזיז. מנהל ההתקן strings מפענח אותו לצורך ההשוואה בלבד — קורא את סימן סדר הבתים במקום להניח אותו, כך ש-.strings מודרני ב-UTF-8 עובר כמות שהוא במקום להפוך לג'יבריש.

‏String Catalogs (‏.xcstrings, מ-Xcode 15 ואילך) הם JSON, ומנהל ההתקן json מכסה אותם: הוא ממיין מפתחות, כך שתרגום שנוסף בראש הקובץ מפסיק לשכתב את כולו בהפרש.

מגבלות הממיר המובנה, בפשטות: .doc (פורמט Word הבינארי הישן) אינו מובן, רק .docx; PDF אינו מכוסה — Gitcito מציג תצוגה מקדימה של PDF עם המציג של הדפדפן, ואין לו מחלץ טקסט לעשות בו שימוש חוזר; וכל דיף של מסמך משלם עלות התנעה קצרה של הממיר. הגדרת git config diff.<name>.cachetextconv true גורמת ל־git לשמור את הפלט במטמון לכל blob.

חצי הממיר חי בתצורה שלכם, לא במאגר — git לא יריץ פקודות ששכפול מוסר לו, וזו תכונת אבטחה ששווה לשמור. הדרייברים המובנים גם מצביעים על נתיב ההתקנה של Gitcito אצלכם, ולכן חבר לצוות שמשכפל מקבל את הכלל diff=word, ועד שיחבר ממיר משלו (Gitcito או אחר) — את הדיף הישן והבלתי קריא. אמרו זאת ב־README שלכם.

מסנני clean/smudge — עם הרצה יבשה קודם

מסנן כותב מחדש תוכן בדרכו אל המאגר וממנו: clean רץ בהעלאה לאינדקס (עץ העבודה ← מאגר), smudge בצ׳קאאוט (מאגר ← עץ העבודה). כך עובד git-lfs, וכך צוותים מסלקים אישורי גישה או רעש מחולל ממה שנכנס לקומיט.

זה גם הדבר המסוכן ביותר ש־.gitattributes יכול להצביע עליו: מסנן רץ בכל צ׳קאאוט של כל קובץ תואם, ומסנן שגוי משחית בשקט את עץ העבודה שלכם. לכן Gitcito מסרב להיות כאן סתם תיבת טקסט. הגדרת מסנן עוברת דרך הרצה יבשה מול קבצים תואמים אמיתיים במאגר שלכם:

  1. פקודת ה־clean רצה על עותק של כל קובץ תואם (עד חמישה) — שום דבר במאגר או בתצורתו אינו נגוע.
  2. אם ניתנת פקודת smudge, היא רצה על הפלט המנוקה והתוצאה מושווית בית אחר בית למקור — בדיקת ההלוך ושוב. מסנן שאינו עובר את ההלוך ושוב פירושו שצ׳קאאוט לא ישחזר את מה שהיה לכם.
  3. רק אחרי הרצה יבשה על בדיוק הערכים שאתם שומרים, כפתור השמירה נדרך. הרצה יבשה שנכשלה — שגיאת פקודה, שום התאמה, או הלוך ושוב שונה — עדיין אפשר לשמור, אבל רק דרך אזהרה מפורשת שאומרת מה עלול ללכת לאיבוד.

שמירה כותבת filter.<name>.clean/smudge לתצורת git המקומית שלכם ואת הכלל filter=<name> לקובץ המאפיינים, ומשאירה רשומת ביטול שמשחזרת את מה שהתצורה החזיקה קודם. המתג required מגדיר filter.<name>.required, שגורם ל־git להיכשל בפעולה במקום להעביר קבצים בשקט כמו שהם כשהמסנן נשבר.

המגבלות, בפשטות: ההרצה היבשה דוגמת עד חמישה קבצים תואמים של עד 5 MB כל אחד, עם פסק זמן של 10 שניות לכל פקודה — מסנן שמתנהג יפה על המדגם עדיין יכול לקלקל קובץ שהמדגם פספס. הפקודות חיות בתצורה שלכם, ולכן חבר לצוות שמשכפל מקבל את הכלל filter=<name> אבל לא את הפקודות; בלעדיהן (ובלי required) הקבצים שלו עוברים כמו שהם.

מגבלות ששווה להכיר

  • text=auto משנה מה נכנס לקומיט, ומנרמל סופי שורה בדרך פנימה. במאגר קיים, הוסיפו אותו ואז הריצו git add --renormalize . בכוונה, בקומיט נפרד משלו.
  • מאפיינים אינם חלים רטרואקטיבית. סימון קובץ כ־binary היום אינו משנה איך הדיפים שלו בעבר נשמרו; הוא משנה איך git מתייחס אליו מעכשיו.
  • כללים חלים רק היכן שהקובץ נראה. כלל ב־design/.gitattributes לא אומר דבר על src/.
  • Gitcito כותב קבצים שלמים, ולכן קובץ שעוצב ביד חוזר עם העיצוב שלו — אבל כלל ש־Gitcito כותב מחדש מעוצב מחדש לריווח הקנוני של git, pattern attr attr.

ראו גם: LFS וצ׳קאאוט חלקי · חבילות וארכיונים · אפשרויות מיזוג · הוקים

שיפור התרגום הזה ב־GitHub