Git¶
Config¶
Cater for different users using git as user root
¶
In root's /.kshrc
SUDO_USER="${SUDO_USER:-'none'}"
if [ ${SUDO_USER} = "johndoe" ]; then
export GIT_AUTHOR_NAME="John Doe"
export GIT_COMMITTER_NAME="John Doe"
export GIT_AUTHOR_EMAIL="[email protected]"
export GIT_COMMITTER_EMAIL="[email protected]"
elif [ ${SUDO_USER} = "janedoe" ]; then
export GIT_AUTHOR_NAME="Jane Doe"
export GIT_COMMITTER_NAME="Jane Doe"
export GIT_AUTHOR_EMAIL="[email protected]"
export GIT_COMMITTER_EMAIL="[email protected]"
fi
Remotes¶
Changing a remote's URL (https or ssh)¶
$ git remote -v
origin https://github.com/Kristijan/notes.git (fetch)
origin https://github.com/Kristijan/notes.git (push)
$ git remote set-url origin https://github.com/somethingelse/notes.git
$ git remote -v
origin https://github.com/somethingelse/notes.git (fetch)
origin https://github.com/somethingelse/notes.git (push)
Add remote upstream after fork¶
$ git remote -v
origin ssh://[email protected]:7999/~kristijan/repo.git (fetch)
origin ssh://[email protected]:7999/~kristijan/repo.git (push)
$ git remote add upstream ssh://[email protected]:7999/unix/repo.git
$ git remote -v
origin ssh://[email protected]:7999/~kristijan/repo.git (fetch)
origin ssh://[email protected]:7999/~kristijan/repo.git (push)
upstream ssh://[email protected]:7999/unix/repo.git (fetch)
upstream ssh://[email protected]:7999/unix/repo.git (push)
Pull down changes from both upstream and origin¶
git remote update
Aliases¶
Decorated oneline graph¶
git config --global alias.lga "log --oneline --all --decorate --graph"
One line summary¶
git config --global alias.lgo "log --color --pretty=format:'%C(yellow)%h%Creset - %C(cyan)%ad%Creset %<(80,trunc)%s %C(cyan)%>(20,trunc)%an - %Cgreen%>(12)%ar%Creset' --date=short --abbrev-commit --all"
Commits¶
Automatically commit all files being tracked¶
git commit -a -m "commit message"
Squashing commits and rebase onto master¶
$ git switch master
$ git pull
$ git switch <other_branch>
$ git rebase -i master
pick dedd08d commit1
squash 8e782a4 commit2
squash 036bca2 commit3
squash ff8a125 commit4
$ git push --force-with-lease
Find parent commits of a merge¶
$ git log --format=raw -n1
commit 61713c9ac641091c20045e9d3bde34f31d8e3621
tree 9d8c97f166cc9082c1949f21ed7b61a4fc33a420
parent c507b242517ba651b4fae5254c607571f666ffe2
parent a12033cb2e0933849a374defd272bd71a06b62ed
The highlighted commit above should be where the branch was before the merge.
Create empty commit¶
Create an empty commit to do things like trigger builds, etc...
git commit --allow-empty -m "Trigger build"
Show commit hash for each file¶
$ git ls-files --sparse --full-name -z | xargs -0 -I FILE -P 20 git log -1 --date=iso-strict-local --format='%ad %>(14) %cr %<(5) %an %h ./FILE' -- FILE | sort --general-numeric-sort
2021-06-05T14:40:30+10:00 2 years, 5 months ago Kristian Milos d280e68 ./docs/gpfs.md
2021-06-05T14:40:30+10:00 2 years, 5 months ago Kristian Milos d280e68 ./docs/index.md
2021-06-05T14:40:30+10:00 2 years, 5 months ago Kristian Milos d280e68 ./docs/nim.md
2021-06-05T14:40:30+10:00 2 years, 5 months ago Kristian Milos d280e68 ./docs/vios.md
2021-06-05T14:40:30+10:00 2 years, 5 months ago Kristian Milos d280e68 ./docs/wpar.md
2021-06-05T14:59:15+10:00 2 years, 5 months ago Kristian Milos 170190d ./.github/workflows/ci.yml
...
Show all commit hashes for file¶
$ git ls-files --sparse --full-name -z | xargs -0 -I FILE -P 20 git log --date=iso-strict-local --format='%ad %>(14) %cr %<(5) %an %h ./FILE' -- FILE | sort --general-numeric-sort
2023-01-11T17:19:25+11:00 10 months ago Kristian Milos cac3a2a ./docs/git.md
2023-03-17T16:09:35+11:00 7 months ago Kristian Milos 9633d50 ./docs/aix.md
2023-03-23T12:41:12+11:00 7 months ago Kristian Milos 0c1ce12 ./docs/aix.md
2023-06-09T12:00:20+10:00 5 months ago Kristian Milos 30b8b9b ./docs/git.md
2023-06-15T17:06:15+10:00 4 months ago Kristian Milos 229804b ./docs/aix.md
2023-06-15T17:14:56+10:00 4 months ago Kristian Milos 358c456 ./docs/aix.md
...
Show commit count for each file¶
This will list which files have been in commits the most.
$ git log --pretty=format: --name-only | sed '/^$/d' | sort | uniq -c | sort -g
1 docs/CNAME
1 docs/gpfs.md
1 docs/nim.md
1 docs/vios.md
1 docs/wpar.md
2 .gitignore
4 docs/hmc.md
4 docs/index.md
4 docs/powerha.md
7 .github/workflows/ci.yml
10 docs/aix.md
11 mkdocs.yml
15 docs/git.md
Branches¶
Create new branch and switch¶
git switch -c <new-branch>
Create new branch from another branch and switch¶
git switch -c <new-branch> <start-point>
Switch back and forth between two different branches¶
git switch -
Update a branch with changes from master¶
git fetch origin master
git rebase origin/master
Reset local branch to match remote¶
git fetch origin
git reset --hard origin/master
Rename a branch¶
git branch -m <new_name>
Rename branch if already pushed to remote¶
git branch -m <new_name>
git push -u origin <new_name>
git push origin --delete <old_name>
Delete a branch¶
git branch -d <branch>
Delete a remote branch¶
git push origin -d <branch>
List all branches and the commit they point to¶
git branch -av
Delete local remote tracking branch if the remote branch has been merged¶
git checkout master
git remote update origin --prune
git branch --merged | grep -v master | xargs git branch -d
Logs¶
Condensed summary¶
git log --summary
Decorated graph¶
git log --oneline --all --decorate --graph
Details of a specific commit¶
git show <commit> [-s]
List of commits per user¶
git shortlog -sne
16 Kristian Milos <[email protected]>
2 Goat Man <[email protected]>
2 Mwark <[email protected]>
List of commits per user after a certain date¶
git shortlog -sne --after 2023-06-01
16 Kristian Milos <[email protected]>
2 Goat Man <[email protected]>
Blame¶
Show blame from a specific line in a file¶
This will show a git blame
of 10 lines commencing at line 14.
git blame -L 14,+10 -- files/to/blame.txt
Diff¶
Diff from staged files¶
git diff --staged
Show committed files to be pushed to remote¶
git diff --stat --cached <remote/branch>
Diff between local and remote file¶
git diff origin/branchname -- location/of/file.txt
Diff between two branches¶
git diff <branch1>..<branch2>
Diff between file in two different branches¶
git diff <branch1>..<branch2> -- location/of/file.txt
Diff of filenames between two commits/branches¶
git diff --name-only <commit1/branch1> <commit2/branch2>
git diff --name-status <commit1/branch1> <commit2/branch2>
git diff --stat <commit1/branch1> <commit2/branch2>
Diff contents of a single file between two commits¶
git diff 9e9384392 61713c9ac <filename>
Difference between ..
and ...
in a git diff
¶
foo..bar
or foo bar
¶
git diff foo..bar
is the same as git diff foo bar
, both will show you the difference between the tips of the two branches foo
and bar
.
%%{init: { 'theme': 'dark', 'gitGraph': {'mainBranchOrder': 1, 'parallelCommits': true}} }%%
gitGraph:
commit id: 'a'
commit id: 'b'
commit id: 'c'
branch feature1 order: 0
branch feature2 order: 2
switch feature1
commit id: 'd'
commit id: 'e'
commit id: 'foo' type: HIGHLIGHT
switch feature2
commit id: 'g'
commit id: 'h'
commit id: 'bar' type: HIGHLIGHT
foo...bar
or $(git merge-base foo bar) bar
¶
git diff foo...bar
(or $(git merge-base foo bar) bar
) will show you the difference between the "merge base" of the two branches and the tip of bar
. The "merge base" is usually the last commit in common between those two branches, so this command will show you the changes that your work on bar
has introduced, while ignoring everything that has been done on foo
in the meantime.
%%{init: { 'theme': 'dark', 'gitGraph': {'mainBranchOrder': 1, 'parallelCommits': true}} }%%
gitGraph:
commit id: 'a'
commit id: 'b'
commit id: 'merge base' type: HIGHLIGHT
branch feature1 order: 0
branch feature2 order: 2
switch feature1
commit id: 'd'
commit id: 'e'
commit id: 'foo'
switch feature2
commit id: 'g'
commit id: 'h'
commit id: 'bar' type: HIGHLIGHT
Tags¶
Tag an existing commit¶
git log --pretty=oneline
git tag -m "Package version 1.5.0.22" -a v1.5.0.22 <commit_id>
Push all tags to remotte¶
git push origin --tags
Push a single tag to remote¶
git push origin v1.5.0.22
Delete local tag¶
git tag -d v1.5.0.22
Delete remote tag¶
git push --delete origin v1.5.0.22
Update local tags from remote¶
git fetch --tags --force
Show the commit a tag is pointing to¶
git rev-list -n 1 <tag>
Reset, Restore, & Remove¶
Unstage a file¶
git reset <file>
Undo last commit that hasn't been pushed¶
git reset HEAD^
Discard all branch changes and refresh from remote¶
git reset --hard origin/master
Unstaging a file, but leaving its actual changes untouched¶
git restore --staged myFile.txt
Discard local changes in a certain file¶
git restore myFile.txt
Undo all local changes in the working copy¶
git restore .
Restore any previous version of a specific file¶
git restore --source master index.html
git restore --source 6bcf266b index.html
Remove a staged file¶
git rm <file>
git showing unstaged changes¶
git rm --cached -r .
git reset --hard
Miscellaneous¶
Using git bisect
to find bad commits¶
-
Start the bisect and provide both the 'good' and 'bad' commit hashes.
$ git bisect start status: waiting for both good and bad commits $ git bisect good 72f09f status: waiting for bad commit, 1 good commit known $ git bisect bad fd1bbb5 Bisecting: 11 revisions left to test after this (roughly 4 steps) [adf2e0caec46fa82eea3ae4754fd0bea8d137e3d] fixed shellcheck SC2015 violation
-
Run your tests, marking each failed test as 'bad'.
$ git bisect bad Bisecting: 2 revisions left to test after this (roughly 2 steps) [de1031a7d43aeb355482890159f53437094bf7a9] make sure to use /usr/bin/infocmp to probe if tmux-256color is available system wide (3), fixes #618 $ git bisect bad Bisecting: 0 revisions left to test after this (roughly 1 step) [044d6336e84034c14760a2fe178f604a89626bfb] make sure to use /usr/bin/infocmp to probe if tmux-256color is available system wide (2), fixes #617
-
When your test passes, mark the commit as 'good'
$ git bisect good 044d6336e84034c14760a2fe178f604a89626bfb is the first bad commit commit 044d6336e84034c14760a2fe178f604a89626bfb Author: Gregory Pakosz <[email protected]> Date: Sat Jan 21 21:57:51 2023 +0100 make sure to use /usr/bin/infocmp to probe if tmux-256color is available system wide (2), fixes #617 some operating systems like NixOS don't have /usr/bin/infocmp .tmux.conf | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
The highlighted commit above should be where the bug/issue was introduced.
-
Once complete, clean up the bisection state and return to the original HEAD.
$ git bisect reset Previous HEAD position was 2cf4d9a make sure to use /usr/bin/infocmp to probe if tmux-256color is available system wide Switched to branch 'master' Your branch is up to date with 'origin/master'.
List of files/blobs sorted by size¶
$ git rev-list --objects --all |
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
sed -n 's/^blob //p' |
sort --numeric-sort --key=2 |
cut -c 1-12,41- |
$(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
...
...
...
83367b100bdf 50KiB docs/aix.md
e0f87ab30a21 50KiB docs/aix.md
815a3edec4d5 50KiB docs/aix.md
a11c5026a642 53KiB docs/aix.md
bd015cca4288 53KiB docs/aix.md
9c8f5774ab55 56KiB git/index.html
6c8a85661a40 58KiB powerha/index.html
11c2602bcedb 60KiB gpfs/index.html
3b7b4ecfc742 66KiB hmc/index.html
Search for a string in a file across all branches¶
The below script takes two parameters. The first being the search string, and the second being the file to search. On a successful match, the script will print the name of the checked-out branch.
Disk space
The script will checkout every remote branch. In large repositories, this can consume a lot of disk space.
#!/bin/bash
# Search for a string in a file across all branches
if [ "$#" -ne 2 ]; then
printf "%s\n" "$0 <search string> <file name>"
exit 1
fi
printf "%s\n\n" "Listing branches containing \"${1}\" in file \"${2}\""
# Fetch all remote branches
git fetch --all
# Loop through each remote branch
git branch -r | awk -F'/' '!/HEAD/{sub(/^[^\/]*\//, ""); print}' | while read -r branch; do
# Switch to branch
git switch --quiet "${branch}"
# Check if the file contains the string
if git grep --quiet "${1}" -- "${2}"; then
echo "${branch}"
fi
# Checkout back to the original branch
git switch - --quiet
done
Commit a change to a file in every remote branch¶
Disk space
The script will checkout every remote branch. In large repositories, this can consume a lot of disk space.
#!/bin/bash
# Commit a change to a file in every remote branch
# Fetch all remote branches
git fetch --all
# Loop through each remote branch
git branch -r | awk -F'/' '!/HEAD/ && !/production/ && !/main/{sub(/^[^\/]*\//, ""); print}' | while read -r branch; do
# Switch to branch
git switch --quiet "${branch}"
# Update Puppetfile
gsed -i '/mod '\''unix\/mwark'\''/,/mod /{//!d;};/mod '\''unix\/mwark'\''/d' Puppetfile
gsed -i '/mod '\''unix\/goats'\''/,/mod /{//!d;};/mod '\''unix\/goats'\''/d' Puppetfile
# Commit and push changes (if any)
if ! git diff --quiet; then
git add Puppetfile
git commit -m "Remove unix/mwark and unix/goats modules"
git push
fi
# Checkout back to the original branch
git switch - --quiet
done