PHASE 5 OF 15

VCS Roots & GitHub Integration

Connect TeamCity to GitHub — VCS Root setup, Personal Access Token vs SSH key auth, branch specifications, Commit Status Publisher, Pull Request builds, webhooks for instant triggering, and troubleshooting

GitHubVCS RootBranch SpecPRsWebhooksSSH Keys
1

VCS Root Concept

A VCS Root defines the connection from TeamCity to a version control repository. One VCS Root per repository — it is shared across all build configurations in the same project or subprojects.

ONE ROOT, MANY CONFIGS

Define your GitHub VCS Root once at the project level. All build configurations in that project (Build, Test, Deploy) use the same root. This means credential changes only need to be made in one place. Never create a duplicate VCS Root for the same repository — it causes independent fetch caches and doubled GitHub API calls.

A VCS Root captures:

  • Repository URL
  • Authentication credentials
  • Branch specification (which branches to watch)
  • Checkout rules (which paths in the repo to check out)
  • Fetch interval (how often to poll for changes)
2

Creating a GitHub VCS Root

  1. Go to Administration → <Project> → VCS Roots → Create VCS root.
  2. Select Git as the VCS type.
  3. Fill in the fields:
FieldValueNotes
VCS root nameGitHub — yourorg/yourrepoDescriptive name shown in UI
VCS root IDYourOrg_YourrepoAuto-generated; used in REST API
Fetch URLhttps://github.com/yourorg/yourrepo.gitHTTPS URL or SSH URL
Default branchrefs/heads/mainFull ref name, not just "main"
Branch specificationSee section 5.4Which branches TeamCity monitors
Authentication methodPassword / SSH keySee section 5.3
Usernameyour-github-usernameGitHub username (for HTTPS auth)

Click Test connection before saving. TeamCity will try to fetch the repository. A green result confirms credentials work. A red result shows the exact error (auth failure, URL not found, etc.).

3

Authentication: PAT vs SSH vs Password

MethodSetupRecommendation
Personal Access Token (PAT)Generate on GitHub → Settings → Developer settings → Personal access tokens. Enter username + token as password in TeamCity.✅ Recommended for most teams
SSH key pairGenerate key pair, add public key to GitHub repo (Deploy Keys) or user account, paste private key in TeamCity VCS Root.✅ Recommended for CI accounts / automated bots
Username + passwordGitHub account password in TeamCity. Will be blocked by GitHub if 2FA is enabled.❌ Avoid — GitHub deprecated password auth for Git in 2021
Personal Access Token setup
  1. In GitHub: Settings → Developer settings → Personal access tokens → Generate new token.
  2. Required scopes for TeamCity: repo (full control of private repositories) OR for public repos: public_repo. For Commit Status Publisher: repo:status is sufficient if you only need status updates, but repo is needed to read PR info.
  3. Copy the token (shown only once).
  4. In TeamCity VCS Root: Authentication method = Password. Username = your GitHub username. Password = the token.
SSH key pair setup
# Generate an ED25519 key pair (no passphrase for CI)
ssh-keygen -t ed25519 -C "teamcity@yourcompany.com" -f ~/.ssh/teamcity_rsa -N ""

# Output: teamcity_rsa (private) + teamcity_rsa.pub (public)
  1. Add teamcity_rsa.pub content to GitHub: Repo → Settings → Deploy keys → Add deploy key. Enable "Allow write access" only if TeamCity needs to push (e.g., tagging). Read-only for CI is safer.
  2. In TeamCity VCS Root: Fetch URL = git@github.com:yourorg/yourrepo.git. Authentication = Uploaded Key. Upload the private key (teamcity_rsa).
  3. Or use Default Private Key if you've placed the key in the TeamCity server's ~/.ssh/ directory.
GOTCHA — SSH known_hosts

On first SSH connection, TeamCity (or the underlying Git) needs to verify GitHub's host key. If ~/.ssh/known_hosts on the server or agent doesn't contain GitHub's key, the connection fails with "Host key verification failed." Fix: run ssh -T git@github.com as the TeamCity service user once to accept the host key, or add GitHub's known host key manually.

4

Branch Specification Syntax

The branch specification tells TeamCity which branches (and PRs) to monitor for changes. It uses a +/- include/exclude pattern syntax matching against full Git ref names.

Pattern syntax
+|-:ref_pattern [=> display_name]
  • +: — include this ref pattern (watch for changes, build on match)
  • -: — exclude this ref pattern (ignore)
  • * — wildcard matching any single path segment
  • ** — wildcard matching any number of path segments
  • => display_name — optional short name shown in TeamCity UI
Common patterns
PatternMatchesUsed for
+:refs/heads/*All branches (main, develop, feature/x)Build all branches
+:refs/heads/mainOnly the main branchProduction builds only
+:refs/heads/feature/*feature/login, feature/cart, etc.Feature branch CI
+:refs/pull/*/headAll GitHub pull request headsBuild every PR
+:refs/pull/*/mergeGitHub PR merge commits (simulated merge)Test merge result before merge
-:refs/heads/experimentalExperimental branch (excluded)Suppress noisy builds
+:refs/heads/* => %branch_short_name%All branches with short display nameCleaner UI
Typical production branch spec
+:refs/heads/*
+:refs/pull/*/head

This watches all branches AND all pull requests. It's the most common setup for a team that wants branch builds and PR builds from one build configuration.

GOTCHA — Default branch must be in spec

The Default branch field (e.g., refs/heads/main) is what TeamCity uses for the "no branch filter" UI view and for determining the "last successful build" for artifact dependencies. The default branch MUST match at least one pattern in the branch specification, otherwise its builds won't appear in the main build list.

5

Checkout Rules

Checkout rules filter which paths in the repository are checked out on the agent. Useful for monorepos where different services live in subdirectories and you only want to check out one service at a time.

# Syntax: +|-:source_path [=> target_path]

# Only check out the backend/ directory (maps it to root)
+:backend => .

# Only check out specific service
+:services/user-service => .
+:shared/common-lib => common-lib

# Exclude generated files (rarely needed — use .gitignore instead)
-:target
-:node_modules
VCS Trigger + Checkout Rules

Checkout rules also filter which changes trigger a build. If you specify +:backend => ., only commits that touch files under backend/ will trigger the build. This is a key technique for monorepo CI — each service's build config only triggers on changes to its own directory.

6

Commit Status Publisher

The Commit Status Publisher build feature posts build results back to GitHub as commit statuses. This shows a ✓ or ✗ check on each commit and on pull requests — the most visible integration point between TeamCity and GitHub.

Setup
  1. In the build configuration, go to Build Features → Add build feature → Commit status publisher.
  2. Publisher: select GitHub.
  3. GitHub URL: https://api.github.com (for GitHub.com) or https://your-github-enterprise/api/v3.
  4. Authentication: select your GitHub connection or enter a Personal Access Token directly.
  5. Token scopes needed: repo:status (minimum) or repo (full).
  6. Save.
RESULT

After setup, every build posts its result to the GitHub commit. Pull requests show a "Checks" section with the TeamCity build status, a link to the build log, and pass/fail indication. Required status checks in GitHub branch protection rules can reference TeamCity builds.

Multiple statuses (build chains)

If you have a build chain (Build → Test → Deploy), add the Commit Status Publisher to each build configuration. GitHub will show separate status checks for each stage, giving developers granular visibility into which stage failed.

7

Pull Request Build Feature (2017.2)

The Pull Request build feature (introduced in TeamCity 2017.2) automatically detects GitHub pull requests and enriches builds with PR metadata. Combined with +:refs/pull/*/head in the branch spec, it enables full PR CI workflow.

Setup
  1. Add build feature: Pull requests.
  2. VCS hosting type: GitHub.
  3. Authentication: GitHub connection or PAT.
  4. Filter by target branch (optional): e.g., only build PRs targeting main.
  5. Filter by author (optional): only build PRs from org members.
Available PR parameters

When a PR build runs, TeamCity exposes these parameters:

ParameterValue
%teamcity.pullRequest.number%PR number (e.g., 42)
%teamcity.pullRequest.title%PR title
%teamcity.pullRequest.source.branch%Source branch of PR (e.g., feature/login)
%teamcity.pullRequest.target.branch%Target branch (e.g., main)
# Use PR parameters in build steps
echo "Building PR #%teamcity.pullRequest.number%: %teamcity.pullRequest.title%"
echo "From %teamcity.pullRequest.source.branch% into %teamcity.pullRequest.target.branch%"
GOTCHA — Security: fork PR builds

If your repository is public, PRs from forked repositories can trigger builds. A malicious PR could modify build scripts to exfiltrate secrets. Use the Filter by author option in the Pull Request build feature to restrict builds to organization members. Alternatively, never inject secrets into PR builds.

8

GitHub Webhooks for Instant Triggering

By default, TeamCity polls GitHub every 60 seconds for changes. Webhooks replace polling with a push notification — GitHub sends a POST to TeamCity the instant a push happens, reducing the trigger latency from up to 60 seconds to under 5 seconds.

Setting up the webhook
  1. In GitHub: go to Repo → Settings → Webhooks → Add webhook.
  2. Payload URL: http://YOUR_TC_SERVER:8111/app/rest/vcs-root-instances/checkingForChanges
    Or for HTTPS: https://ci.yourcompany.com/app/rest/vcs-root-instances/checkingForChanges
  3. Content type: application/json
  4. Secret: leave blank (or set a shared secret for validation)
  5. Which events: select Just the push event (and optionally Pull requests).
  6. Click Add webhook.
Verification

After adding the webhook, push a commit to GitHub. TeamCity should queue a build within seconds. In GitHub, the webhook shows a green ✓ delivery in the Recent Deliveries section.

TEAMCITY SERVER MUST BE PUBLICLY ACCESSIBLE

For GitHub webhooks to work, your TeamCity server must be reachable from the internet (GitHub's servers). If your server is behind a firewall or VPN, webhooks won't work. In that case, keep polling (set VCS Root polling interval to 30 seconds) or use a GitHub Enterprise installation inside your network.

9

SSH Deploy Keys

Deploy keys are SSH keys attached to a specific repository (not a user account). They are the most secure authentication method for CI systems because:

  • Access is limited to one repository
  • Read-only by default (write access is optional)
  • Revocable without affecting user accounts
  • No user credentials in TeamCity's config
# 1. Generate a dedicated key pair for this repository
ssh-keygen -t ed25519 -C "teamcity-deploy-key-myrepo" \
  -f ~/.ssh/myrepo_deploy_key -N ""

# 2. Add public key to GitHub (repo-level)
cat ~/.ssh/myrepo_deploy_key.pub
# Copy output → GitHub Repo → Settings → Deploy keys → Add deploy key
# Title: TeamCity CI
# Key: (paste public key)
# Allow write access: unchecked (unless TC needs to push tags)

# 3. In TeamCity:
# Administration → <Project> → SSH keys → Upload SSH key
# Upload: myrepo_deploy_key (private key, no .pub)

# 4. In VCS Root:
# Authentication method: Uploaded Key
# Uploaded key: myrepo_deploy_key
# Passphrase: (leave blank — CI keys should not have passphrases)
10

Auto-Labeling Builds in VCS

TeamCity can automatically create a Git tag (label) on every successful build. This gives you a permanent reference to the exact commit that produced a passing build.

  1. In the build configuration, go to Version Control Settings → Labeling > Label successful builds.
  2. Set the label pattern: build-%system.build.number% or release-%build.number%.
  3. Branch filter (optional): only label builds on main.
GOTCHA — Write access required for labeling

To push tags to GitHub, TeamCity's credentials (PAT or SSH key) need write access to the repository. If using a deploy key, enable "Allow write access" on it. If using a PAT, the token needs the full repo scope, not just repo:status.

11

Troubleshooting VCS Issues

SymptomCauseFix
Test connection fails: "Authentication failed"Wrong token/password, or token lacks repo scopeRegenerate token with repo scope; check username
Test connection fails: "Host key verification failed"GitHub SSH host key not in known_hostsRun ssh-keyscan github.com >> ~/.ssh/known_hosts as TC service user
Build triggered but wrong branch checked outDefault branch in VCS Root doesn't match actual defaultUpdate "Default branch" to refs/heads/main (not master)
PR builds not triggeringBranch spec missing +:refs/pull/*/headAdd PR ref pattern to branch specification
Builds only on default branch, not feature branchesBranch spec only has default branchAdd +:refs/heads/* to branch specification
Commit status not appearing on GitHub PRCommit Status Publisher not added as build feature; wrong token scopeAdd the build feature; ensure PAT has repo:status
VCS polling too slow (60s+ delay)Default poll interval; no webhook configuredSet up GitHub webhook, or reduce poll interval in VCS Root settings
"Could not read from remote repository"Firewall blocking TeamCity → GitHubCheck outbound HTTPS (443) or SSH (22) from TC server to github.com
VCS fetch log

To see detailed fetch output: in the build log, look for the Checkout step. Or go to Administration → Diagnostics → VCS Status to see all VCS root fetch statuses and errors.

Up Next — Phase 6: Build Agents

Learn the agent architecture, install additional agents, configure agent pools, set up agent requirements for compatibility matching, and troubleshoot common agent issues.

Continue to Phase 6 → Back to Hub