Skip to content

Remotes & Workflows

By:  Al-Fahami Toihir   🏷️ git •  workflow •  ⏱️ ~8 min read

"GitHub is a free tool that lets you host your local repository."


Remote Repositories

git remote                                       # List all linked remote repositories
git remote -v                                    # Verify remotes with URLs
git remote show origin                           # Show URL of remote repository
git remote add origin <url>                      # Add remote via HTTPS
git remote add origin git@github.com:user/repo.git  # Add remote via SSH
git remote set-url origin git@github.com:user/repo.git  # Update remote URL to SSH
git remote remove <name>                         # Remove a linked remote
git push                                         # Push to remote
git push -u origin main                          # Push and set upstream tracking
git pull                                         # Pull latest from remote
git clone <url>                                  # Clone a repository
git push origin +master                          # Remove a commit already pushed remotely

Merging a Pull Request Locally

git pull origin main                             # Step 1: update local repo
git checkout main                                # Step 2: switch to base branch
git merge <branch-name>                          # Step 3: merge the PR branch
git push -u origin main                          # Step 4: push the result

The Push Workflow: Always Pull Before You Push

A safe and consistent push habit for every project:

git add .                                        # stage your changes
git commit -m "your message"                     # commit
git pull                                         # sync with remote first
git push                                         # then push

This avoids rejected pushes when someone else or your own CI/CD pipeline has committed to the remote while you were working locally.

Make pull always rebase

git config --global pull.rebase true
This keeps your history linear; no merge commits from pulls, just a clean straight line of work. Good habit for all projects.

Note

The only time you can skip the pull is when you're 100% certain you're the only one touching that branch and no automation commits back. Even then, pulling costs nothing.


Fetch a Single File from Another Branch

Pull one specific file from another branch without merging everything:

git checkout upstream/<branch> -- path/to/file.java   # overwrite local file with branch version
git checkout HEAD -- path/to/file.java                # undo; restore from current branch

The file is overwritten locally and staged automatically.


Ignore Future Changes but Keep the File in the Repo

assume-unchanged (performance hint)

git update-index --assume-unchanged <path/to/file>    # git won't notice local edits
git update-index --no-assume-unchanged <path/to/file> # resume tracking

Warning

assume-unchanged can be silently overwritten by Git during merges and checkouts. Use skip-worktree instead for files you actively modify locally.

skip-worktree (local config files you never want to push)

.gitignore only works for untracked files. If a file is already committed, use skip-worktree:

git update-index --skip-worktree path/to/application.properties
git update-index --skip-worktree path/to/logback.xml

The file won't appear in git status, won't be touched by git add ., and won't be committed. Your local changes stay permanently without any effort.

To undo:

git update-index --no-skip-worktree path/to/application.properties

Warning

skip-worktree breaks during merges; if the incoming merge touches that file, Git blocks. Workaround:

cp application.properties application.properties.local.bak   # backup local values
git update-index --no-skip-worktree application.properties    # lift skip-worktree
git merge upstream/<branch>                                   # merge
git update-index --skip-worktree application.properties       # re-apply skip-worktree
cp application.properties.local.bak application.properties    # restore local values
echo "*.local.bak" >> .git/info/exclude                       # never track backups

Adding SSH to a Remote Platform

Check for existing SSH keys

ls -al ~/.ssh                                    # list existing SSH keys

Default public key filenames: id_rsa.pub, id_ecdsa.pub, id_ed25519.pub

Generate a new SSH key

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

For legacy systems that don't support Ed25519:

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Press Enter to accept the default file location, then enter a passphrase.

Add the key to the SSH agent

eval "$(ssh-agent -s)"                           # start the SSH agent
ssh-add ~/.ssh/id_ed25519                        # add your private key

Copy the public key

sudo apt-get install xclip
xclip -selection clipboard < ~/.ssh/id_ed25519.pub   # copies key to clipboard

Then go to your platform (GitHub, GitLab, Gitea) → Settings → SSH Keys → New SSH key → paste → Save.


Fork Workflow & Remote Tracking

git remote -v                                    # check all configured remotes
git remote add upstream <url>                    # add upstream when missing
git push origin -u <branch-name>                 # push to fork AND fix tracking
git branch -u origin/<branch-name>               # fix tracking without pushing
git push origin --delete <branch-name>           # delete a remote branch

Warning

When you git switch to a branch fetched from upstream, Git auto-sets tracking to upstream. Fix it to point to your fork before pushing using git push origin -u <branch-name>.

Note

"Write access not granted" on git push means your branch is still tracking upstream where you have no write access. Always use git push origin <branch-name> explicitly until tracking is fixed.

Re-fork / Syncing with Upstream

When the upstream repo has new commits you want in your fork:

git remote add upstream <original-repo-url>      # link to the original repo
git fetch upstream                               # fetch upstream changes
git rebase upstream/master                       # rebase your fork on upstream

Multiple Git Identities (Conditional Includes)

Problem: work PC with work credentials, wanting personal project commits attributed to a personal identity.

Solution: Git's [includeIf] with hasconfig:remote.*.url switches credentials automatically based on the repo's remote URL; no folder structure required.

~/.gitconfig

[user]
    email = work@company.com
    name = Work Name

[includeIf "hasconfig:remote.*.url:git@github.com:yourusername/**"]
    path = ~/.gitconfig-personal

[includeIf "hasconfig:remote.*.url:git@gitea.example.com:yourusername/**"]
    path = ~/.gitconfig-work

~/.gitconfig-personal

[user]
    email = personal@gmail.com
    name = Personal Name

Useful verification commands:

git config --show-origin user.email              # which config file is being used
git config --list --show-origin                  # inspect the full config chain

Warning

The [includeIf] block must go in ~/.gitconfig, NOT in ~/.ssh/config. SSH config only understands Host blocks; mixing them breaks git clone.


Transfer a Gist to GitHub

git clone https://gist.github.com/<gist-id>     # clone the gist
mv <gist-id>/ gist-github/                      # rename the directory
cd gist-github/
git remote add github https://github.com/<user>/<repo>  # add github as remote
git push github master                           # push to github

# Sync changes going forward
git push github master                           # to GitHub
git push origin master                           # to Gist (origin = gist)

# Clean up remotes
git remote rename origin gist
git remote rename github origin
git remote remove gist

Git Large File Storage (LFS)

Git LFS replaces large files (audio, video, datasets, graphics) with text pointers inside Git, while storing the actual file contents on a remote server.

Setup

git lfs install                                  # set up LFS once per user account
git lfs track "*.psd"                            # track all .psd files with LFS
git add .gitattributes                           # always track .gitattributes

Migrate existing files to LFS

git lfs migrate import --include="*.ipynb"       # convert pre-existing files to LFS

Then commit and push as normal; LFS handles the rest.

Download LFS: git-lfs releases


Revert a Commit Pushed Remotely

Reverting creates a new commit that undoes the bad one. The original commit stays in history but no longer affects the current state.

git revert <commit-id>                           # safe revert; creates a new commit

For reverting a range of commits:

git revert --no-commit <old-commit>..HEAD
git commit
git push

See: Git HowTo: revert a pushed commit


Hard Reset to Match Upstream Exactly

When your branch has diverged too far and you want to discard everything and match upstream exactly:

git fetch upstream <branch>                      # fetch latest from upstream
git reset --hard upstream/<branch>               # discard ALL local changes
git push --force origin <branch>                 # update your fork to match

Warning

This is destructive; all local commits and changes are permanently lost. Only use when you're sure you want to start from upstream's state.

Save your work first

If you want to keep your changes but still reset:

git stash push -m "wip/my-changes"           # save your work
git fetch upstream <branch>
git reset --hard upstream/<branch>
git stash pop                                # re-apply your changes
# resolve any conflicts
git add .
git commit -m "feat: reapply changes on top of upstream"
git push origin <branch>


Moving or Retargeting a Pull Request

Change the base branch on GitHub (easiest)

If you just need to retarget an existing PR to merge into a different branch; no git commands needed:

Go to your PR on GitHub > Edit (pencil icon next to title) > change the base branch > confirm.

PR closed after upstream rebase

When the maintainer rebases the base branch, GitHub rewrites commit hashes. Your PR may be automatically closed because the original commits no longer exist. Fix:

git fetch upstream <new-base-branch>
git checkout -b feat/resubmit-branch upstream/<new-base-branch>
git cherry-pick <your-commit-hash>               # bring your changes over
git push origin feat/resubmit-branch

Then open a new PR from feat/resubmit-branch and close the old one.

Rebase your PR branch onto a new base

If the base branch changed and you want to move your commits on top of it:

git fetch origin
git rebase --onto <new-base> <old-base> <your-pr-branch>
git push --force origin <your-pr-branch>

Then update the PR's base branch on GitHub.


Git Garbage Collection

Git sometimes runs automatic cleanup (auto packing) in the background to optimize repository storage. On Windows you may see:

Unlink of file '.git/objects/pack/pack-xxx.pack' failed. Should I try again? (y/n)

Press n; this is just a file lock issue on Windows, not an error. Your actual git operation completed successfully. Run manual cleanup later if needed:

git gc                                           # manual garbage collection
git gc --aggressive                              # deeper cleanup, takes longer

Categories