Jak zmodyfikować określony commit w git?
Zazwyczaj wysyłam listę commitów do przeglądu. Jeśli mam:
-
HEAD
-
Commit3
-
Commit2
Commit1
Wiem, że mogę modyfikować head commit za pomocą git commit --amend
, ale jak mogę modyfikować Commit1
, biorąc pod uwagę, że nie jest to HEAD
zaangażować?
12 answers
Możesz użyć git rebase, na przykład, jeśli chcesz zmodyfikować z powrotem do commit bbc643cd
, Uruchom
$ git rebase --interactive 'bbc643cd^'
W domyślnym edytorze zmodyfikuj pick
na edit
w linii, której commit chcesz zmodyfikować. Wprowadź zmiany, a następnie zatwierdź je tą samą wiadomością, którą miałeś wcześniej:
$ git commit --all --amend --no-edit
Aby zmodyfikować commit, a następnie
$ git rebase --continue
Aby powrócić do poprzedniego Head commit.
WARNING: zauważ, że spowoduje to zmianę SHA-1 tego commita , jak również wszystkich dzieci -- innymi słowy, to przepisuje historię od tego momentu do przodu. możesz złamać repos robiąc to jeśli wciśniesz polecenie git push --force
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-14 14:14:16
Użyj niesamowitego interaktywnego rebase:
git rebase -i @~9 # Show the last 9 commits in a text editor
Znajdź odpowiedni commit, Zmień pick
na e
(edit
), i zapisz i zamknij plik. Git będzie przewijał do tego commita, pozwalając na:
- użyj
git commit --amend
do wprowadzania zmian lub - użyj
git reset @~
, aby odrzucić ostatni commit, ale nie zmiany w plikach (tzn. przeniesie Cię do punktu, w którym edytowałeś pliki, ale jeszcze nie zatwierdziłeś).
Ten ostatni jest przydatny do wykonywania bardziej złożonych takie rzeczy jak dzielenie na wiele commitów.
Następnie uruchom git rebase --continue
, a Git odtworzy kolejne zmiany na Twoim zmodyfikowanym commicie. Możesz zostać poproszony o naprawienie niektórych konfliktów scalania.
Uwaga: @
jest skrótem od HEAD
, a {[10] } jest zatwierdzeniem przed podanym zatwierdzeniem.
Przeczytaj więcej o przepisywaniu historii w dokumentacji Git.
Nie bój się rebase
ProTip™: nie bój się eksperymentowanie z" niebezpiecznymi " poleceniami, które przepisują historię* - Git domyślnie nie usuwa Twoich commitów przez 90 dni; możesz je znaleźć w reflogu:
$ 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 jednak na opcje takie jak --hard
i --force
- mogą one odrzucić dane.
* nie zapisuj również historii w żadnych gałęziach, nad którymi współpracujesz.
Na wielu systemach, git rebase -i
domyślnie otworzy Vima. Vim nie działa jak większość nowoczesnych edytorów tekstu, więc zobacz jak rebase używać Vim . Jeśli wolisz używać innego edytora, zmień go za pomocą git config --global core.editor your-favorite-text-editor
.
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-05-23 12:18:24
Interactive rebase with --autosquash
jest czymś, czego często używam, gdy muszę naprawić poprzednie commity głębiej w historii. Zasadniczo przyspiesza proces, który ilustruje odpowiedź ZelluX, i jest szczególnie przydatny, gdy masz więcej niż jeden commit, który musisz edytować.
Z dokumentacji:
--autosquash
Gdy komunikat dziennika zmian zaczyna się od " squash! ... "(lub "fixup! ... "), a istnieje commit, którego tytuł zaczyna się od tego samego …, automatycznie Modyfikuj listę todo rebase-i tak, aby commit oznaczony do squashowania pojawił się zaraz po commicie, który ma zostać zmodyfikowany
Załóżmy, że masz historię, która wygląda tak:
$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1
I masz zmiany, które chcesz zmienić w commit 2, a następnie zatwierdź zmiany za pomocą
$ git commit -m "fixup! Commit2"
Alternatywnie możesz użyć commit-sha zamiast komunikatu commit, więc "fixup! e8adec4
lub nawet tylko prefiks komunikatu commit.
Następnie zainicjuj interaktywną rebazę na commit przed
$ git rebase e8adec4^ -i --autosquash
Twój edytor otworzy się z poprawnym zatwierdzeniem
pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3
Wszystko, co musisz zrobić, to zapisać i zakończyć
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
2015-09-29 17:59:45
Run:
$ git rebase --interactive commit_hash^
Każdy ^
wskazuje, ile commitów chcesz edytować, jeśli jest to tylko jeden (hash commitów, który podałeś), to po prostu dodajesz jeden ^
.
Używając Vima zmieniasz słowa pick
na reword
dla commitów, które chcesz zmienić, Zapisz i zakończ(:wq
). Następnie git wyświetli monit z każdym zatwierdzeniem, które zostało oznaczone jako przeredagowanie, abyś mógł zmienić wiadomość zatwierdzania.
Każda wiadomość commit musisz zapisać i zamknąć (:wq
) aby przejść do następnego commit message
Jeśli chcesz wyjść bez stosowania zmian, naciśnij :q!
EDIT: aby nawigować w vim
, używasz j
, aby przejść do góry, k
, aby przejść do dołu, h
, aby przejść do lewej i l
, aby przejść do trybu NORMAL
).
Aby edytować tekst, naciśnij i
, aby przejść do trybu INSERT
, w którym wstawiasz tekst.
Naciśnij ESC
, aby wrócić do trybu NORMAL
:)
UPDATE : oto świetny link z github listing jak cofnąć (prawie) wszystko z git
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-04-13 19:45:40
Jeśli z jakiegoś powodu nie lubisz edytorów interaktywnych, możesz użyć git rebase --onto
.
Powiedz, że chcesz zmodyfikować Commit1
. Najpierw gałąź z przed Commit1
:
git checkout -b amending [commit before Commit1]
Drugi, chwyć Commit1
z cherry-pick
:
git cherry-pick Commit1
Teraz popraw swoje zmiany, tworząc Commit1'
:
git add ...
git commit --amend -m "new message for Commit1"
I na koniec, po ukryciu wszelkich innych zmian, przenieś resztę commitów do master
na wierzch
nowy commit:
git rebase --onto amending Commit1 master
Powinno być: "rebase, na gałęzi amending
, wszystkie committs between Commit1
(non-inclusive) and master
(inclusive)". Oznacza to, że commit 2 I commit 3, całkowicie odcinając Stary commit 1. Możesz je po prostu wybrać, ale ten sposób jest łatwiejszy.
Pamiętaj, aby oczyścić swoje gałęzie!
git branch -d amending
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-10-22 12:19:44
Przyszedł do tego podejścia (i jest to prawdopodobnie dokładnie to samo, co za pomocą interaktywnego rebase), ale dla mnie jest to dość proste.
Uwaga: przedstawiam to podejście ze względu na ilustrację tego, co można zrobić, a nie codzienną alternatywę. Ponieważ ma wiele kroków (i ewentualnie pewne zastrzeżenia.)
Powiedz, że chcesz zmienić commit 0
i jesteś aktualnie na feature-branch
some-commit---0---1---2---(feature-branch)HEAD
Sprawdź ten commit i utwórz quick-branch
. Możesz również sklonować swoją funkcję gałąź jako punkt regeneracji (przed rozpoczęciem).
?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch
Teraz będziesz miał coś takiego:
0(quick-branch)HEAD---1---2---(feature-branch)
Zmiany sceny, Schowaj Wszystko inne.
git add ./example.txt
git stash
Zatwierdź zmiany i Kasuj z powrotem do feature-branch
git commit --amend
git checkout feature-branch
Teraz będziesz miał coś takiego:
some-commit---0---1---2---(feature-branch)HEAD
\
---0'(quick-branch)
Rebase feature-branch
na quick-branch
(rozwiąż wszelkie konflikty po drodze). Apply stash and remove quick-branch
.
git rebase quick-branch
git stash pop
git branch -D quick-branch
I kończy się na:
some-commit---0'---1'---2'---HEAD(feature-branch)
Git nie powieli (chociaż I nie mogę powiedzieć w jakim stopniu) 0 commit podczas rebasingu.
Uwaga: wszystkie skróty zmian są zmieniane począwszy od zmiany, którą pierwotnie zamierzaliśmy zmienić.
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-09-23 16:51:41
Całkowicie nieinteraktywne polecenie(1)
Pomyślałem, że podzielę się pseudonimem, którego do tego używam. Opiera się na nieinteraktywnej interaktywnej 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 jest to no-vim .
(1)biorąc pod uwagę, że nie ma konfliktów podczas rebase, oczywiście
Użycie
git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111
The Nazwa amend-to
wydaje 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 do git revision i przypisuje wynik do zmiennejSHA
-
git commit --fixup "$SHA"
- fixup-commit dlaSHA
. Zobacz teżgit-commit
docs -
GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
-
git rebase --interactive "$SHA^"
część została pokryta innymi odpowiedziami. -
--autosquash
jest to, co jest używane w połączeniu zgit commit --fixup
, zobaczgit-rebase
docs aby uzyskać więcej informacji - To sprawia, że całość nie jest interaktywna. Tego hacka nauczyłem się Z tego posta na blogu .
-
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-02-27 01:47:51
Aby uzyskać polecenie nieinteraktywne, 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 przez inscenizację zmian (za pomocą git add
), a następnie uruchom git fixup <commit-to-modify>
. Oczywiście nadal będzie interaktywny, jeśli pojawią się konflikty.
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-01-16 15:27:09
Na podstawie dokumentacji
Zmiana wiadomości starszych lub wielu komunikatów commit
git rebase -i HEAD~3
Powyższe wyświetla listę ostatnich 3 commitów w bieżącej gałęzi, Zmień 3 na coś innego, jeśli chcesz więcej. Lista będzie wyglądać podobnie do:
pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.
Zastąp pick z przeredaguj przed każdą wiadomością commit, którą chcesz zmienić. Powiedzmy, że zmienisz drugi commit na liście, Twój plik będzie wyglądał jak "po": {]}
pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.
Zapisz i zamknij plik listy zatwierdzeń, pojawi się nowy edytor, aby zmienić wiadomość zatwierdzania, zmienić wiadomość zatwierdzania i zapisać.
Ostatecznie Wymuś-wciśnij zmienione commity.
git push --force
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-05-17 08:38:57
Dla mnie to było za usunięcie niektórych poświadczeń z repo. Próbowałem rebasingu i napotkałem mnóstwo pozornie niepowiązanych konfliktów po drodze, próbując rebase -- Kontynuuj. Nie trudź się próbując rebase siebie, użyj narzędzia o nazwie BFG (brew install bfg) na mac.
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-11-07 07:24:20
I solved this,
1) tworząc nowy commit ze zmianami, które chcę..
r8gs4r commit 0
2) wiem, który commit muszę z nim połączyć. czyli commit 3.
Więc git rebase -i HEAD~4
# 4 reprezentuje ostatnie 4 commit (tutaj commit 3 jest na 4 miejscu)
3) w interaktywnym rebase Ostatnie zatwierdzenie będzie umieszczone 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ć commit, jeśli chcemy połączyć się z konkretnym. powinno być tak:
parent
|_child
pick q6ade6 commit 3
f r8gs4r commit 0
pick vr43de commit 2
pick ac123d commit 1
Po przestawianiu Ciebie trzeba wymienić p
pick
z f
(fixup połączy się bez komunikatu commit) lub s
(squash merge with commit message can change in run time)
A następnie zapisać swoje drzewo.
Teraz połącz z istniejącym commitem.
Uwaga: nie jest to preferowana metoda, chyba że utrzymujesz ją samodzielnie. jeśli masz duży rozmiar zespołu to nie jest akceptowalna metoda przepisywania Gita drzewo skończy w konfliktach, które znasz inne zwyczaje. jeśli chcesz na utrzymanie drzewa czyste z mniej commitów może spróbować tego i jeśli jego mały zespół w przeciwnym razie nie jest preferowany.....
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-01-05 18:35:50
Automatyczna, interaktywna edycja rebase, po której następuje commit revert gotowy do powtórzenia
Znalazłem się naprawiając poprzedni commit na tyle często, że napisałem do niego skrypt.
Oto przebieg pracy:
-
git commit-edit <commit-hash>
Spowoduje to usunięcie zmian, które chcesz edytować.
-
Popraw i ustaw commit tak, jak chcesz, aby był na pierwszym miejscu.
(możesz użyć
git stash save
, Aby zachować pliki, których nie jesteś committing) -
Powtórz commit za pomocą
--amend
, np:git commit --amend
-
Uzupełnij rebase:
git rebase --continue
Aby powyższy skrypt zadziałał, umieść poniższy skrypt w pliku wykonywalnym o nazwie git-commit-edit
gdzieś 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
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-09-14 04:41:11