Почему Git GUI продолжает называть меня Jon Skeet?
В шутку я назвал учетную запись пользователя моего ноутбука Джона Скита. Я настроил параметры для каждого репозитория, чтобы звонить мне wizzwizz4
Тем не менее, когда я просматриваю свои коммиты, я вижу это:
Author: Jon Skeet <jon@myLaptop> 2018-12-21 22:07:11
Committer: wizzwizz4 <wizzwizz4@users.noreply.github.com> 2018-12-21 22:12:07
Parent: 39c31f5aebe43cdddbe00432207e4bb2cc6a777e (Initial commit)
Branches: master
Follows:
Precedes:
Почему он продолжает это делать, когда в настройках моего репозитория четко указаны мои намерения? Я не хочу, чтобы Джон получил кредит на мой код! Фиксация из командной строки дает ожидаемый результат.
1 ответ
Есть несколько способов, которые могут произойти. Прежде чем мы доберемся до них всех, нам нужно будет предоставить соответствующую справочную информацию. Стоит также подчеркнуть ключевой момент: никакие данные в любой существующей фиксации не могут быть изменены, даже один бит. Пока совершать 39c31f5aebe43cdddbe00432207e4bb2cc6a777e
существует в вашем хранилище, он будет по-прежнему иметь ту же информацию. (Обратите внимание, что это родитель показанного вами коммита. Вы не указали фактический хэш-идентификатор самого коммита, поэтому я не смог его использовать.)
В очень конкретном случае Git-GUI (git-gui.sh
, который я никогда не использую), это выглядит из источника, как будто есть функция, где использование "поправить" читает HEAD
фиксирует информацию об авторе и копирует ее. Обычно это следует делать, когда вы выбираете "внесение изменений" (что, как отмечено выше и ниже, является ложной ложью), и не следует делать это, когда не вносятся поправки. В отличие от командной строки git commit
Похоже, что нет никакой ручки Git-GUI, чтобы сделать поправку, не сохраняя автора. Если он случайно применяет сохранение автора ко всем новым коммитам, это просто ошибка.
Подробнее читайте дальше.
Фон
С каждым коммитом связаны метаданные. В необработанном объекте фиксации есть две соответствующие строки метаданных, называемые автором и коммиттером. Эти два, как правило, но не обязательно, одинаковы, как можно видеть из различных коммитов в Git-репозитории для самого Git. Например:
$ git cat-file -p 5d826e972970a784bd7a7bdf587512510097b8c7
tree c790c47fe551d5ed812cfefdac243eb972c1fde3
parent b5796d9a3263b26a8ef32eeca76b3c1d62fcedc5
author Junio C Hamano <gitster pobox.com> 1544328981 +0900
committer Junio C Hamano <gitster pobox.com> 1544328981 +0900
Git 2.20
Signed-off-by: Junio C Hamano <gitster pobox.com>
(Я заменил @
с по возможности сократить сбор спама). Но:
$ git cat-file -p 6fcbad87d476d7281832af843dd448c94673fbfc
tree aa05bc7af6e92f3db5d5d738adf0d0b1b3dd23b6
parent b00bf1c9a8dd5009d5102aef7af9e2b886b1e5ad
author Johannes Sixt <j6t kdbg.org> 1543858489 +0100
committer Junio C Hamano <gitster pobox.com> 1543891852 +0900
rebase docs: fix incorrect format of [... snip]
Обратите внимание, что на самом деле в каждом из двух полей есть три части: полное имя, адрес электронной почты в <угловых скобках> и отметка времени с указанием зоны.
Когда вы делаете новый коммит, используя git commit
, Git обычно устанавливает и автора, и коммиттера в те же три строки. Но многие команды Git копируют некоторые существующие коммиты в новую улучшенную замену. Новый коммит, по определению, имеет новый и другой хэш-идентификатор, но предназначен для использования вместо старого. В этих случаях Git обычно сохраняет исходную информацию об авторе и устанавливает вас (и сейчас) в качестве коммиттера.
Для справки: сохраняющие автора команды коммита-копирования: git commit
с любым из --amend
или -c
/ -C
опции; git cherry-pick
; а также git rebase
, git am
Команда предназначена для того, чтобы превратить отправленные по электронной почте патчи в коммиты: она принимает в качестве входных данных нечто иное, чем коммит, поэтому мы могли бы сказать, что это сохраняет автора, но затем мы должны определить, что мы подразумеваем под автором. В этом случае, git am
угадывает информацию об авторстве, анализируя сообщение в формате почтового ящика.
Механизмы для каждого поля
Существует одна основная команда Git, git commit-tree
, которые другие команды либо используют, либо встроили в них. Это фактически создает объект фиксации, который содержит вышеуказанные метаданные. Могут потребоваться различные директивы для индивидуальной настройки каждого поля. Если какое-то поле не установлено, git commit-tree
может взять значение по умолчанию откуда-то.
Поскольку для каждого автора и коммиттера существует шесть частей - имя, адрес электронной почты и отметка времени, - есть шесть мест, где можно получить конкретные директивы, и много мест - не шесть на этот раз! - для получения значений по умолчанию. Сначала давайте перечислим первичную шестерку.
Вместо того, чтобы использовать параметры командной строки, git commit-tree
берет эти шесть элементов из переменных среды, как описано в документации:
GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE
Если вы установите какую-либо или все эти переменные, это задает значение, которое будет входить во все последующие новые коммиты (пока вы не сбросите переменные или ваш сеанс с этой средой не истечет, сбросив переменные).
Если нет, то в документации говорится:
В случае, если (некоторые из) эти переменные среды не установлены, информация берется из элементов конфигурации user.name и user.email или, если не присутствует, переменной среды EMAIL, или, если она не установлена, системного пользователя имя и имя хоста, используемые для исходящей почты (взяты из
/etc/mailname
и возврат к полному имени хоста, когда этот файл не существует).
Это немного ложная ложь, поскольку фактический путь к коду зависит от параметров времени компиляции, поэтому разные установки Git могут иметь разные индивидуальные настройки по умолчанию. Но общая общая идея верна: Git будет использовать ваш user.name
а также user.email
установка в первую очередь, как для автора, так и для коммиттера, если вы не переопределили одну или обе переменные окружения.
Конечно, отметка времени по умолчанию - это просто представление вашего компьютера о текущем времени. Относительно новый user.useConfigOnly
установка говорит современному Git не догадываться user.name
и / или user.email
, В более старых версиях Git Git не догадывался: если они не установлены, git commit-tree
а также git commit
просто потерпит неудачу с сообщением об ошибке, в котором говорится, что он не знает, кто вы.
git commit
команда front-end также принимает --author
а также --date
в качестве аргументов. Эти аргументы могут указывать имя пользователя, адрес электронной почты и / или метку времени для использования в новом коммите; git commit
эффективно реализует их, устанавливая на время операции фиксации GIT_AUTHOR_*
переменные.
При использовании git commit
передний конец с --amend
флаг - который, несмотря на его название, фактически не меняет коммит; он просто использует новый вместо текущего, со всеми вытекающими отсюда последствиями: --reset-author
флаг говорит внешнему интерфейсу не сохранять информацию об авторе исходного коммита.
Заключение
Если новые коммиты получают не того автора, а правильный коммитер, то одна из двух вещей должна иметь место:
Вы используете
--author
, Стоп!У тебя есть
GIT_AUTHOR_NAME
а такжеGIT_AUTHOR_EMAIL
установить в вашей среде. Прекратите устанавливать их!
Если у вас есть какой-либо существующий коммит, и вы пытаетесь заменить его новым улучшенным коммитом через git commit --amend
, но он сохраняет настройки автора, просто добавьте --reset-author
, Конечно, это работает только из командной строки. Если вы используете что-то еще, выясните, есть ли у него аналогичная опция.
Если какой-то существующий коммит имеет неправильного автора, вы застряли с этим. Вы можете скопировать существующий, не очень хороший, фиксацию в новый и улучшенный коммит и попытаться убедить всех остальных, у кого есть копия этого же хранилища - клон, - взять и использовать новый и улучшенный коммит вместо старого. То, насколько сложным это будет, очевидно, зависит от того, насколько упрямы другие пользователи, а также от того, где находится коммит.
Коммиты, которые находятся на вершине своей ветви и не входят ни в какую другую ветку, довольно легко заменить, используя git commit --amend
, Дальнейшие коммиты в истории более сложны: вы можете использовать интерактивный ребаз или git replace
или, в особо безобразных случаях, git filter-branch
, чтобы поменять их местами (иногда комбинируя эти приемы). Любое "изменение" в более старом коммите обязательно отражается на дизайне всех его потомков 1, поэтому такого рода изменения могут быть весьма разрушительными. Однако, если она "меняется" - действительно, заменяет - историю, которую еще никто не видел, это достаточно безопасно.
1 Непосредственные потомки "плохого" коммита содержат идентификатор хэша родительского плохого коммита. Следовательно, чтобы дети обращались к замене, мы должны заменить и детей. Это означает, что мы должны затем заменить их потомков, и так далее, вплоть до коммитов наконечника каждой затронутой ветви.