How to Push Code to GitHub: A Step by Step Guide

August 29, 2026 Dejan Protich Cloud Infrastructure, DevOps, Tutorials

Writing code is the easy part. The step that stalls most new developers, and more than a few experienced sysadmins moving into automation, is getting that code off a local machine and onto a shared remote where teammates, CI pipelines, and deployment tooling can actually reach it. Learning how to push code to GitHub is the moment a folder of scripts becomes a versioned, reviewable, recoverable project. It is also the entry point to every modern DevOps workflow, from automated testing to infrastructure provisioning.

This guide walks the full path in order: installing and configuring Git, choosing an authentication method that will not break in six months, initializing a repository, making a first commit, connecting a remote, and running the push itself. It then covers branch based workflows, the errors that block first time pushes, and the hygiene rules that keep a repository clean once several people are committing to it. Every command is copy ready and current with GitHub’s present day authentication requirements.

Push Code to GitHub: The Short Version

If you already have Git installed and a GitHub account set up, these seven commands take a project folder from untracked files to a published repository. The rest of this guide explains each one, covers authentication, and works through what to do when a push fails.

  1. Initialize the repository with git init.
  2. Write a .gitignore file before you stage anything, so secrets never enter the history.
  3. Stage your files with git add. and review the result with git status.
  4. Commit the snapshot with git commit -m "Initial commit".
  5. Name the branch with git branch -M main.
  6. Connect the empty GitHub repository with git remote add origin followed by your repository URL.
  7. Publish the work with git push -u origin main.

The same sequence, ready to copy:

git init
git add.
git commit -m "Initial commit"
git branch -M main
git remote add origin git@github.com:username/repository.git
git push -u origin main

Free download: every command on this page, plus the fix for each common push error, condensed onto a single printable page. Get the Git and GitHub command cheat sheet (PDF). No email required.

Key Takeaways

  • A commit is local and a push is a network operation. Nothing reaches GitHub until you run git push, which is why a full day of committing can still leave an empty repository.
  • GitHub has not accepted account passwords for Git operations since August 2021. Authenticate with an SSH key, a personal access token, or the GitHub CLI.
  • Write .gitignore before your first git add. A secret that reaches the history has to be rotated, not deleted.
  • Create the GitHub repository empty. Initializing it with a README is the single most common cause of a rejected first push.
  • On any repository with more than one contributor, push to a branch and merge through a reviewed pull request, with branch protection enabled on main.

What This Guide Covers

What Pushing Code to GitHub Actually Does

Git is a distributed version control system. Your machine holds a complete copy of the project history, and GitHub holds another copy on its servers. A push is the one way transfer that sends commits from your local copy to the remote copy. Nothing leaves your machine until you push, which is why a long day of committing can still result in an empty repository on GitHub.

Four stages sit between an edited file and a remote repository:

  1. Working directory. The files as they exist on disk right now, edited but not yet tracked for the next snapshot.
  2. Staging area. A deliberate selection of changes you intend to record, built with git add.
  3. Local repository. The permanent snapshot created by git commit, stored in the hidden .git directory inside your project.
  4. Remote repository. The copy hosted on GitHub, updated only when you run git push.

Understanding this separation explains most beginner confusion. A commit is a local act of record keeping. A push is a network operation that publishes those records. They are deliberately distinct so you can work offline, rewrite messy history before anyone sees it, and control exactly when your work becomes visible.

Prerequisites: What to Set Up Before Your First Push

Install and Verify Git

Most Linux distributions and macOS installations ship with Git or make it a single package away. Confirm what you have before assuming anything:

git --version
# git version 2.43.0

# Debian and Ubuntu
sudo apt update && sudo apt install git

# RHEL, Rocky, and AlmaLinux
sudo dnf install git

# macOS with Homebrew
brew install git

Windows users should install Git for Windows, which bundles Git Bash and the Git Credential Manager. Anything from version 2.28 forward supports the default branch settings referenced later in this guide.

Configure Your Identity and Default Branch

Every commit is stamped with a name and email address. Set them once, globally, before you commit anything. Use the email tied to your GitHub account so contributions are attributed correctly.

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main

# Confirm the result
git config --list

Setting init.defaultBranch to main matches GitHub’s default and saves you from renaming a branch on every new project. If you prefer to keep your address private, GitHub can issue a no reply email address in your account settings, and you can use that value instead.

Create the Remote Repository

Sign in to GitHub, select New repository, give it a name, and choose public or private. One detail matters more than the rest: when you are pushing an existing local project, do not let GitHub initialize the repository with a README, a license, or a .gitignore file. Those files create a commit on the remote that your local history knows nothing about, which produces the rejected push error covered later in this guide. Start the remote empty and let your local commits populate it.

Choosing an Authentication Method: HTTPS, SSH, or GitHub CLI

GitHub stopped accepting account passwords for Git operations in August 2021. If you have followed an older tutorial and been rejected at the password prompt, this is why. Three supported methods remain, and the right choice depends on how the machine will be used.

MethodBest ForSetup EffortHow Credentials Are StoredKey Advantage
HTTPS with a personal access tokenLaptops, shared workstations, environments where outbound SSH is blockedLowCredential helper or OS keychainWorks through restrictive corporate firewalls on port 443
SSH key pairDaily development machines and long lived serversMediumPrivate key on disk, optionally passphrase protected in an agentNo token expiry to manage, fastest daily experience
GitHub CLIDevelopers who create repositories oftenLowManaged automatically by the CLIHandles repository creation and authentication in one flow
Deploy key or fine grained tokenCI runners, build servers, automation accountsMediumSecrets manager or CI secret storeScoped to a single repository, easy to revoke

Setting Up SSH Key Authentication

SSH is the better long term choice for a machine you use every day. Generate an Ed25519 key pair, load it into the agent, and register the public half with GitHub.

ssh-keygen -t ed25519 -C "you@example.com"

# Start the agent and add the key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# Copy the public key, then paste it into
# GitHub Settings, SSH and GPG keys, New SSH key
cat ~/.ssh/id_ed25519.pub

# Verify the connection
ssh -T git@github.com

A successful verification returns a greeting that names your account and notes that GitHub does not provide shell access. That message is the expected result, not an error. GitHub’s SSH documentation covers passphrase handling and hardware security key options in more depth.

Using a Personal Access Token Over HTTPS

If SSH is impractical, generate a token in Settings, Developer settings, Personal access tokens. Prefer fine grained tokens, scope them to the specific repositories they need, and set the shortest expiry your workflow tolerates. When Git prompts for a password during a push, paste the token instead. Then tell Git to remember it so you are not pasting on every operation:

# macOS
git config --global credential.helper osxkeychain

# Windows
git config --global credential.helper manager

# Linux, cached in memory for one hour
git config --global credential.helper "cache --timeout=3600"

Avoid credential.helper store on anything but a disposable machine. It writes the token to a plain text file in your home directory, which is exactly the kind of credential sprawl that turns one compromised laptop into a compromised organization.

How to Push Code to GitHub From an Existing Local Project

This is the core sequence. It assumes a project folder that already contains files and an empty repository waiting on GitHub. Run each command from the root of your project.

Step 1: Initialize the Local Repository

cd ~/projects/my-application
git init

Git creates a hidden .git directory that holds the entire history of the project. Nothing is tracked yet, and no files have been altered.

Step 2: Add a.gitignore Before You Add Anything Else

This step is out of order in most tutorials, and that ordering causes real damage. Once a secret is committed and pushed, rotating it is the only safe remedy, because the value lives in the repository history even after you delete the file. Write the ignore rules first.

cat >.gitignore <<'END'.env
*.key
*.pem
credentials.json
terraform.tfvars.terraform/
*.tfstate
*.tfstate.backup
node_modules/
__pycache__/.venv/.DS_Store
END

Infrastructure repositories deserve particular care here. Terraform state files routinely contain database passwords and generated credentials in plain text, and they should live in a remote backend rather than in version control. That principle and several others are covered in our guide to infrastructure as code best practices.

Step 3: Stage Your Files

# Stage everything not excluded by.gitignore
git add.

# Or stage selectively, which is the better habit
git add src/ README.md

# Review exactly what is staged before committing
git status

Read the output of git status rather than skimming it. It is the last checkpoint before a file becomes part of a permanent history, and it is where you catch the stray build artifact or the log file full of production hostnames.

Step 4: Create the First Commit

git commit -m "Initial commit: application scaffold and build config"

Write the message for the person who will read it in eighteen months, quite possibly you. Describe what changed and why in the imperative mood. A message such as “Fix timeout on Proxmox API calls during bulk provisioning” earns its place in the log. A message such as “stuff” costs someone an afternoon.

Step 5: Name the Default Branch

git branch -M main

If you set init.defaultBranch earlier, this command simply confirms the existing name. On older Git installations it renames master to main so the local branch matches what GitHub expects.

Step 6: Connect the Remote

# SSH, recommended for daily development
git remote add origin git@github.com:username/repository.git

# HTTPS, if you are authenticating with a token
git remote add origin https://github.com/username/repository.git

# Confirm the remote resolved correctly
git remote -v

The name origin is a convention, not a requirement. It is the conventional alias for the primary remote, and nearly every tool and tutorial assumes it, so keep it unless you have a specific reason to do otherwise.

Step 7: Push

git push -u origin main

The -u flag sets the upstream tracking relationship between your local main and the remote main. You only need it once per branch. After that, plain git push and git pull know where to go, and git status can tell you how many commits you are ahead or behind. Refresh the GitHub page and your files are there.

Pushing to a Repository You Cloned

When the repository already exists on GitHub, the flow is shorter because the remote and the upstream tracking are configured by the clone itself.

git clone git@github.com:username/repository.git
cd repository

# Make your changes, then
git add.
git commit -m "Add health check endpoint for load balancer probes"
git pull --rebase
git push

The git pull --rebase before pushing is worth adopting as a reflex. It replays your local commits on top of whatever teammates pushed while you were working, which produces a linear, readable history instead of a merge commit for every synchronization.

Creating and Pushing in One Step With the GitHub CLI

If you create repositories regularly, the GitHub CLI collapses the browser visit, the remote configuration, and the first push into a single command.

gh auth login

cd ~/projects/my-application
git init
git add.
git commit -m "Initial commit"

# Create the remote repository and push in one step
gh repo create my-application --private --source=. --remote=origin --push

This approach is especially useful on servers and in provisioning scripts, where opening a browser to click through repository creation is impractical.

Branch Based Workflows: How Teams Actually Push

Pushing directly to main is fine for a solo project. On any repository with more than one contributor, or any repository that triggers a deployment, work belongs on a branch and reaches main through review.

# Create and switch to a feature branch
git switch -c feature/add-backup-verification

# Work, stage, commit as usual
git add.
git commit -m "Add checksum verification to nightly backup job"

# Push the branch and set its upstream
git push -u origin feature/add-backup-verification

# Open a pull request without leaving the terminal
gh pr create --fill

Three habits make this pattern hold up under pressure:

  • Enable branch protection on main. Require a pull request and at least one approving review. This single setting prevents the majority of accidental production incidents that trace back to a hurried push.
  • Keep branches short lived. A branch that lives for three weeks becomes a merge conflict rather than a contribution. Aim for days, not weeks.
  • Never force push a shared branch. git push --force rewrites history that other people have already pulled. If you must rewrite, use git push --force-with-lease, which refuses to overwrite work you have not seen.

Common Git Push Errors and How to Fix Them

Nearly every failed first push falls into one of the following categories. The error text is quoted as Git prints it.

Use this table to jump straight to the cause, then read the matching section below for the full fix.

What Git tells youWhat it actually meansThe fix
Updates were rejected because the remote contains work that you do not have locallyThe GitHub repository was created with a README, license, or.gitignore, so it holds a commit your history has never seengit pull --rebase origin main, then push again
Support for password authentication was removedGitHub has not accepted account passwords for Git operations since August 2021Use a personal access token in place of the password, or switch the remote to SSH
src refspec main does not match anyThe branch you are pushing has no commits, or it exists under a different nameCommit first, then confirm the branch name with git branch
Permission denied (publickey)GitHub was not offered a key it recognizes, either because it was never added or the agent is not holding itAdd the public key to your account and load the private key with ssh-add
remote origin already existsA remote named origin is already configured, usually from an earlier attemptgit remote set-url origin followed by the correct URL
This exceeds GitHub’s file size limit of 100.00 MBA single file is too large for a source repository, and it stays in history even after you delete itRewrite the history to drop the file, then use Git LFS or object storage instead
Everything up to date, but GitHub shows nothingChanges were staged but never committed, or committed on a branch you are not pushingCheck git log --oneline and git branch

Updates were rejected because the remote contains work that you do not have locally

This is the README problem. GitHub initialized the repository with a file, so the remote has a commit your local history has never seen. Fetch and reconcile the two histories, then push:

git pull --rebase origin main
git push -u origin main

# If the two histories share no common ancestor
git pull origin main --allow-unrelated-histories
git push -u origin main

Support for password authentication was removed

Your account password is not a valid credential for Git operations. Generate a personal access token and use it in place of the password, or switch the remote to SSH:

git remote set-url origin git@github.com:username/repository.git
git remote -v

src refspec main does not match any

You are pushing a branch that has no commits, or a branch under a different name. Git cannot push an empty branch. Confirm the state and commit first:

git status
git branch
git add.
git commit -m "Initial commit"
git push -u origin main

Permission denied (publickey)

GitHub did not receive a key it recognizes. Either the key was never added to your account, or the agent is not offering it. Test and diagnose:

ssh -T git@github.com
ssh-add -l
ssh-add ~/.ssh/id_ed25519
ssh -vT git@github.com

remote origin already exists

A remote named origin is already configured, usually from an earlier attempt. Update it rather than adding a second one:

git remote set-url origin git@github.com:username/repository.git

This exceeds GitHub’s file size limit of 100.00 MB

GitHub blocks individual files above 100 MB and warns above 50 MB. Large binaries, disk images, and database dumps belong in object storage or Git Large File Storage, not in a source repository. If the oversized file is already committed, removing it from the working directory is not enough, because it remains in history and the push will keep failing until the history is rewritten with git filter-repo or the commit is amended.

Everything up to date, but GitHub shows nothing

You staged files but never committed them, or you committed on a different branch than the one you are pushing. Run git log --oneline to confirm commits exist and git branch to confirm which branch holds them.

Push Hygiene: Practices That Keep a Repository Trustworthy

Getting a first push to succeed is a milestone. Keeping a repository useful over years is a discipline. These practices cost little and prevent the failures that are expensive to unwind.

  • Scan for secrets before they leave your machine. Enable GitHub secret scanning and push protection on the repository, and add a pre commit hook with a tool such as gitleaks. A blocked push is a minor annoyance. A leaked API key in a public repository is an incident with a timeline measured in minutes.
  • Commit in small, coherent units. One logical change per commit makes review meaningful, makes git bisect useful for tracking down regressions, and makes reverting a single mistake possible without unwinding a week of work.
  • Pull before you push. Making this reflexive eliminates most rejected pushes and most merge conflicts before they have a chance to grow.
  • Sign your commits. Configure GPG or SSH commit signing so the verified badge on GitHub means something. In regulated environments, signed commits are frequently an audit requirement rather than a preference.
  • Treat the repository as source of truth, not as backup. Git protects code history. It does not protect databases, uploaded media, or virtual machine state. Those need a separate strategy, ideally built on immutable backup solutions that ransomware cannot alter.

Pushing Infrastructure Code, Not Just Application Code

The same push workflow becomes considerably more powerful when the code being pushed defines servers rather than software features. Terraform plans, Ansible playbooks, Kubernetes manifests, and Proxmox templates all belong in version control, where every change to production infrastructure carries an author, a timestamp, a reviewer, and a rollback path.

Once infrastructure definitions live in a repository, a push becomes a trigger. A GitHub Actions workflow can validate syntax, run a plan against a staging environment, post the proposed changes to the pull request for review, and apply them after approval. The push you just learned to run is the first link in that chain. Teams building this pattern often pair it with reproducible base images, such as a Debian Cloud-Init template in Proxmox, so that both the infrastructure definition and the machine image it provisions are versioned and predictable.

Organizations with compliance constraints or heavy build workloads frequently run self hosted GitHub Actions runners on their own hardware rather than on shared cloud runners. That approach keeps source code, build artifacts, and deployment credentials inside infrastructure the organization controls, and it removes the per minute billing that makes large CI pipelines expensive.

Frequently Asked Questions

What is the difference between git commit and git push?

A commit records a snapshot of your staged changes in the local repository on your own machine. A push uploads one or more of those commits to the remote repository on GitHub. You can commit dozens of times offline; nothing appears on GitHub until you push.

Why does GitHub reject my password when I push?

GitHub removed support for account passwords in Git operations in August 2021. Authenticate with a personal access token in place of the password, use an SSH key, or sign in through the GitHub CLI.

What does git push -u origin main actually do?

It pushes the local branch main to the remote named origin and records an upstream tracking relationship between them. After that first push, plain git push and git pull operate on the correct branch without further arguments.

How do I undo a push?

On a shared branch, create a new commit that reverses the change with git revert <commit> and push that. This preserves history and is safe for collaborators. Rewriting history with a reset and a force push is appropriate only on a private branch nobody else has pulled.

Can I push code to GitHub without using the command line?

Yes. GitHub Desktop, the built in source control panel in Visual Studio Code, and the drag and drop upload on the GitHub website all work. The command line remains worth learning because it is the only interface available on a remote server and the only one that scales into automation scripts.

I accidentally pushed a password or API key. What now?

Rotate the credential immediately, before doing anything else. Deleting the file or rewriting history does not help, because the value may already have been cloned, cached, or scraped. Treat the secret as compromised, issue a replacement, then clean the history with git filter-repo and add the file to .gitignore.

From First Push to Full Automation

Knowing how to push code to GitHub is a small technical skill with an outsized payoff. It converts local work into shared, reviewable, recoverable history, and it is the prerequisite for continuous integration, automated deployment, and infrastructure as code. Configure authentication properly once, write a .gitignore before your first git add, commit in coherent units, and push through branches that get reviewed. Those four habits carry from a first personal project to a production platform.

Keep the commands close while the habits settle in: the Git and GitHub command cheat sheet puts the setup, the daily loop, the branch workflow, and every common push error on one printable page.

Ready to run your pipelines and self hosted runners on infrastructure you control? ARPHost, LLC provides high performance bare metal servers, customizable private clouds built on Proxmox VE, and managed IT services for teams that want predictable performance without per minute CI billing. Contact our team to size the right platform for your build and deployment workloads.

Tags: , , , ,

Leave a Reply