Git: beste Möglichkeit, alle Änderungen aus einer bestimmten Datei für einen Zweig zu entfernen

Lesezeit: 4 Minuten

Ich habe einen etwas chaotischen Zweig mit etwa 20 Commits und bereite mich auf eine Zusammenführung zurück zum Master vor. Ich habe es auf Master umgestellt, und bei näherer Betrachtung stelle ich fest, dass Dateien auf eine Weise geändert werden, die für diesen Zweig völlig irrelevant ist und nicht zum Festschreiben bereit sind. Die Änderungen an diesen Dateien sind nicht auf bestimmte Commits beschränkt.

Grundsätzlich möchte ich, dass diese Dateien nach Möglichkeit nicht in diesen Zweig aufgenommen werden. Gibt es einen guten Weg, dies zu tun? Meine Ausweichposition Nr. 1 besteht offensichtlich darin, einfach die neueste Kopie jeder dieser Dateien zu kopieren und dann zu committen. Aber dann wird die Geschichte immer noch die Änderungen enthalten und die Git-Götter werden mich missbilligen.

Fallback-Position Nr. 2 besteht darin, dasselbe zu tun und dann den gesamten Zweigverlauf auf einen Commit zu reduzieren.

Gibt es diesbezüglich Verbesserungen?

Sagen Sie, Ihre Geschichte ist

$ git lola
* 6473d7f (master) Update
| * 9bcfa7e (HEAD, topic) Munge a, b, and c
| * 99af942 Munge b and c
| * 8383e2c Munge a and b
|/
* d1363f4 Baseline

Notiz: lola ist ein nicht standardmäßiger, aber hilfreicher Alias.

Die Commits haben drei verschiedene Dateien geändert.

$ git log --decorate=short --pretty=oneline --name-status topic
9bcfa7e946a92c226ad50ce430a9e4ae55b32490 (HEAD, topic)
M       a
M       b
M       c
99af942dbb922effcad8a72e96bec9ee9afcc437 Munge b and c
M       b
M       c
8383e2c8d6092550fec13d3c888c037b3a68af15 Munge a and b
M       a
M       b
d1363f4fba67d94999b269b51bdb50a8a68ba27a Baseline
A       a
A       b
A       c

Die Änderungen an der Datei b sind diejenigen, die Sie behalten möchten und an denen Sie alle Änderungen verwerfen möchten a Und c. Eine Möglichkeit, dies zu tun, ist mit git filter-branch.

$ git checkout -b tmp topic
Switched to a new branch 'tmp'

$ git merge-base topic master
d1363f4fba67d94999b269b51bdb50a8a68ba27a

$ git filter-branch --tree-filter 'git checkout d1363f -- a c' master..tmp
Rewrite 8383e2c8d6092550fec13d3c888c037b3a68af15 (1/3)
Rewrite 99af942dbb922effcad8a72e96bec9ee9afcc437 (2/3)
Rewrite 9bcfa7e946a92c226ad50ce430a9e4ae55b32490 (3/3)
Ref 'refs/heads/tmp' was rewritten

Der obige Baumfilter checkt die Commits im genannten Bereich aus und stellt Dateien wieder her a Und c auf den Inhalt an der „Merge-Basis“, also dem Commit, bei dem topic abgezweigt von master.

Jetzt tmp hat alles topic‘s ändert sich zu b aber keine Änderungen an einer anderen Datei.

$ git log --decorate --pretty=oneline --name-status tmp
9ee7e2bd2f380cc338b0264686bcd6f071eb1087 (HEAD, tmp) Munge a, b, and c
M       b
226c22f150af1ddc1f9adc19f97fc4f220851ada Munge b and c
M       b
45e706f7b22c37ee2025ee0d04c651135e7b31cd Munge a and b
M       b
d1363f4fba67d94999b269b51bdb50a8a68ba27a Baseline
A       a
A       b
A       c

Als Sicherheitsmaßnahme git filter-branch speichert eine Sicherungskopie Ihrer ursprünglichen Referenz. Wenn Sie mit Ihren Änderungen zufrieden sind und das Backup löschen möchten tmplaufen

$ git update-ref -d refs/original/refs/heads/tmp

  • +1 Ausgezeichnete Antwort. Die Verwendung von filter-branch ist ein erstaunliches Werkzeug, wenn man sich erst einmal damit beschäftigt.

    – ralphtheninja

    17. März 2012 um 19:21 Uhr

  • Es gibt viele tolle Sachen hier, die ich immer noch verdaue. ‘log –name-status ‘ ist cool.

    – Steve Bennett

    18. März 2012 um 0:17

  • Buh. Ich habe alle Schritte dieser hervorragenden Antwort befolgt und bis zum Ende des Filterzweigs lief alles reibungslos. „WARNUNG: Ref ‚refs/heads/tmp‘ ist unverändert.“ Beim Überprüfen des Verlaufs sind die Dateiänderungen immer noch vorhanden und keine der Commit-IDs hat sich geändert (soweit ich das beurteilen kann), obwohl Git gemeldet hat, dass sie alle „neu geschrieben“ wurden. Hmm.

    – Steve Bennett

    18. März 2012 um 0:43

  • Ah. Seltsamerweise wurde beim Argument „git checkout“ die Groß-/Kleinschreibung beachtet (obwohl ich unter Windows arbeite). Es hat jetzt funktioniert. Das Ausführen dieses Befehls „git log“ ist jetzt in zweierlei Hinsicht seltsam: Die Datei wird immer noch als geändert aufgeführt (auch wenn im Diff keine Änderungen daran vorgenommen wurden), und die alte Commit-ID wird beibehalten (wird jetzt jedoch gelb angezeigt). Gruseliger Befehl!

    – Steve Bennett

    18. März 2012 um 0:51

  • Ähm, nächste Frage: Wie stellt man das Backup wieder her, das ich in refs/original/heads/… sehe?

    – Steve Bennett

    18. März 2012 um 1:30

Um zu einer bestimmten Version auszuchecken, können Sie dies tun
git checkout <sha1> <file>
Wo sha1 ist der eindeutige SHA1-Hash der Version, in der sich die Datei befinden soll.

  • Sind Sie neugierig, ob Sie eine auf diese Weise wiederhergestellte Datei in einem Zweig einchecken – ob dadurch im Wesentlichen alle Änderungen dieser Datei aus dem Zweigverlauf entfernt werden?

    – colm.anseo

    31. März 2022 um 15:52 Uhr

Als Windows-Benutzer bin ich auf ein paar Probleme gestoßen:

  1. Verwenden Sie doppelte Anführungszeichen für den Befehl –tree-filter.
  2. Verwenden Sie Schrägstriche für den Dateipfad.
  3. Beginnen Sie den Dateipfad nicht mit einem Schrägstrich.

So sah mein Befehl letztendlich aus:

git filter-branch -f --tree-filter "git checkout a59f75 -- source/_posts/blog1.md source/_posts/blog2.md" master..tmp

1450530cookie-checkGit: beste Möglichkeit, alle Änderungen aus einer bestimmten Datei für einen Zweig zu entfernen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy