4.4. Git#
4.4.2. Git config#
4.4.2.1. Get git info#
# check version
git --version
# help
git --help
4.4.2.2. Modify config#
# view list config
git config --list
# user.name
git config --global user.name <name>
# user.email
git config --global user.email <email>
4.4.2.3. Git authenticate account#
Authenticate with GitHub CLI then run gh auth login
in cmd
4.4.3. Git-flow#
Master/Prod/Main: branchs có sẵn trong git và là branchs chứa mã nguồn khởi tạo của ứng dụng và các version đã sẵn sàng để realease cho người dùng có thể sử dụng (đặt Tag trên mỗi version). Thường cấu hình cho manage tương tác. Đây là branch dùng cho sản phẩm chính thức. Đây luôn là branch ổn định nhất và nó chưa lịch sử các lần release của dự án
Hotfix: Khi sản phẩm trên
master
branch của chúng ta gặp phải trục trặc và cần có bản vá ngay lập tức thì ta sẽ tạo rahotfix
branch. Branch này tương tự nhưrelease
branch nhưng nó được tạo ra từ master branch thay vì từdevelop
branch nhưrelease
(Chú ýhotfix
branch cũng cần được gộp lại vớimaster
branch vớidevelop
branch để các versiondevelop
tiếp theo đã được fix bug từ bảnhotfix
), teamlead sẽ tạo branchshotfix
base trên branchsMaster
để hotfix sau đó merge lại vàoMaster
(thường thì sẽ không được thay đổi trược tiếp mã nguồn trên branchmaster
nên phải lam cách này)Release: Trước khi Release một phần mềm, dev team cần được tạo ra để kiểm tra lại lần cuối trước đi release sản phần để người dùng có thể sử dụng (Thuông thường mã nguồn tại thời điểm này sẽ tạo ra bản build để test và kiểm tra lại bussiness). Khi
develop
branch đã có đủ số tính năng cần thiết để có thể release, ta có thể tạo branch mới với tên quy ướcrelease/tên_version
. Khi đến thời điểm release ứng dụng, teamlead sẽ merge lên branchsmaster
để release cho ngời dùng.Develop: Được khởi tạo từ
master
branches để lưu lại tất cả lịch sử thay đổi của mã nguồn, là nhánh dùng cho sản phẩm trong quá trình phát triển.Develop
branchs là merge code của tất cả các branchsfeature
. Khi dev team hoàn thành hếtfeature
của một topic, teamlead sẽ review ứng dụng và merge đến branchsrelease
để tạo ra bản một bản release cho sản phẩm.Feature: Được base trên branchs
Develop
. Mỗi khi phát triển một feature mới chúng ta cần tạo một branchs để việt mã nguồn cho từng feature. Khi có một feature mới dev tạo một branchs mới (thường đặt theo tên feature/<tên feature đó>) base trên branchsDevelop
để code cho feature đó. Sau khi code xong, dev tạo merge request đến branchsdevelop
để teamlead review mà merge lại vào branchsDevelop
. (Lưu ý: các Feature không được phép gộp trực tiếp với master branch)
Ngoài ra còn một số branchs mà chúng ta thường tạo ra tùy vào yêu cầu của dự án:
Pre-pro: môi trường chưa mã nguồi của bản buil chạy trên môi trường user test,
QC: Môi trường chứa mã nguồi của bản build chạy trên môi trường test,
BugFix: để chứa mã nguồn khi thực hiện công việc fix bug.
Git-flow là một set of command của git, để thực hiện dự án theo đúng git-flow Tham khảo cheatsheet về git-flow
# khởi tạo một git-flow cho một project, Lệnh này sẽ tạo ra hai branch ban đầu là master và develop
# Bạn sẽ cần trả lời một số câu hỏi cho việc thiết lập git-flow sau câu lệnh khởi tạo
git flow init
# tạo một feature: Sẽ tạo ra một nhánh mới có tên dạng feature/<tên-feature> từ nhánh 'develop' và tự động chuyển sang nhánh mới này
git flow feature start <tên-feature>
# Sau khi feature đó được thực hiện xong, ta có thể công bố feature đó lên remote server để mọi người cùng có thể cập nhật
# Khi bạn làm việc với những người khác trên cùng một chức năng, bạn sẽ cần đẩy (push) phần mã nguồn của bạn cho chức năng đó lên máy chủ (remote) để những người khác có thể kéo về (pull) được.
git flow feature publish <tên-feature>
# pull feature của người khác về
git flow feature pull REMOTE_NAME MYFEATURE
# Để tiến hành gộp branch đó vào develop branch ta dùng lệnh
# merge to "develop" + del "feature" branch + checkout "develop" branch
git flow feature finish <tên-feature>
# Tạo ra nhánh 'release' từ nhánh 'develop' để bắt đầu một phát hành mới
git flow release start <verion-no>
# Để công bố phần code 'release' của mình cho các thành viên khác
git flow release publish <verion-no>
# Để tiến hành merge bản release đó vào master branch và develop branch
# = merge "release" to "master" + tag "master" theo "release" + merge "release" to "dev" + del "release"
git flow release finish <version-no>
# Để tạo một bản "hotfix" ta dùng lệnh
git flow hotfix start <tên-hotfix>
# Sau khi bản "hotfix" hoàn thiện ta có thể tiến hành merge lại với "master" branch và "develop" branch như sau
git flow hotfix finish <tên-hotfix>
4.4.4. Github-flow#
Việc thao tác, vận dụng với Git-flow khá lằng nhằng, nên GitHub-flow đã đơn giản nó đi rất nhiều
Github Flow là một quy trình đơn giản dựa trên các branch với mục đích hỗ trợ team và các project được deploy một cách thường xuyên, automated deployments
Gitflow thường sử dụng cho các product có tần suất release ít hơn Github-flow,
GitHub-flow bao gồm nhánh master và nhánh feature.
Từ nhánh master dùng cho Product, tạo 1 nhánh có tên phù hợp với mục đích. (ở đây gọi là feature, gần giống với _feature/hotfix ở git-flow)
Làm việc trên nhánh feature đã tạo, sau khi hoàn thành công việc thì
push
lên nhánh remote.Sử dụng chức năng tạo
Pull Request
của GitHub, sau khi review thìmerge
vào nhánh master.Sau khi
merge
vào nhánh master thì lập tức đượcdeploy
lên Product
4.4.5. Git command#
4.4.5.1. Create new repo#
4.4.5.1.1. init#
# install git for new project
git init
4.4.5.1.2. clone#
# clone repo from link
git clone <link.git - HTTPS>
4.4.5.1.3. connect to remote#
# set new remote với tên là "origin", tạo new repo từ github.com xong copy paste SSH url của repository
git remote add origin <remote_url>
# Verifies the new remote URL
git remote -v
4.4.5.2. File change#
4.4.5.2.1. file’s status#
4 type of status: Untracked
–> Unmodified
–> Modified
–> Staged
(Untracked) ------------------------------add-------------------------------------->>(Staged)
(Untracked) <<----remove----- (Unmodified) -----edit---->> (Modified)-----stage---->>(Staged)
(Unmodified) <<------------commit----------------------(Staged)
4.4.5.2.2. status#
# check status
git status
# check status each file
git status -s
4.4.5.2.3. add#
# Thêm tất cả thay đổi
git add -A
# track all file (exclude file/folder begin ".")
git add *
# track all file (include file/folder begin ".") , trừ xóa file
git add .
# add file from untracked to status
git add <filename>
# Thêm tất cả các file có phần mở rộng .c
git add *.c
4.4.5.2.4. commit#
Việc thực commit
là thao tác đưa toàn bộ nội dung trong staged
vào dữ liệu của Git
- nó tạo ra ảnh chụp toàn bộ thư mục làm việc ở thời điểm đó.
Như sơ đồ trên nếu đã commit thì nó chuyển file từ trạng thái staged
sang unmodified
# commit include the message
git commit -m "C0 - Khoi tao du an"
# commit, nhưng sửa lại commit message ngay trước đó
git commit --amend -m "Thông báo ..."
Xóa commit khi commit nhầm
# Tuỳ vào từng trường hợp mà ta có 3 cách sau để đưa lịch sử commit về như cũ
# 1. Chỉ đưa HEAD về như cũ
git reset --soft HEAD~
# 2. Đưa HEAD và index về như cũ
git reset HEAD~
# 3. Đưa cả index, working tree về 1 commit trước đó
git reset --hard HEAD~
Hồi phục commit đã xóa
# Xem lại toàn bộ lịch sử commit
git reflog
# Chọn commit muốn phục hồi và khôi phục lại
# git reset --hard HEAD@{2}
git reset --hard <commit>
Xóa bỏ 1 vài commit gần đây
# tạo ra một commit mới đảo ngược lại những thay đổi trong commit được chỉ định
git revert <commit-hash-code>
4.4.5.2.5. log#
# check log commit
git log --oneline
# xem log nhánh master của remote origin
!git log --oneline origin/master
4.4.5.2.6. diff#
check sự khác nhau nội dung trong thư mục đang làm việc, staged với commit cuối
Nó cho biết bản có màu đỏ là bản gốc (ở commit cuối), bản có màu xanh là bản đang sửa đổi.
# Kiểm tra thay đổi giữa hai commit
git diff commit1 commit2
# Kiểm tra sự thay đổi của hai nhánh
git diff branch1 branch2
4.4.5.2.7. rollback#
Chuyển trạng thái file về commit trước đó / phục hồi file
# chuyển về commit trước
git checkout -- <tên file>
# phục hồi file test2.html nếu xóa
git checkout [hash] filename # khôi phục lại filename
git reset HEAD test2.html
git checkout -- test2.html
4.4.5.3. Branch command#
# check current brancha
git branch
# tao branch mới
git branch <branch_name>
# switch to other branch
git checkout <branch>
# add and switch new branch
git checkout -b <branch>
# rename branch
git branch -m <newname>
# delete branch remotely
git push origin --delete <remoteBranchName>
# Xóa branch đã tồn tại
git branch -d BRANCH_NAME
# Xóa branch có commit nhưng chưa được merge
git branch -D BRANCH_NAME
Phục hồi branch đã xóa
# Xem lại toàn bộ lịch sử commit
git reflog
# Từ các commit này, chọn rồi tạo branch mới
git branch <tên branch> <commit>
4.4.5.4. Repository command#
Ưu tiên sử dụng luồng Git-flow hoặc github-flow ở trên.
4.4.5.4.1. fetch#
git fetch
tải xuống các nội dung từ Remote repository mà không làm thay đổi trạng thái của Local repository (các dữ liệu như commit, các file, refs), git sẽ thu thập và lưu trữ những thay đổi mới từ các branch của Remote repository về máy tính của bạn, nhưng không hợp nhất chúng với Local repository.
Với git fetch
, bạn có thể theo dõi các commit
người khác đã cập nhật lên server, đồng thời nắm bắt được những thông tin khác nhau giữa remote và local.
# Tải về thông tin của tất cả các nhánh của remote có trong folder "origin"
git fetch origin
# Get all
git fetch --all
# tải 1 nhánh cụ thể
git fetch origin <branch>
4.4.5.4.2. merge#
merge
sẽ tạo ra một commit
mới là kết hợp từ 2 commit
cuối cùng của 2 nhánh cần gộp vào với nhau. Log commit
sẽ không bị thay đổi và thứ tự các commit
sẽ được sắp xếp theo thời gian tạo commit
.
==>
# chuyển nhánh "master"
git checkout master
# Lấy code mới nhất về nhánh master trên local
git pull origin master
# merge "feature1" into current branch (master)
git merge feature1
Lưu ý khi merge: Không nên merge
trực tiếp code vào develop
branch, mà hãy tạo và push
lên feature
branch, sau đó sử dụng merge request
:
tạo merge request để teamlead hoặc review có thể review mã nguồi trước khi merge để đảm bảo tính toàn vẹn của mã nguồn
người review sẽ comment trực tiếp cần thay đổi lên merge request để giảm thời gian trao đổi tăng tính hiệu quả khi làm việc nhóm
tạo merge request để lưu lại lịch sử thay đổi của mã nguồi.Khi có vấn đề về lỗi, chất lượng phần mềm…. chúng ta có thể xem lại tất cả những sự thay đổi trên từ dòng code ( việc này có thể kiếm tra bằng cách kiểm tra trên từng commit nhưng commit thì rất nhiều)
đây còn là nơi để lưu lại các comment của người review, các lỗi thông thường để các member sao không còn mắc lại lỗi cũ và là nơi để học hỏi code lẫn nhau thông qua việc xem lại sự thay đổi từng dòng code của member khác.
Để tránh conflict code, nên thường xuyên merge code ở branchs về để đảm bảo code hiện tại là mới nhất, merge code của branchs trước và sau khi code nếu có conflict thì merge conflict trước khi tạo merge request.
Thông thường thì tất cả các thay đổi về mã nguồi của branchs develop
, release
, master
đều thông qua merge request (trừ mã nguồn lúc khởi tạo dự án).
4.4.5.4.3. rebase#
rebase
sẽ đưa toàn bộ branch Feature lên trên top branch master
, làm thay đổi lịch sử commit
.
==>
# Chuyển sang nhánh master
git checkout master
# Lấy code mới nhất về nhánh master trên local
git pull origin master
# Quay lại branch bạn muốn bổ sung phần thay đổi của master mới nhất trước khi chạy đến các commit của BRANCH_NAME
git checkout BRANCH_NAME
# BRANCH_NAME sẽ được bắt đầu bằng last commit của master, rồi mới chạy các commit tiếp theo của BRANCH_NAME
git rebase master
Nếu bị conflict khi rebase
# Kiểm tra các file bị conflict
git status
# Sửa các file bị conflict (sửa bằng tay)
# Sau khi sửa conflict, dùng lệnh add để phản ảnh sự điều chinhr
git add FILE_PATH
# Sau khi sửa conflict, tiếp tục lại lệnh rebase
git rebase --continue
# Hủy rebase
git rebase --abort
4.4.5.4.4. cherry-pick#
cherry-pick
tương tự với merge
và rebase
là lấy thay đổi từ một branch này và gộp vào branch khác, tuy nhiên cherry-pick
chỉ gộp một commit được chỉ định từ một nhánh khác vào nhánh hiện tại trong khi merge
và rebase
sẽ gộp toàn bộ các commit lại.
Để sử dụng cherry-pick
, ta cần xem lại log
các commit sau đó lấy mã hash của commit cần được cherry-pick
và checkout
sang nhánh cần được gộp commit của mã hash kia và thực hiện lệnh:
git cherry-pick <commit-hash-code>
Ví dụ lấy commit C
từ nhánh master gộp vào nhanh cherry-pick:
===>
4.4.5.4.5. pull#
pull
= fetch
+ merge
git pull <tên-remote> <tên-remote-branch>
4.4.5.4.6. push#
push local repository to remote repository
# set new remote với tên là "origin", tạo new repo từ github.com xong copy paste SSH url của repository
git remote add origin <remote_url>
# Verifies the new remote URL
git remote -v
# add file to stage status
git add .
# commit file to git snapshoot with the message comment with push
git commit -m "initial commit"
# đẩy từ local repo lên remote repo với folder tên "origin"
git push origin <remote branch>
# force push the file is in working
git push origin <branch> --force
4.4.5.5. git stash#
Khi muốn tạm dừng công việc hiện tại và chuyển sang một branch khác. git stash
cho bạn khả năng lưu lại trạng những thay đổi mà bạn đã tạo ra mà không cần thiết phải commit nó giúp bạn có thể dễ dàng chuyển sang nhánh khác làm việc và sau đó quay lại và tiếp tục những gì bạn đang làm ở nhánh đó
# Để lưu được những thay đổi mà không cần commit nó
git add .
# Tạm thời lưu lại các phần công việc còn đang làm dở
git stash -u
# xem lại các thay đổi đã lưu
git stash list
# Chuyển sang một branch khác và làm việc
git checkout -b other-branch
#### ~làm việc, làm việc, làm việc~
git add <các file cần thiết>
git commit -m "commit message"
# Trở về branch cũ
git checkout origin-branch
# Lấy lại các nội dung công việc đang làm dở trước đó
git stash pop
# Để xóa toàn bộ những lần đã lưu
git stash clear
# Để drop một lần lưu chỉ định
git stash drop 'stash@{n}'
4.4.6. Git ignore#
File .gitignore sử dụng để chỉ định các file/folder mà sẽ untrack từ git. Trong file .gitignore sẽ là list danh sách các TH:
Một file cụ thể cần ignore: example.exe
Một folder cụ thể cần ignore: example_folder/
Dấu
!
phía trước có ý nghĩa phủ định: !abc/example.exeSử dụng 1
*
để tìm các file có cùng định dạng.
Ví dụ 1:
*.xml
(ignore tất cả các file.xml
trong project)
Ví dụ 2:
config/*.xml
(ignore các file*.xml
trong thư mục config)
Sử dụng
**
để có hiệu lực cho các thư mục không cần định rõ tên.
Ví dụ 1:
**/foo
(ignore tất cả file/thư mục có tên là “foo” ở mọi nơi trong project)
Ví dụ 2:
folder/**
(ignore tất cả các file bên trong folder)
Tips:
Sử dụng
#
để comment và có thể để cách dòng cho dễ đọc.Khi ignore thư mục nên có dấu
/
ở sau tên thư mục để nhận biết đó là thư mục, nếu không nó có thể là coi là thư mục hoặc file hay symbolic link.Cách tạo gitignore
# create file gitignore
touch .gitignore
# các file trong git cache vẫn sẽ được git quản lý mặc dù đã list trong gitignore, phải xoá git cache (xong add các file lại để commit)
git rm -r --cached .
4.4.8. Git CI/CD#
CI (Continuous Integration) và CD (Continuous Delivery) tức là quá trình tích và triển khai hợp nhanh và liên tục, là quá trình tự động thực hiện các quá trình build
, test
, release
, deploy
khi có các trigger như commit/merge
code lên một branch định sẵn hoặc có thể là tự động chạy theo một lịch cố định
khi hoàn thành một feature thì teamlead tạo merge request rồi
merge
vào branch develop, đúng 5h chiều hàng ngày hệ thống sẽ tự độngbuild
,test
,quét sonar
…. vàdeploy
lên develop eviroment (quá trình này là CD).(không trigger merger code để deploy với branch này vì code được merge vào đây liên tục nếu trigger merger code sẽ dẫn đến việc build liên tục, làm chậm hệ thống)Với branch prepro thì sẽ được trigger mỗi lần có sự thay đổi về code sẽ tự động thực hiện các bước như với branch develop.
Với branch master thì có hơi khách một chúc, Git cũng sẽ tự động trigger và tiến hành các bước
build
,run unit test
,quét sonar
…. nhưng không tiến hànhdeploy
(quá trình này chỉ là CI) lên server mà chỉ đượcdeploy
khi có confirm từ một người có quyền hoặcdeploy
bằng tay để đảm bảo quá trình delevery sản phẩm không xảy ra lỗi và đúng với thời gian khách hàng mong muốn.
4.4.8.1. GitHub Actions#
Github actions được sinh ra để hỗ trợ việc tự động hóa các tác vụ trong vòng đời của một phần mềm. Git actions hoạt động theo hướng sự kiện, nghĩa là nó sẽ thực hiện một loạt commands đã được định nghĩa sẵn khi có một sự kiện được xảy ra.
Ví dụ như, bạn có thể cấu hình để mỗi khi có người tạo một
mergers request
lên một repository nào đó hệ thống sẽ tự động runcommands
để run các unit test case của bạn.
4.4.9. Git Submodule#
1. Bản chất: Submodule là một con trỏ đến một commit cụ thể của repo Child (C), chứ không phải là bản sao hoàn chỉnh của repo Child trong repo Parent (P).
2. Thêm submodule
git submodule add https://github.com/example/repo-c.git <C folder>
git commit -m "Add submodule C"
3. Cách lưu trữ: Repo C vẫn là một repository độc lập, nhưng repo P chỉ lưu trữ một tệp .gitmodules
chứa thông tin về submodule và commit hash của repo C. Khi cập nhật repo B, repo A chỉ lưu commit hash mới của repo B chứ không lưu trực tiếp nội dung thay đổi. Do đó:
Khi clone repo P, submodule C không tự động tải về, cần chạy lệnh:
git submodule update --init --recursive
Nếu muốn luôn cập nhật submodule C tự động về commit mới nhất khi pull repo P, bạn có thể chạy:
git submodule update --remote --merge
4. Cập nhật (Push/Pull) repo C trong repo P
Pull
cd <C folder>
git pull origin main
cd ..
git add C
git commit -m "Update submodule C"
Push
cd <C folder>
git status # Kiểm tra trạng thái
git add . # Thêm tất cả thay đổi
git commit -m "Cập nhật code trong repo C"
git push origin <branch_name>
cd ..
git add <C folder>
git commit -m "Cập nhật submodule C lên commit mới nhất"
git push origin <branch_name>
5. Xóa submodule nếu không cần nữa
git submodule deinit -f -- <C folder>
git rm -rf C
rm -rf .git/modules/C