| |

GitHub 06 ๐ŸŒ Pushing Local Code to GitHub (git remote and git push)

โฑ๏ธ Estimated read: 11 min | |

A local Git repository is an island. Commits accumulate in the .git directory, branches are created and merged, but none of it is visible to anyone else until the repository is connected to a remote. git remote establishes that connection, and git push transmits the commits across it. For a new project, this is a two-step operation: create an empty repository on GitHub, then wire it to the local repository and push. For an existing project, the commands are identicalโ€”the only difference is whether the local repository already has commits or is being initialized from scratch.

Key point: git remote add origin <url> names the connection. git push -u origin main transmits the commits and, with the -u flag, records the remote branch as the upstream for the current local branch so future pushes require only git push.


Why git remote and git push exist

The synchronization problem. Git is distributed. Every clone is a complete repository with its own history, branches, and staging area. There is no central authority unless one is explicitly configured. git remote creates that configuration: it assigns a name (conventionally origin) to a URL and tells Git where to send and receive data. Without a remote, git push has nowhere to go .

The push direction problem. git fetch and git pull bring commits from the remote to the local repository. git push does the opposite: it uploads local commits to the remote and advances the remote branch pointer. The operation succeeds only if the remote branch is a direct ancestor of the local branchโ€”a fast-forward. If someone else pushed in the meantime, Git rejects the push. That rejection is a safety feature, not a failure .

The upstream tracking problem. Typing git push origin main every time is tedious. The -u flag (--set-upstream) records the relationship between the local branch and the remote branch. After the first push with -u, a bare git push knows exactly where to send commits. A bare git pull knows exactly where to retrieve them. git status can report how many commits ahead or behind the local branch is .

The empty repository problem. When creating a GitHub repository to receive an existing local project, the repository must be empty. If it contains a README, a license, or a .gitignore, the remote has a commit that the local repository does not. The first push will be rejected as a non-fast-forward. The resolution is to pull and merge before pushing, or to create the repository without any initialization files .

The authentication problem. GitHub no longer accepts account passwords for Git operations over HTTPS. Authentication requires a personal access token (PAT) or an SSH key. A PAT is pasted in place of the password when Git prompts. An SSH key must be generated, added to the GitHub account, and the remote URL must use the git@github.com: format instead of https:// .


a. Creating the remote repository and connecting it

The first step is creating an empty repository on GitHub. The “Initialize this repository with a README” checkbox must remain unchecked, as must the .gitignore and license options. Any of these would create a commit on the remote that the local repository lacks .

Once the repository exists, GitHub displays a URL. The local repository is connected to it with git remote add.

# Navigate to the local project directory
cd /path/to/your-project

# Initialize Git if the project is not already tracked
git init

# Connect the local repository to the GitHub remote
git remote add origin https://github.com/USERNAME/REPOSITORY.git

# Verify the connection
git remote -v

The output of git remote -v confirms the connection:

origin  https://github.com/USERNAME/REPOSITORY.git (fetch)
origin  https://github.com/USERNAME/REPOSITORY.git (push)

The name origin is a convention, not a requirement. It is the default name that Git uses when a repository is cloned, and sticking with it avoids confusion. The URL can use either HTTPS or SSH. HTTPS requires a personal access token for authentication. SSH requires a pre-configured key pair .


b. Staging, committing, and pushing

A remote connection does nothing on its own. Commits must exist locally before they can be pushed. For a project that has never been tracked, this means staging all files and creating the first commit.

# Stage all files (respecting .gitignore)
git add .

# Create the first commit
git commit -m "Initial commit"

# Ensure the branch is named main (GitHub's default)
git branch -M main

# Push and set the upstream branch
git push -u origin main

The git branch -M main command renames the current branch to main if it is still named master. GitHub’s default branch is main, and aligning the local branch name with the remote avoids confusion .

The -u flag in git push -u origin main is the critical addition for first-time pushes. It sets origin/main as the upstream branch for the local main branch. After this command succeeds, subsequent pushes require only git push, and subsequent pulls require only git pull .

If the push is rejected with a non-fast-forward error, the remote contains commits that the local repository does not. This happens when the GitHub repository was initialized with a README or license. The resolution is to integrate the remote changes first.

# Fetch and rebase onto the remote branch
git pull --rebase origin main

# Resolve any conflicts, then push
git push -u origin main

Using --force as a first response to a rejected push is dangerous. It overwrites the remote history and can destroy commits that others have pushed .


c. Subsequent pushes and remote management

After the first push with -u, the workflow simplifies. Changes are made, staged, committed, and pushed with a bare git push.

# Check what has changed
git status

# Stage changes
git add .

# Commit
git commit -m "Add feature X"

# Push to the tracked upstream
git push

The remote can be inspected and modified as needed. git remote -v lists all remotes and their URLs. If the URL is incorrectโ€”for example, if the repository was renamed on GitHubโ€”git remote set-url updates it without removing the remote .

# Change the remote URL
git remote set-url origin https://github.com/USERNAME/NEW-REPOSITORY.git

A second remote can be added for collaborating with a fork. The convention is to name the original repository upstream and use it to fetch changes while pushing to origin (the fork) .

# Add the original repository as upstream
git remote add upstream https://github.com/ORIGINAL/REPOSITORY.git

Complete Example Session

# ============================================
# PART 1: CREATE THE GITHUB REPOSITORY
# ============================================

# On GitHub: New repository
# Name: my-project
# Do NOT check "Add a README file"
# Do NOT add .gitignore or license
# Click "Create repository"
# ============================================
# PART 2: INITIALIZE LOCAL REPOSITORY
# ============================================

cd ~/projects/my-project
git init
# Output: Initialized empty Git repository in /home/user/projects/my-project/.git/
# ============================================
# PART 3: STAGE AND COMMIT
# ============================================

# Create a .gitignore first if needed
echo "node_modules/" > .gitignore
echo ".env" >> .gitignore

git add .
git commit -m "Initial commit"
# ============================================
# PART 4: CONNECT TO GITHUB
# ============================================

git remote add origin https://github.com/USERNAME/my-project.git
git remote -v
# origin  https://github.com/USERNAME/my-project.git (fetch)
# origin  https://github.com/USERNAME/my-project.git (push)
# ============================================
# PART 5: PUSH AND SET UPSTREAM
# ============================================

git branch -M main
git push -u origin main
# Output: branch 'main' set up to track 'origin/main'.
# ============================================
# PART 6: AUTHENTICATION PROMPT
# ============================================

# Git prompts for credentials.
# Username: your GitHub username
# Password: your Personal Access Token (not your account password)
# ============================================
# PART 7: SUBSEQUENT PUSHES
# ============================================

# Make a change
echo "# My Project" > README.md
git add README.md
git commit -m "Add README"

# No remote or branch arguments needed
git push
# ============================================
# PART 8: HANDLE REJECTED PUSH
# ============================================

# If push is rejected:
git pull --rebase origin main
# Resolve conflicts if any, then:
git push
# ============================================
# PART 9: UPDATE REMOTE URL
# ============================================

# If the repository was renamed on GitHub:
git remote set-url origin https://github.com/USERNAME/new-name.git
git remote -v

The nine parts trace the complete workflow: creating the empty remote, initializing the local repository, staging and committing, connecting the remote, pushing with upstream tracking, authenticating, subsequent pushes, handling rejection, and updating the remote URL.


Quick Reference

Remote Commands

CommandPurpose
git remote add origin <url>Connect to a remote
git remote -vList remotes and URLs
git remote set-url origin <url>Change remote URL
git remote remove originRemove a remote

Push Commands

CommandPurpose
git push -u origin mainFirst push, set upstream
git pushPush to tracked upstream
git push origin mainPush to specific remote/branch
git push origin --delete branchDelete a remote branch

URL Formats

ProtocolFormatAuthentication
HTTPShttps://github.com/user/repo.gitPersonal Access Token
SSHgit@github.com:user/repo.gitSSH key pair

Best Practices

โœ… Do This:

git remote add origin https://github.com/USERNAME/REPO.git
git push -u origin main
  • โœ… Set upstream on first push
git remote -v
  • โœ… Verify the remote URL before pushing
git pull --rebase origin main
  • โœ… Integrate remote changes before retrying a rejected push

โŒ Don’t Do This:

git push --force
  • โŒ Overwrites remote history and can destroy others’ work
# Create GitHub repo with README
# Then try to push a local repo
  • โŒ Causes non-fast-forward rejection
# Use account password for HTTPS
  • โŒ GitHub requires a Personal Access Token

Common Pitfalls

PitfallWhy It HappensFix
Non-fast-forward rejectionRemote has README/licensegit pull --rebase origin main
Authentication failedUsing account passwordCreate and use a Personal Access Token
remote origin already existsRemote already configuredgit remote set-url origin <new-url>
Push asks for credentials every timeCredential helper not configuredEnable a Git credential helper
Branch name mismatchLocal master, remote maingit branch -M main before pushing

Real-World Examples

1. Connect to GitHub

git remote add origin https://github.com/user/repo.git

2. Verify Connection

git remote -v

3. First Push with Upstream

git push -u origin main

4. Subsequent Push

git push

5. Change Remote URL

git remote set-url origin git@github.com:user/repo.git

6. Add Upstream for Fork

git remote add upstream https://github.com/original/repo.git

7. Pull Before Push

git pull --rebase origin main

8. Delete Remote Branch

git push origin --delete feature-x

9. Check Tracking Status

git branch -vv

10. Set Auto-Configure Upstream

git config --global push.autoSetupRemote true

Visual

Local and Remote Repositories

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  LOCAL REPOSITORY                            โ”‚
โ”‚                                              โ”‚
โ”‚  .git/                                       โ”‚
โ”‚  โ”œโ”€โ”€ commits (a1b2c3d, e4f5g6h)              โ”‚
โ”‚  โ”œโ”€โ”€ branches (main)                         โ”‚
โ”‚  โ””โ”€โ”€ working tree (files)                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ”‚ git push
                   โ”‚ (uploads commits)
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  REMOTE REPOSITORY (GitHub)                  โ”‚
โ”‚                                              โ”‚
โ”‚  origin                                      โ”‚
โ”‚  โ”œโ”€โ”€ commits (a1b2c3d, e4f5g6h)              โ”‚
โ”‚  โ””โ”€โ”€ branches (main)                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

git push moves commits from local to remote. git fetch moves them the other way.

Upstream Tracking

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  git push -u origin main                     โ”‚
โ”‚                                              โ”‚
โ”‚  1. Upload local main commits to origin      โ”‚
โ”‚  2. Advance origin/main pointer              โ”‚
โ”‚  3. Record: local main tracks origin/main    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  git push                                    โ”‚
โ”‚                                              โ”‚
โ”‚  Git knows: main โ†’ origin/main               โ”‚
โ”‚  No arguments needed.                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The -u flag is a one-time operation. After it succeeds, the relationship is persistent.


Summary

ItemValue
Connect remotegit remote add origin <url>
Verify remotegit remote -v
First pushgit push -u origin main
Subsequent pushgit push
Rejected push fixgit pull --rebase origin main
URL changegit remote set-url origin <url>
HTTPS authPersonal Access Token
SSH URL formatgit@github.com:user/repo.git

Key takeaways:

  • git remote add names the connection. It does not transfer data. The name origin is a convention, not a requirement .
  • The first push requires -u. Without --set-upstream, every subsequent push needs the full git push origin main arguments .
  • The remote repository must be empty for the first push. A README or license on the remote creates a commit the local repository lacks, causing a non-fast-forward rejection .
  • Authentication uses a token or key. GitHub does not accept account passwords for HTTPS Git operations. A Personal Access Token replaces the password .
  • Rejected pushes require integration, not force. git pull --rebase origin main integrates remote changes before retrying. --force is destructive .
  • git branch -M main aligns branch names. If the local branch is master and the remote default is main, renaming before the first push avoids confusion .

Remember: git remote and git push are the bridge between a local repository and the world. The remote is just a name for a URL; the push is the transmission of commits. The first push is the only one that requires explicit argumentsโ€”after -u, Git remembers the relationship. The connection is fragile only if it is forced. A rejected push is a signal to integrate, not to override.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!