Wie kann man mit git nur einen Teil einer neuen Datei inszenieren?

221

Ich liebe Git Add - Interactive . Es ist jetzt Teil meines täglichen Workflows.

Das Problem scheint, dass es mit nicht verfolgten Dateien nicht funktioniert. Ich möchte eine neue Datei verfolgen, aber nur einen Teil davon hinzufügen, dh einige Teile dieser neuen Datei können noch nicht bereitgestellt werden.

Mit git add -i kann ich beispielsweise die Patch-Option auswählen und sogar einzelne Hunks bearbeiten, um Teile des neuen Codes zu inszenieren, wobei Debug-Code-Kommentare nicht bereitgestellt werden. Ich liebe es, auf diese Weise zu arbeiten, weil es offensichtlich macht, an welchen Stellen des Mega-Patches, an dem ich gerade arbeite, noch Arbeit benötigt wird.

Leider scheine ich mit einer nicht verfolgten Datei nicht in der Lage zu sein, dasselbe zu tun. Entweder inszeniere ich die ganze Datei oder nichts. Die Problemumgehung, die ich verwendet habe, besteht darin, eine neue Datei bereitzustellen oder sogar festzuschreiben, wenn sie leer ist, und dann einzelne Änderungen auf die übliche Weise bereitzustellen. Aber diese Lösung fühlt sich wie ein schmutziger Hack an und wenn ich sie vergesse oder meine Meinung ändere, entstehen mehr Probleme, als es geben sollte.

Die Frage ist also: Wie kann nur ein Teil einer neuen Datei inszeniert werden, damit diese neue Datei verfolgt wird, aber der gesamte Inhalt oder Teile davon nicht bereitgestellt werden?

Augustin
quelle

Antworten:

415

Whoa, all das update-indexund das hash-objectGeschäft scheinen zu kompliziert. Wie wäre es stattdessen damit:

git add -N new_file
git add -i

Von git help add:

-N, --intent-to-add
    Record only the fact that the path will be added later.  An entry
    for the path is placed in the index with no content.  This is useful
    for, among other things, showing the unstaged content of such files
    with git diff and committing them with git commit -a.
Richard Hansen
quelle
9
++ 1! fällige Gutschrift. Ich vertraue ein bisschen zu sehr, dass ich diese Manpages inzwischen kenne ...</shame>
sehe
1
Gut gefunden. Ich hätte die Manpage etwas weiter scrollen sollen. Vielleicht sollte ich das Git Pro-Abzeichen zurückgeben.
Dave1010
3
Ich frage mich, warum git-gui dies intern nicht verwendet, um Zeilen aus einer neuen Datei inszenieren zu können.
Deiwin
6
Wunderbare -NEntdeckung, danke! Obwohl ich es -pin diesem Fall lieber kombinieren würde . gid add -N the_file& git add -p. Man sollte hinzufügen, dass das -Nauch mit-A
Cyril CHAPON
@Deiwin - Sie können Ihrer .gitconfig ein [Guitool] hinzufügen, um ein "git add -N $ FILENAME" auszuführen: [guitool "Mit Absicht hinzufügen"] cmd = "git add -N $ FILENAME" needfile = yes noconsole = yes
Steve Folly
7

Der einfachste Weg, dies zu tun (und imho interaktive Inszenierung im Allgemeinen), ist git gui. Es wird mit git geliefert und sollte auf fast allen Plattformen funktionieren, die von git unterstützt werden.

Einfach ausführen git guiund eine GUI wird geöffnet, mit der Hunks und sogar einzelne Zeilen von verfolgten und nicht verfolgten Dateien bereitgestellt und aufgehoben werden können.

Git Gui Screenshot

Chronial
quelle
Dies ist eine kreative Antwort und manchmal sehr, sehr nützlich.
Pablo Olmos de Aguilera C.
3
Nur eine Anmerkung, die nicht alle Git-Distributionen enthalten git gui. In Debian befindet es sich beispielsweise in einem separaten Paket namens 'git-gui'.
Cristoper
Ich habe jahrelang nach dieser Funktion gesucht (nicht hart genug), dies ist ein Lebensveränderer
Austinmarton
2
Für mich hat die Inszenierung einzelner Zeilen nicht verfolgter Dateien git guinie funktioniert. Tatsächlich werden diese Menüoptionen deaktiviert .
Deiwin
2
@Deiwin Ich muss dies in der Frage tatsächlich übersehen haben - mein Screenshot zeigt eine bereits verfolgte Datei. Wenn Sie git guifür eine neue Datei verwenden möchten , müssen Sie git add -N new_filezuerst ausführen - siehe Richard Hansens Antwort.
Chronial
6
git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
git add --interactive newfile

Einfache Demo:

mkdir /tmp/demo
cd /tmp/demo
git init .

echo hello > newfile
git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
  • Tipp Wenn Sie sicher sind, dass der 'leere' Blob bereits in Ihrer Git-Objektdatenbank vorhanden ist, können Sie e69de29bb2d1d6434b8b29ae775ad8c2e48c5391stattdessen den Hash fest codieren . Ich empfehle nicht, das zu tun
  • Tipp Wenn Sie unter Windows arbeiten, können Sie wahrscheinlich nur NUL:anstelle von verwenden /dev/null. Verwenden Sie andernfalls so etwas wieecho -n '' | git hash-object --stdin -w

Jetzt enthält der Index newfileden leeren Blob, und der leere Blob wurde in die Objektdatenbank eingegeben, falls er noch nicht vorhanden war:

$ find .git/objects/ -type f 
.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   newfile
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   newfile
#

$ git diff
diff --git a/newfile b/newfile
index e69de29..ce01362 100644
--- a/newfile
+++ b/newfile
@@ -0,0 +1 @@
+hello

Dies sollte genau das sein, was Sie wollen. Darf ich auch das vim fugitive Plugin für eine sehr intelligente Indexverwaltung empfehlen (siehe Better git add -p? )

sehe sehen
quelle
1
Das scheint gut zu funktionieren. Ich habe es auf "Stage-Empty-File" aliasiert, da es etwas komplex ist, sich daran zu erinnern.
Dave1010
@ dave1010: Schön, dass es geholfen hat! Ja, ich habe darüber nachgedacht, einen Alias ​​hinzuzufügen, aber ich wusste nicht, wie Sie z. B. Platzhalter oder Argumente mit mehreren Dateinamen im Allgemeinen behandeln würden. So entschied ich mich nicht an
sehe
2

Bearbeiten: Dies scheint jetzt nicht zu funktionieren. Ich bin mir sicher, dass es vorher war (auf Git 1.7.1). Falls es nicht funktioniert, schlage ich eine Inszenierung vor, /dev/nullwie siehe oben vorschlägt:

git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile

Wenn Sie unter Windows (ohne /dev/null) arbeiten, können Sie es durch den Pfad zu einer leeren Datei ersetzen.

Ursprüngliche Antwort

Sie wollen

git add -p # (or --patch)

Dies fügt mir nicht verfolgte Dateien hinzu. Von der Manpage:

Wählen Sie interaktiv Patch-Hunks zwischen dem Index und dem Arbeitsbaum aus und fügen Sie sie dem Index hinzu. Dies gibt dem Benutzer die Möglichkeit, den Unterschied zu überprüfen, bevor dem Index geänderte Inhalte hinzugefügt werden.

Dadurch wird add --interactive effektiv ausgeführt, das anfängliche Befehlsmenü wird jedoch umgangen und direkt zum Unterbefehl patch gesprungen. Weitere Informationen finden Sie unter „Interaktiver Modus“.

dave1010
quelle
2
Wie interessant es auch sein mag, es funktioniert bei mir nicht (Git 1.7.4); git add -p newfilefunktioniert überhaupt nicht (nu-Effekt) und git add --interactive'[a] dd untracked' hat den Effekt, der git add newfilehat; Bearbeiten auch mit git 1.7.5.3 überprüft; keine Würfel
sehe
Guter Hinweis für Windows, dazu Hinweise in meiner Antwort hinzugefügt. Thx
sehe
-3

Nur zur Aufzeichnung einer anderen Möglichkeit: Ich benutze

git add -N file
git add -p file

Und dann können Sie Hunks inszenieren oder an Ort und Stelle bearbeiten.

Pedro Adame Vergara
quelle
1
Diese Antwort entspricht der akzeptierten Antwort aus dem Jahr 2011. Downvote.
Stanislav Pankevich
Die akzeptierte Antwort kombiniert add -Nmit add -i. Ich habe das nur hinzugefügt, add -panstatt auch add -izu arbeiten.
Pedro Adame Vergara