You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Want to inspect a container's contents, not an image (e.g. to view files generated during the container's execution that aren't in the image originally)
The container does not run a continuous process (if run, will probably shut down while you're still inside it)
If it does, use docker exec -it [name] /bin/sh to start a shell inside it directly
Since learning about git status it is approximately one third of my terminal commands. (ohmyzsh: gst)
What are branches?
There's nothing special about them. They're just pointers to a commit. The 'branch' as you imagine it visually is just two (or more) commits who both think they have the same parent. There's nothing stopping you from creating that situation where the 'branch' doesn't have any refs pointing to it, in which case it will eventually be garbage collected.
Initialise a PR
I like to have an empty PR where I can draft my proposal and set myself a series of tasks/requirements before I start any work at all. GitHub won't let me make a PR on a branch without any commits, so I can make an empty commit:
I like to say "Init PR" for personal projects, but for team projects it's probably more traditional to go with "Initial commit".
Unless I want that empty commit to appear in the pull request until the end of time, it's probably a good idea to make the next commit an amend commit. Alternatively, I can just run interactive rebase later, and the empty commit wil automatically be dropped (it will be commented out by default in the todo list).
Worth noting that this whole kerfuffle is only necessary for GitHub. On GitLab you can just make an MR (merge request - GitLab terminology) without any commits and it's totally chill about it.
Trial changes from another branch
If I want to use changes in branchB to test changes in branchA, without merging branchB into branchA because while they're obviously dependent they're unrelated features, I can trial the merge:
git merge --no-commit --squash branchB
branchB will be merged into branchA and the changes will be staged, but not committed.
Then to undo:
git reset HEAD
A single reset is fine because the commits were squashed into one.
Track branches automatically
If I want to be able to git push and git pull on a branch without having to specify git push origin branchname, I need to set it to track the corresponding branch on origin. The best way to do that is to add -u the first time I push the branch to origin:
git push origin branchname -u
(ohmyzsh: gpsup)
From then onwards, the branch is automatically tracked. This also enables powerlevel10k indicators that show how many commits my local branch is ahead/behind compared to origin.
Patch adding
If I've been naughty and accumulated a bunch of changes that should be in several different commits, and if those commits aren't cleanly divided between files for easy separation with git add, I can use git add -p to select by change rather than by file.
(ohmyzsh: gapa)
Patch removing
To remove staged changes from the index patchwise: git reset -p
To remove unstaged changes from the working tree patchwise: git checkout -p
Patch reverting
To revert changes made in a previous commit patchwise (to i.e. partially revert a commit):
git bisect is a lifesaver for finding out when bugs were introduced.
Doesn't need to be a bug - any question of the form 'what the first commit where X?' can be answered by bisect.
git bisect start - start bisecting
git bisect bad [ref] - mark a bad commit that contains the bug
git bisect good [ref] - mark a good commit from before the bug was introduced
Bisect will show me a bunch of commits. Check if the bug is present and communicate that with git bisect good and git bisect bad. Best to write a test script for it and leave it untracked. Git will show me which commit the bug is first present in.
git bisect reset - go back to wherever I was before I started bisecting
E.g. for an automated bisect that just checks the entire history...
git bisect start HEAD $(git rev-list --max-parents=0 HEAD)
git bisect run sh -c "some command"
The command could be e.g. rg text, where a commit is considered good if it contains the text (or ! rg text to consider it good only if it does not)
Amend the last commit: git commit --amend and optionally --no-edit (OMZ: gc! / gcn!)
Amend the commit with hash X: git commit --fixup=X, then git rebase -i --autosquash HEAD~N where N is at least the number of commits between HEAD and X
--autosquash just causes the special commit-message commands created by --fixup to automatically edit the interactive rebase's todo list, but doesn't actually mutate anything.
.gitignore magic
To ignore a directory without matching files of the same name, append /.
To ignore a path without globbing (e.g. to ignore only a file in the root dir and not files elsewhere with the same name), prepend /.
To ignore a file without adding it to .gitignore, e.g. a personal utility script or symlink that nobody else needs to know about, add it to .git/info/exclude instead. gitignore syntax works here too.
Pull without checkout
To pull another branch without first checking out that branch: git fetch origin <branch>:<branch>
e.g. git fetch origin develop:develop is equivalent to
For a branch that's had the main branch merged into it a few times, git log loses its meaning as it starts to fill with unrelated commits.
git log --no-merges branchname ^main will filter those commits out.
Fixups
git rebase --interactive --autosquash automatically sets fixup commits to fixup the commit that they target.
--autosquash can be applied to grbi by default with git config --global rebase.autosquash true.
A fixup commit can be created with git commit --fixup=SHA, or if the SHA is unknown (i.e. you are too lazy to open the log) but you remember a sufficiently-unique part of the commit message, git commit --fixup=:/message will work too.
Just remember to rebase before pushing.
Stashing
git stash --include-untracked (gstu) is good for not having untracked files follow you across branches.
Use commit message from another commit
git commit -C [ref] uses the commit message from another commit. Useful for recovering commit messages when rebasing etc.
Finding the merge base
To find the common ancestor of two refs:
git merge-base <ref><ref>
e.g. git merge-base HEAD develop.
This can be useful when resolving merge conflicts in a file, and you want to know what changes were actually introduced in both sides of the conflict (instead of just seeing the net effect of both changes):
The above can be simplified if your branch name and their branch name match, but if you wanted to e.g. namespace your branch name with their actual name, that won't be the case.
Purge stale branches
To remove branches that have accumulated locally but were deleted on the remote:
Colleague is working on feature-A. You start work on related feature building on that, feature-B. You branch feature-B from feature-A and commence work. Colleague completes work on feature-A and squash-merges it. This creates a squash commit on the merge target branch containing the work but none of the history of feature-A. You try to merge feature-B into the merge target and there are one million conflicts between the squash commit and the old feature-A commits in your feature-B branch.
Solution: git rebase --onto <merge target> feature-A feature-B. All merge conflicts during rebase should be between feature-A work and feature-B work (which, having worked on feature-B, you should be able to resolve yourself) rather than between feature-A work and old feature-A work.
See a file at a commit
git show <commit>:<file>
Reset a local branch to be the same as its remote counterpart
In this case @ is a shortcut for HEAD, and u is a shorthand for upstream. @{u} effectively expands to 'the upstream counterpart of whatever is currently checked out'.
Git keeps asking for auth creds
If the Git server has your SSH key and you keep trying to pull it over HTTP(S), it'll keep asking for your creds instead of using that key. Fix it by making it use SSH
Look in .git/config for:
[remote "origin"]
url = https://<server>/<repo>
Replace with:
[remote "origin"]
url = git@<server>:<repo>
To avoid this in future, when cloning a repo, use the SSH URI rather than the HTTP(S) URL
Dot dot dot
git diff A..B finds commits in B that aren't in A
git diff A...B finds commits in B that aren't in A, and commits in A that aren't in B
E.g.:
A - B - C - D - E
\
F - G
git log E..G gets you F and G
git log E...G traces the path from E to G, returning all commits along the way, except for C which is in both histories
stat of changed files
git status --porcelain | awk '{print $2}'| xargs ls -al -d 2>/dev/null