Jak zmodyfikować określone zatwierdzenie?

2233

Zwykle przesyłam listę do zatwierdzenia. Jeśli mam następujące zatwierdzenia:

  1. HEAD
  2. Commit3
  3. Commit2
  4. Commit1

... Wiem, że mogę modyfikować zatwierdzanie głowy git commit --amend. Ale jak mogę zmodyfikować Commit1, biorąc pod uwagę, że nie jest to HEADzatwierdzenie?

Sam Liao
źródło
31
Zobacz alternatywną odpowiedź tutaj: stackoverflow.com/a/18150592/520567 Twoja zaakceptowana odpowiedź jest naprawdę dokładną odpowiedzią na twoje pytanie, ale jeśli masz nowe zatwierdzenie, zanim zdecydujesz się na edycję, to odpowiedź byłaby prostsza. Może także współpracować z wieloma zatwierdzeniami, które chcesz scalić / zgnieść ze starszym.
akostadinov,
6
Możesz także zobaczyć Podział zatwierdzenie w Git Tools - Przepisywanie historii, aby uzyskać więcej informacji.
hakre

Odpowiedzi:

2954

Możesz użyć git rebase . Na przykład, jeśli chcesz zmodyfikować zatwierdzenie bbc643cd, uruchom

$ git rebase --interactive 'bbc643cd^'

Zwróć uwagę na daszek ^na końcu polecenia, ponieważ tak naprawdę musisz cofnąć bazowanie do zatwierdzenia przed tym, które chcesz zmodyfikować .

W edytorze domyślnym zmień pickna editw wierszu z opcją „bbc643cd”.

Zapisz plik i zakończ: git zinterpretuje i automatycznie wykona polecenia w pliku. Znajdziesz się w poprzedniej sytuacji, w której właśnie utworzyłeś zatwierdzenie bbc643cd.

W tym momencie bbc643cdjest twoje ostatnie zatwierdzenie i możesz je łatwo zmienić : wprowadź zmiany, a następnie zatwierdź je za pomocą polecenia:

$ git commit --all --amend --no-edit

Następnie wpisz:

$ git rebase --continue

aby powrócić do poprzedniego zatwierdzenia HEAD.

OSTRZEŻENIE : Zauważ, że spowoduje to zmianę SHA-1 tego zatwierdzenia, a także wszystkich dzieci - innymi słowy, przepisuje historię od tego momentu. Możesz przerwać repozytorium, robiąc to , naciskając poleceniegit push --force

ZelluX
źródło
125
Inną interesującą opcją w tym przepływie jest to, że po przejściu do zatwierdzenia, które chcesz zmodyfikować, zamiast modyfikować pliki i przesuwać nad zatwierdzeniem na górze (tym, który edytujesz), możesz podzielić to zatwierdzenie na dwa różne zatwierdzenia (lub nawet więcej). W takim przypadku wróć do zatwierdzenia do edycji i uruchom „git reset HEAD ^”. które umieści zmodyfikowane pliki tego zatwierdzenia na scenie. Teraz wybierz i zatwierdz dowolne pliki, jak chcesz. Ten przepływ jest dość dobrze wyjaśniony na stronie podręcznika „git-rebase”. Patrz sekcja „Dzielenie zatwierdzeń”. bit.ly/d50w1M
Diego Pino
200
W Git 1.6.6 i nowszych możesz zamiast tego użyć rewordakcji (automatycznie otwiera edytor i kontynuuje pozostałe kroki zmiany bazy; to eliminuje użycie i kiedy trzeba tylko zmienić komunikat zatwierdzenia, a nie treść ). git rebase -ieditgit commit --ammendgit rebase --continue
Chris Johnsen
108
Warto zauważyć, że może być konieczne uruchomienie git stashprzed git rebasei git stash poppo, jeśli masz oczekujące zmiany.
user123444555621,
3
Czy istnieje polecenie shortucut do edycji określonego zatwierdzenia w interaktywnej bazie bez otwierania edytora, znajdowania zatwierdzenia, oznaczania go do edycji, a następnie powrotu do wiersza poleceń?
sstur
15
Zauważ, że w przypadku nowszego gita rozsądniej byłoby zastosować się do szybkich instrukcji zamiast ślepo korzystać z git commit --all --amend --no-edittego miejsca. Wszystko co musiałem zrobić po git rebase -i ...było git commit --amendnormalnie potem git rebase --continue.
Eric Chen
452

Skorzystaj z niesamowitej interaktywnej bazy:

git rebase -i @~9   # Show the last 9 commits in a text editor

Znajdź żądane zatwierdzenie, zmień pickna e( edit) oraz zapisz i zamknij plik. Git przewinie do tego zatwierdzenia, umożliwiając:

  • używać git commit --amenddo wprowadzania zmian, lub
  • użyj, git reset @~aby odrzucić ostatni zatwierdzenie, ale nie zmiany w plikach (tj. przejdź do punktu, w którym byłeś, kiedy edytowałeś pliki, ale jeszcze nie zatwierdziłeś).

To drugie jest przydatne do wykonywania bardziej skomplikowanych czynności, takich jak dzielenie na wiele zatwierdzeń.

Następnie uruchom git rebase --continue, a Git odtworzy kolejne zmiany na zmodyfikowanym zatwierdzeniu. Możesz zostać poproszony o naprawienie niektórych konfliktów scalania.

Uwaga: @jest skrótem dla HEADi ~jest zatwierdzeniem przed określonym zatwierdzeniem.

Przeczytaj więcej o przepisywaniu historii w dokumentach Git.


Nie bój się bazować

ProTip ™: Nie bój się eksperymentować z „niebezpiecznymi” poleceniami, które przepisują historię * - Git domyślnie nie usuwa twoich zobowiązań przez 90 dni; możesz je znaleźć w reflog:

$ git reset @~3   # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* Uważaj na opcje takie jak --hardi --forcechociaż - mogą odrzucać dane.
* Nie zapisuj także historii oddziałów, z którymi współpracujesz.



W wielu systemach git rebase -idomyślnie otworzy Vima. Vim nie działa jak większość współczesnych edytorów tekstu, więc spójrz, jak zmienić bazę danych za pomocą Vima . Jeśli wolisz użyć innego edytora, zmień go za pomocą git config --global core.editor your-favorite-text-editor.

Zaz
źródło
29
Środek twojej odpowiedzi to dziwne miejsce na umieszczenie tego, co mogę jedynie opisać jako reklamę miniture dla VIM. To nie ma znaczenia dla pytania i po prostu zaśmieca twoją odpowiedź.
Intentss
21
@Intentss: Ach, rozumiem, dlaczego to wyglądało dziwnie. Powodem tego było to, że Vim jest domyślnym edytorem tekstu w wielu systemach, więc pierwsze doświadczenie interaktywnego bazowania wielu ludzi to ekran, na którym pisanie sprawia, że ​​kursor lata w kółko. Następnie zmieniają edytor na coś innego, a ich drugie doświadczenie interaktywnego przekształcania jest dość normalne, ale pozostawia ich zastanawianie się, dlaczego używa pliku tekstowego zamiast GUI. Aby osiągnąć przepływ z rebasingiem, potrzebujesz czegoś takiego jak Vim lub tryb rebase Emacsa.
Zaz
9
W porządku. Ponieważ tylu ludzi uważa tę część za nieistotną, skróciłem ją do 3 wierszy i wyjaśniłem, jak w razie potrzeby zmienić edytor.
Zaz
17
Niesamowite! Nie wiedziałem, że możesz użyć tego @jako skrótu HEAD. Dzięki za opublikowanie tego.
James Ko
3
git reset @~dokładnie to, co chciałem zrobić po wybraniu zatwierdzenia git rebase .... Jesteś moim bohaterem)
sierpnia
79

Interaktywny rebase z --autosquashjest czymś, z czego często korzystam, gdy muszę naprawić wcześniejsze zatwierdzenia głębiej w historii. Zasadniczo przyspiesza proces, który ilustruje odpowiedź ZelluX, i jest szczególnie przydatny, gdy masz więcej niż jeden zatwierdzenie, które musisz edytować.

Z dokumentacji:

--autosquash

Gdy komunikat dziennika zatwierdzeń zaczyna się od „squash!…” (Lub „fixup!…”) I istnieje zatwierdzenie, którego tytuł zaczyna się od tego samego…, automatycznie zmodyfikuj listę czynności do wykonania rebase -i, aby zatwierdzenie Zaznaczony do zgniatania pojawia się zaraz po zmodyfikowaniu zatwierdzenia

Załóżmy, że masz historię, która wygląda następująco:

$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1

i masz zmiany, które chcesz zmienić w Commit2, a następnie zatwierdzić je za pomocą

$ git commit -m "fixup! Commit2"

alternatywnie możesz użyć commit-sha zamiast komunikatu zatwierdzenia, więc "fixup! e8adec4lub nawet tylko prefiksu komunikatu zatwierdzenia.

Następnie wcześniej zainicjuj interaktywny rebase na zatwierdzeniu

$ git rebase e8adec4^ -i --autosquash

Twój edytor otworzy się z zatwierdzonymi już porządkami

pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3

wszystko, co musisz zrobić, to zapisać i wyjść

thrau
źródło
21
Możesz także użyć git commit --fixup=@~zamiast git commit -m "fixup! Commit2". Jest to szczególnie przydatne, gdy twoje komunikaty zatwierdzania są dłuższe i napisanie wszystkiego byłoby trudne.
Zaz
42

Biegać:

$ git rebase --interactive commit_hash^

każdy ^wskazuje, ile zatwierdzeń z powrotem chcesz edytować, jeśli jest tylko jeden (hash zatwierdzenia, który podałeś), to po prostu dodajesz jeden ^.

Korzystanie Vim zmienić słowa pick, aby reworddla zatwierdzeń chcesz zmienić, zapisz i zamknij ( :wq). Następnie git wyświetli monit o każde zatwierdzenie oznaczone jako przeredagowanie, aby można było zmienić komunikat zatwierdzenia.

Każdy komunikat zatwierdzenia należy zapisać i wyjść ( :wq), aby przejść do następnego komunikatu zatwierdzenia

Jeśli chcesz wyjść bez zastosowania zmian, naciśnij :q!

EDYCJA : aby nawigować w vimtobie używaj, jaby przejść w górę, kzejść w dół, hw lewo i lw prawo (wszystko w NORMALtrybie, naciśnij, ESCaby przejść do NORMALtrybu). Aby edytować tekst, naciśnij i, aby przejść do INSERTtrybu, w którym wstawiasz tekst. Naciśnij, ESCaby wrócić do NORMALtrybu :)

AKTUALIZACJA : Oto świetny link z listy github Jak cofnąć (prawie) cokolwiek za pomocą git

betoharres
źródło
4
Działa idealnie dla mnie. Warto wspomnieć git push --force?
u01jmg3
Co git push --forcerobi jest zastąpienie pilotów zobowiązuje z lokalnymi zobowiązuje. Tak nie jest w tym temacie :)
betoharres,
@BetuUuUu oczywiście, jeśli twoje zatwierdzenia są wypychane na odległość, a lokalnie modyfikujesz komunikat zatwierdzenia, chciałbyś wymusić wypychanie na odległość, prawda?
Sudip Bhandari,
@SudipBhandari Takie mam wrażenie. Nie wymusiłem, a teraz mam dodatkową gałąź, odzwierciedlającą wszystkie zmiany z powrotem do tego, którego wiadomość zmieniłem, co jest bardzo brzydkie.
ruffin
2
@greenhouse jeśli zmodyfikujesz i wymusisz push, wtedy inni członkowie zespołu najprawdopodobniej napotkają konflikty łączenia. Więc powinieneś być na ogół bardzo ostrożny. Ale jeśli zmodyfikujesz coś, czego nikt inny jeszcze nie ściągnął, powinno to być w porządku (nie zauważy tego). Dlatego uważam --force za ostateczność i zawsze konsultuję stan repo z innymi członkami.
Tomasz Kaczmarzyk
18

Jeśli z jakiegoś powodu nie lubisz interaktywnych edytorów, możesz użyć git rebase --onto.

Powiedz, że chcesz zmodyfikować Commit1. Po pierwsze, gałąź z wcześniej Commit1 :

git checkout -b amending [commit before Commit1]

Po drugie, złap Commit1za cherry-pick:

git cherry-pick Commit1

Teraz popraw swoje zmiany, tworząc Commit1':

git add ...
git commit --amend -m "new message for Commit1"

I wreszcie, po skasowaniu jakichkolwiek innych zmian, przeszczep resztę swoich commits masterna szczycie nowego zatwierdzenia:

git rebase --onto amending Commit1 master

Przeczytaj: „rebase na gałęzi amending, wszystkie zatwierdzenia między Commit1(nie włącznie) i master(włącznie)”. To znaczy Commit2 i Commit3, całkowicie odcinając stary Commit1. Możesz po prostu je wybrać, ale w ten sposób jest łatwiej.

Pamiętaj, aby posprzątać swoje gałęzie!

git branch -d amending
FeepingCreature
źródło
4
możesz użyć, git checkout -b amending Commit1~1aby uzyskać wcześniejsze zatwierdzenie
Arin Taylor
Czy pierwsze dwa kroki są równoważne git checkout -b amending Commit1?
Haoshu
16

Na podstawie dokumentacji

Poprawianie wiadomości starszych lub wielu wiadomości zatwierdzania

git rebase -i HEAD~3 

Powyżej wyświetla listę 3 ostatnich zatwierdzeń w bieżącej gałęzi, zmień 3 na coś innego, jeśli chcesz więcej. Lista będzie wyglądać podobnie do poniższej:

pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Zamień pick z przeredagowaniem przed każdą wiadomością zatwierdzenia, którą chcesz zmienić. Załóżmy, że zmienisz drugi zatwierdzenie na liście, plik będzie wyglądał następująco:

pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Zapisz i zamknij plik listy zmian, pojawi się nowy edytor, w którym możesz zmienić komunikat zmiany, zmienić komunikat zmiany i zapisać.

W końcu forsuj zmienione zatwierdzenia.

git push --force
tylko ja
źródło
Pojawia się następujący błąd: błąd: Wystąpił problem z edytorem „vi”. Podaj wiadomość za pomocą opcji -m lub -F.
Erick Maynard
12

Całkowicie nieinteraktywne polecenie (1)

Pomyślałem, że udostępnię alias, którego używam do tego. Opiera się na nieinteraktywnym interaktywnym rebase. Aby dodać go do swojego gita, uruchom to polecenie (wyjaśnienie podane poniżej):

git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'

Największą zaletą tego polecenia jest fakt, że nie jest to vim .


(1) oczywiście biorąc pod uwagę, że nie ma żadnych konfliktów podczas bazy

Stosowanie

git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111

Nazwa amend-towydaje się odpowiednia IMHO. Porównaj przepływ z --amend:

git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>

Wyjaśnienie

  • git config --global alias.<NAME> '!<COMMAND>'- tworzy globalny alias git o nazwie <NAME>, który wykona polecenie inne niż git<COMMAND>
  • f() { <BODY> }; f - „anonimowa” funkcja bash.
  • SHA=`git rev-parse "$1"`; - konwertuje argument na wersję git i przypisuje wynik do zmiennej SHA
  • git commit --fixup "$SHA"- fixup-commit dla SHA. Zobacz git-commitdokumenty
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" część została objęta innymi odpowiedziami.
    • --autosquashCzy to, co jest wykorzystywane w połączeniu z git commit --fixup, patrz git-rebasedokumenty , aby uzyskać więcej informacji
    • GIT_SEQUENCE_EDITOR=trueto sprawia, że ​​całość nie jest interaktywna. Tego hacka nauczyłem się z tego postu na blogu .
Dethariel
źródło
1
Można także amend-toobsłużyć pliki niestacjonarne: git config --global alias.amend-to '!f() { SHA=git rev- ; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
parsować
2
Jedną z obaw związanych z tą metodą jest to, że może ona stosować niepowiązane poprawki.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
Czy nie chodzi o pytanie, czy zmienić komunikat zatwierdzenia? Ponieważ ta odpowiedź nie dotyczy tego, a przynajmniej nie bezpośrednio.
wytten
@wytten pytanie nie pyta o zmianę komunikatu zatwierdzenia, dotyczy modyfikacji zatwierdzenia, to nie jest HEAD. Odpowiedź na twoje pytanie brzmiałaby: „nie, nie o to chodzi w pytaniu”
Dethariel,
Jestem zdezorientowany, więc jak zmienić komunikat zatwierdzenia?
ggb667
8

Zautomatyzowana interaktywna edycja bazy bazowej, po której następuje powrót do zatwierdzenia gotowy do zmiany

Naprawdę często naprawiałem wcześniejsze zatwierdzenie, więc napisałem dla niego skrypt.

Oto przepływ pracy:

  1. git commit-edit <commit-hash>
    

    Spowoduje to upuszczenie przy zatwierdzeniu, które chcesz edytować.

  2. Napraw i dostosuj zatwierdzenie tak, jak chcesz.

    (Możesz użyć, git stash saveaby zachować wszelkie pliki, których nie popełniasz)

  3. Ponów zatwierdzenie za pomocą --amend, np .:

    git commit --amend
    
  4. Uzupełnij bazę:

    git rebase --continue
    

Aby powyższe zadziałało, umieść poniższy skrypt w pliku wykonywalnym o nazwie git-commit-editgdzieś w twoim $PATH:

#!/bin/bash

set -euo pipefail

script_name=${0##*/}

warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }

[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"

# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
message=$(git log -1 --format='%h %s' "$commit")

if [[ $OSTYPE =~ ^darwin ]]; then
  sed_inplace=(sed -Ei "")
else
  sed_inplace=(sed -Ei)
fi

export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)"  # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty  #  Commit an empty commit so that that cache diffs are un-reversed

echo
echo "Editing commit: $message" >&2
echo
Tom Hale
źródło
7

Przyszło do tego podejścia (i prawdopodobnie jest to dokładnie to samo, co przy użyciu interaktywnego rebase), ale dla mnie jest to dość proste.

Uwaga: przedstawiam to podejście w celu zilustrowania tego, co możesz zrobić, zamiast codziennej alternatywy. Ponieważ ma wiele kroków (i ewentualnie pewne zastrzeżenia).

Powiedz, że chcesz zmienić zatwierdzenie 0i jesteś aktualnie włączonyfeature-branch

some-commit---0---1---2---(feature-branch)HEAD

Przejdź do tego zatwierdzenia i utwórz quick-branch. Możesz także sklonować gałąź funkcji jako punkt przywracania (przed rozpoczęciem).

?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch

Będziesz teraz mieć coś takiego:

0(quick-branch)HEAD---1---2---(feature-branch)

Zmieniaj scenę, przechowuj wszystko inne.

git add ./example.txt
git stash

Zatwierdź zmiany i wróć do feature-branch

git commit --amend
git checkout feature-branch

Będziesz teraz mieć coś takiego:

some-commit---0---1---2---(feature-branch)HEAD
           \
             ---0'(quick-branch)

Rebase feature-branchna quick-branch(rozwiąż wszelkie konflikty po drodze). Zastosuj skrytkę i usuń quick-branch.

git rebase quick-branch
git stash pop
git branch -D quick-branch

I kończysz na:

some-commit---0'---1'---2'---HEAD(feature-branch)

Git nie powieli się (chociaż nie mogę tak naprawdę powiedzieć, do jakiego stopnia) zatwierdzenie 0 podczas bazowania.

Uwaga: wszystkie skróty zatwierdzania są zmieniane, zaczynając od zatwierdzenia, które pierwotnie zamierzaliśmy zmienić.

Olga
źródło
6

Aby uzyskać nieinteraktywne polecenie, umieść skrypt z tą zawartością w ŚCIEŻCE:

#!/bin/sh
#
# git-fixup
# Use staged changes to modify a specified commit
set -e
cmt=$(git rev-parse $1)
git commit --fixup="$cmt"
GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"

Użyj go, wprowadzając zmiany (za pomocą git add), a następnie uruchom git fixup <commit-to-modify>. Oczywiście nadal będzie interaktywny, jeśli wystąpią konflikty.

Pelle Nilsson
źródło
1
To działa dobrze. Dodałem dodatkową funkcjonalność, aby wykonać fragmentaryczne naprawy brudnego drzewa w celu udoskonalenia zestawu zatwierdzeń. `dirtydiff = $ (git diff); if ["$ {dirtydiff}"! = ""]; następnie powtórz „Ukrywanie brudnego drzewa”> & 2; skrytka git; fi;
Simon Feltman
6

git stash+ rebaseautomatyzacja

Ponieważ kiedy muszę wielokrotnie modyfikować stare zatwierdzanie dla recenzji Gerrit, robiłem:

git-amend-old() (
  # Stash, apply to past commit, and rebase the current branch on to of the result.
  current_branch="$(git rev-parse --abbrev-ref HEAD)"
  apply_to="$1"
  git stash
  git checkout "$apply_to"
  git stash apply
  git add -u
  git commit --amend --no-edit
  new_sha="$(git log --format="%H" -n 1)"
  git checkout "$current_branch"
  git rebase --onto "$new_sha" "$apply_to"
)

GitHub w górę .

Stosowanie:

  • zmodyfikuj plik źródłowy, nie musisz tego git addrobić już w repo
  • git-amend-old $old_sha

Podoba mi się to, --autosquashponieważ nie niszczy innych niepowiązanych poprawek.

Ciro Santilli
źródło
Bardzo fajne obejście, powinna być domyślną opcją do git amendzastosowania zmian do konkretnego zatwierdzenia za pomocą bieżącego skrytki, bardzo sprytnie!
caiohamamura
5

Rozwiązałem to

1) tworząc nowe zatwierdzenie ze zmianami, które chcę ..

r8gs4r commit 0

2) wiem, które zobowiązanie muszę z nim połączyć. czyli zatwierdzenie 3.

więc git rebase -i HEAD~4# 4 reprezentuje ostatnie 4 zatwierdzenie (tutaj zatwierdzenie 3 jest na 4 miejscu)

3) w bazie interaktywnej ostatnie zatwierdzenie będzie znajdować się na dole. będzie wyglądać podobnie,

pick q6ade6 commit 3
pick vr43de commit 2
pick ac123d commit 1
pick r8gs4r commit 0

4) tutaj musimy zmienić kolejność zatwierdzenia, jeśli chcesz połączyć się z konkretnym. powinno być jak

parent
|_child

pick q6ade6 commit 3
f r8gs4r commit 0
pick vr43de commit 2
pick ac123d commit 1

po Przegrupuj trzeba wymienić p pickz f( fixup połączą bez popełnienia wiadomości) lub s( squash seryjnej z popełnić wiadomość może się zmienić w czasie wykonywania)

a następnie zapisz swoje drzewo.

teraz scalanie wykonane z istniejącym zatwierdzeniem.

Uwaga: Nie jest to preferowana metoda, chyba że jesteś sam. jeśli masz duży zespół, jego niedopuszczalna metoda przepisywania drzewa git zakończy się konfliktami, o których wiesz, że nie będą. jeśli chcesz utrzymać swoje drzewo w czystości przy mniejszej liczbie zobowiązań, możesz spróbować tego, a jeśli jego mały zespół w przeciwnym razie nie jest preferowany .....

Mohideen bin Mohammed
źródło
Jest to dobre rozwiązanie, jeśli nie chcesz dokonywać modyfikacji na żywo podczas interaktywnej bazy.
Dunatotatos
4

Najlepszą opcją jest użycie „Interaktywnego polecenia rebase” .

git rebaseKomenda jest niezwykle silny. Pozwala edytować komunikaty zatwierdzania , łączyć zatwierdzenia, zmieniać ich kolejność ... itd.

Za każdym razem, gdy zmienisz bazę zatwierdzenia, dla każdego zatwierdzenia zostanie utworzona nowa SHA, bez względu na to, czy treść zostanie zmieniona, czy nie! Powinieneś być ostrożny, kiedy używasz tego polecenia, ponieważ może to mieć drastyczne konsekwencje, szczególnie jeśli pracujesz we współpracy z innymi programistami. Mogą zacząć pracować z twoim zatwierdzeniem, gdy ty wypuszczasz niektóre. Po wymuszeniu wypychania zatwierdzeń nie będą one zsynchronizowane, a możesz później dowiedzieć się, w nieporządnej sytuacji. Więc uważaj!

Zaleca się utworzenie backupgałęzi przed zmianą wersji, aby za każdym razem, gdy znajdziesz coś poza kontrolą, możesz powrócić do poprzedniego stanu.

Teraz jak korzystać z tego polecenia?

git rebase -i <base> 

-ioznacza „interaktywny” . Zauważ, że możesz wykonać rebase w trybie nieinteraktywnym. dawny:

#interactivly rebase the n commits from the current position, n is a given number(2,3 ...etc)
git rebase -i HEAD~n 

HEADwskazuje twoją bieżącą lokalizację (może to być również nazwa oddziału lub zatwierdzenie SHA). ~nŚrodki „n beforeé, więc HEAD~nbędzie wykaz«n»zobowiązuje przed jednym jesteś obecnie.

git rebase ma inne polecenia, takie jak:

  • plub pickaby kontynuować, tak jak jest.
  • rlub reword: aby zachować treść zatwierdzenia, ale zmienić komunikat zatwierdzenia.
  • slub squash: aby połączyć zmiany tego zatwierdzenia z poprzednim zatwierdzeniem (zatwierdzenie nad nim na liście).
  • ... itd.

    Uwaga: Lepiej jest, aby Git pracował z edytorem kodu, aby uprościć sprawę. Na przykład jeśli używasz kodu wizualnego, możesz dodać w ten sposób git config --global core.editor "code --wait". Możesz też wyszukać w Google, jak powiązać preferowany edytor kodu z GIT.

Przykład git rebase

Chciałem zmienić ostatnie 2 zatwierdzenia, które zrobiłem, więc przetwarzam w następujący sposób:

  1. Wyświetl aktualne zatwierdzenia:
    #This to show all the commits on one line
    $git log --oneline
    4f3d0c8 (HEAD -> documentation) docs: Add project description and included files"
    4d95e08 docs: Add created date and project title"
    eaf7978 (origin/master , origin/HEAD, master) Inital commit
    46a5819 Create README.md
    
  2. Teraz używam git rebasedo zmiany 2 ostatnich zatwierdzeń wiadomości: $git rebase -i HEAD~2 Otwiera edytor kodu i pokazuje to:

    pick 4d95e08 docs: Add created date and project title
    pick 4f3d0c8 docs: Add project description and included files
    
    # Rebase eaf7978..4f3d0c8 onto eaf7978 (2 commands)
    #
    # Commands:
    # p, pick <commit> = use commit
    # r, reword <commit> = use commit, but edit the commit message
    ...
    

    Ponieważ chcę zmienić komunikat zatwierdzenia dla tych 2 zatwierdzeń. Więc napiszę rlub rewordzamiast pick. Następnie zapisz plik i zamknij kartę. Pamiętaj, że rebasejest wykonywany w procesie wieloetapowym, więc następnym krokiem jest aktualizacja wiadomości. Zauważ też, że zatwierdzenia są wyświetlane w odwrotnej kolejności chronologicznej, więc ostatnie zatwierdzenie jest wyświetlane w tym jednym, a pierwsze zatwierdzenie w pierwszej linii i tak dalej.

  3. Zaktualizuj wiadomości: Zaktualizuj pierwszą wiadomość:

    docs: Add created date and project title to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...
    

    zapisz i zamknij Edytuj drugą wiadomość

    docs: Add project description and included files to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...
    

    Zapisz i zamknij.

  4. Otrzymasz taki komunikat do końca bazy: Successfully rebased and updated refs/heads/documentationco oznacza, że ​​ci się uda. Możesz wyświetlić zmiany:

    5dff827 (HEAD -> documentation) docs: Add project description and included files to the documentation "README.md"
    4585c68 docs: Add created date and project title to the documentation "README.md"
    eaf7978 (origin/master, origin/HEAD, master) Inital commit
    46a5819 Create README.md
    

    Chciałbym, żeby to pomogło nowym użytkownikom :).

DINA TAKLIT
źródło
2

Dla mnie było to usunięcie niektórych danych uwierzytelniających z repozytorium. Próbowałem się opierać i natknąłem się na tonę pozornie niezwiązanych ze sobą konfliktów, gdy próbowałem zmienić podstawę - kontynuuj. Nie przejmuj się próbami zmiany bazy, użyj narzędzia o nazwie BFG (brew install bfg) na komputerze Mac.

Śrut
źródło
0

Jeśli jeszcze nie wypchnąłeś zatwierdzeń, możesz wrócić do poprzedniego zatwierdzenia za pomocą git reset HEAD^[1,2,3,4...]

Na przykład

git commit <file1> -m "Updated files 1 and 2"
git commit <file3> -m "Updated file 3"

Ups, zapomniałem dodać plik2 do pierwszego zatwierdzenia ...

git reset HEAD^1 // because I only need to go back 1 commit

git add <file2>

Spowoduje to dodanie pliku2 do pierwszego zatwierdzenia.

rharvey
źródło
0

Cóż, to rozwiązanie może wydawać się bardzo głupie, ale może cię uratować w pewnych warunkach.

Mój przyjaciel przypadkowo popełnił przypadkowe popełnienie bardzo dużych plików (cztery automatycznie wygenerowane pliki o wielkości od 3 GB do 5 GB każdy), a następnie dokonał dodatkowych zatwierdzeń kodu, zanim zdał sobie sprawę, że problem git pushjuż nie działa!

Pliki zostały wymienione, .gitignoreale po zmianie nazwy folderu kontenera zostały ujawnione i zatwierdzone! A teraz było jeszcze kilka zmian w kodzie, ale pushdziałało to wiecznie (próba przesłania GB danych!) I ostatecznie zakończyło się niepowodzeniem z powodu ograniczeń rozmiaru pliku Github .

Problem z interaktywnym rebase'em lub czymkolwiek podobnym polegał na tym, że poradziliby sobie z przeszukiwaniem tych ogromnych plików i zajęłoby im wieczność. Niemniej jednak, po spędzeniu prawie godziny w interfejsie CLI, nie byliśmy pewni, czy pliki (i delty) zostały faktycznie usunięte z historii, czy po prostu nie zostały uwzględnione w bieżących zatwierdzeniach. Push też nie działał, a mój przyjaciel naprawdę utknął.

Tak więc rozwiązaniem, które wymyśliłem, było:

  1. Zmień nazwę bieżącego folderu git na ~/Project-old.
  2. Sklonuj ponownie folder git z github (do ~/Project).
  3. Kasa do tego samego oddziału.
  4. Ręcznie cp -rpliki z ~/Project-oldfolderu do ~/Project.
  5. Upewnij się, że ogromne pliki, które nie muszą być rejestrowane, są odpowiednio mvedytowane i dołączone .gitignore.
  6. Upewnij się również, że nie nadpisujesz .gitfolderu w ostatnio sklonowanym ~/Projectprzez stary. Tam właśnie żyją dzienniki problematycznej historii!
  7. Teraz przejrzyj zmiany. Powinien to być związek wszystkich ostatnich zatwierdzeń, z wyjątkiem problematycznych plików.
  8. Na koniec zatwierdz zmiany i dobrze jest je pushedytować.

Największym problemem z tym rozwiązaniem jest to, że zajmuje się ręcznym kopiowaniem niektórych plików, a także scala wszystkie ostatnie zatwierdzenia w jeden (oczywiście z nowym hashem zatwierdzającym). B

Dużymi zaletami jest to, że jest bardzo wyraźny na każdym kroku, działa świetnie w przypadku dużych plików (a także wrażliwych) i nie pozostawia po sobie żadnych śladów w historii!

Aidin
źródło