Anwenden von Git-Commits auf den Arbeitsbaum nicht hinzugefügt?

Lesezeit: 6 Minuten

Benutzeravatar von Andrew Tomazos
Andreas Tomassos

Angenommen, ich habe einen linearen Git-Verlauf von 8 Commits und einem Branch (Master):

1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> [8=master]

Ich möchte den Master auf 4 verschieben (was ich damit machen kann git branch -f master 4):

1 -> 2 -> 3 -> [4=master] -> 5 -> 6 -> 7 -> 8

Jetzt befindet sich der Arbeitsbaum im Zustand 4.

Ich möchte nun die Änderungen übernehmen 4 -> 8 zu meinem Arbeitsbaum als Patch.

Das heißt, ohne den Status des .git-Ordners zu beeinflussen, von dem ich die Änderungen anwenden möchte 4->8 unstaged zu meinem Arbeitsbaum. Danach sollte sich der Arbeitsbaum im Zustand 8 befinden, aber der festgeschriebene Zustand und der Master-Zweig sollten sich im Zustand 4 befinden.

Anders gesagt: Stellen Sie sich vor, nachdem ich den Master auf 4 verschoben habe, habe ich die Änderungen von 4->8 manuell an meinem Arbeitsbaum vorgenommen, ohne sie dem Index hinzuzufügen. Das Ergebnis sollte das gleiche sein.

Was ist der einfachste Weg, dies zu tun?

Benutzeravatar von GabeSullice
Gabe Sullice

Ich weiß, dass ich zu spät zur Party komme, aber für andere als Referenz denke ich, der einfachste Weg ist:

git cherry-pick --no-commit 4..8

  • Plus git reset danach, um Änderungen ungestagt zu erhalten.

    – Roman Susi

    12. Januar 2017 um 18:34 Uhr

Benutzeravatar von jthill
jthill

git format-patch 4..8 | xargs git apply

[edit: this next one from the comment below skips making individual patch files]

git diff 4..8 | git apply

  • Oder gleichermaßen git diff 4..8 | git apply

    – cmbuckley

    9. Januar 2013 um 23:27 Uhr

In Ihrem Fall ist es wahrscheinlich am einfachsten, wenn Sie sich nicht für das “nicht inszenierte” Bit interessieren

git checkout 8 -- .

Dadurch werden Ihr Baum und Ihr Index so aktualisiert, dass sie mit denen von Commit 8 übereinstimmen, ohne Ihren Commit-Verlauf zu ändern. Sie können dann git reset um die Indexänderungen zu verwerfen.

Wenn Sie die Indexdatei wirklich ungestört lassen möchten, ist es etwas komplizierter, da git den Arbeitsbaum immer aus dem Index aktualisiert. Du könntest sowas machen

GIT_INDEX_FILE=/tmp/foo git checkout 8 -- .

Dies wird den Pfad verwenden /tmp/foo als temporäre Indexdatei nur für diesen Befehl. Eventuell möchten Sie diese Datei anschließend löschen.


In einer komplizierteren Situation, in der Sie Patches erneut anwenden möchten, die Sie nicht wirklich auf den genauen Zustand von Commit 8 zurückbringen würden, können Sie verwenden git cherry-pick --no-commit commit1 commit2 ... um die Commits nacheinander anzuwenden. Dadurch wird der Index natürlich immer noch geändert.

Benutzeravatar von UncleSniper
Onkel Scharfschütze

Den Zustand des OP geschehen lassen:

cyclone% mkdir myrepo
cyclone% cd myrepo
cyclone% git init
Initialized empty Git repository in /tmp/myrepo/.git/
cyclone% echo 'Hello, world!' >hello
cyclone% git add hello
cyclone% git commit -m 'Initial import'
[master (root-commit) 6ec97b1] Initial import
 1 file changed, 1 insertion(+)
 create mode 100644 hello
cyclone% echo 'How are you?' >>hello
cyclone% git add hello
cyclone% git commit -m "Added 'How are you?'"
[master 8786161] Added 'How are you?'
 1 file changed, 1 insertion(+)
# Now, if I reset back, the commit object
# seems to be removed (possibly due to my current
# version of Git vs. OP's older version?). To prevent
# this, I'll "name" the commit OP considers '8'.
# Thus, OP would put the commit ID corresponding
# to their '8' wherever I put 'tip'.
cyclone% git branch tip
# In all my years, I've never heard of
# 'git branch --force' -- then again, I'm not
# Linus Torvalds, so I guess I know only like
# half of Git, as do all of you (unless you ARE
# Linus Torvalds). Nonetheless, if I try the next,
# commented-out line, I get:
#     fatal: Cannot force update the current branch.
#git branch -f master 'HEAD^'
# A (too?) quick Google doesn't really help on the
# matter, so... In the undying words of...
# well, somebody-or-other in the whole long history
# of ever: Lemme fix that for ya...
cyclone% git update-ref HEAD 'HEAD^'
# Now this is the crucial point: If this is going
# to be easy, you need a recent enough version of
# Git to support 'git restore', because that DOES
# make things easy (see below).
cyclone% git restore --staged .
# Now, this is actually the state OP wants, but
# since they are at a different state, I guess we'll
# wantonly destroy it...
cyclone% git checkout .
Updated 1 path from the index

Damit sind wir beim Zustand von OP:

# We are on master, with no changes (staged nor unstaged)
# and master is the "old" commit:
cyclone% git status
On branch master
nothing to commit, working tree clean
# The working tree reflects the "old" commit:
cyclone% cat hello
Hello, world!
# Commit '8' (i.e. 'tip') reflects the "new"
# commit:
cyclone% git show tip:hello
Hello, world!
How are you?

Jetzt kommt also der eine einfache Befehl, der den aktuellen Zustand von OP in den gewünschten Zustand von OP bringt:

cyclone% git restore --source=tip .

Jetzt sind wir genau dort, wo wir sein wollen:

# The changes between '4' and '8' are present, but
# not staged nor committed:
cyclone% git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   hello

no changes added to commit (use "git add" and/or "git commit -a")
# The current branch (master, as Git tells us above) is on
# what OP considers '4':
cyclone% git log
commit f4661e0c12a20acb6dd0bc4afe8c9b2301667608 (HEAD -> master)
Author: Simon "UncleSniper" Bausch <(REDACTED)>
Date:   (no matter)

    Initial import
# The working tree includes the changes between '4'
# and '8':
cyclone% cat hello
Hello, world!
How are you?
# The changes between '4' and '8' are "present" (see
# above), but neither staged nor committed:
cyclone% git diff
diff --git a/hello b/hello
index af5626b..b076fc1 100644
--- a/hello
+++ b/hello
@@ -1 +1,2 @@
 Hello, world!
+How are you?
# In fact, nothing is staged at all:
cyclone% git diff --cached
cyclone% 

Also ja, es gibt genau einen Befehl (git restore --source=tip .) zwischen dem aktuellen Zustand von OP und dem gewünschten Zustand von OP – vorausgesetzt, eine ausreichend aktuelle Version von Git.

 git checkout master@{1} -- .

ist alles, was du brauchst. Es lautet “Checke die Dateien aus, auf die der Commit, auf den der Master vor einer Zeit verwiesen hat”. Auschecken git reflog um zu sehen, wie das funktioniert.

Außerdem sollten Sie die Verzweigung nicht gewaltsam neu erstellen, wie Sie es getan haben. Dadurch kann Git alle Orte verfolgen, auf die der Master früher gezeigt hat. Verwenden

git stash -u 

falls Sie etwas Arbeit im Arbeitsverzeichnis haben. Dann

git reset --hard master^^^^

oder

git reset --hard master~4

  • “Damit kann Git alle Orte verfolgen, auf die der Master früher gezeigt hat.” – wie meinst du? Können Sie dieses Tracking etwas näher erläutern?

    – Andreas Tomazos

    10. Januar 2013 um 0:13 Uhr


  • Er sagte, er wolle die Änderungen ungestaffelt anwenden. Checkout stellt sie bereit.

    – jthill

    10. Januar 2013 um 1:39 Uhr

Khalah Jones - Benutzeravatar von Golden
Khalah Jones – Golden

git cherry-pick master~4 master~5 master~6 master~7 master~8

Ihr Arbeitsbaum muss jedoch sauber sein

git help cherry-pick

  • “Damit kann Git alle Orte verfolgen, auf die der Master früher gezeigt hat.” – wie meinst du? Können Sie dieses Tracking etwas näher erläutern?

    – Andreas Tomazos

    10. Januar 2013 um 0:13 Uhr


  • Er sagte, er wolle die Änderungen ungestaffelt anwenden. Checkout stellt sie bereit.

    – jthill

    10. Januar 2013 um 1:39 Uhr

1439180cookie-checkAnwenden von Git-Commits auf den Arbeitsbaum nicht hinzugefügt?

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

Privacy policy