GIT
GIT version management snippets.
Revert Changes and Keep Commit History
git revert --no-edit {LAST GOOD COMMIT}..{LAST BAD COMMIT}
Force Repository to Previous Commit
Should use Revert Changes and Keep Commit History.
git reset --hard {COMMIT ID}
git push --force origin master
Danger
This is data destructive. Ensure any files are cleaned up before committing.
Currently checked out versions of this repository will break.
Force Pull from Master Repository
Forces local repository to be in sync with master, discarding all local changes and unpushed commits.
git fetch --all
git reset --hard origin/master
git checkout {BRANCH}
git fetch --all
git branch {BRANCH}-backup
git reset --hard origin/{BRANCH}
Revert Entire Directory to HEAD
git checkout -- {DIR}
git clean -fd {DIR}
Note
{DIR}/..
can be used to target all files and directories within that
directory.
Add Tag to Previous Commit
git pull --tags
git tag {TAG} {COMMIT}
git push --tags
Squash Commits to a Single Commit (Rebase)
This will squash a series of commits into a single commit, which is useful to cleanup multiple commits before pushing upstream.
git rebase --interactive {COMMIT}
Note
The COMMIT
is the last commit that should be collapsed (e.g. rolled into a
single commit).
Editor will appear with rebase configuration. Generally use pick
for the
first commit and squash
for the remaining commits.
git rebase --continue
Note
If done correctly, this will show all commit messages that were rolled up. Update as needed and commit as normal.
Modify Specific Historical Commit
Warning
This will re-write commit history from the changed commit; if tags, releases are used they will need to be deleted and re-created. Existing clones will break. Be careful.
git rebase --interactive '{COMMIT}^'
Note
Set edit for the desired commit; save and exit. Make desired changes.
git commit --all --amend --no-edit
git rebase --continue
git tag -l
git rev-list -n 1 {TAG}
git tag -d {TAG}
git push --delete origin {TAG}
git tag {TAG} {NEW COMMIT HASH}
git push --tags
Note
Ensure affected releases, tags are removed before pushing the changed repo.
git push -f
Remove Tracked Files without Deleting Them
git rm --cached {FILE TO REMOVE FROM COMMIT}
git rm --cached {FILE1} {FILEN}
git rm -r --cached {DIR}
Create a Branch
Multiple branches can be made to focus changes on specific efforts. These are
cut from the current branch; most cases this should be master
.
git branch -a
git checkout -b {NEW BRANCH}
Use git normally.
Merging Branches
Completed branches can be merged back into any branch, typically master
.
git branch -a
git checkout master
git merge {BRANCH} --no-ff
Note
--no-ff
retains all commit messages from the branch. Leave this off to
squish the commit (it may be helpful to get branch log for merge message
git --no-pager log > /tmp/git.log
.
You may reset the merge before committing with no data loss with
get merge --abort
.
Deleting Branches
Git will throw an error if deleting a branch with commits that has not been merged.
git branch -a
git branch -d {BRANCH}
Create Worktree
Allows the use of multiple branches simultaneously.
git branch -a
git checkout -b {NEW BRANCH}
git checkout master
git worktree add ../{WORKTREE NAME} {BRANCH}
Merge Worktree
Works like normal branch merging. Execute merge from master worktree.
See Merging Branches.
Removing Worktree
After the branch is merged worktree can be removed.
cd {MASTER WORKTREE}
git worktree remove {WORKTREE}
Then delete branch as normal. See Deleting Branches.
Migrate git stash to another machine
Export a stash as a patch to import in another git client.
git stash show "stash@{0}" -p > changes.patch
git apply changes.patch
git apply changes.patch --reverse
Repo git hooks
Hooks are located in .git/hooks
but are not versioned. This enables
repository tracked hooks.
See .git/hooks
for examples. Custom pre-commit example. Hooks must have
exact names.
mkdir {REPO}/.githooks
git config -f .gitconfig core.hooksPath .githooks
#!/usr/bin/env bash
#
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit. See .git/hooks for examples.
# Unset variables produce errors
set -u
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Redirect output to stderr.
exec 1>&2
EXIT_STATUS=0
# Check that vault files are encrypted.
# read: -r do not allow backslashes to escape characters; -d delimiter
while IFS= read -r -d $'\0' file; do
[[ "$file" != *.vault &&
"$file" != *.vault.yml &&
"$file" != *vault ]] && continue
# cut gets symbols 1-2
file_status=$(git status --porcelain -- "$file" 2>&1 | cut -c1-2)
file_status_index=${file_status:0:1}
file_status_worktree=${file_status:1:1}
[[ "$file_status_worktree" != ' ' ]] && {
echo "ERROR: *.vault file is modified in worktree but not added to the index: $file"
echo "Can not check if it is properly encrypted. Use git add or git stash to fix this."
EXIT_STATUS=1
}
# check is neither required nor possible for deleted files
[[ "$file_status_index" = 'D' ]] && continue
head -1 "$file" | grep --quiet '^\$ANSIBLE_VAULT;' || {
echo "ERROR: non-encrypted *.vault file: $file"
EXIT_STATUS=1
}
done < <(git diff --cached --name-only -z "$against")
exit $EXIT_STATUS
git config --local include.path ../.gitconfig
Note
Command executes from .git
directory, hence going up a directory to read
the config.
List All Respositories for An Organization/User
Useful for determining if there are new repositories to sync.
curl "https://api.github.com/orgs/{ORGANIZATION NAME}/repos?per_page=1000&page=1" | jq -r '.[] | .name' | sort
curl "https://api.github.com/users/{USER}/repos?per_page=1000&page=1" | jq -r '.[] | .name' | sort
Pull Latest Tarball Release from Github
Useful for projects that have periodic releases but are not in OS packages.
#!/bin/bash
#
# Args:
# 1: github username
# 2: repository name
# 3: tarball download target (absolute path)
# 4: tarball extract target (absolute path)
RELEASE_DATA=$(curl --silent "https://api.github.com/repos/${1}/${2}/releases/latest")
TAG=$(echo ${RELEASE_DATA} | jq -r .tag_name)
URL=$(echo ${RELEASE_DATA} | jq -r '.assets[0].browser_download_url')
NAME=$(echo ${RELEASE_DATA} | jq -r '.assets[0].name')
TARBALL=${3}/${NAME}
if [ ! -f "${TARBALL}" ]; then
curl --silent --location ${URL} --output ${TARBALL}
tar xf ${TARBALL} --strip-components=1 -C ${4}
fi