Почему 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 Непосредственные потомки "плохого" коммита содержат идентификатор хэша родительского плохого коммита. Следовательно, чтобы дети обращались к замене, мы должны заменить и детей. Это означает, что мы должны затем заменить их потомков, и так далее, вплоть до коммитов наконечника каждой затронутой ветви.

Другие вопросы по тегам