Podziel poprzedni commit na wiele commitów

Bez tworzenia gałęzi i wykonywania kilku ciekawych prac nad nową gałęzią, czy można rozbić pojedynczy commit na kilka różnych commitów po tym, jak został on zatwierdzony w lokalnym repozytorium?

 864
git
Author: Jakuje, 2011-06-02

11 answers

git rebase -i zrobię to.

Po pierwsze, zacznij od czystego katalogu roboczego: git status nie powinien pokazywać oczekujących modyfikacji, usunięć ani dodatków.

Aby rozdzielić swój najnowszy commit, najpierw:

$ git reset HEAD~

Teraz commit poszczególnych elementów w zwykły sposób, tworząc tyle commitów, ile potrzebujesz.

Jeśli było dalej na drzewie, to

$ git rebase -i HEAD~3

Gdzie 3 jest liczbą commitów wstecz.

Gdyby było dalej w drzewo niż chcesz policzyć, to

$ git rebase -i 123abcd~

Gdzie 123abcd jest SHA1 commitu, który chcesz rozdzielić.

Kiedy pojawi się ekran edycji rebase, znajdź commit, który chcesz rozdzielić. Na początku tej linii zamień pick na edit (e W skrócie). Zapisz bufor i zakończ. Rebase zatrzyma się zaraz po zatwierdzeniu, które chcesz edytować. Następnie:

$ git reset HEAD~

Zatwierdzaj elementy pojedynczo w zwykły sposób, tworząc tyle commitów, ile potrzebujesz, wtedy

$ git rebase --continue
 1325
Author: Wayne Conrad,
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-03-05 18:40:49

From Git-rebase manual (SPLITTING commits section)

W trybie interaktywnym możesz oznaczyć commity akcją "edytuj". Nie musi to jednak oznaczać, że git rebase oczekuje, że wynik tej edycji będzie dokładnie jednym zatwierdzeniem. Rzeczywiście, możesz cofnąć zatwierdzenie lub dodać inne zmiany. To może być użyte do podzielenia commita na dwa:

  • Uruchom interaktywną rebase z git rebase -i <commit>^, gdzie <commit> jest zatwierdzeniem, które chcesz podzielić. W rzeczywistości, każdy zakres commitów wystarczy, o ile zawiera ten commit.

  • Zaznacz commit, który chcesz podzielić za pomocą akcji "edytuj".

  • Jeśli chodzi o edycję tego commita, wykonaj git reset HEAD^. Efekt polega na tym, że głowica jest przewijana o jeden, A Indeks podąża za nim. Jednak drzewo robocze pozostaje takie samo.

  • Teraz dodaj zmiany do indeksu, które chcesz mieć w pierwszym zatwierdzeniu. Możesz użyć git add (ewentualnie interaktywnie) lub git gui (lub oba), aby to zrobić.

  • Commit indeks now-current z dowolnym Komunikatem commit jest teraz odpowiedni.

  • Powtórz dwa ostatnie kroki, aż drzewo robocze będzie czyste.

  • Kontynuuj rebase za pomocą git rebase --continue.

 252
Author: MBO,
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-10-07 17:53:38

Użyj git rebase --interactive, aby edytować wcześniejszy commit, Uruchom git reset HEAD~, a następnie git add -p, aby dodać kilka, następnie zrobić commit, następnie dodać kilka więcej i zrobić kolejny commit, tyle razy, ile chcesz. Gdy skończysz, Uruchom git rebase --continue, a będziesz mieć wszystkie commity podzielone wcześniej w swoim stosie.

Ważne : pamiętaj, że możesz bawić się i wprowadzać wszystkie zmiany, które chcesz, i nie musisz się martwić o utratę starych zmian, ponieważ zawsze możesz uruchomić git reflog, aby znaleźć punkt w swoim projekcie, który zawiera zmiany, które chcesz, (nazwijmy to a8c4ab), a następnie git reset a8c4ab.

Oto seria poleceń, aby pokazać, jak to działa:

mkdir git-test; cd git-test; git init

Teraz Dodaj plik A

vi A

Dodaj ten wiersz:

one

git commit -am one

Następnie dodaj ten wiersz do A:

two

git commit -am two

Następnie dodaj ten wiersz do A:

three

git commit -am three

Teraz plik A wygląda tak:

one
two
three

I nasz git log wygląda następująco (cóż, używam git log --pretty=oneline --pretty="%h %cn %cr ---- %s"

bfb8e46 Rose Perrone 4 seconds ago ---- three
2b613bc Rose Perrone 14 seconds ago ---- two
9aac58f Rose Perrone 24 seconds ago ---- one

Powiedzmy, że chcemy podzielić drugi commit, two.

git rebase --interactive HEAD~2

To wyświetla wiadomość, która wygląda tak:

pick 2b613bc two
pick bfb8e46 three

Zmień pierwszy pick na e, aby edytować ten commit.

git reset HEAD~

git diff pokazuje nam, że właśnie odinstalowaliśmy commit, który zrobiliśmy dla drugiego commita: {]}

diff --git a/A b/A
index 5626abf..814f4a4 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two

Ustawmy tę zmianę i dodaj "i trzecią" do tej linii w pliku A.

git add .

Jest to zwykle punkt podczas interaktywnej rebazy, gdzie uruchamiamy git rebase --continue, ponieważ zwykle chcemy wrócić do naszego stosu commitów, aby edytować wcześniejszy commit. Ale tym razem chcemy stworzyć nowy commit. Więc uciekniemy git commit -am 'two and a third'. Teraz edytujemy plik A i dodajemy linię two and two thirds.

git add . git commit -am 'two and two thirds' git rebase --continue

Mamy konflikt z naszym commitem, three, więc rozwiążmy go: {]}

Zmienimy

one
<<<<<<< HEAD
two and a third
two and two thirds
=======
two
three
>>>>>>> bfb8e46... three

To

one
two and a third
two and two thirds
three

git add .; git rebase --continue

Teraz nasz git log -p wygląda tak:

commit e59ca35bae8360439823d66d459238779e5b4892
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 13:57:00 2013 -0700

    three

diff --git a/A b/A
index 5aef867..dd8fb63 100644
--- a/A
+++ b/A
@@ -1,3 +1,4 @@
 one
 two and a third
 two and two thirds
+three

commit 4a283ba9bf83ef664541b467acdd0bb4d770ab8e
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 14:07:07 2013 -0700

    two and two thirds

diff --git a/A b/A
index 575010a..5aef867 100644
--- a/A
+++ b/A
@@ -1,2 +1,3 @@
 one
 two and a third
+two and two thirds

commit 704d323ca1bc7c45ed8b1714d924adcdc83dfa44
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 14:06:40 2013 -0700

    two and a third

diff --git a/A b/A
index 5626abf..575010a 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two and a third

commit 9aac58f3893488ec643fecab3c85f5a2f481586f
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 13:56:40 2013 -0700

    one

diff --git a/A b/A
new file mode 100644
index 0000000..5626abf
--- /dev/null
+++ b/A
@@ -0,0 +1 @@
+one
 36
Author: Rose Perrone,
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
2013-07-08 15:28:58

Poprzednie odpowiedzi opisywały użycie git rebase -i do edycji commita, który chcesz podzielić i zatwierdzania go w częściach.

Działa to dobrze podczas dzielenia plików na różne commity, ale jeśli chcesz podzielić zmiany w poszczególnych plikach, musisz wiedzieć więcej.

DostajÄ ... c commit, ktĂłry chcesz podzielić, uĹźywajÄ ... C rebase -i i oznaczajÄ ... C GO dla edit, masz dwie opcje.

  1. Po użyciu plastra git reset HEAD~ należy przejść przez plastry indywidualnie użycie git add -p, aby wybrać te, które chcesz w każdym commicie

  2. Edytuj kopię roboczą, aby usunąć zmiany, których nie chcesz; Zatwierdź ten tymczasowy stan; a następnie przeciągnij pełny commit na następną rundę.

Opcja 2 jest przydatna, jeśli dzielisz duży commit, ponieważ pozwala sprawdzić, czy wersje tymczasowe budują i działają poprawnie w ramach scalania. Odbywa się to w następujący sposób.

Po użyciu rebase -i i editw commit, użycie

git reset --soft HEAD~

Aby cofnąć zatwierdzenie, ale pozostawić zatwierdzone pliki w indeksie. Możesz również wykonać reset mieszany, pomijając --soft, w zależności od tego, jak blisko będzie ostatecznego wyniku początkowego commitu. Jedyną różnicą jest to, czy zaczynasz od wszystkich zmian w poczekalni, czy od nich wszystkich w stanie niezmienionym.

Teraz wejdź i edytuj kod. Możesz usuwać zmiany, usuwać dodane pliki i robić wszystko, co chcesz, aby stworzyć pierwszy commit z serii, której szukasz. Możesz zbuduj go, Uruchom i potwierdź, że masz spójny zestaw źródeł.

Kiedy będziesz zadowolony, Ustaw/Odinstaluj pliki zgodnie z potrzebami (lubię używać git gui do tego) i zatwierdź zmiany za pomocą interfejsu użytkownika lub linii poleceń

git commit

To pierwszy commit zrobiony. Teraz chcesz przywrócić kopię roboczą do stanu, który miał po podziale commit, tak, że można wziąć więcej zmian do następnego commit. Aby znaleźć sha1 edytowanego commitu, użyj git status. W pierwszych kilku wierszach stanu zobaczysz aktualnie wykonywaną komendę rebase, w której znajdziesz sha1 oryginalnego commita:

$ git status
interactive rebase in progress; onto be83b41
Last commands done (3 commands done):
   pick 4847406 US135756: add debugging to the file download code
   e 65dfb6a US135756: write data and download from remote
  (see more in file .git/rebase-merge/done)
...

W tym przypadku commit, który edytuję ma sha1 65dfb6a. Wiedząc o tym, mogę sprawdzić zawartość tego commita w moim katalogu roboczym, używając formy git checkout, która pobiera zarówno commit, jak i lokalizację pliku. Tutaj używam . jako lokalizacji pliku, aby zastąpić całą kopię roboczą:

git checkout 65dfb6a .

Nie przegap kropka na końcu!

Spowoduje to sprawdzenie i zapisanie plików w takim stanie, w jakim były po edytowanym zatwierdzeniu, ale w stosunku do poprzedniego zatwierdzania, więc wszelkie zmiany, które już wprowadziłeś, nie będą częścią zatwierdzania.

Możesz albo przejść do przodu i zatwierdzić go w taki sposób, aby zakończyć podział, albo przejść do tyłu, usuwając niektóre części commita przed dokonaniem kolejnego tymczasowego commita.

Jeśli chcesz ponownie użyć oryginalnej wiadomości commit dla jednego lub więcej commitów, możesz użyj go bezpośrednio z plików roboczych rebase:

git commit --file .git/rebase-merge/message

Wreszcie, gdy już popełnisz wszystkie zmiany,

git rebase --continue

Będzie kontynuować i zakończyć operację rebase.

 20
Author: Andy Mortimer,
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-06-08 11:33:13

git rebase --interactive może być użyty do podzielenia commita na mniejsze commity. W przypadku, gdy nie jest to możliwe, nie jest to możliwe.]}

W trybie interaktywnym możesz oznaczyć commity akcją "edytuj". Nie musi to jednak oznaczać, że git rebase spodziewa się, że wynik tej edycji będzie dokładnie jednym zatwierdzeniem. Rzeczywiście, możesz cofnąć zatwierdzenie lub dodać inne zmiany. To może być użyte do podzielenia commita na dwa:

  • Uruchom interaktywną rebase z git rebase -i <commit>^, Gdzie <commit> jest zatwierdzeniem, które chcesz podzielić. W rzeczywistości każdy zakres commitów wystarczy, o ile zawiera ten commit.

  • Zaznacz commit, który chcesz podzielić za pomocą akcji "edytuj".

  • Jeśli chodzi o edycję tego commita, wykonaj git reset HEAD^. Efekt polega na tym, że głowica jest przewijana o jeden, A Indeks podąża za nim. Jednak drzewo robocze pozostaje takie samo.

  • Teraz dodaj zmiany do indeksu, który chcesz mieć w pierwszym commicie. Możesz użyć git add (ewentualnie interaktywnie) lub git gui (lub obu), aby to zrobić.

  • Commit indeks now-current z dowolnym Komunikatem commit jest teraz odpowiedni.

  • Powtórz dwa ostatnie kroki, aż drzewo robocze będzie czyste.

  • Kontynuuj rebase za pomocą git rebase --continue.

Jeśli nie jesteś absolutnie pewien, że wersje pośrednie są spójne (kompilują, zdać testsuite itp.) powinieneś użyć git stash, aby ukryć niezaangażowane zmiany po każdym commicie, przetestować i zmienić commit, jeśli poprawki są konieczne.

 17
Author: ,
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
2013-07-14 22:25:14

Możesz wykonać interaktywną rebase git rebase -i. Strona Man ma dokładnie to, czego chcesz:

Http://git-scm.com/docs/git-rebase#_splitting_commits

 10
Author: manojlds,
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
2013-07-14 22:22:07

Zwróć uwagę, że istnieje również git reset --soft HEAD^. Jest podobny do git reset (domyślnie --mixed), ale zachowuje zawartość indeksu. Tak, że jeśli dodałeś / usunąłeś pliki, masz je już w indeksie.

Okazuje się bardzo przydatny w przypadku commitów giant.

 7
Author: lethalman,
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-11-27 15:23:41

Teraz w najnowszym TortoiseGit na Windows możesz to zrobić bardzo łatwo.

Otwórz okno rebase, skonfiguruj go i wykonaj następujące kroki.

  • kliknij prawym przyciskiem myszy commit, który chcesz podzielić i wybierz "Edit " (wśród pick, squash, delete...).
  • Kliknij " Start", Aby rozpocząć rebasing.
  • gdy dotrze do commit to split, zaznacz przycisk" Edit/Split" i kliknij bezpośrednio na "Amend". Okno zatwierdzania otwiera.
    Edytuj / podziel commit
  • usuń zaznaczenie plików, które chcesz umieścić w osobnym zatwierdzeniu.
  • Edytuj komunikat o zatwierdzeniu, a następnie kliknij " commit".
  • dopóki nie będzie plików do zatwierdzenia, okno dialogowe zatwierdzania będzie się otwierać ponownie i ponownie. Gdy nie ma już pliku do zatwierdzenia, nadal zapyta cię, czy chcesz dodać jeszcze jeden commit.

Bardzo pomocny, dzięki TortoiseGit !

 7
Author: Mikaël Mayer,
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
2016-04-22 10:32:46

Myślę, że najlepszy sposób używam git rebase -i. Stworzyłem film pokazujący kroki dzielenia commita: https://www.youtube.com/watch?v=3EzOz7e1ADI

 1
Author: Nguyen Sy Thanh Son,
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
2016-07-25 11:47:20

Najprostszą rzeczą do zrobienia bez interaktywnego rebase jest (prawdopodobnie) utworzenie nowej gałęzi zaczynającej się od commita przed tą, którą chcesz podzielić, cherry-pick-n commit, reset, stash, commit przenieś plik, ponownie zastosuj stash i zatwierdź zmiany, a następnie albo połącz się z poprzednią gałęzią, albo cherry-pick commity, które nastąpiły. (Następnie zmień poprzednią nazwę gałęzi na bieżącą głowicę.) (Prawdopodobnie lepiej postępować zgodnie z radami MBOs i zrobić interaktywną rebase.)

 0
Author: William Pursell,
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
2010-01-22 17:04:50

Jeśli masz to:

A - B <- mybranch

Gdzie popełniłeś jakąś treść w commit B:

/modules/a/file1
/modules/a/file2
/modules/b/file3
/modules/b/file4

Ale chcesz podzielić B na C-D i uzyskać taki wynik:

A - C - D <-mybranch

Możesz podzielić zawartość w ten sposób na przykład (zawartość z różnych katalogów w różnych zatwierdzeniach)...

Zresetuj gałąź z powrotem do commita przed rozdzieleniem:

git checkout mybranch
git reset --hard A

Utwórz pierwszy commit (C):

git checkout B /modules/a
git add -u
git commit -m "content of /modules/a"

Utwórz drugi commit (D):

git checkout B /modules/b
git add -u
git commit -m "content of /modules/b"
 0
Author: Martin G,
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-02-08 17:44:48