Mastering Git
Staging
Stage all files git add -A
and unstage git restore .
Commit
To immediately commit all changed files git commit -am "Commit message"
Change last commit git commit --amend
. You can quickly rewrite a commit without editor git commit --amend --no-edit
Restore file from specific commit git restore -s abcd123 file.txt
Diff
Show the state of a file in a specific commit git show abcd123 file.c
Show the difference between two commits git diff abcd123..efgh123
Log
Show last five commits git log -5
Show history of changes in patch format git log -p
Show branch tree of commits git log --pretty=oneline --graph
Stashing
You can hide your raw work with the git stash
command, git stash list
to show the stashes and git stash apply
to apply the last stash, or git stash apply stash@{2}
to apply stash by its index.
Search
Search for a keyword in whole project git grep -n myClass
Display files with count of matching git grep --count myClass
Display commits which contains keyword git log -S ZLIB_BUF_MAX --oneline
By the way, you can specify the path to the directory in which you want to search as the last argument.
Show how the function git_deflate_bound() in the file zlib.c evolved over time git log -L :git_deflate_bound:zlib.c
Branching
git pull = git fetch + git merge
git switch -c = git branch + git switch
Process of integration feature branch:
1git switch main
2git pull origin main
3git merge feature-branch-name
4git push origin main
Tags
Tags usually calls as v1.0.0 where numbers signify major.minor.patch
major β Breaking changes π₯
minor β New features β¨
patch β Bug fixes π§
There are types of pre-release versions:
alpha β raw version of the build
beta β testing version of the build
rc β release candidate or nearly finished release
v1.0.0-alpha < v1.0.0-beta < v1.0.0-rc < v1.0.0
You can create an annotated tag like this git tag -a v1.0.0 -m "First release"
or lightweight tag git tag v1.0.0
without descriptions. To push on server git push origin --tags
. To delete git tag -d v1.0.0
or delete on server git push origin --delete v1.0.0
. You can switch to tag by git checkout v1.0.0
, if you make changes and commit them in tag’s “detached HEAD” state, your new commit wonβt belong to any branch and will be unreachable. Then you need to create a new branch git switch -c branch-name v1.0.0
which will contain your commit.
You can generate a build number with this command git describe main
if you have annotated tags; if you use lightweight tags, you should add --tags
flag.
Archives
Git allows you to create archives for your releases:
git archive main | gzip > `git describe main`.tar.gz
git archive main --format=zip > `git describe main`.zip
Submodules
You can add a submodule by this command git submodule add <url>
. To update a submodule, you must execute this git submodule update --remote <submodule_name>
. To clone a project with submodules git clone --recurse-submodules <url>
or in an already cloned repo run this git submodule update --init --recursive
.
History rewriting
Change the base commit to solve merge problems when pulling git pull --rebase
When you fetch a feature branch from remote repo with few commits, you can merge it from a specific commit, skipping all commits above git cherry-pick abcd123
Interactive mode git rebase -i
is a powerful tool to rewrite your Git history; for example, squash several commits in one, split one commit to several, change the commit order, or delete some commits. You can check out Drew DeVault’s guide or read chapter “Rewriting History” in the book “Pro Git”.
Debugging
Git provides two commands for debugging your project: git blame
and git bisect
.
The first command shows you line by line who last changed each line of a file git blame -L 70,80 Makefile
. If you are refactoring a file into multiple files, you can see where sections of the code originally came from by passing the -C
option.
And the second one carries out binary search in interactive mode. When you start it by git bisect start
you should enter git bisect good
if the current commit is good or git bisect bad
if not. If you answered positively, it means that all commits below are also good and do not contain bugs, and Git will switch to the middle commit between the good commit and the last commit for effective search. The search continues until you find the bug, then run git bisect reset
to reset HEAD to where you were before you started.
You can fully automate this process by passing a script that runs tests and returns 0 in case of success or 1 in error.
$ git bisect start HEAD v1.0.0
$ git bisect run test-error.sh
Configuration
If you use HTTP authentication, you can save your credentials in order to avoid entering a password git config --global credential.helper cache
Aliases
Aliases is useful shortcuts, like in .bashrc
, here’s an instance of a handy ones:
1git config --global alias.co checkout
2git config --global alias.br branch
3git config --global alias.ci commit
4git config --global alias.st status
GUI
Git has graphical tools based on the tk library; git gui
for managment and gitk
for browsing repository.
Contributing
Git is decentralized VCS (Version Control System) by default, like Email, and there are a few methods for co-development:
- Sending patches via Email
- Main developer, clone and merge the feature branch from your own git repository
- Sending a git bundle as you wish
As a general rule, your commit messages should start with a single line that’s no more than about 50 characters and that describes the changeset concisely, followed by a blank line, followed by a more detailed explanation. The Git project requires that the more detailed explanation include your motivation for the change and contrast its implementation with previous behavior β this is a good guideline to follow. Write your commit message in the imperative: “Fix bug” and not “Fixed bug” or “Fixes bug.” Here is a template you can follow, which we’ve lightly adapted from one originally written by Tim Pope.
Patches via Email
Email setup guide for Git.
Get patch: git show -p HEAD > patch.diff
Get pretty patch for contributing: git format-patch -M origin/main
Apply patch: git apply patch.diff
Apply pretty patch: git am 0001-your-patch-name.patch
Remote repository
In this case, you clone the project, create a feature branch in which you’re creating your feature, and then you push this feature branch to your own git repository. You inform the main developer about your feature branch, and he should add it to remotes or just pull your branch. If everything is okay, he can merge it into the main branch.
Git bundle
In this case, you create a single binary file of the repository with all your changes, for example, in the feature branch, and send this file via email or as you wish.
Suppose, your repository looks like this:
$ git log --oneline
71b84da Last commit - second repo
c99cf5b Fourth commit - second repo
7011d3d Third commit - second repo
9a466c5 Second commit
b1ec324 First commit
and you want to send only your last three commits, then you need to define a range of commits in this command: git bundle create <filename>.bundle main ^9a466c5
You can send this file to the developer. For first, he has to verify your bundle git bundle verify <filename>.bundle
and after this it can be applied git pull <filename>.bundle
Plumbing and Porcelain
Show commit count git rev-list HEAD --count
Paradigms
Lately, developers have been returning to Trunk Based Development. It acts as an antagonist against branch hell. The emphasis here is on CI, which runs tests and ensures that the code being contributed is error-free, so developers with a high development culture can afford to send commits directly to the main branch. Larger projects, use short-term feature branches, in which developers work throughout the day and at the end of which they merge their changes. However, some old projects such as a Git still using a four-branch model: main, next for merging stable feature branches, seen for merging raw feature branches, and maint for maintenance backport.
Git on server
Usually used Nginx and Fcgiwrap for http connections and cgit as a frontend. In the case of ssh you almost don’t need to set up anything, just the home directory of Git user with repositories. To handle git://
connections used git-daemon git daemon --reuseaddr --base-path=/srv/git/ --export-all --enable=receive-pack --informative-errors --verbose /srv/git/
.
Here are useful links if you decide to raise your own git server:
Hooks
It’s a standard way to organize CI/CD by handwriting scripts, which live in the .git/hooks
directory. There are client-side and server-side hooks. Sadly, but the hooks are not cloned, so you need to hold it in a separate place or repo. Server side hooks are located in the bare repository on the server and can function to build and deploy your Hugo website every time you pull your changes, for example.
Summary
It’s just a quick overview that includes only general functionality, and I strongly recommend you to read the book Git Pro.