Git & GitHub

Pushing Changes

13 min Lesson 13 of 35

Pushing Changes

Pushing is the process of uploading your local repository commits to a remote repository. In this lesson, we'll explore how to push changes effectively, handle common scenarios, and understand the various push options.

Basic Push Command

The basic syntax for pushing changes is:

# Push to the default remote branch git push # Push to a specific remote and branch git push <remote> <branch> # Example: Push to origin remote, main branch git push origin main
Key Concept: Pushing uploads your local commits to the remote repository, making them available to other collaborators.

Understanding Push Behavior

When you push, Git uploads all commits from your local branch that don't exist on the remote branch:

# Check what will be pushed (before pushing) git log origin/main..HEAD # Or see a summary git status # Example output: Your branch is ahead of 'origin/main' by 3 commits. (use "git push" to publish your local commits)

Pushing a New Branch

When pushing a branch for the first time, you need to set up the tracking relationship:

# Create and checkout a new branch git checkout -b feature-login # Make some commits git add . git commit -m "Add login feature" # Push and set upstream tracking git push -u origin feature-login # OR git push --set-upstream origin feature-login # Now you can use just "git push" in the future git push
Tip: The -u flag (short for --set-upstream) sets up the tracking relationship, so future pushes and pulls know which remote branch to use.

Checking Push Status

Before pushing, it's good practice to check your status:

# Check current branch status git status # See commits that will be pushed git log origin/main..HEAD --oneline # See detailed changes git diff origin/main..HEAD # Verify remote branch exists git branch -r

Push Rejected Scenarios

Sometimes your push will be rejected. Here are common scenarios:

Scenario 1: Remote has changes you don't have Error: Updates were rejected because the remote contains work that you do not have locally. Solution: git fetch origin git merge origin/main # Or use pull (fetch + merge) git pull origin main # Then try pushing again git push origin main
Important: Never force push to shared branches unless you absolutely know what you're doing and have coordinated with your team.

Force Pushing

Force pushing overwrites the remote branch with your local version. Use with extreme caution:

# Force push (dangerous!) git push --force origin feature-branch # OR git push -f origin feature-branch # Safer alternative: force with lease git push --force-with-lease origin feature-branch

Differences between force push options:

--force: - Overwrites remote regardless of changes - Can lose other people's work - Very dangerous on shared branches --force-with-lease: - Only overwrites if remote hasn't changed since you last fetched - Safer alternative to --force - Protects against accidentally overwriting others' work - Recommended when force push is necessary
When to Force Push: ✓ After rebasing your own feature branch ✓ After amending commits on your feature branch ✓ Cleaning up your own work-in-progress branch ✗ Never on main/master branch ✗ Never on branches others are working on ✗ Never on public release branches

Pushing Multiple Branches

You can push multiple branches at once:

# Push all branches with matching names on remote git push --all origin # Push all tags git push --tags origin # Push specific branch git push origin feature-login # Push multiple specific branches git push origin main develop

Deleting Remote Branches

You can delete branches on the remote repository:

# Delete a remote branch git push origin --delete feature-old # OR git push origin :feature-old # Verify the branch was deleted git branch -r # Clean up local tracking references git fetch --prune
Tip: Deleting a remote branch doesn't delete the local branch. You need to delete it separately with git branch -d.

Pushing Tags

Tags are not automatically pushed with commits. You must push them explicitly:

# Create a tag git tag v1.0.0 # Push a specific tag git push origin v1.0.0 # Push all tags git push origin --tags # Push commits and tags together git push --follow-tags origin main

Setting Push Defaults

You can configure default push behavior:

# Set push to only push current branch git config --global push.default current # Set push to only push if remote branch has same name git config --global push.default simple # Set push to push all matching branches git config --global push.default matching # View current push configuration git config --get push.default
Recommended: Use "simple" or "current" as your push default. "matching" can accidentally push branches you didn't intend to push.

Dry Run Push

Test what would be pushed without actually pushing:

# Perform a dry run git push --dry-run origin main # Example output: To https://github.com/user/repo.git abc1234..def5678 main -> main # Nothing was actually pushed

Verbose Push Output

Get detailed information about what's being pushed:

# Verbose push output git push --verbose origin main # OR git push -v origin main # See exactly what objects are being transferred

Push with Lease Options

Advanced force push protection:

# Force push only if remote matches expected value git push --force-with-lease=main:abc1234 origin main # Force push with lease on current branch git push --force-with-lease origin feature-branch # This fails if someone else pushed to the branch # since your last fetch

Pushing to Multiple Remotes

Push to multiple remote repositories:

# Push to origin git push origin main # Push to backup remote git push backup main # Set up a remote to push to multiple URLs git remote set-url --add --push origin https://github.com/user/repo.git git remote set-url --add --push origin https://gitlab.com/user/repo.git # Now git push origin main pushes to both git push origin main

Tracking Branch Information

View and configure upstream tracking:

# View tracking information git branch -vv # Output shows upstream relationship: * main abc1234 [origin/main] Latest commit feature def5678 [origin/feature: ahead 2] Work in progress # Set upstream for current branch git branch --set-upstream-to=origin/main # Remove upstream tracking git branch --unset-upstream

Push Hooks

Git can run scripts before and after pushing:

# Pre-push hook runs before push # Located at: .git/hooks/pre-push # Example pre-push hook (prevents pushing to main): #!/bin/sh if [ "$(git rev-parse --abbrev-ref HEAD)" = "main" ]; then echo "Direct push to main is not allowed" exit 1 fi # Make it executable chmod +x .git/hooks/pre-push
Security Note: Always review your commits before pushing, especially to public repositories. Never push sensitive information like passwords, API keys, or private data.

Common Push Workflows

Workflow 1: Basic Feature Development git checkout -b feature-new # Make changes and commit git add . git commit -m "Implement new feature" git push -u origin feature-new Workflow 2: Update and Push git fetch origin git merge origin/main git push origin feature-branch Workflow 3: Rebase and Force Push git fetch origin git rebase origin/main git push --force-with-lease origin feature-branch Workflow 4: Push After Amend git commit --amend git push --force-with-lease origin feature-branch

Troubleshooting Push Issues

Issue: "failed to push some refs" Cause: Remote has commits you don't have Solution: git pull origin main git push origin main Issue: "insufficient permission" Cause: No write access to repository Solution: Check repository permissions or use correct credentials Issue: "would clobber existing tag" Cause: Tag already exists on remote Solution: git push origin :refs/tags/v1.0.0 # Delete remote tag git push origin v1.0.0 # Push new tag Issue: "push declined due to email privacy" Cause: GitHub email privacy settings Solution: git config user.email "your-github-username@users.noreply.github.com" git commit --amend --reset-author git push origin main

Practice Exercise:

Complete Push Workflow:

# 1. Create a test repository mkdir push-practice cd push-practice git init # 2. Create initial commit echo "# Push Practice" > README.md git add README.md git commit -m "Initial commit" # 3. Add remote (use your own repository) git remote add origin https://github.com/user/repo.git # 4. Push with upstream tracking git push -u origin main # 5. Create and push a feature branch git checkout -b feature-test echo "Feature content" > feature.txt git add feature.txt git commit -m "Add feature" git push -u origin feature-test # 6. Check status and tracking git branch -vv git status # 7. Make another commit and push (no -u needed now) echo "More content" >> feature.txt git commit -am "Update feature" git push # 8. Practice dry run git push --dry-run origin feature-test

Push Best Practices

✓ Always pull before pushing to avoid conflicts ✓ Use --force-with-lease instead of --force ✓ Push small, focused changes frequently ✓ Write clear commit messages before pushing ✓ Test your code before pushing to shared branches ✓ Use feature branches for experimental work ✓ Set up upstream tracking with -u on first push ✗ Never force push to main/master ✗ Never push sensitive data (passwords, keys) ✗ Avoid pushing large binary files ✗ Don't push broken or untested code to shared branches

Summary

In this lesson, you learned:

  • git push uploads local commits to remote repositories
  • Use -u flag when pushing a new branch to set up tracking
  • Force push with --force-with-lease for safety
  • Never force push to shared branches like main
  • Push rejected means remote has changes you need to pull first
  • You can delete remote branches with git push --delete
  • Tags must be pushed explicitly with --tags or individually
  • Configure push defaults for consistent behavior
Next Up: In the next lesson, we'll learn about fetching and pulling changes from remote repositories!

ES
Edrees Salih
21 hours ago

We are still cooking the magic in the way!