- Create a branch from unstaged/uncommitted changes
- Move the most recent 3 commits to a new branch
- Move the most recent 3 commits to an existing branch
- Copy a sequence of changes from one branch onto another
- Push to a new upstream branch
- Change the URL for an existing remote
- Delete a Git branch locally and remotely
- Find the most recent ancestor commit of two branches
- List un-pushed commits
- List divergent changes on two branches
- Creating a pull request on GitHub
- Merge changes from a forked repository (pull-request) on GitHub
- Merge changes from a forked repository (pull-request) locally
- Rename a branch
- Show upstream tracking branch
- Change upstream tracking branch
- Setup a "triangular" git workflow
- Search branches for a file or directory
- Add executable permissions to a file in Git
- Recover your repo from a forced-push
# Added in Git v2.23
git switch -c <new-branch>
# Wind back 3 commits on current branch
# Keep: fail on uncommitted changes
git reset --keep HEAD~3
# Create new branch here on current branch and switch to new-branch
git checkout --track -b <new-branch>
# Use reflog reference for HEAD from 2 operations ago - preceding the last two commands
# Apply all the commits following HEAD@{2} to the current branch (new-branch)
git cherry-pick ..HEAD@{2}
# Create <new-branch> as a duplicate of <existing-branch>
git branch -c --track <new-branch>
# Truncate last 3 commits from <existing-branch>, failing on uncommitted changes
git reset --keep HEAD~3
# Merge changes into existing branch
git merge <changed-branch> <existing-branch>
# Rewind 3 commits on changed branch
git checkout <changed-branch> && git reset --keep HEAD~3
git checkout <existing-branch>
- The current branch is
b1
- There is a sequence of commits,
first..last
, on branchb2
. - Note: The immediately preceding commit to
first
can be identified asfirst~1
. - You wish to apply the sequence from branch
b2
ontob1
# Mark the current head of "b1" by creating a branch there, `oldhead`
git checkout b1 && git checkout -b old-head
# Re-point the head of "b1" to the _end_ commit of the sequence (last). This will become the new HEAD of branch "b1"
git branch --force b1 last
# 1. The last entry on the command below tells git to first switch to branch b1.
# Remember, the "head" commit of b1 is now "last"
# 2. Rebase will apply all the commits _following_ first~1 (i.e. starting with first) through to the "head" of b1 (now "last") onto/after the commit "old-head"
git rebase --onto old-head first~1 b1
# Branch b1 has been patched and the "head" is still pointing to commit "last", now on the b1 branch, as desired.
# 3. Delete temporary branch 'old-head'
git branch --delete old-head
git push -u <remote-name> <branch-name>
git remote set-url <remote-name> <new-url>
# Delete the remote branch
git push <remote-name> --delete <branch-name>
# Move away from the branch to be deleted
git checkout <other-branch>
# Delete the local branch
git branch --delete <branch-name>
git merge-base branch2 branch3
# git log --oneline <since>..<until>
git log --oneline origin/main..HEAD
# Show the difference
git diff origin/main..HEAD
git log --oneline --decorate --left-right main...origin/main
- Video (youtube)
- Video (youtube)
Follow this recipe
git branch --move <oldname> <newname>
# For current branch
git rev-parse --abbrev-ref @{u}
git branch <branch_name> --set-upstream-to <your_new_remote/branch_name>
Follow this recipe
# From repo root
git log --all --name-only -- <filename/dirname>
# Supports globbing - NOTE single quotes
git log --all -- '**/filename'
# List containing branch(es)
for ref in $(git log --all --pretty=format:"%H" -- <filename/directory>); do git branch -a --contains $ref; done
# Staging a file...
git add --chmod=+x path/to/file
# To set the flag on a versioned file
git update-index --chmod=+x path/to/file
# To reset/remove the flag on a versioned file
git update-index --chmod=-x path/to/file
So you've just discovered a colleague has force-pushed changes to your upstream remote.
# Replace the chevron'd text below (<...>) with the name of your upstream remote and branch-name
export upstream=<remote-name>
export branch=<branch-name>
# Fetch the upstream changes
git fetch $upstream &&
# Switch to your branch
git switch $branch &&
# Create a new temporary branch for your local changes with tip at the current HEAD
git branch tmp$branch &&
# Reset HEAD to match the upstream head
git reset --HARD $upstream/$branch &&
# Rebase your local changes on top of the upstream changes
git rebase $branch tmp$branch
Only after you've merged and committed your changes...
# Delete the temporary branch
git branch --delete tmp$branch
The procedure is similar to above, except we need to return your workspace
to how it looked before you pulled the change. We will use git reflog
to return to that happy place.
# Identify the last commit <restore-point> before you pulled the change
git reflog
# Replace the chevron'd text below (<...>)
export restorepoint=<commit-id>
export upstream=<remote-name>
export branch=<branch-name>
# Find the commit corresponding the last commit of your own work
# Fetch the upstream changes
git fetch $upstream &&
# Switch to your branch
git switch $branch &&
# Create a new temporary branch for your local changes with tip at <restore-point>
git branch tmp$branch $restorepoint &&
# Reset HEAD to match the upstream head
git reset --HARD $upstream/$branch &&
# Rebase your local changes on top of the upstream changes
git rebase $branch tmp$branch
Only after you've merged and committed your changes...
# Delete the temporary branch
git branch --delete tmp$branch