Что Claude Code добавляет в ваши коммиты
Проверьте трейлер Co-authored-by и ссылку claude.ai в коммитах Claude Code, особенно в cloud-сессиях, и узнайте, как убрать атрибуцию до push.
Что Claude Code добавляет в коммит
Claude Code добавляет трейлер Co-authored-by: в конец создаваемых им сообщений коммитов, а также строку атрибуции в описания открываемых им pull request. Сессии, запущенные в облаке или через Remote Control, также содержат ссылку на сессию на сайте claude.ai. Все эти данные представляют собой обычный текст, который сохраняется в истории git. После отправки (push) в публичный репозиторий эти данные становятся общедоступными и остаются там до тех пор, пока кто-либо не перепишет историю.
Точная формулировка меняется от релиза к релизу, поэтому не стоит полагаться на текст трейлера, приведенный в каком-либо руководстве, включая это. Вместо этого проверяйте свои собственные коммиты. Приведенные ниже команды git являются надежной частью этой темы: механизм обработки трейлеров в git работает одинаково на протяжении многих лет и продолжит работать так же после того, как в следующем релизе изменится текст.
Что такое git trailer
Trailer — это строка формата Token: value в последнем блоке сообщения коммита. Git не содержит фиксированного списка токенов. Signed-off-by:, Reviewed-by:, Fixes: и Co-authored-by: — это соглашения, построенные на одном механизме, а системы управления репозиториями, такие как GitHub или GitLab, считывают их, чтобы определить, что отображать на странице коммита.
Git строго регламентирует расположение этого блока. В документации к git interpret-trailers указано, что перед группой должна идти пустая строка, которая определяется как «строка, содержащая только пробельные символы или пустая строка». Блок должен находиться в конце сообщения, а сообщение заканчивается либо в конце ввода, либо на последних строках без пробельных символов перед строкой, начинающейся с ---, за которой следует пробел или конец строки. Группа также должна либо полностью состоять из trailers, либо содержать «как минимум один сгенерированный Git или настроенный пользователем trailer и состоять из trailers не менее чем на 25%».
Это последнее правило имеет значение. Обычный URL или просто текст внутри последнего блока не является trailer, и достаточное количество строк, не являющихся trailers, препятствует распознаванию всего блока как trailers. Именно поэтому коммит может визуально содержать строку Co-authored-by:, но при этом все инструменты, корректно считывающие trailers, ничего не обнаружат.
Как прочитать трейлеры, которые уже есть в истории?
Начните с исходного сообщения последнего коммита.
git log -1 --format=%B%B выводит тему и тело сообщения в исходном виде, без переносов строк и переформатирования. Этот вывод является эталонным. Всё, что вы видите в веб-интерфейсе репозитория — это лишь его визуализация.
Теперь узнайте, какие из этих строк git распознает как трейлеры.
git log -1 --format=%B | git interpret-trailers --parse--parse — это сокращение для --only-trailers --only-input --unfold, поэтому на выходе будет только блок трейлеров. Корректный результат — по одной строке на каждый трейлер. Если вывод пуст, хотя вы видите строку Co-authored-by:, значит, блок не соответствует правилам размещения, описанным выше.
Чтобы просканировать всю историю, запросите трейлер по ключу.
git log --format='%h %(trailers:key=Co-authored-by,valueonly)'Старые версии git не поддерживают опцию key= в команде %(trailers). Поиск по тексту сообщения работает везде.
git log -i --grep='^Co-authored-by:' --format='%h %an %s'--grep выполняет поиск по сообщению коммита, а -i делает поиск регистронезависимым. Это важно, так как написание этого трейлера с заглавной буквы различается в разных инструментах. Перед отправкой (push) сузьте область поиска до тех коммитов, которые вы еще не отправили.
git log origin/main..HEAD --format=%BЭти коммиты всё еще находятся локально, а значит, их можно легко изменить.
Что делает Co-authored-by: с атрибуцией на GitHub?
GitHub считывает этот заголовок и отображает второго автора на странице коммита. Он связывает этого автора с профилем только в том случае, если адрес электронной почты принадлежит какой-либо учетной записи. Согласно документации GitHub, коммиты отображаются на графике вклада, если они «сделаны с использованием адреса электронной почты, привязанного к вашей учетной записи на GitHub», поэтому адрес, который никому не принадлежит, не может быть привязан к профилю. Для работы в паре это и является основной целью: адрес вашего коллеги привязан к его учетной записи, и коммит засчитывается обоим. Если адрес не принадлежит ни одной учетной записи, заголовок меняет только отображение на странице коммита, не затрагивая список контрибьюторов репозитория.
Сам Git полностью игнорирует этот заголовок. git shortlog -sn и git log --author считывают заголовок автора, который содержит ваше имя и адрес электронной почты, поэтому локальная статистика никогда не покажет соавтора. Атрибуция здесь — это функция платформы, надстроенная над соглашением о простом тексте, что и составляет различие между самим git и платформой, на которой вы размещаете репозиторий.
Ссылка на сессию — это другая проблема
Trailer указывает соавтора. URL сессии — это указатель на транскрипт. В справочнике настроек Claude Code attribution.sessionUrl указан как ключ, который исключает «ссылку на сессию claude.ai из облачных коммитов и коммитов Remote Control», что также объясняет происхождение ссылки: сессии в веб-интерфейсе и сессии, запущенные через Remote Control. В том же справочнике сказано, что ссылка записывается как trailer Claude-Session в коммитах и как ссылка в описаниях pull request, поэтому git log --format='%h %(trailers:key=Claude-Session,valueonly)' выводит список всех коммитов, содержащих такую ссылку.
Ссылка не является учетными данными. Возможность открытия сессии определяется доступом к аккаунту, а не секретностью URL. Причина исключения ссылки из публичного репозитория проще. Это постоянный публичный текст, содержащий внутренний идентификатор сессии, который указывает на рабочий транскрипт, не предназначенный для сторонних читателей. В приватном репозитории аргумент обратный: рецензент может перейти по ссылке и прочитать, как было достигнуто изменение. Информация о том, где хранятся эти транскрипты и как долго они существуют, приведена в как Claude Code хранит сессии и возобновляет их.
Настройки, управляющие атрибуцией коммитов в Claude Code
Эти ключи, сверенные со справочником настроек Claude Code по состоянию на 11 октября 2026 года, задокументированы в разделе «Git and attribution»:
attribution: «Настройка атрибуции, которую Claude Code добавляет к коммитам и pull requests»attribution.commit: «Изменение или скрытие trailer, который Claude Code добавляет к коммитам»attribution.pr: «Изменение или скрытие строки атрибуции в описаниях pull request»attribution.sessionUrl: «Исключение ссылки на сессию claude.ai из облачных коммитов и коммитов Remote Control»includeGitInstructions: «Удаление встроенных инструкций для коммитов и PR из контекста Claude»includeCoAuthoredBy: помечен как устаревший, с примечанием «используйтеattributionдля скрытия или изменения атрибуции коммитов и PR»
Значение, принимаемое каждым ключом, следует брать из соответствующей записи в справочнике настроек, а не из руководств. Имена ключей стабильны. Допустимые значения и значения по умолчанию могут меняться, и файл настроек с правильно написанным ключом, но неверным значением, не выдаст ошибку при выполнении.
Место записи определяет область действия. ~/.claude/settings.json применяется ко всем проектам, которые вы открываете. Файл .claude/settings.json, закоммиченный в корне репозитория, будет действовать для всех, кто его клонирует. Файл .claude/settings.local.json является локальным для конкретного проекта, и Claude Code добавляет его в глобальный git excludes при первом создании файла, поэтому он не попадает в ваши коммиты. Приоритет настроек: управляемые настройки, затем командная строка, затем локальные настройки проекта, затем общие настройки проекта, затем пользовательские настройки. Таким образом, локальный файл коллеги имеет приоритет над файлом, который вы закоммитили, поэтому рассматривайте закоммиченную настройку как значение по умолчанию, а не как гарантию.
Затем выполните проверку, так как уверенность в настройке не является доказательством. Позвольте Claude Code сделать следующий коммит обычным способом, а затем проверьте результат.
git log -1 --format=%B
git log -1 --format=%B | git interpret-trailers --parseЕсли trailer по-прежнему выводится, значит, изменение не было применено к сессии. Проверьте, какой файл вы редактировали, и сверьтесь с порядком приоритетов выше, прежде чем делать вывод о неисправности ключа.
Элементы управления, не зависящие от настроек
Настройка конфигурирует один конкретный инструмент. Правило репозитория должно работать даже в том случае, если участник использует другой инструмент или вообще не использует агентов. Git предоставляет место для размещения такого правила: хук commit-msg запускается с путем к файлу сообщения в качестве первого аргумента; он может изменить этот файл или полностью отклонить коммит.
#!/bin/sh
# .githooks/commit-msg
grep -qi '^co-authored-by: claude' "$1" || exit 0
grep -vi '^co-authored-by: claude' "$1" > "$1.new" && mv "$1.new" "$1"chmod +x .githooks/commit-msg
git config core.hooksPath .githooksПервый grep завершается досрочно, если нет работы, поэтому обычный коммит практически не требует затрат ресурсов. Второй записывает сообщение обратно без соответствующей строки. Сопоставляйте один точный токен, а не все трейлеры, так как фильтр, написанный как «удалить последний блок», также удалит строку Signed-off-by:, которая требуется проекту.
.git/hooks не является частью репозитория, поэтому хук, помещенный туда, никогда не попадет к другим участникам. core.hooksPath указывает Git на директорию, которую можно закоммитить, и каждый человек все равно должен самостоятельно выполнить эту одну строку git config. Git не установит ее автоматически, и это сделано намеренно: репозиторий, который мог бы устанавливать собственные исполняемые файлы при клонировании, стал бы способом запуска кода на вашей машине.
Чтобы отклонить коммит вместо его перезаписи, выведите сообщение в стандартный поток ошибок и выполните exit 1 из хука. Отказ — это честный выбор для общего репозитория, так как скрытое редактирование сообщения коммита другого человека маскирует правило, вместо того чтобы обучать пользователя. Это другой уровень по сравнению с собственными хуками агента, которые срабатывают при вызове инструмента еще до того, как в процесс вовлекается Git, и в том, как хук Claude Code сопоставляет инструмент и блокирует его рассматривается именно эта сторона.
Ни один из этих методов не помогает при получении pull request из форка, так как хук находится на машине, которую вы не контролируете. Проверка в CI (непрерывной интеграции) — это единственный уровень, который видит каждый коммит перед его слиянием.
if git log --format=%B "origin/${BASE_BRANCH:-main}..HEAD" | grep -qi '^co-authored-by: claude'; then
echo "Attribution trailer found. Rewrite the branch before merging." >&2
exit 1
fiЗапишите правило, а также обеспечьте его соблюдение. Файл AGENTS.md, расположенный рядом с понятным человеку CONTRIBUTING.md, сообщает агенту и человеку одно и то же, а проверка в CI делает это правило обязательным.
Удаление трейлера перед отправкой (push)
Для только что созданного коммита:
git log -1 --format=%B | grep -vi '^co-authored-by: claude' | git commit --amend -F --F - считывает новое сообщение из стандартного потока ввода. Git автоматически удаляет пустые строки в начале и конце сообщения, переданного таким образом, поэтому пустая строка, оставшаяся после удаления трейлера, исчезнет сама. Проверьте результат с помощью git log -1 --format=%B, прежде чем продолжить работу.
Для нескольких коммитов в ветке выполните интерактивный rebase относительно ветки, в которую планируется слияние, и отметьте каждое сообщение, которое требуется изменить, как reword.
git rebase -i origin/mainКаждый коммит, начиная с самого раннего из отредактированных, получает новый хеш, так как хеш коммита включает в себя его сообщение и родительский коммит. Это безопасно, пока коммиты находятся только в локальном репозитории, и требует дополнительных действий, если они уже были отправлены на удаленный сервер.
Удаление trailer после отправки
В ветке, которой пользуетесь только вы, перепишите историю описанным выше способом, а затем отправьте изменения поверх существующей ветки.
git push --force-with-lease--force-with-lease отклоняет отправку, если состояние удалённой ветки изменилось с момента последнего получения изменений, поэтому он не может незаметно удалить коммит, добавленный кем-то другим. Обычный --force такой проверки не выполняет.
Если trailer встречается в длинной истории, git filter-repo переписывает все сообщения за один проход. Запускайте клонирование из существующей рабочей копии, чтобы URL был взят из уже настроенного remote.
pip install git-filter-repo
git clone "$(git remote get-url origin)" ../project-rewrite
cd ../project-rewrite
git filter-repo --message-callback '
return b"\n".join(l for l in message.split(b"\n") if not l.lower().startswith(b"co-authored-by: claude"))
'Callback получает каждое сообщение в виде байтов и возвращает сообщение для сохранения, поэтому каждая строка в нём содержит префикс b. filter-repo отказывается работать с репозиторием, который не является свежим клоном, если не передать --force. После завершения команда удаляет remote origin, поэтому вы не сможете случайно отправить результат переписывания обратно. Добавьте remote снова намеренно, выполните force-push, а затем попросите всех заново клонировать репозиторий, поскольку теперь каждый имеющийся у них hash неверен.
Чётко учитывайте ограничения переписывания. Оно изменяет вашу копию репозитория. Оно не затрагивает forks, существующие clones, mirrors, страницы pull request, где сообщение уже было процитировано, или индекс поиска кода, который сканировал ваш репозиторий на прошлой неделе. Если секрет утёк, исправление состоит в ротации секрета, а переписывание истории является очисткой. Disclosure trailer не является секретом, поэтому сопоставьте полное переписывание истории с его стоимостью: потребуется пересоздать каждый открытый pull request.
Чего ожидает рецензент на другой стороне
Мейнтейнеры не имеют единого мнения по этому вопросу, и именно эти разногласия — реальная причина проверить правила перед тем, как что-либо удалять. Некоторые проекты требуют раскрытия информации и попросят вас вернуть её обратно, так как рецензент иначе воспринимает патч, написанный машиной. Другие запрещают это, часто из-за вопросов о том, кто юридически является автором изменений. Проекты, использующие DCO (developer certificate of origin), требуют наличия строки Signed-off-by: — это ваше заявление о праве на отправку кода, и неосторожный фильтр сообщений удаляет её вместе с атрибуцией.
Сначала прочитайте CONTRIBUTING.md. Если в проекте ничего не сказано, выберите одно правило для репозитория и зафиксируйте его. Трейлер, который присутствует только в половине коммитов, хуже любого из вариантов: он делает историю одного проекта похожей на два разных.
Если вы запускаете агент на сервере, а не на своем ноутбуке, тот же вопрос возникает на уровень ниже. Запуск Claude Code на VPS под собственной учетной записью определяет, к каким репозиториям агент вообще имеет доступ, а что кодинг-агент отправляет за пределы машины описывает трафик, который никогда не отображается в сообщении коммита.
FAQ
Учитывается ли Co-authored-by-трейлер для Claude в статистике участников моего репозитория?
Нет. GitHub привязывает коммит к профилю через адрес электронной почты, связанный с учетной записью GitHub, и на этом основании ведет учет вкладов. Адрес, не принадлежащий ни одной учетной записи, не может быть привязан, поэтому трейлер меняет страницу коммита, но оставляет список участников без изменений. Сам Git никогда не считывает трейлеры для этой цели. git shortlog -sn учитывает только заголовок автора, поэтому соавтор там никогда не отображается.
Как найти все коммиты, которые уже содержат этот трейлер?
git log -i --grep='^Co-authored-by:' --format='%h %an %s' выводит их список по всей истории без учета регистра. В актуальных версиях git git log --format='%h %(trailers:key=Co-authored-by,valueonly)' считывает значение через собственный парсер трейлеров git, вместо поиска по «сырому» тексту. Чтобы увидеть только те коммиты, которые вы еще не отправили в удаленный репозиторий, добавьте диапазон: git log origin/main..HEAD --format=%B.
Можно ли удалить трейлер из уже отправленных коммитов?
Да, путем перезаписи истории, но это сопряжено с реальными издержками. В ветке, которую используете только вы, выполните amend или rebase, а затем git push --force-with-lease. В общей ветке каждый коммит, начиная с самого первого измененного, получит новый хеш, поэтому каждый клон и каждый открытый pull request придется пересоздавать. Кроме того, перезапись никогда не затронет форки, зеркала или клоны, сделанные кем-либо ранее.
Является ли ссылка на сессию claude.ai в сообщении коммита угрозой безопасности?
Это не учетные данные, и доступ к сессии определяется учетной записью, а не тем, насколько сложно угадать URL. Проблема в том, что это постоянный публичный текст, указывающий на транскрипт, который создавался как рабочие заметки. В документации к настройкам Claude Code указан attribution.sessionUrl как ключ, который исключает эту ссылку из коммитов в облаке и Remote Control, а хук commit-msg удаляет ее из всего, что не охвачено этой настройкой.
Стоит ли вообще отключать атрибуцию?
Это зависит от репозитория, а не от личных предпочтений. В публичном проекте следуйте файлу CONTRIBUTING.md, так как сопровождающий, которому нужно раскрытие информации, попросит вернуть его обратно. В корпоративном репозитории сохранение трейлера часто полезно, так как это позволяет проверяющему спустя год понять, почему изменение выглядит именно так. Примите решение один раз для всего репозитория и обеспечьте его соблюдение через CI, чтобы история оставалась согласованной.