Jak podzielić ostatni commit na dwa w Git

Mam dwie działające gałęzie, master i forum i właśnie wprowadziłem kilka modyfikacji w gałęzi forum , które chciałbym wybrać do master . Ale niestety, commit, który chcę wybrać, zawiera również pewne modyfikacje, których nie chcę.

Rozwiązaniem byłoby usunięcie błędnego commita i zastąpienie go dwoma osobnymi commitami, jednym ze zmianami, które chcę wybrać w master, a innymi, które nie należą tam.

Próbowałem robić

git reset --hard HEAD^

Który usunął wszystkie zmiany, więc musiałem wrócić z

git reset ORIG_HEAD

Więc moje pytanie brzmi: jaki jest najlepszy sposób na podzielenie ostatniego commita na dwa oddzielne commity?

Author: Jakub Arnold, 2009-09-17

8 answers

Powinieneś użyć indeksu. Po wykonaniu mieszanego resetu ("Git reset HEAD^"), dodaj pierwszy zestaw zmian w indeksie, a następnie zatwierdź je. Następnie zatwierdź odpoczywaj.

Możesz użyć "git add " aby umieścić wszystkie zmiany w pliku w indeksie. Jeśli nie chcesz umieszczać każdej modyfikacji w pliku, tylko niektóre z nich, ty można użyć "git add-p".

Zobaczmy przykład. Załóżmy, że miałem plik o nazwie myfile, który zawiera następujące tekst:
something
something else
something again

Zmodyfikowałem go w moim ostatnim commicie tak, że teraz wygląda tak:

1
something
something else
something again
2

Teraz decyduję, że chcę podzielić ją na dwie części i chcę wstawić pierwszy wiersz, który ma być w pierwszym zatwierdzeniu, a wstawianie ostatniego wiersza, który ma być w drugim commit.

Najpierw wracam do rodzica HEAD ' a, ale chcę zachować modyfikacje w systemie plików, więc używam "Git reset" bez argumentu (co zrobi tzw. " mixed" "reset"): {]}

$ git reset HEAD^
myfile: locally modified
$ cat myfile
1
something
something else
something again
2

Teraz używam "git add-p" aby dodać zmiany, które chcę zatwierdzić do indeksu (=I etapie). "git add-p" jest interaktywnym narzędziem, które pyta o to, co zmiany w pliku, jeśli zostanie dodany do indeksu.

$ git add -p myfile
diff --git a/myfile b/myfile
index 93db4cb..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,5 @@
+1
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,s,e,?]? s    # split this section into two!
Split into 2 hunks.
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? y  # yes, I want to stage this
@@ -1,3 +2,4 @@
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,K,g,e,?]? n   # no, I don't want to stage this

Wtedy zatwierdzam tą pierwszą zmianę:

$ git commit -m "Added first line"
[master cef3d4e] Added first line
 1 files changed, 1 insertions(+), 0 deletions(-)

Teraz mogę zatwierdzić wszystkie inne zmiany (mianowicie cyfrę "2" umieszczoną w ostatniej linijce):

$ git commit -am "Added last line"
[master 5e284e6] Added last line
 1 files changed, 1 insertions(+), 0 deletions(-)

Sprawdźmy log, aby zobaczyć jakie commity mamy:

$ git log -p -n2 | cat
Commit 5e284e652f5e05a47ad8883d9f59ed9817be59d8
Author: ...
Date: ...

    Added last line

Diff --git a/myfile b/myfile
Index f9e1a67..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -2,3 +2,4 @@
 something
 something else
 something again
+2

Commit cef3d4e0298dd5d279a911440bb72d39410e7898
Author: ...
Date: ...

    Added first line

Diff --git a/myfile b/myfile
Index 93db4cb..f9e1a67 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again
 323
Author: hcs42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-25 12:44:08

Bramki:

  • chcę podzielić poprzedni commit (splitme) na dwa.
  • chcę utrzymać komunikat commit.

Plan:

  1. rebase interactive from one before splitme.
  2. edit splitme.
  3. Zresetuj pliki, aby podzielić je na drugi commit.
  4. Zmień commit, zachowując wiadomość, zmodyfikuj w razie potrzeby.
  5. Dodaj z powrotem pliki rozdzielone od pierwszego commita.
  6. Commit z nową wiadomością.
  7. Kontynuuj rebase.

Kroki rebase (1 i 7) można pominąć, jeśli splitme jest ostatnim zatwierdzeniem.

git rebase -i splitme^
# mark splitme commit with 'e'
git reset HEAD^ -- $files
git commit --amend
git add $files
git commit -m "commit with just some files"
git rebase --continue

Jeśli chciałbym, aby split files był najpierw zatwierdzony, potem ponownie przełączyłbym kolejność

git rebase -i splitme^
# swap order of splitme and 'just some files'
 81
Author: spazm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-27 20:55:15

Aby zmienić bieżący commit na dwa commity, możesz zrobić coś takiego jak poniżej.

Albo:

git reset --soft HEAD^

To wycofuje ostatni commit, ale pozostawia wszystko zainscenizowane. Następnie możesz usunąć określone pliki:

git reset -- file.file

Opcjonalnie Przywróć części tych plików:

git add -p file.file

Utwórz nowy pierwszy commit:

git commit

Etap i zatwierdź resztę zmian w drugim commicie:

git commit -a

Lub:

Cofanie i cofanie wszystkich zmian z ostatniego commita:

git reset HEAD^

Selektywnie zaplanuj pierwszą rundę zmian:

git add -p

Commit:

git commit

Zatwierdź resztę zmian:

git commit -a

(w każdym kroku, jeśli usunąłeś commit, który dodał nowy plik i chcesz dodać go do drugiego commita, będziesz musiał ręcznie dodać go jako commit -a tylko etapy zmian do już śledzonych plików.)

 52
Author: CB Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-17 21:13:25

Uruchom git gui, wybierz przycisk radiowy "Zmień Ostatnie zatwierdzenie" i odinstaluj (Zatwierdź > Odinstaluj z zatwierdzenia lub Ctrl-U) zmiany, których nie chcesz wprowadzać do pierwszego commita. Myślę, że to najłatwiejszy sposób.

Kolejną rzeczą, którą możesz zrobić, to wybrać zmianę bez zatwierdzania (git cherry-pick -n), a następnie ręcznie lub za pomocą git gui wybrać pożądane zmiany przed zatwierdzeniem.

 22
Author: Michael Krelin - hacker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-04 03:37:19
git reset HEAD^
Trudne jest to, co zabija twoje zmiany.
 15
Author: semanticart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-17 16:58:42

Dziwi mnie, że nikt nie zasugerował. Spowoduje to wprowadzenie zmian z ostatniego commita forum, ale ich nie zatwierdzi - możesz wtedy reset usunąć zmiany, których nie potrzebujesz i zatwierdzić To, co chcesz zachować.

 13
Author: dahlbyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-12 22:12:41

Metoda double-revert-squash

  1. wykonaj kolejny commit, który usuwa niepożądane zmiany. (Jeśli jest na plik, to jest to naprawdę proste: git checkout HEAD~1 -- files with unwanted changes i git commit. Jeśli nie, pliki z mieszanymi zmianami mogą być częściowo zainscenizowane git reset file i git add -p file jako etap pośredni.) Nazwij to revert .
  2. git revert HEAD - wykonaj kolejny commit, który doda niepożądane zmiany. To jest double-revert
  3. z 2 commitów, które teraz wykonałeś, pierwszy na commit to split (git rebase -i HEAD~3). Ten commit staje się teraz wolny od niechcianych zmian, ponieważ są one w drugim commicie.

Korzyści

  • zachowuje komunikat commit
  • działa nawet jeśli commit do split nie jest ostatnim. Wymaga tylko, aby niepożądane zmiany nie były sprzeczne z późniejszymi commitami
 2
Author: user2394284,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-06 15:33:57

Skoro jesteś cherry-picking, możesz:

  1. cherry-pick z dodaną opcją --no-commit.
  2. reset i używać add --patch, add --edit lub po prostu add, aby ustawić to, co chcesz zachować.
  3. commit inscenizowane zmiany.
    • aby ponownie użyć oryginalnej wiadomości zatwierdzającej, możesz dodać opcje --reuse-message=<old-commit-ref> lub --reedit-message=<old-commit-ref> do polecenia commit.
  4. zdmuchnij niezakłócone zmiany za pomocą reset --hard.

W inny sposób, zachowując lub edytując oryginalny commit wiadomość:

  1. cherry-pick oryginalny commit jak zwykle.
  2. Odwróć zmiany, których nie chcesz i użyj add, aby ustawić odwrócenie.
    • ten krok byłby łatwy, jeśli usuwasz to, co dodałeś, ale trochę trudny, jeśli dodajesz to, co usunąłeś lub cofasz zmianę.
  3. commit --amend w celu wywołania odwrócenia na commit cherry-picked.
    • otrzymasz ponownie ten sam komunikat commit, który możesz zachować lub zmienić jako konieczne.
 0
Author: ADTC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-08 04:22:23