Chcę zmienić autora jednego konkretnego commitu w historii. Nie jest to ostatni commit.
Wiem o tym pytaniu - Jak zmienić autora commitu w git?.
Ale zastanawiam się nad czymś, gdzie identyfikuję commit przez hash lub short-hash.
Interaktywny rebase z punktu wcześniejszego w historii niż commit, który chcesz zmodyfikować (git rebase -i <earliercommit>
). Na liście commitów poddawanych rebase, zmień tekst z pick
na edit
obok hasha tego, który chcesz zmodyfikować. Następnie, gdy git poprosi cię o zmianę commitu, użyj tego:
git commit --amend --author="Author Name <[email protected]>"
Na przykład, jeśli twoja historia commitów to A-B-C-D-E-F
z F
jako HEAD
, a ty chcesz zmienić autora C
i D
, to...
git rebase -i B
(tutaj jest przykład tego co zobaczysz po wykonaniu komendy git rebase -i B
)A
, użyj git rebase -i --root
.C
i D
z pick
na edit
.C
.git commit --amend --author="Author Name <[email protected]>"
.git rebase --continue
.D
.git commit --amend --author="Author Name <[email protected]>"
ponownie.git rebase --continue
.git push -f
, aby zaktualizować swój origin o zaktualizowane commity.Odpowiedzi w pytaniu, do którego się odniosłeś, są dobre i obejmują twoją sytuację (inne pytanie jest bardziej ogólne, ponieważ obejmuje przepisywanie wielu commitów).
Jako pretekst do wypróbowania git filter-branch
, napisałem skrypt do przepisywania Author Name i / lub Author Email dla danego commitu:
#!/bin/sh
#
# Change the author name and/or email of a single commit.
#
# change-author [-f] commit-to-change [branch-to-rewrite [new-name [new-email]]]
#
# If -f is supplied it is passed to "git filter-branch".
#
# If <branch-to-rewrite> is not provided or is empty HEAD will be used.
# Use "--all" or a space separated list (e.g. "master next") to rewrite
# multiple branches.
#
# If <new-name> (or <new-email>) is not provided or is empty, the normal
# user.name (user.email) Git configuration value will be used.
#
force=''
if test "x$1" = "x-f"; then
force='-f'
shift
fi
die() {
printf '%s\n' "$@"
exit 128
}
targ="$(git rev-parse --verify "$1" 2>/dev/null)" || die "$1 is not a commit"
br="${2:-HEAD}"
TARG_COMMIT="$targ"
TARG_NAME="${3-}"
TARG_EMAIL="${4-}"
export TARG_COMMIT TARG_NAME TARG_EMAIL
filt='
if test "$GIT_COMMIT" = "$TARG_COMMIT"; then
if test -n "$TARG_EMAIL"; then
GIT_AUTHOR_EMAIL="$TARG_EMAIL"
export GIT_AUTHOR_EMAIL
else
unset GIT_AUTHOR_EMAIL
fi
if test -n "$TARG_NAME"; then
GIT_AUTHOR_NAME="$TARG_NAME"
export GIT_AUTHOR_NAME
else
unset GIT_AUTHOR_NAME
fi
fi
'
git filter-branch $force --env-filter "$filt" -- $br
Podczas wykonywania git rebase -i
jest ten interesujący fragment w doc:
Jeśli chcesz złożyć dwa lub więcej commitów w jeden, zamień komendę
"pick"
dla drugiego i kolejnych commitów na"squash"
lub"fixup"
. Jeśli commity miały różnych autorów, złożony commit będzie przypisany do autora pierwszego commitu. Sugerowana wiadomość commit dla złożonego commitu jest konkatenacją wiadomości commit z pierwszego commitu i tych z komendą"squash"
, ale pomija wiadomości commit z commitów z komendą"fixup"
.
A-B-C-D-E-F
,B
i D
(= 2 commity),to możesz zrobić:
git config user.name "Popraw nową nazwę"
.git config user.email "[email protected]"
.git commit --allow-empty -m "empty"
.git rebase -i B^
B^
wybiera rodzica B
.pick
na squash
dla tych.Przykład tego co da ci git rebase -i B^
:
pick sha-commit-B some message
pick sha-commit-C some message
pick sha-commit-D some message
pick sha-commit-E some message
pick sha-commit-F some message
# pick sha-commit-empty1 empty
# pick sha-commit-empty2 empty
zmień to na:
# change commit B's author
pick sha-commit-empty1 empty
squash sha-commit-B some message
# leave commit C alone
pick sha-commit-C some message
# change commit D's author
pick sha-commit-empty2 empty
squash sha-commit-D some message
# leave commit E-F alone
pick sha-commit-E some message
pick sha-commit-F some message
Zostaniesz poproszony o edycję wiadomości:
# This is a combination of 2 commits.
# The first commit's message is:
empty
# This is the 2nd commit message:
...some useful commit message there...
i możesz po prostu usunąć kilka pierwszych linii.