DEV Community

Jordan Huang
Jordan Huang

Posted on

FAQ: Whose Git Identity Did the Agent Use?

Who authored that commit, you or a stranger process?

Agent chats still love a cheap victory lap. They claim the branch already landed on origin.

Did git on the box actually agree with that story? You should run the boring commands before you merge.

I keep hearing the same claims in agent logs. They sound reasonable in a hurry. They are usually false once you touch git.

This FAQ is a working-copy audit. It is not a vibes check. You will query identity, remotes, and unpublished commits.

How to read each myth

Each myth has three parts. The claim people repeat. Commands that can falsify it. A corrected mental model.

Treat the agent box as a stranger's clone. Prove identity. Prove the remote. Prove the unpublished range.

Do not skip the commands. Chat text is not git ls-remote.

Myth 1: The box inherited my git config

"It committed as me. It must have my config."

Why would it? Did you copy ~/.gitconfig into that filesystem?

Most agent boxes start empty of your identity. They are not your laptop in disguise. A missing config still produces a commit object.

Ask the boring questions first. Then believe the author field.

Run this inside the clone the agent used:

git config --show-origin --get user.name
git config --show-origin --get user.email
git log -1 --format='%an <%ae>%n%cn <%ce>'
env | grep -E '^GIT_(AUTHOR|COMMITTER)_' || true
Enter fullscreen mode Exit fullscreen mode

See a name? Good. Now compare it to your laptop config.

See unknown, an empty string, or a bot email? Stop merging. Fix identity before the PR grows.

Corrected model: author is local config plus environment variables. Nothing else fills that gap.

The box does not magically inherit your company identity. Not from chat. Not from your laptop process list.

Myth 2: A local commit means GitHub already has it

"The agent committed, so the pull request is updated."

Committed where? On which remote? Under which ref name?

git commit writes objects in one repository. That is all it does. Origin does not move until a push succeeds.

Chat cannot push on git's behalf. It can only narrate a push that may never happen.

Check the unpublished range before you review anything else:

git status -sb
git remote -v
git rev-parse --abbrev-ref @{u} 2>/dev/null || echo "no upstream"
git log --oneline @{u}..HEAD
git log --oneline HEAD..@{u}
Enter fullscreen mode Exit fullscreen mode

Empty unpushed range? Then maybe origin matches HEAD. Still verify with ls-remote.

No upstream tracking branch? The agent never published. Do not say the work shipped.

Corrected model: commit is local. Publish is a separate event with separate failure modes.

I still ask one extra question. Did ls-remote show that SHA?

Myth 3: The remote box forwarded my ssh-agent

"Push worked on my laptop, so the box can push."

Can it, though? Are your keys in that process at all?

SSH agent forwarding is an explicit choice. It is not a hidden default. A remote server should not hold your personal keys.

That absence is a feature during an audit. It shows what the agent can really do.

Probe credentials without printing secrets:

ssh-add -l 2>/dev/null || echo "no ssh-agent identities"
git config --get credential.helper || echo "no credential.helper"
git config --get-regexp 'url\..*\.insteadof' || true
ssh -o BatchMode=yes -T git@github.com 2>&1 | sed -n '1,3p'
Enter fullscreen mode Exit fullscreen mode

BatchMode avoids hanging on a password prompt. Use it every time.

Permission denied? The box cannot push as you. That result is useful data.

A silent success is not proof either. Check the remote SHA after any claimed push.

Corrected model: auth is extra state. A clone is not credentials.

Never paste a private key into the agent chat. Ever. Rotate anything that leaked there.

Myth 4: The model said "pushed successfully"

"The last message was clear. It pushed."

Clear to whom? To a language model finishing a sentence.

Models narrate intent. They do not hold the remote's reflog. They also do not feel network errors the way git does.

I treat every "pushed" line as a hypothesis. Then I try to falsify it with remote evidence.

branch="$(git rev-parse --abbrev-ref HEAD)"
sha="$(git rev-parse HEAD)"
echo "local $branch $sha"
git ls-remote --heads origin "$branch"
git merge-base --is-ancestor HEAD "origin/$branch" \
  && echo "HEAD is on origin" \
  || echo "HEAD not on origin"
Enter fullscreen mode Exit fullscreen mode

ls-remote talks to the remote today. The chat log does not. Mismatch means the sentence was fiction, or auth failed, or the network failed.

Those three failures look identical in a cheerful summary. Commands split them apart.

Corrected model: remote evidence beats prose. Always. If ls-remote fails, you learned something real.

Myth 5: Global config on the box is my work identity

"I set user.email once. Every commit is now compliant."

Once where? On the box? In this repo only? In CI later?

Git has layers. System. Global. Local. Then environment. Then the commit object itself.

A global config in an ephemeral box feels sticky. It is still not your laptop identity. It may vanish. It may collide with CI rules.

Also check the noreply pattern. Hosting sites accept several emails for one human. Your laptop might use a private noreply address. The box might use something else.

git config --list --show-origin | grep -E 'user\.(name|email)|gpg|gpgsign|commit.gpgsign'
git log -1 --show-signature 2>/dev/null || echo "no signature data"
Enter fullscreen mode Exit fullscreen mode

Unsigned commits can be fine in a personal repo. Surprise unsigned commits are not fine on a protected branch.

The box will not warn you about org policy. Git just writes the object.

Corrected model: identity is per-clone until you wire it on purpose.

Do not copy a signing key onto a shared server. Do not. Keep signing on a machine you control.

Artifact: a proposed git identity audit

Label this as unexecuted until you run it. It is a checklist, not a trophy script.

Save it as scripts/agent-git-audit.sh. Execute it in the worktree the agent used.

#!/usr/bin/env bash
# Proposed audit. Run in the clone the agent used.
# Does not print tokens. Does not push. Does not rewrite history.
set -euo pipefail

echo "## identity"
git config --show-origin --get user.name || echo "user.name unset"
git config --show-origin --get user.email || echo "user.email unset"
printf 'GIT_AUTHOR_EMAIL=%s\n' "${GIT_AUTHOR_EMAIL:-<unset>}"
printf 'GIT_COMMITTER_EMAIL=%s\n' "${GIT_COMMITTER_EMAIL:-<unset>}"
git log -1 --format='HEAD %H%nauthor %an <%ae>%ncommitter %cn <%ce>'

echo "## remotes"
git remote -v
git status -sb
branch="$(git rev-parse --abbrev-ref HEAD)"
echo "branch ${branch}"

echo "## unpublished range"
if git rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1; then
  echo "unpushed commits:"
  git log --oneline '@{u}..HEAD' || true
  echo "unpulled commits:"
  git log --oneline 'HEAD..@{u}' || true
else
  echo "NO UPSTREAM SET. Do not claim a push."
fi

echo "## remote evidence"
sha="$(git rev-parse HEAD)"
echo "local HEAD ${sha}"
if git ls-remote --heads origin "${branch}"; then
  :
else
  echo "ls-remote failed. Network, auth, or missing remote."
fi

echo "## auth presence only"
ssh-add -l >/dev/null 2>&1 && echo "ssh-agent has identities" || echo "ssh-agent empty or missing"
git config --get credential.helper >/dev/null && echo "credential.helper set" || echo "credential.helper unset"
Enter fullscreen mode Exit fullscreen mode

Make it executable. Then run it twice. Once on the box. Once on your laptop.

chmod +x scripts/agent-git-audit.sh
./scripts/agent-git-audit.sh
Enter fullscreen mode Exit fullscreen mode

Diff the two outputs by hand. The interesting lines are the mismatches, not the matches.

I care about three mismatches. Author email. Upstream existence. Remote SHA for HEAD.

If those three line up, you earned a real review. Not before.

Decision table

Use this when the chat already sounds finished.

  • Chat says committed, git log -1 missing: believe git. The write failed.
  • Chat says committed, author email is not yours: do not merge yet.
  • Chat says pushed, no upstream: nothing was published.
  • Chat says pushed, unpushed range nonempty: origin is behind the box.
  • Chat says pushed, ls-remote SHA differs: the sentence was fiction.
  • ssh-add -l empty and HTTPS helper unset: a push should have failed.
  • gpgsign required, log shows no signature: protection may reject it.
  • git remote -v points at a fork you do not own: stop and read the URL.

Write the decision in the PR description. Do not leave it in the agent transcript.

A cold box is the right kind of hostile

You want a clone that does not borrow laptop magic. Your PATH, your agent socket, and your global git config are all cheating.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

MonkeyCode offers free model access and a free server option. Use that pairing as a hostile clone: let the model draft the audit script, then run the script on the free server, which does not inherit your ssh-agent. If the draft and git ls-remote disagree, trust the server.

The value is the mismatch. Not a vendor badge on the PR.

What this does not prove

Passing the audit is not a merge. It is a sanity gate before humans look.

It does not review the diff. It does not run tests. It does not prove CI will accept the push, because CI has its own identity and its own checkout.

It does not prove the remote host is the host you think. Read git remote -v every time. Forks lie politely.

The script never prints tokens. Do not "improve" it by dumping env. Free models invent confident git stories. That is why you audit instead of quoting them.

Free servers are still not your laptop. That gap is the lesson. Do not store deploy keys on a shared box to make the myth come true.

Who should not use this workflow

Skip this extra ritual if your org already blocks unsigned agent commits. Merge queues, required reviews, and verified-commit rules already catch push fiction.

Do not use a free server for secret rotation. Wrong tool. Wrong threat model.

Do not run this audit as an excuse to disable branch protection. Please do not.

If you cannot explain @{u}, pause here. Read git help revisions before you automate anything.

If the repo uses submodules, this script is incomplete. Extend it on purpose.

If you need GPG or SSH signing, keep those keys off the agent box. Sign on a machine you control, after the audit is green.

So, whose identity was it?

Prove it. Do not summarize it.

Ask three questions every time an agent claims done. Who authored the commit. What is still unpushed. What does ls-remote say about that SHA.

The chat will still sound sure. Git will still be quieter. Prefer git.

Top comments (0)