Jak zgnieść commity w git po ich wypchnięciu?

550

To daje dobre wytłumaczenie zgniatania wielu zatwierdzeń:

http://git-scm.com/book/en/Git-Branching-Rebasing

ale nie działa dla zatwierdzeń, które zostały już wypchnięte. Jak zmiażdżyć kilka ostatnich zatwierdzeń w moich lokalnych i zdalnych repozytoriach?

EDYCJA: Kiedy to zrobię git rebase -i origin/master~4 master, zachowaj pierwszą jako pick, ustaw pozostałe trzy jako squash, a następnie zakończ (przez cx cc w emacs), otrzymuję:

$ git rebase -i origin/master~4 master
# Not currently on any branch.
nothing to commit (working directory clean)

Could not apply 2f40e2c... Revert "issue 4427: bpf device permission change option added"
$ git rebase -i origin/master~4 master
Interactive rebase already started

gdzie 2f40 jest pickzatwierdzeniem. A teraz żaden z 4 zatwierdzeń nie pojawia się w git log. Spodziewałem się zrestartowania mojego edytora, aby móc wprowadzić komunikat zatwierdzenia. Co ja robię źle?

Loren
źródło

Odpowiedzi:

779

Squash zatwierdza się lokalnie za pomocą

git rebase -i origin/master~4 master

a następnie wymuś naciśnięcie

git push origin +master

Różnica między --forcei+

Z dokumentacji git push:

Należy zauważyć, że --forcedotyczy wszystkich wypychanych referencji, dlatego użycie go z push.defaultustawionymi na matchinglub z wieloma miejscami docelowymi wypychania skonfigurowanymi za pomocą remote.*.pushmoże zastąpić referencje inne niż bieżąca gałąź (w tym lokalne referencje, które są ściśle za ich zdalnym odpowiednikiem). Aby wymusić wypychanie tylko do jednej gałęzi, użyj + znaku przed refspec, aby pchnąć (np. git push origin +masterAby wymusić wypychanie do mastergałęzi).

Alan Haggai Alavi
źródło
30
możesz takżegit push --force origin master
Daenyth
7
Daenyth : Tak, ale zawsze wolę tę składnię, ponieważ jest ona krótsza.
Alan Haggai Alavi
85
I oczywiście zdaj sobie sprawę, że jeśli ktokolwiek mógł pobrać ze zdalnego repozytorium, prawdopodobnie nie chcesz tego robić - w takim przypadku odpowiedź brzmi „nie”.
Cascabel,
10
Sądzę też, że OP dokładnie kopiuje polecenie git rebase -i origin/masteri naprawdę chce wiedzieć, jak zmienić bazowe zatwierdzenia dalej, np git rebase -i origin/master~20 master.
Cascabel
6
gstackoverflow :+wymusza tylko poprzedzający go refspec. --forcewymusi wypchnięcie wszystkich referencji. Zobacz zaktualizowaną odpowiedź.
Alan Haggai Alavi,
119

Na gałęzi mogłem to zrobić w ten sposób (dla ostatnich 4 zmian)

git checkout my_branch
git reset --soft HEAD~4
git commit
git push --force origin my_branch
jakob-r
źródło
1
Wykonanie tego za pomocą miękkiego polecenia na już wypchniętej gałęzi ostatecznie skończyło się dla mnie popychaniem wielu innych ludzi.
cchamberlain
3
Tona? Jak może być więcej niż 4? Czy możesz rozwinąć?
jakob-r
Nie jestem tego pewien, ale miało to coś wspólnego z próbą zmiażdżenia już wciśniętego zatwierdzenia. Wygląda na to, że inni doświadczyli podobnego tutaj - stackoverflow.com/questions/5189560/…
cchamberlain
4
Przyjąłbym to zgodnie z oczekiwaniami. Bardziej czystszy, który zaakceptował odpowiedź.
vikramvi
4
To najbardziej zrozumiała i zaakceptowana odpowiedź w zaledwie 4 krokach
Ameya Salagre,
45

Drobna różnica w stosunku do zaakceptowanej odpowiedzi, ale miałem wiele trudności ze zgnieceniem i w końcu ją dostałem.

$ git rebase -i HEAD~4
  • Na ekranie interaktywnym, który otwiera się, należy wymienić wybrać z dyni na szczycie dla wszystkich zatwierdzeń, które chcesz zgnieść.
  • Zapisz i zamknij edytor za pomocą esc --> :wq

Wciśnij do pilota za pomocą:

$ git push origin branch-name --force
BLRBoy
źródło
2
krótkie i skuteczne, rozbudowane:
terwxqian
22

Wiele problemów można uniknąć tylko przez stworzenie branchdo pracy na i nie działa na master:

git checkout -b mybranch

Następujące działa dla remotezatwierdzeń już wypchniętych i mieszaniny remotewypychanych zatwierdzeń / localtylko zatwierdzeń:

# example merging 4 commits

git checkout mybranch
git rebase -i mybranch~4 mybranch

# at the interactive screen
# choose fixup for commit: 2 / 3 / 4

git push -u origin +mybranch

Mam też kilka notatek z prośbą o ściągnięcie, które mogą być pomocne.

Stuart Cardall
źródło
17

git rebase -i master

otworzy się edytor vm i msgs coś takiego

Pick 2994283490 commit msg1
f 7994283490 commit msg2
f 4654283490 commit msg3
f 5694283490 commit msg4
#Some message 
#
#some more

Tutaj zmieniłem pick dla wszystkich innych zatwierdzeń na „f” (oznacza naprawę).

git push -f origin feature/feature-branch-name-xyz

to naprawi wszystkie zatwierdzenia do jednego zatwierdzenia i usunie wszystkie pozostałe zatwierdzenia. Zrobiłem to i to mi pomogło.

Nupur
źródło
3

Podczas pracy z Gitlab lub Github możesz w ten sposób wpaść w kłopoty. Zgniatasz swoje zobowiązania jedną z powyższych metod. Moim ulubionym jest:

git rebase -i HEAD~4
or
git rebase -i origin/master

wybierz squash lub fixup dla swojego zatwierdzenia. W tym momencie sprawdziłbyś status git. Wiadomość może być:

    On branch ABC-1916-remote
    Your branch and 'origin/ABC-1916' have diverged,
    and have 1 and 7 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)

I możesz pokusić się o to. NIE rób tego, bo będziesz w takiej samej sytuacji jak poprzednio.

Zamiast tego pchnij do swojego źródła za pomocą:

git push origin +ABC-1916-remote:ABC-1916

+ Pozwala na wymuszenie push tylko do jednej gałęzi.

Alex
źródło
nie ma nic złego w ciągnięciu, szczególnie jeśli masz konflikty, można je rozwiązać łatwiej niż przy użyciu siły
Ray_Poly
2

Do zgniatania dwóch zatwierdzeń, z których jeden został już wypchnięty, w jednym oddziale działały:

git rebase -i HEAD~2
    [ pick     older-commit  ]
    [ squash   newest-commit ]
git push --force

Domyślnie będzie to zawierać komunikat zatwierdzenia najnowszego zatwierdzenia jako komentarz do starszego zatwierdzenia.

homary
źródło
2

1) git rebase -i HEAD~4

Aby rozwinąć: Działa na bieżącym oddziale; HEAD ~ 4 oznacza zgniecenie ostatnich czterech zmian; tryb interaktywny (-i)

2) W tym momencie edytor otworzył z listą zatwierdzeń, aby zmienić drugi i kolejne zatwierdzenia, zamieniając pick na squash, a następnie zapisz go.

dane wyjściowe: Pomyślnie ponownie wydano i zaktualizowano refs / heads / branch-name.

3) git push origin refs/heads/branch-name --force

wynik:

remote:
remote: To create a merge request for branch-name, visit:
remote: http://xxx/sc/server/merge_requests/new?merge_request%5Bsource_branch%5D=sss
remote:To ip:sc/server.git
 + 84b4b60...5045693 branch-name -> branch-name (forced update)
terwxqian
źródło