Remotes & Workflows¶
"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
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