Jak usunąć wybrane wpisy dziennika zatwierdzenia z repozytorium Git, zachowując ich zmiany?

241

Chciałbym usunąć wybrane wpisy dziennika zatwierdzeń z liniowego drzewa zatwierdzeń, aby wpisy nie były wyświetlane w dzienniku zatwierdzeń.

Moje drzewo zmian wygląda mniej więcej tak:

R--A--B--C--D--E--HEAD

Chciałbym usunąć wpisy B i C, aby nie były wyświetlane w dzienniku zatwierdzeń, ale zmiany z A na D powinny zostać zachowane. Może przez wprowadzenie pojedynczego zatwierdzenia, aby B i C stały się BC, a drzewo wygląda.

R--A--BC--D--E--HEAD

Lub, idealnie, po A następuje D bezpośrednio. D 'reprezentujące zmiany z A na B, B na C i C na D.

R--A--D'--E--HEAD

czy to możliwe? jeśli tak to jak?

Jest to dość nowy projekt, więc na razie nie ma oddziałów, dlatego też nie łączy się.

xk0der
źródło
@ xk0der: „commits” jest tutaj właściwym terminem. rebasemoże usunąć stare / utworzyć nowe zatwierdzenia. Nie wiem, co oznaczają „wpisy dziennika zatwierdzania”.
jfs
@JFSebastian Nie widzę problemu z „dziennikiem zatwierdzeń” - dziennik wszystkich zatwierdzeń. I chciałem usunąć kilka wpisów z dziennika - zachowując rzeczywiste zmiany (zmiany).
xk0der,
@ xk0der: zatwierdzenia git są adresowalne treściowo, tzn. jeśli zmienisz cokolwiek w zatwierdzeniu, np. w komunikacie dziennika; tworzysz nowy zatwierdzenie. Możesz przeczytać zatwierdzenie gita bez gita i przekonać się sam .
jfs
@JFSebastian - Dzięki za linki - Wiem o tym - Ale czy ta technika naprawdę zmienia problem, z którym się spotkałem i jak go przedstawiłem? Nie sądzę. Na koniec: chciałem usunąć „komunikaty dziennika zmian” - bez usuwania „zmian zmian” - proszę ponownie przeczytać moje pytanie - szczególnie drugi akapit. Aby dodać więcej, git logpokazuje „dziennik zatwierdzenia” git-scm.com/docs/git-log . I chciałem pozbyć się dwóch wpisów z tego dziennika - nie zmian.
xk0der,

Odpowiedzi:

273

git-rebase (1) robi dokładnie to.

$ git rebase -i HEAD~5

git awsome-ness [git rebase --interactive] zawiera przykład.

  1. Nie używaj git-rebasew publicznych (zdalnych) zatwierdzeniach.
  2. Upewnij się, że katalog roboczy jest czysty ( commitlub stashbieżące zmiany).
  3. Uruchom powyższe polecenie. Uruchamia twój $EDITOR.
  4. Wymień pickprzed Ci Dprzez squash. Połączy C i D z B. Jeśli chcesz usunąć zatwierdzenie, po prostu usuń jego linię.

Jeśli się zgubiłeś, wpisz:

$ git rebase --abort  
jfs
źródło
Dziękuję za szybką odpowiedź. Więc czy mam kasę A i zrobić rebase, coś w stylu git rebase -i D [A]?
xk0der
3
Jak możemy to zrobić na zdalnych repozytoriach?
Eray
6
@Eray: tylko push -ftwoje zmiany. Nie rób tego, jeśli nie pracujesz sam.
jfs,
2
@ ripper234: Naprawiłem linki do git-rebaseinstrukcji obsługi punktu i maszyny powrotnej do posta na blogu.
jfs
75
# detach head and move to D commit
git checkout <SHA1-for-D>

# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>

# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>

# Re-apply everything from the old D onwards onto this new place 
git rebase --onto HEAD <SHA1-for-D> master
CB Bailey
źródło
To też działa i pomogło mi zrozumieć, co to jest miękki reset. To prawda, że ​​odpowiedź „górna” jest również odpowiednia i krótsza, ale dziękuję również za tę odpowiedź.
cgp
41

Oto sposób na usunięcie określonego identyfikatora zatwierdzenia, znając tylko identyfikator zatwierdzenia, który chcesz usunąć.

git rebase --onto commit-id^ commit-id

Zauważ, że faktycznie usuwa to zmianę wprowadzoną przez zatwierdzenie.

rado
źródło
7
Dodatkowa HEAD w tym poleceniu spowoduje, że baza zakończy się z odłączoną HEAD, co jest niepożądane. Należy to pominąć.
Mroźny
3
To przywraca zmiany wprowadzone przez mój identyfikator zatwierdzenia, OP chce zachować zmiany, po prostu zgnieść zatwierdzenia.
CB Bailey,
1
-1, ponieważ nie robi tego, o co poprosił PO (raczej niszczy coś, co wyraźnie chciał zachować).
Emil Styrke
1
Chociaż nie robi tego, o co poprosił PO, dokładnie tego potrzebowałem, więc +1 za przydatną odpowiedź.
Edvins
20

Aby rozwinąć odpowiedź JF Sebastiana:

Możesz użyć git-rebase, aby łatwo wprowadzać wszelkiego rodzaju zmiany w historii zmian.

Po uruchomieniu git rebase --interactive w edytorze $ pojawi się:

pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

Możesz przenosić wiersze, aby zmienić kolejność zatwierdzeń, i usuwać wiersze, aby usunąć to zatwierdzenie. Możesz też dodać polecenie, aby połączyć (zgnieść) dwa zatwierdzenia w jeden zatwierdzenie (poprzednie zatwierdzenie jest powyższym zatwierdzeniem), edytować zatwierdzenia (co zostało zmienione) lub zmienić komunikaty zatwierdzenia.

Myślę, że pick oznacza po prostu, że chcesz zostawić to zatwierdzenie w spokoju.

(Przykład pochodzi stąd )

idbrii
źródło
14

Możesz nieinteraktywnie usunąć B i C w swoim przykładzie za pomocą:

git rebase --onto HEAD~5 HEAD~3 HEAD

lub symbolicznie

git rebase --onto A C HEAD

Zauważ, że zmiany w B i C nie będą w D; będą one zniknął .

Głowa
źródło
Zobacz tutaj, aby uzyskać więcej informacji: sethrobertson.github.io/GitFixUm/fixup.html#remove_deep
Maks.
3

Jeszcze jeden sposób

git rebase -i ad0389efc1a79b1f9c4dd6061dca6edc1d5bb78a (C's hash)
and
git push origin master  -f

wybierz skrót, którego chcesz użyć jako podstawy, a powyższe polecenie powinno uczynić go interaktywnym, abyś mógł zgnieść wszystkie najważniejsze wiadomości (musisz zostawić najstarszy)

wyniki
źródło
2

Uważam ten proces za znacznie bezpieczniejszy i łatwiejszy do zrozumienia, tworząc kolejną gałąź z SHA1 A i wybierając pożądane zmiany, aby upewnić się, że jestem zadowolony z wyglądu tej nowej gałęzi. Następnie łatwo jest usunąć starą gałąź i zmienić jej nazwę na nową.

git checkout <SHA1 of A>
git log #verify looks good
git checkout -b rework
git cherry-pick <SHA1 of D>
....
git log #verify looks good
git branch -D <oldbranch>
git branch -m rework <oldbranch>
Eric Woodruff
źródło
jeśli to zrobisz, stracisz również zatwierdzenie E, prawda? Jak zrozumiałem, usuwasz master i zmieniasz nazwę przeróbki na master (biorąc pod uwagę, że przepływ ABCDE jest gałęzią master).
Renan Bandeira,
1

Właśnie zebrałem odpowiedzi wszystkich ludzi: (m new to git plz użyj go tylko w celach informacyjnych)

git rebase, aby usunąć wszelkie zatwierdzenia

git log

-first check from which commit you want to rebase

git rebase -i HEAD ~ 1

-Here i want to rebase on the second last commit- commit count starts from '1')
-this will open the command line editor (called vim editor i guess)

Wtedy ekran będzie wyglądał mniej więcej tak:

wybierz 0c2236d Dodano nową linię.

Rebase 2a1cd65..0c2236d na 2a1cd65 (1 polecenie)

#

Polecenia:

p, pick = użyj zatwierdzenia

r, reword = użyj zatwierdzenia, ale edytuj komunikat zatwierdzenia

e, edycja = użyj zatwierdzenia, ale przestań zmieniać

s, squash = użyj zatwierdzenia, ale połącz z poprzednim zatwierdzeniem

f, fixup = like "squash", ale odrzuć komunikat dziennika tego zatwierdzenia

x, exec = uruchom polecenie (reszta wiersza) przy użyciu powłoki

d, drop = usuń zatwierdzenie

#

Linie te można ponownie zamówić; są wykonywane od góry do dołu.

#

Jeśli usuniesz tutaj linię, KTÓRE ZGODNIE ZOSTANĄ UTRACONE.

#

Jeśli jednak usuniesz wszystko, zmiana bazy zostanie przerwana.

#

Zauważ, że puste zatwierdzenia są komentowane ~ ~

~
~
~
~
~
~
~
~
~ ~

Tutaj zmień pierwszy wiersz zgodnie z potrzebami (używając komend wymienionych powyżej, tj. „Upuść”, aby usunąć zatwierdzenie itp.) Po zakończeniu edycji naciśnij „: x”, aby zapisać i wyjść z edytora (dotyczy tylko edytora vim)

I wtedy

git push

Jeśli występuje problem z wyświetlaniem, musisz na siłę przesuwać zmiany do pilota (JEST BARDZO KRYTYCZNY: nie zmuszaj do popychania, jeśli pracujesz w zespole)

git push -f origin

Shrinath Kopare
źródło
-1

Możesz do tego użyć git cherry-pick. „cherry-pick” zastosuje zatwierdzenie do gałęzi, na której jesteś teraz.

to zrób

git rebase --hard <SHA1 of A>

następnie zastosuj zatwierdzenia D i E.

git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>

Spowoduje to pominięcie zatwierdzenia B i C. Powiedziawszy, że zastosowanie D zatwierdzenia do gałęzi bez B może być niemożliwe, więc YMMV.

Rory
źródło
2
OP chce łączyć zatwierdzenia B, C, D, a nie usuwać ich zmiany.
jfs
3
Myślę, że miałeś na myśli reset --hard, że nie rebase --hard(co nie istnieje)
Mauricio Scheffer,