Git
Quote
Git is an Open Source Distributed Version Control System Designed to handle everything from small to very large projects with speed and efficiency.
Git is the best version control tools for any developer, you can read the Official Documents.
- Save and Track different versions of your repositories
- Coordinate changes across different teams without impacting the work of other collaborators
- Share local copies of the same codebases as other developers when working offline
- Isolate new fixes and features in development without impacting production
Workflow
Details:
When you want to create .git
file in your local project, you can use:
Another command, git init –bare
will create and keep only configuration
values of version control without source code.
$ echo -e "Hello World" > demo.txt
$ git hash-object demo.txt
1910283f238bc06de68f6a2ac63f3ec8c7a0dfef
$ git status
On branch main
...
Untracked files:
(use "git add <file>..." to ...)
demo.txt
nothing added to commit but untracked files present (use "git add" to track)
Note
Remove all untracked files that was created in working, git clean -f
.
Restore Added file that was added from staging to working
Note
The file in object/
was compressed, and you will see value in this file
when you use zlib
like: blob 11<nil>Hello World
.
Note
git add -p <file>
, this command will split changed file to hunks of code for
review and what to do with that hunk,
such as y n q a d / j J g e ?
.
-y
: (yes) for add that hunk to staged zone-n
: (no) ignore to add this hunk-q
: (quit) quit this interactive with modegit add -p
-s
: (split) divide this hunk to smaller hunks
Sub-Folder
This command, git add :/
, using when you stay in sub-folder of working
area and want to add all changed files include outside to staged status.
# Get type of Git file
$ git cat-file -t 3c6d
commit
# Get content of Git file
$ git cat-file -p 3c6d
tree a611c6cc...
author ...
...
$ git cat-file -p a611
100644 blob 1910283f238bc06de68f6a2ac63f3ec8c7a0dfef demo.txt
Note
In commit hash file, Git will add parent
information if you add new commit
after first commit.
Note
The git commit --amend
or git commit --amend -m "YOUR MESSAGE"
command use
for create new commit replace the latest commit.
This solution use only local repository, before push branch to remote repository. If it is not any changed file to Staged, this command will allow you to edit the latest Commit Message.
Note
git ldm
for list history commits that you do in local repository before daily
standup meeting.
Common Command
Git Hash
Git have build-in hash function that use for create file name in Git.
Manual Hash
You see the above hash process, Git does not create hash file name from the real filename, but it uses content information in the file.
Git Config
The git config
will override config values in local from global configuration.
Config Editor
Configuration in Git can use: git config
command line. The simple way to edit
Git configuration is using editor like VS Code, Atom, or Vim by Git
default.
Git Log
# Set Disable Git Log pager
$ git config --globlal pager.log false
$ git log
commit 3c6d5a4... (HEAD -> main)
Author: ...
...
Filtering your commit history:
- by date -
--before
or--after
- by message -
--grep
- by author -
--author
- by file -
-- ${filename}
- by branch -
${branch-name}
$ git log --after="2021-7-1"
$ git log --after="2021-7-1" --before="2021-6-5"
$ git log --grep="refactor"
Git Diff
Use difftool
Git Branch
Note
If you want to check out previous branch, you can use: git checkout -
.
Git Checkout
# Revert all modified files to clean status
$ git checkout .
# Switch to previous branch
$ git checkout -
# Revert to specific commit
$ git checkout "<commit>"
# Revert to specific file and commit
$ git checkout "<commit>" <file-name>
# Create new branch in local repository from existing branch in remote repository
$ git checkout -b feature/xxx origin/feature/xxx
Git Tag
Git Tags are used to capture the specific point in the history that is further used to point to a released version. A tag does not change like a branch.
$ git log --oneline
816998a <commit-message>
7c576ab <commit-message>
dd9a333 stable
...
# Switch HEAD to that commit
$ git switch --detach dd9a333
$ git tag alpha
$ git switch --detach alpha
$ git tag "<tag-name>" "<commit>"
$ git show "<tag-name>"
$ git tag --list
$ git tag -d "<tag-name>"
Note
- Annotated tags -
git tag -a '<tag-name>' -m '<message>' HEAD
- Lightweight tags -
git tag <tag-name>
$ git ls-remote --tags
$ git ls-remote --tags origin
$ git push --delete origin "<tag-name>"
$ git push origin :refs/tags/"<tag-name>"
NOTE: If you want to push tag on local repository to remote, you will use
git push my_remote –tags
Git Stash
The git stash
does hide all changes, stash the changes in a dirty working directory
away. The local repository will be clean because git stash
will tell HEAD commit
hash revert to any commit (the latest commit always dirty).
Git Remote
$ git push -u origin master
Enumerating objects: 7, done.
...
To https://github.com/username/myproject.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
Warning
The command git push origin master --force
for force push to remote repository
that mean it does not use git pull origin
command before push.
Note
Above remote is use http
access, so it always pass username/password after
git push
command. The another way is
use ssh for connect to remote.
Git Fork
Git Fork is the GitHub's feature for task owner of remote repository, it seems like
clone but the repository will be yours. If you want to sync update from original
repository to yours repository, you will add upstream
.
$ git remote add upstream https://github.com/<original_owner>/<original_repo>.git
$ git remote -v
origin git@github.com:Phonbopit/bootstrap.git (fetch)
origin git@github.com:Phonbopit/bootstrap.git (push)
upstream git@github.com:Phonbopit/bootstrap.git (fetch)
upstream git@github.com:Phonbopit/bootstrap.git (push)
Advance Command
Git Revert
Revert specific commit to new commit
Git Merge & Rebase
- Will keep all commits history of the feature branch and move them into the master branch
- Will add extra dummy commit.
- Will group all feature branch commits into one commit then append it in the front of the master branch
- Will add extra dummy commit.
- Will append all commits history of the feature branch in the front of the master branch
- Will NOT add extra dummy commit.
# Rebase all commit from dev branch to main branch
$ git switch dev
$ git rebase main
$ git rebase --continue
$ git switch main
$ git merge dev
$ git branch -d dev
Note
If you want to cancel the rebase process, you can use git rebase --abort
.
Git Rebase Self
Instead, use it for cleaning up your local commit history before merging it into
a shared team branch. git rebase
will use for
- Change a commit message
- Delete/Reorder commits
- Combine multiple commits into one (squash)
- Edit/Split an existing commit into multiple new ones
Warning
Do NOT use Interactive Rebase on commits that you've already pushed/shared on a remote repository.
$ git rebase -i HEAD~3
pick adfa804 Update config.yaml
pick 81529d3 update config.yaml
pick 3d8cc7a Update config.yaml
# Rebase 5a30adf..ae76b2e onto 5a30adf (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
:q!
$ git rebase --abort
$ git log --oneline
ae76b2e (HEAD -> master, origin/master) USE OURS ON CONFLICT FILE
81529d3 update config.yaml
3d8cc7a Update config.yaml
adfa804 Update config.yaml
5a30adf ADD CONFIG
4e133da YOUR MESSAGE
Note
When you want to control commit with rebase, git rebase master --interactive
Note
If you want to squash all commit together, you can use git merge --squash "<branch>"
command. (Or git rebase -i --autosquash
)
Git Conflict
Note
Above command can use opposite option, like git checkout --theirs config.yaml
.
Or use it together with merge strategy,
git merge --strategy-option ours
git merge --strategy-option theirs
Git Cherry Pick
If you want to take some commit (such as bug fix commit) from another branch to your branch (Allows you to select individual commits to be integrated).
Cherry Pick fixed file from dev to main branch
$ git add <fix-filename>
$ git commit -m "bug fix"
$ git switch main
$ git log dev --oneline
<commit-hash> (dev) bug fix
...
$ git cherry-pick "<commit-hash>"
Note
git does not that delete commit from source branch and in your branch will be exists that commit in new id.
Git Submodules
Git Submodule help you to develop main project together with subproject and separate the commits of subproject from main project.
The file .submodule
is configuration of git submodule
that keep project’s URL,
local subdirectory, and subproject branches that was tracked.
$ git submodule add -b master https://github.com/username/module sub-project
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: sub-project
$ cd sub-project
sub-project$ ls
README.md ...
$ cat .gitmodules
[submodule "sub-project"]
path = sub-project
url = https://github.com/username/sub-project.git
branch = master
Note
When you already push, you will see submodule in main project repository and the submodule does not keep the source code but it keep hash commit number of submodule.
$ git clone https://github.com/username/mainproject.git
$ cd sub-project
sub-project$ ls
sub-project$ git submodule init
sub-project$ git submodule update
Cloning into '/username/mainproject/sub-project'...
Submodule path 'sub-project': checked out 'a5635f67626c1c224e733fe407aaa132b5e5d1e3
Note
The git clone --recurse-submodules "<repository-url>"
is auto initialize
and update submodules.
git submodule update --init --recursive
Note
git submodule update --remote
will auto fetch and merge with track branch. If you do not set trank, you will use
username/myproject$ git config -f .gitmodules submodule.sub-project.branch develop
username/myproject$ cat .gitmodules
[submodule "sub-project"]
path = sub-project
url = https://github.com/username/sub-project.git
branch = develop
Optional, git submodule update --remote --merge
or git submodule update --remote --rebase
username/myproject/sub-project$ git commit -am 'update readme.md'
username/myproject/sub-project$ git push
username/myproject/sub-project$ cd ..
username/myproject$ git commit -am 'update submodule'
username/myproject$ git push
NOTE: You can push along with the main project, where the submodule is pushed before the main project is pushed using the command
git push — recurse-submodules=on-demand
username/myproject$ git submodule deinit -f sub-project
> Cleared directory 'sub-project'
> Submodule 'sub-project' (https://github.com/username/sub-project.git) unregistered for path 'sub-project'
username/myproject$ rm -rf .git/modules/sub-project
username/myproject$ git rm --cached sub-project
> rm 'sub-project'
username/myproject$ rm .gitmodules
username/myproject$ git commit -am "REMOVED submodule"
> [master 66b1703] removed submodule
> 2 files changed, 5 deletions(-)
> delete mode 160000 sub-project
username/myproject$ git push origin master
Git Reflog
A protocol of HEAD Pointer movements. Reflog is a mechanism to record when the tip of branches is updated. This command is to manage the information recorded in it.
ใช้แสดง Log ของการเปลี่ยนแปลงใน HEAD ของ Local Repository มันเหมาะสำหรับการค้นหางานที่สูญหายไป
username/myproject$ git reflog --all
> ae76b2e (HEAD -> master, origin/master) HEAD@{0}: rebase -i (abort): updating HEAD
> 81529d3 HEAD@{1}: rebase -i (start): checkout HEAD~3
> ae76b2e (HEAD -> master, origin/master) refs/remotes/origin/master@{0}: update by push
> ae76b2e (HEAD -> master, origin/master) refs/heads/master@{0}: commit (merge): USE OURS ON CONFLICT FILE
> ae76b2e (HEAD -> master, origin/master) HEAD@{2}: commit (merge): USE OURS ON CONFLICT FILE
> 81529d3 refs/heads/master@{1}: commit: update config.yaml
> 81529d3 HEAD@{3}: commit: update config.yaml
> adfa804 refs/heads/master@{2}: reset: moving to HEAD~1
> :
Git Blame
Use to track change inline of file.
$ git blame config.yaml
5a30adf5 (usernaem 2022-03-06 13:52:04 +0700 1) env:
adfa8044 (usernaemDEV 2022-03-06 19:30:39 +0700 2) develop: "/dev"
adfa8044 (usernaemDEV 2022-03-06 19:30:39 +0700 3) remote: "/remote"
81529d32 (usernaem 2022-03-07 11:19:06 +0700 4) production: "/prod"
Git Bisect
Start bisect
username/myproject$ git bisect start
username/myproject$ git bisect bad "<commit-start>"
username/myproject$ git bisect good "<commit-end>"
Unittest until the latest commit exists
username/myproject$ run app
username/myproject$ git bisect bad
> Bisecting: 7 revisions left to test after this (roughly 3 steps)
> [12sasa53261sdfas4235sdab721c2405abv0*****] COMMIT MESSAGE
...
username/myproject$ run app
username/myproject$ git bisect bad
> Bisecting: 0 revisions left to test after this (roughly 0 steps)
> [jk1p1634sda78v93kla13asdfscc23140030*****] COMMIT MESSAGE
username/myproject$ git bisect bad
> 5a30adf5d4f184fd4586891e26d6826ab66***** COMMIT MESSAGE
> commit 5a30adf5d4f184fd4586891e26d6826ab66*****
> Author: username <username@email.com>
> Date: Sun Jan 01 00:00:00 1999 +0700
>
> COMMIT MESSAGE
username/myproject$ git show 5a30adf5d4f184fd4586891e26d6826ab66*****
If found the bug success, you should exit bisect first
Note
git bisect log
will show the log of bisect, should use this command before
reset.