Skip to content

Instantly share code, notes, and snippets.

@pvspain
Last active January 27, 2024 01:47
Show Gist options
  • Save pvspain/bd6716e1a789475bc84a98c1c70867ff to your computer and use it in GitHub Desktop.
Save pvspain/bd6716e1a789475bc84a98c1c70867ff to your computer and use it in GitHub Desktop.
Git use cases

Git use cases

Index

Create a branch from unstaged/uncommitted changes

# Added in Git v2.23
git switch -c <new-branch>

Move the most recent 3 commits to a new branch

Method 1:

# 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}

Method 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

Move the most recent 3 commits to an existing branch

# 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>

Copy a sequence of changes from one branch onto another

-Reference

  • The current branch is b1
  • There is a sequence of commits, first..last, on branch b2.
  • Note: The immediately preceding commit to first can be identified as first~1.
  • You wish to apply the sequence from branch b2 onto b1
# 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

Push to a new upstream branch

git push -u <remote-name> <branch-name>

Change the URL for an existing remote

git remote set-url <remote-name> <new-url>

Delete a Git branch locally and remotely

# 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>

Find the most recent ancestor commit of two branches

git merge-base branch2 branch3

List un-pushed commits

# git log --oneline <since>..<until>
git log --oneline origin/main..HEAD

# Show the difference
git diff origin/main..HEAD

List divergent changes on two branches

git log --oneline --decorate --left-right main...origin/main

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

Follow this recipe

Rename a branch

git branch --move <oldname> <newname>

Show upstream tracking branch

# For current branch
git rev-parse --abbrev-ref  @{u}

Change upstream tracking branch

git branch <branch_name> --set-upstream-to <your_new_remote/branch_name>

Setup a "triangular" git workflow

Follow this recipe

Search branches for a file or directory

# 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 

Add executable permissions to a file in Git

# 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

Recover your repo from a forced-push

So you've just discovered a colleague has force-pushed changes to your upstream remote.

If you haven't yet pulled or merged upstream...

# 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

If you have pulled or merged upstream...

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment