it-swarm.com.de

Nur eine Datei aus mehreren Dateien, die sich mit Git geändert haben, unterbringen?

Wie kann ich nur eine von mehreren geänderten Dateien in meinem Zweig speichern?

2638
Rachel

Warnung

Wie in den Kommentaren erwähnt, wird dadurch sowohl alles als auch nicht inszeniert. Der Index -keep-Index lässt den Index nach dem Verarbeiten einfach stehen. Dies kann zu Zusammenführungskonflikten führen, wenn Sie den Stash später wieder öffnen.


Dadurch wird alles, was Sie noch nicht hinzugefügt haben, gespeichert. Einfach git add die Dinge, die Sie behalten möchten, und dann ausführen.

git stash --keep-index

Wenn Sie beispielsweise ein altes Commit in mehrere Änderungssätze aufteilen möchten, können Sie dieses Verfahren verwenden:

  1. git rebase -i <last good commit>
  2. Markieren Sie einige Änderungen als edit.
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. Reparieren Sie die Dinge nach Bedarf. Vergessen Sie nicht, Änderungen zu git add zu machen.
  7. git commit
  8. git stash pop
  9. Wiederholen Sie den Vorgang ab Nummer 5 nach Bedarf.
  10. git rebase --continue
1260
bukzor

Sie können auch git stash save -p "my commit message" verwenden. Auf diese Weise können Sie auswählen, welche Hunks zur Ablage hinzugefügt werden sollen. Es können auch ganze Dateien ausgewählt werden. 

Sie werden für jedes Stück mit einigen Aktionen aufgefordert:

   y - stash this hunk
   n - do not stash this hunk
   q - quit; do not stash this hunk or any of the remaining ones
   a - stash this hunk and all later hunks in the file
   d - do not stash this hunk or any of the later hunks in the file
   g - select a hunk to go to
   / - search for a hunk matching the given regex
   j - leave this hunk undecided, see next undecided hunk
   J - leave this hunk undecided, see next hunk
   k - leave this hunk undecided, see previous undecided hunk
   K - leave this hunk undecided, see previous hunk
   s - split the current hunk into smaller hunks
   e - manually edit the current hunk
   ? - print help
2868

Da es bei git im Wesentlichen darum geht, ein gesamtes Repository content und einen Index (und nicht eine oder mehrere Dateien) zu verwalten, behandelt git stash nicht überraschend mit dem ganzen Arbeitsverzeichnis.

Eigentlich können Sie seit Git 2.13 (Q2 2017) einzelne Dateien mit git stash Push ablegen:

git stash Push [--] [<pathspec>...]

Wenn pathspec an 'git stash Push' übergeben wird, zeichnet der neue Stash den geänderten Status nur für die Dateien auf, die der Pfadspezifikation entsprechen

Weitere Informationen finden Sie unter " Stash-Änderungen an bestimmten Dateien ".

Der Testfall ist selbsterklärend:

test_expect_success 'stash with multiple pathspec arguments' '
    >foo &&
    >bar &&
    >extra &&
    git add foo bar extra &&

    git stash Push -- foo bar &&   

    test_path_is_missing bar &&
    test_path_is_missing foo &&
    test_path_is_file extra &&

    git stash pop &&
    test_path_is_file foo &&
    test_path_is_file bar &&
    test_path_is_file extra

In der ursprünglichen Antwort (unten, Juni 2010) ging es darum, manuell auszuwählen, was Sie speichern möchten. 

Casebash Kommentare:

Diese (die stash --patch-Originallösung) ist Nizza, aber oft habe ich viele Dateien geändert, so dass die Verwendung von Patch ärgerlich ist

bukzor 's answer (angehoben, November 2011) schlägt eine praktischere Lösung vor, basierend auf
git add + git stash --keep-index.
.__ Gehen Sie und sehen Sie seine Antwort, die die offizielle sein sollte (anstatt meiner).

In dieser Option weist chhh auf einen alternativen Workflow in den Kommentaren hin:

sie sollten "git reset --soft" nach so einem Zwischenstopp eingeben, um Ihre eindeutige Inszenierung wieder herzustellen:
Um in den ursprünglichen Zustand zu gelangen - der ein klarer Bereitstellungsbereich ist und mit nur wenigen ausgewählten, nicht inszenierten Modifikationen - kann man den Index sanft zurücksetzen, um ihn zu erhalten (ohne etwas wie Sie - bukzor - zu tun).


(Ursprüngliche Antwort Juni 2010: manuelle Aufbewahrung)

Mit git stash save --patch können Sie jedoch die teilweise Einlagerung erreichen, die Sie suchen:

Mit --patch können Sie in der Differenz zwischen HEAD und dem zu verblendenden Arbeitsbaum interaktiv Hunks auswählen.
Der Stash-Eintrag ist so aufgebaut, dass sein Indexstatus mit dem Indexstatus Ihres Repositorys übereinstimmt und sein Arbeitsbaum nur die Änderungen enthält, die Sie interaktiv ausgewählt haben. Die ausgewählten Änderungen werden dann von Ihrem Arbeitsbaum zurückgesetzt.

Dadurch wird jedoch der vollständige Index gespeichert (der möglicherweise nicht das ist, was Sie möchten, da er andere bereits indizierte Dateien enthalten kann) und einen teilweisen Worktree (der wie der aussehen könnte, den Sie speichern möchten).

git stash --patch --no-keep-index

könnte eine bessere Passform sein.


Wenn --patch nicht funktioniert, kann ein manueller Prozess

Für eine oder mehrere Dateien wäre eine Zwischenlösung:

  • kopiere sie außerhalb des Git-Repos
    (Eigentlich eleotlecram schlägt eine interessante Alternative vor )
  • git stash
  • kopiere sie zurück
  • git stash # Dieses Mal werden nur die gewünschten Dateien gespeichert
  • git stash pop [email protected]{1} # Wenden Sie alle Änderungen an Ihren Dateien erneut an
  • git checkout -- afile # setzt die Datei vor lokalen Änderungen auf den Inhalt HEAD zurück

Am Ende dieses ziemlich umständlichen Prozesses haben Sie nur eine oder mehrere Dateien.

324
VonC

Wenn git stash -p (oder git add -p mit stash --keep-index) zu umständlich wäre, fiel mir die Verwendung von diff, checkout und apply leichter.

Um nur eine bestimmte Datei/ein bestimmtes Verzeichnis zu "speichern":

git diff path/to/dir > stashed.diff
git checkout path/to/dir

Dann nachher

git apply stashed.diff
80
blueyed

Verwenden Sie git stash Push wie folgt:

git stash Push [--] [<pathspec>...]

Zum Beispiel:

git stash Push -- my/file.sh

Dies ist verfügbar seit Git 2.13, veröffentlicht im Frühjahr 2017.

58
sandstrom

Nehmen wir an, Sie haben 3 Dateien 

a.rb
b.rb
c.rb

und Sie möchten nur b.rb und c.rb, nicht jedoch a.rb unterbringen

sie können so etwas tun

# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp" 

# then stash the other files
git stash save "stash message"

# then undo the previous temp commit
git reset --soft HEAD^
git reset

Und du bist fertig! HTH.

45
venkatareddy

Eine andere Möglichkeit, dies zu tun:

# Save everything
git stash 

# Re-apply everything, but keep the stash
git stash apply

git checkout <"files you don't want in your stash">

# Save only the things you wanted saved
git stash

# Re-apply the original state and drop it from your stash
git stash apply [email protected]{1}
git stash drop [email protected]{1}

git checkout <"files you put in your stash">

Ich kam dazu, nachdem ich (wieder) auf diese Seite gekommen war und die ersten beiden Antworten nicht mochte (die erste Antwort beantwortet die Frage einfach nicht und ich habe nicht gern mit dem -p-interaktiven Modus gearbeitet).

Die Idee ist die gleiche wie die von @VonC vorgeschlagene Verwendung von Dateien außerhalb des Repositorys. Sie speichern die gewünschten Änderungen an einem beliebigen Ort, entfernen die Änderungen, die Sie nicht in Ihrem Vorrat haben möchten, und übernehmen dann die Änderungen, die Sie außerhalb des Speicherbereichs verschoben haben. Ich habe den Git-Stash jedoch als "irgendwo" verwendet (und am Ende gibt es noch einen zusätzlichen Schritt: Entfernen Sie die Cahnges, die Sie in den Stash gesteckt haben, da Sie diese ebenfalls aus dem Weg geschoben haben).

27
Jasper

Update (14.02.2015) - Ich habe das Skript ein wenig umgeschrieben, um Konflikte besser handhaben zu können, die jetzt als nicht zusammengeführte Konflikte und nicht als .rej-Dateien dargestellt werden sollten.


Ich finde es oft intuitiver, die Umkehrung von @ bukzors Ansatz durchzuführen. Das heißt, um einige Änderungen zu inszenieren und dann nur die inszenierten Änderungen zu verwahren. 

Leider bietet git keinen git-stash -only-index oder ähnliches an, deshalb habe ich ein Skript dazu erstellt.

#!/bin/sh

# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`

# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`

# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`

# get back to a clean state with no changes, staged or otherwise
git reset -q --hard

# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to succeed
git cherry-pick -n $INDEXCOMMIT
git stash

# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT

CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
    # If there are no conflicts, it's safe to reset, so that
    # any previously unstaged changes remain unstaged
    #
    # However, if there are conflicts, then we don't want to reset the files
    # and lose the merge/conflict info.
    git reset -q
fi

Sie können das obige Skript als git-stash-index irgendwo in Ihrem Pfad speichern und es dann als git stash-index aufrufen

# <hack hack hack>
git add <files that you want to stash>
git stash-index

Der Stash enthält jetzt einen neuen Eintrag, der nur die von Ihnen bereitgestellten Änderungen enthält, und Ihr Arbeitsbaum enthält noch nicht gespeicherte Änderungen.

In einigen Fällen hängen die Änderungen der Arbeitsstruktur von den Indexänderungen ab. Wenn Sie also die Indexänderungen speichern, besteht ein Konflikt zwischen den Änderungen der Arbeitsstruktur. In diesem Fall erhalten Sie die üblichen nicht zusammengeführten Konflikte, die Sie mit git merge/git mergetool/etc lösen können.

23
JesusFreke

Da das Erstellen von Verzweigungen in Git trivial ist, können Sie einfach einen temporären Zweig erstellen und die einzelnen Dateien darin einchecken.

19
shangxiao

Nur für den Fall, dass Sie eigentlich verwerfen Änderungen verwenden, wenn Sie git stash verwenden (und nicht wirklich git stash verwenden, um es temporär zu speichern), können Sie in diesem Fall verwenden 

git checkout -- <file>

[HINWEIS

Dieser git stash ist nur eine schnellere und einfachere Alternative zum Verzweigen und Erstellen von Dingen.

11
Devesh

Speichern Sie den folgenden Code in einer Datei, beispielsweise mit dem Namen stash. Die Verwendung ist stash <filename_regex>. Das Argument ist der reguläre Ausdruck für den vollständigen Pfad der Datei. B. ein/b/c.txt, stash a/b/c.txt oder stash .*/c.txt usw. verstauen.

$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml

Code zum Kopieren in die Datei:

#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]

spawn git stash -p

for {} 1 {} {
  expect {
    -re "diff --git a/($filename_regexp) " {
      set filename $expect_out(1,string)
    }
    "diff --git a/" {
      set filename ""
    }
    "Stash this hunk " {
      if {$filename == ""} {
        send "n\n"
      } else {
        send "a\n"
        send_user "$filename\n"
      }
    }
    "Stash deletion " {
      send "n\n"
    }
    eof {
      exit
    }
  }
}
10
apricot

Das Problem mit der "Intermediate" -Lösung von VonC, Dateien außerhalb des Git-Repos zu kopieren, besteht darin, dass Pfadinformationen verloren gehen, was dazu führt, dass ein paar Dateien später zu einem gewissen Aufwand zurückkopiert werden.

Es ist einfacher, tar (anstelle ähnlicher Tools) zu verwenden:

  • tar cvf /tmp/stash.tar Pfad/zu/einige/Dateipfad/zu/einige/andere/Datei (... usw.)
  • git checkout path/to/some/dateipfad/to/some/other/datei
  • git stash
  • tar xvf /tmp/stash.tar
  • etc. (siehe VonCs "Zwischenvorschlag")
7
eleotlecram

Dies kann leicht in 3 Schritten mit SourceTree durchgeführt werden.

  1. Legen Sie vorübergehend alles fest, was Sie nicht verstauen möchten.
  2. Git alles hinzufügen und dann verstauen.
  3. Machen Sie Ihr temporäres Commit durch, indem Sie git reset ausführen, um das Commit vor dem temporären zu erreichen.

Dies alles kann in SourceTree in wenigen Sekunden erledigt werden. Klicken Sie einfach auf die Dateien (oder sogar einzelne Zeilen), die Sie hinzufügen möchten. Einmal hinzugefügt, verpflichten Sie sie einfach zu einem temporären Commit. Klicken Sie anschließend auf das Kontrollkästchen, um alle Änderungen hinzuzufügen, und klicken Sie dann auf Stash, um alles zu speichern. Wenn die Änderungen nicht im Weg sind, werfen Sie einen Blick auf Ihre Commit-Liste, und notieren Sie den Hash für das Commit vor dem temporären Commit. Führen Sie dann 'git reset hash_b4_temp_commit' aus. Dies ist im Wesentlichen wie das "Poppen" des Commits, indem Sie Ihren Zweig auf das Programm zurücksetzen begehen Sie direkt davor. Jetzt hast du nur noch das Zeug, das du nicht verstauen willst.

7
Triynko

Ich würde git stash save --patch verwenden. Ich finde die Interaktivität nicht störend, da es Optionen gibt, um die gewünschte Operation auf ganze Dateien anzuwenden.

Manchmal habe ich in meinem Zweig eine nicht zusammenhängende Änderung vorgenommen, bevor ich ihn festgeschrieben habe, und ich möchte ihn in einen anderen Zweig verschieben und separat festlegen (wie den Master). Ich mache das:

git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...

Beachten Sie, dass die erste stash & stash pop entfernt werden kann. Sie können alle Ihre Änderungen beim Auschecken in den Zweig master übertragen, jedoch nur, wenn keine Konflikte vorliegen. Wenn Sie einen neuen Zweig für die Teiländerungen erstellen, benötigen Sie den Vorrat.

Sie können es vereinfachen, vorausgesetzt, es gibt keine Konflikte und keinen neuen Zweig:

git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...

Versteck nicht einmal nötig ...

6
void.pointer

Sie können dies einfach tun:

git stash Push "filename"

oder mit einer optionalen Nachricht

git stash Push -m "Some message" "filename"
6
vinodsaluja

Jede Antwort hier ist so kompliziert ...

Was ist mit diesem "Stash":

git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash

Um die Datei zurückzublättern:

git apply /tmp/stash.patch

Genau das gleiche Verhalten wie das Einlagern einer Datei und das Wiederherstellen der Datei.

6

Ich habe die Antworten und Kommentare zu diesem Thema und einer Reihe ähnlicher Threads überprüft. Beachten Sie, dass keiner der folgenden Befehle korrekt ist, um alle bestimmten verfolgten/nicht nachverfolgten Dateien unterbringen zu können:

  • git stash -p (--patch): Auswahl der Hunks manuell, wobei nicht nachverfolgte Dateien ausgeschlossen werden
  • git stash -k (--keep-index): Bewahren Sie alle verfolgten/nicht nachverfolgten Dateien auf und bewahren Sie sie im Arbeitsverzeichnis auf
  • git stash -u (--include-untracked): Alle verfolgten/nicht nachverfolgten Dateien werden gespeichert
  • git stash -p (--patch) -u (--include-untracked): ungültiger Befehl

Derzeit ist es die vernünftigste Methode, bestimmte verfolgte/nicht aufgespürte Dateien zu speichern:

  • Bestätigen Sie vorübergehend die Dateien, die Sie nicht verstauen möchten
  • Hinzufügen und stash
  • Pop das temporäre Commit

Ich habe ein einfaches Skript für diese Prozedur in einer Antwort auf eine andere Frage geschrieben, und es gibt Schritte zum Ausführen der Prozedur in SourceTree hier .

3
ZimbiX

Lösung

Lokale Änderungen: 

  • file_A (modifiziert) nicht inszeniert 
  • file_B (modifiziert) nicht inszeniert 
  • file_C (modifiziert) nicht inszeniert 

So erstellen Sie einen Stash "my_stash" mit nur den Änderungen an file_C :

1. git add file_C
2. git stash save --keep-index temp_stash
3. git stash save my_stash
4. git stash pop [email protected]#{1}

Erledigt.


Erläuterung

  1. fügen Sie file_C zum Bereitstellungsbereich hinzu
  2. erstellen Sie einen temporären Stash mit dem Namen "temp_stash" und behalten Sie die Änderungen in file_C
  3. erstellen Sie den gewünschten Stash ("my_stash") nur mit den Änderungen an file_C
  4. Übernehmen Sie die Änderungen in "temp_stash" (file_A und file_B) auf Ihren lokalen Code und löschen Sie den Stash

Sie können git status zwischen den Schritten verwenden, um zu sehen, was los ist.

3
Alex 75

Wenn Sie keine Nachricht mit Ihren gespeicherten Änderungen angeben möchten, übergeben Sie den Dateinamen nach einem Doppelstrich.

$ git stash -- filename.ext

Wenn es sich um eine nicht verfolgte/neue Datei handelt, müssen Sie sie zuerst bereitstellen.

Diese Methode funktioniert in Git-Versionen 2.13+

2
sealocal
git add .                           //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash                           //stash the file(s)
git reset .                         // unstage all staged files
git stash pop                       // unstash file(s)
2
novice

Um eine einzelne Datei zu speichern, verwenden Sie git stash --patch [file].

Dies wird zu Prompt: Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?. Geben Sie einfach a ein (dieses Hunk und alle späteren Hunks in der Datei) und schon geht es Ihnen gut.

2
vnbrs

In dieser Situation git add -p (interaktiv), git commit -m blah und verstaue dann ggf. den Rest.

2
J0hnG4lt

Ähnliche Situation. Hat begangen und festgestellt, dass es nicht in Ordnung ist.

git commit -a -m "message"
git log -p

Basierend auf den Antworten hat mir das geholfen.

# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it's ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it's ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually Push tu remote
git Push
1
David Hrbáč

Wenn Sie versuchen, zwischen zwei Zweigen zu wechseln, tritt diese Situation auf.

Versuchen Sie, die Dateien mit "git add filepath" hinzuzufügen.

Führen Sie diese Zeile später aus 

git stash --keep-index

1

Ich weiß nicht, wie ich es in der Kommandozeile machen soll, nur mit SourceTree. Nehmen wir an, Sie haben Datei A geändert und haben zwei Änderungsgruppen in Datei B. Wenn Sie nur die zweite Gruppe in Datei B speichern möchten und alles andere unberührt lassen möchten, gehen Sie folgendermaßen vor:

  1. Bühne alles
  2. Nehmen Sie Änderungen an Ihrer Arbeitskopie vor, um alle Änderungen in Datei A rückgängig zu machen (z. B. externes Diff-Tool starten und Dateien zusammenbringen.)
  3. Lassen Sie die Datei B so aussehen, als würde nur eine zweite Änderung vorgenommen. (z. B. externes Diff-Tool starten und erste Änderung rückgängig machen.)
  4. Erstellen Sie einen Vorrat mit "Behalten Sie die Änderungen".
  5. Alles inszenieren
  6. Erledigt!
1

Ich habe keine Antwort gefunden, was ich brauchte und das ist so einfach wie:

git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash

Dies speichert genau eine Datei.

0
Sebastian

Ein komplizierter Weg wäre, zuerst alles zu begehen:

git add -u
git commit // creates commit with sha-1 A

Zurück zum ursprünglichen Commit, aber check the_one_file vom neuen Commit aus:

git reset --hard HEAD^
git checkout A path/to/the_one_file

Jetzt kannst du the_one_file unterbringen:

git stash

Bereinigung durch Speichern des zugesicherten Inhalts in Ihrem Dateisystem, während der ursprüngliche Commit wiederhergestellt wird:

git reset --hard A
git reset --soft HEAD^

Ja, etwas unbeholfen ...

0
Martin G

Schnelle Antwort


Um eine bestimmte geänderte Datei in git zurückzusetzen, können Sie die folgende Zeile ausführen:

git checkout <branch-name> -- <file-path>

Hier ist ein aktuelles Beispiel:

git checkout master -- battery_monitoring/msg_passing.py

0
Benyamin Jafari