11 Punkte von GN⁺ 4 시간 전 | 3 Kommentare | Auf WhatsApp teilen
  • Git hat drei Ebenen für Regeln zum Ignieren von Dateien, je nach Geltungsbereich: .gitignore, .git/info/exclude und ~/.config/git/ignore
  • .gitignore wird zusammen mit dem Repository-Code committet und ist daher der richtige Ort für gemeinsame Regeln, die ein Team oder Projekt zusammen anwenden soll
  • Einträge wie persönliche Dateien oder Dateien für lokale Arbeiten, die im Repository nicht nötig sind, sich aber schlecht als Team-Regel eignen, passen besser in .git/info/exclude
  • Dateien, die in allen Repositories immer wieder ausgeschlossen werden sollen, wie .DS_Store unter macOS, kann man in die maschinenweite Ignore-Datei ~/.config/git/ignore eintragen
  • git check-ignore -v <Dateiname> ist nützlich, um nachzuverfolgen, welche Regel eine Datei ignoriert; gibt es keine passende Regel, erfolgt keine Ausgabe

Wo Git Ignore-Regeln angewendet werden

  • Git kann Regeln zum Ignieren von Dateien an drei Stellen verarbeiten
    • .gitignore
    • .git/info/exclude
    • ~/.config/git/ignore

.gitignore: Gemeinsame Regeln, die ins Repository committet werden

  • .gitignore ist die übliche Datei, in der Dateinamen eingetragen werden, die ignoriert werden sollen
  • Sie wird zusammen mit dem restlichen Code in Git eingecheckt
  • Dateien, die auf Regeln in .gitignore passen, werden bei der Ausführung von git-Befehlen nicht berücksichtigt

.git/info/exclude: Persönliche Regeln pro Repository

  • Die Datei exclude befindet sich im .git-Verzeichnis jedes Git-Repositories
  • Änderungen an dieser Datei werden nicht in Git eingecheckt
  • In neuen Git-Repositories enthält sie normalerweise ein paar Kommentarzeilen
  • Sie eignet sich für Dateien, die nur in diesem Repository ignoriert werden sollen, aber nicht in .gitignore gehören
    • Beispiel: Wenn du notes.txt, das du nur für deinen persönlichen Workflow brauchst, weder in das Repository committen noch zur .gitignore des Projekts hinzufügen willst, trägst du notes.txt in .git/info/exclude ein

~/.config/git/ignore: Maschinenweite Regeln

  • Die globale ignore-Datei liegt im Home-Verzeichnis unter ~/.config/git/ignore
  • Dateinamen, die hier hinzugefügt werden, werden maschinenweit global ignoriert
  • Sie wird nicht in Git eingecheckt und ist nicht mit einem bestimmten Repository verknüpft
  • Das ist ein guter Ort für Dateien, die du in allen Git-Repositories auf deinem Computer ignorieren willst
    • Beispiel: Unter macOS ist es sinnvoll, .DS_Store hier einzutragen

Pfad der globalen Ignore-Datei ändern

  • Die globale Ignore-Datei kann auch auf eine andere Datei gesetzt werden
  • Wenn du .gitignore_global als globale Git-Ignore-Datei verwenden willst, führe den folgenden Befehl aus
git config --global core.excludesFile ~/.gitignore_global
  • Um zur Standardeinstellung zurückzukehren, führe den folgenden Befehl aus
git config --global --unset core.excludesFile

Prüfen, welche Regel eine Datei ignoriert

  • Mit git check-ignore -v <Dateiname> kannst du prüfen, durch welche Regel eine bestimmte Datei ignoriert wird
  • Um zu prüfen, wie .DS_Store ignoriert wird, führe im Git-Repository den folgenden Befehl aus
git check-ignore -v .DS_Store
  • Wenn .gitignore des Repositories .DS_Store ignoriert, sieht die Ausgabe zum Beispiel so aus
$ git check-ignore -v .DS_Store
.gitignore:1:.DS_Store	.DS_Store
  • Wenn .git/info/exclude des Repositories .DS_Store ignoriert, sieht die Ausgabe zum Beispiel so aus
$ git check-ignore -v .DS_Store
.git/info/exclude:7:.DS_Store	.DS_Store
  • Wenn die globale Datei ~/.config/git/ignore .DS_Store ignoriert, sieht die Ausgabe zum Beispiel so aus
$ git check-ignore -v .DS_Store
/Users/nelson/.config/git/ignore:2:.DS_Store	.DS_Store
  • Wenn die benutzerdefinierte globale Ignore-Datei .gitignore_global .DS_Store ignoriert, sieht die Ausgabe zum Beispiel so aus
$ git check-ignore -v .DS_Store
/Users/nelson/.gitignore_global:1:.DS_Store	.DS_Store
  • Wenn es keine Regel gibt, die eine bestimmte Datei ignoriert, liefert der Befehl git check-ignore -v keine Ausgabe

3 Kommentare

 
sudoeng 1 시간 전

Es wäre wohl auch nützlich, Dinge wie Arbeits-Specs oder die Datei plan.md in .git/info/exclude aufzunehmen.

 
yangeok 2 시간 전

Es gab also doch eine Einstellung im Root, haha.

 
GN⁺ 4 시간 전
Hacker-News-Kommentare
  • Interessanter Artikel, aber es fehlt .gitattributes, meine liebste Funktion zum fast Ignorieren in Git.
    Damit kann man festlegen, dass Git Unterschiede in bestimmten Dateien „ignoriert“. In einem Node-Projekt ist zum Beispiel package-lock.json aus Git-Sicht fast nur Rauschen. Man bekommt riesige Diffs mit konkreten Bibliotheksversionen, während die eigentlichen, für Menschen gut lesbaren Versionsinformationen separat in package.json stehen.
    Fügt man im Projekt-Root in .gitattributes einfach die Zeile package-lock.json -diff hinzu, wird die Datei weiterhin gestaged/committet, aber in git diff erscheinen keine bedeutungslosen riesigen Unterschiede mehr.

    • package-lock.json sollte kein Rauschen sein. Wenn man es nicht absichtlich aktualisieren will, sollte man es nicht ändern, sonst setzt man sich ohne Grund einem Supply-Chain-Risiko aus.
      Wenn Änderungen an package-lock.json häufig unerwartet auftauchen, macht man irgendetwas falsch.
    • package-lock.json zeigt alle transitiven Abhängigkeiten, package.json dagegen nur direkte Abhängigkeiten. Deshalb stimmt die Aussage nicht, Letzteres enthalte die „echten, menschenlesbaren Versionen“.
      Beide haben unterschiedliche Zwecke, und zu sagen, man könne Diffs der Lock-Datei immer ignorieren, ist gefährlich.
    • Wer Abhängigkeiten upgraded und Fehlerursachen nachvollzieht, wäre vermutlich ziemlich verärgert, wenn git diff keine Unterschiede in der Lock-Datei zeigt.
      Ich verstehe, dass es wie zeilenweises Rauschen wirkt, aber wenn man es braucht, braucht man es wirklich.
  • Ausschlussregeln auf globaler/Benutzerebene sollten viel bekannter sein. Ich bekomme oft Änderungen, die IDE-/OS-/AI-bezogene Dateien in die .gitignore aller Projekte aufnehmen wollen. Wenn man erklärt, dass man sie stattdessen in die Standardkonfiguration setzen kann, sodass sie überall ignoriert werden, ohne jedes Projekt anzufassen, und dass man dann auch nicht riskiert, sie versehentlich in Projekte ohne aktualisierte .gitignore zu committen, reagieren die meisten positiv.
    Meine persönliche Regel ist, .gitignore im Repository nur für Repository-spezifische Einträge wie Build-Artefakte oder Abhängigkeitsordner zu verwenden; die meisten Benutzerwerkzeuge sollten in die jeweilige Benutzerkonfiguration.

    • Dass man die globale .gitignore immer wieder erklären muss, ist die natürliche Folge des Prinzips, die .gitignore im Repository nur für Repository-spezifische Einträge zu verwenden.
      Wenn alle weniger Zeit verschwenden sollen, ist es besser, solche Dateien einfach in allen Projekten in .gitignore zu packen.
    • Ich habe sie immer in die .gitignore des Projekts aufgenommen, damit niemand aus Unwissenheit solche Dateien zum Projekt hinzufügt.
      Am Ende würde man sie sowieso wieder aus Git entfernen und der Person damit Schmerzen bereiten, also habe ich das aus Höflichkeit von vornherein verhindert. Vielleicht bin ich in Zukunft weniger höflich.
    • Ich bevorzuge die gitignore-Variante, weil sie auch einen Neuaufbau von Development-Containern überlebt.
      Wenn man gitignore vermeiden will, kann man die Konfiguration zwar über Generierungsskripte oder Volumes wiederherstellen/beibehalten, aber dann braucht man statt einer Zeile in .gitignore zusätzliche Skripte oder devcontainer-Mount-Konfiguration.
    • Ist das nicht ein Widerspruch: ständig dasselbe falsche Verhalten zu beobachten und zugleich eine strenge Regel aufzustellen, die die einfachste Korrektur dieses Verhaltens ausdrücklich verbietet?
  • Für globale Git-Konfiguration und Ignore-Dateien halte ich ~/.config/git/ignore und ~/.config/git/config für richtiger als ~/.gitignore_global plus geänderte Einstellungen.
    Wenn man ~/.config/ für mehrere Zwecke nutzt, werden die Dotfiles auf Root-Ebene viel kleiner.
    Git exclude wird wohl deshalb seltener genutzt, weil es nicht ins Repository committet wird und man es daher jedes Mal neu anlegen muss, wenn man es verwenden will. Das soll nicht heißen, dass es schlecht ist; nur deshalb wird es weniger verwendet.

    • Wenn man zusätzlich das Verzeichnis ~/.config unter Versionskontrolle stellt, lassen sich spätere Änderungen und das Teilen vereinfachen.
    • Für andere Werkzeuge, die dieselbe Datei verwenden, kann man auch ~/.cvsignore nutzen.
  • Ich weiß nicht mehr, wo ich das gelernt habe, aber ich habe attic zu meinem globalen Git-Ignore hinzugefügt.
    So kann ich in jedem Projekt ein Verzeichnis attic anlegen, um allerlei Dinge abzulegen, die auf keinen Fall committet werden dürfen. Ein Repository, das tatsächlich nach solchen Verzeichnissen sucht, ist mir noch nicht begegnet.

    • Man kann es auch etwas umgekehrt machen, aber dann jeweils pro Fall.
      Wenn es ein Verzeichnis wie attic gibt, kann man darin attic/.gitignore mit /** anlegen; dann werden das Verzeichnis und alles darin ignoriert, inklusive der Ignore-Datei selbst.
      Normalerweise benenne ich meine Version dieses Verzeichnisses mit einem einzelnen U+1F4A9-Zeichen, aber HN erlaubt das in Kommentaren nicht.
    • Bei mir heißt es aux.
      Wenn ich darin eine .gitignore mit nur einem Stern * ablege, wird sie selbst und alles darin ignoriert.
    • Ich mache das auch. Bei mir heißt es nur .local.
    • Bei mir ist es scratch/.
      Das hat mir bisher noch keine Probleme gemacht.
  • Bei benutzerspezifischen Ignore-Regeln gilt für macOS: .DS_Store dort hinzuzufügen ist zwar ideal, aber dann müssten das alle Mac-Nutzer des Projekts tun.
    Wenn es mehr als einen gibt, ist es vielleicht besser, das nicht jedem selbst zu überlassen.

    • Ich weiß nicht genau, woher das kommt, aber auf meinen beiden Macs (einer mit Ventura, einer mit Sequoia) gibt es in der Datei ~/.gitignore_global einen Eintrag für .DS_Store, und in der globalen Git-Konfiguration ist eingestellt, dass die Einträge dieser Datei ignoriert werden.
      Das Datum dieser Datei auf dem neuen Mac liegt zwei Tage vor der Bestellung, und ich kann mich nicht erinnern, das selbst eingerichtet zu haben, daher scheint sie standardmäßig vorhanden gewesen zu sein. Ich vermute, auf dem alten Mac war es ähnlich; angesichts der macOS-Versionen könnte das also schon seit geraumer Zeit die Voreinstellung sein.
      Vielleicht ist die Zeit also vorbei, in der man .DS_Store/ zu .gitignore hinzufügen musste.
    • Eine ziemlich eigenartige Sicht auf Minderheit und Mehrheit. Wenn ein einziger macOS-Nutzer an zehn Projekten arbeitet, sollten dann wirklich alle zehn Projekte diese Zeile hinzufügen, oder ist es nicht besser, das bei diesem einen Nutzer zu lösen?
  • Wow, wie konnte ich das nicht wissen? Ich bin seit 20 Jahren professioneller Softwareentwickler und habe immer nur .gitignore verwendet.
    Mir wird gerade klar, dass ich mich nie gefragt habe, ob es einen besseren Weg gibt, als .gitignore mit allen möglichen Ausschlüssen vollzustopfen, die nur für mich relevant sind. Ich habe die Welt einfach so akzeptiert, wie sie sich gezeigt hat.
    Heute ist die Welt ein kleines bisschen besser geworden.

  • Ich benutze .git/info/exclude wirklich oft. Das passt hervorragend für Skripte/Makefile, die nur lokal verwendet werden und die Mitarbeitende weder brauchen noch verwenden können.

    • Mich würde interessieren, was Beispiele für Skripte sind, die andere Mitarbeitende nicht verwenden können. Meinst du etwa Skripte für den PR-Workflow?
    • Seit ziemlich langer Zeit nutze ich eine Shell-Funktion, die alle in git status angezeigten untracked Dateien direkt nach .git/info/exclude schiebt.
      Meistens wende ich sie an, nachdem ich die Dinge, die tatsächlich ins Repository sollen, per add und commit übernommen habe.
  • In Projektverzeichnissen mit mehreren Repositories nutze ich Excludes-Dateien so, um projektbezogene Git-Konfigurationen unterschiedlich anzuwenden.
    https://laszlo.nu/blog/project-level-git-config.html

  • Dazu habe ich einige Aliase im Einsatz.
    assume = update-index --assume-unchanged
    unassume = update-index --no-assume-unchanged
    assumed = "!git ls-files -v | grep ^h | cut -c 3-"
    unassumeall = "!git assumed | xargs git update-index --no-assume-unchanged"
    assumeall = "!git st -s | awk {'print $2'} | xargs git assume"

  • Für bereits verfolgte Dateien gibt es auch git update-index --[no]-skip-worktree.
    Das kann für lokale Experimente nützlich sein, aber Git macht diese Funktion nicht gerade gut sichtbar, daher ist ihre Nutzung etwas umständlich. Man muss sich merken, dass man sie gesetzt hat, und wenn man das vergisst, können andere Vorgänge wie ein Checkout blockiert werden.