git tag




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

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


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" nur mit 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 dem Staging-Bereich file_C 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. Wenden Sie die Änderungen in "temp_stash" (file_A und file_B) auf Ihren lokalen Code an und löschen Sie den Stash

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


Schnelle Antwort

Um eine bestimmte geänderte Datei in git wiederherzustellen, 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

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


Da es bei git im Wesentlichen darum geht, den gesamten Inhalt und den Index des Repositorys (und nicht eine oder mehrere Dateien) zu verwalten, handelt es sich nicht überraschend um mit dem ganzen Arbeitsverzeichnis .

Tatsächlich können Sie seit Git 2.13 (Q2 2017) einzelne Dateien mit git stash push :

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 pathspec entsprechen

Weitere Informationen finden Sie unter " Änderungen an bestimmten Dateien ändern ".

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 ursprüngliche Lösung von stash --patch ) ist zwar nett, aber ich habe oft eine Vielzahl von Dateien geändert, so dass die Verwendung von Patch ärgerlich ist

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

chhh weist in den Kommentaren auf einen alternativen Workflow hin:

Sie sollten " git reset --soft " nach einem solchen Stash verwenden, um Ihre eindeutige git reset --soft :
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 irgend 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 interaktiv Hunks aus dem Unterschied zwischen HEAD und dem zu --patch 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 möglicherweise andere indizierte Dateien enthält) 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 schlägt eleotlecram 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 HEAD-Inhalt zurück

Am Ende dieses ziemlich umständlichen Prozesses werden nur eine oder mehrere Dateien gespeichert.


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. Setzen 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, machen 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 Dateisystem zurücksetzen begehen Sie direkt davor. Jetzt hast du nur noch das Zeug, das du nicht verstauen willst.


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

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

Setzen Sie das ursprüngliche Commit zurück, und überprüfen Sie die Datei "the_one_file" aus dem neuen Commit:

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

Jetzt können Sie the_one_file ablegen:

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 ...


Ich fand keine Antwort auf das, 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.


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 bestimmte verfolgte / nicht protokollierte Dateien unterbringen zu können :

  • git stash -p (--patch) : Hunks manuell auswählen, wobei nicht aufgezeichnete Dateien ausgeschlossen werden
  • git stash -k (--keep-index) : Verstopfung aller verfolgten / nicht aufgespürten Dateien und Aufbewahrung im Arbeitsverzeichnis
  • git stash -u (--include-untracked) : Alle verfolgten / nicht protokollierten Dateien werden abgelegt
  • git stash -p (--patch) -u (--include-untracked) : ungültiger Befehl

Derzeit ist die vernünftigste Methode, um bestimmte verfolgte / nicht nachverfolgte Dateien unterzubringen, folgende Möglichkeiten:

  • 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 dieses Verfahren in einer Antwort auf eine andere Frage geschrieben , und es gibt Schritte, um das Verfahren in SourceTree auszuführen .


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, machen Sie Folgendes:

  1. Bühne alles
  2. Nehmen Sie Änderungen an Ihrer Arbeitskopie vor, die alle Änderungen in Datei A rückgängig 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. (zB 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!

In dieser Situation git add -p ich git add -p (interaktiv) hinzu, git commit -m blah und verstaue dann das, was noch übrig ist.


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 der erste stash & stash pop eliminiert werden kann. Sie können alle Ihre Änderungen beim Checkout in den Hauptzweig übernehmen, 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 ...


Nehmen wir an, Sie haben 3 Dateien

a.rb
b.rb
c.rb

und Sie möchten nur b.rb und c.rb, aber nicht 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.


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

Sie werden zu jedem Hunk 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

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

$ 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
    }
  }
}

Update (14.02.2015) - Ich habe das Skript ein wenig umgeschrieben, um Konflikte besser bewältigen 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, daher 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 Ihre Arbeitsstruktur enthält noch nicht gespeicherte Änderungen.

In einigen Fällen hängen die Änderungen der Arbeitsstruktur von den Indexänderungen ab. Wenn Sie 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.


Verwenden Sie git stash push wie git stash push :

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

Zum Beispiel:

git stash push -- my/file.sh

Dies ist seit Git 2.13 im Frühjahr 2017 verfügbar.


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

Versuchen Sie, die Dateien mit " git add filepath " git add filepath .

Führen Sie diese Zeile später aus

git stash --keep-index


Warnung

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

Dies wird alles, was Sie noch nicht hinzugefügt haben, unterbringen. git add Sie einfach die Dinge git add die Sie behalten möchten, und führen Sie sie aus.

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 vorzunehmen.
  7. git commit
  8. git stash pop
  9. Wiederholen Sie den Vorgang ab Nummer 5 nach Bedarf.
  10. git rebase --continue




git-stash