Những tips cơ bản về Git
I. Các khái niệm cơ bản của Git
Working directory
Staging Area
Local/Remote Repo
Con trỏ HEAD
Working directory (hoặc working tree): Là thư mục trên máy tính của developer chứa các file và thư mục của dự án.
Khi thay đổi file source code, git sẽ theo dõi sự thay đổi và phân loại vào các trạng thái sau: Untracked, Unmodified, Modified, Staged
-Untracked: các file được tạo mới
-Unmodified: các file cũ không bị sửa đổi
-Modified: các file cũ bị sửa đổi
-Staged: các file được add vào index (aka staging area)Staging Area (hoặc index): Là khu vực trung gian giữa working directory và local repo
Khi thực hiện lệnh git add thì các file được thêm mới (untracked) hay được sửa đổi(modified) sẽ được chuyển vào staging areaLocal/Remote Repo
Local Repo: Kho chứa mã nguồn dự án ở máy tính cá nhân, để đưa source code lên local repo sử dụng lệnh git commit
Remote Repo: Kho chứa mã nguồn được lưu trữ trên internet như Github, Gitlab, để đưa source lên remote repo sử dụng lệnh git push
Tên mặc định của remote repo là originCon trỏ HEAD
Trỏ đến commit hiện tại trên nhánh đang làm việc, thường là commit cuối cùng của nhánh. Khi chuyển nhánh bằng lệnh git checkout, con trỏ HEAD sẽ thay đổi để trỏ đến commit cuối cùng của nhánh mới

Notes: Đối với các files mới tạo không được tracked bởi Git nên Git không có cách nào để xác định được thay đổi của các files đó. Do vậy khi dùng git diff sẽ không thấy được các files này.
Để các files này hiện ra khi chạy git diff thì cần chạy git add -N (hoặc --intent-to-add). Lệnh này chưa add các files vào index mà chỉ để git biết các files untracked này sẽ trở thành modification thì khi chạy git diff nó mới hiện ra.
II. GitFlow
GitFlow thực ra chỉ là các uy ước về việc sử dụng các branches và cách hợp nhất các branches nhằm giúp team dự án có thể làm việc đồng bộ và tiện lợi trong quá trình release các tính năng. GitFlow được biết đến phổ biến có lẽ ra của Vincent Driessen. GitFlow nói đến việc sử dụng các nhánh master (main), develop, feature, hotfix, release. Tuy nhiên, trong thực tế dự án, việc sử dụng các nhánh không nhất thiết tuân theo flow như vậy. Đối với các dự án Agile, việc quyết định các User Story nào sẽ được release, User Story nào cần lùi lại có thể gây ra khó khăn nếu chúng ta baseline code của các User Story này không phải từ nhánh main mà lại baseline từ nhánh develop. Hoặc đối với các dự án phát triển multi-vendor, mỗi vendor phát triển một tính năng thì việc dùng chung nhánh develop để tích hợp thì có thể được nhưng việc tách các nhánh feature để phát triển phải nên xuất phát từ nhánh master(main).
Thông thường thì nên có 3 loại nhánh chính để làm việc:
- Nhánh master(main) để phục vụ deploy cho môi trường production
- Nhánh featuređể phát triển các tính năng, nhánh này cần tách từ master (main)
- Nhánh taskđể phát triển các phần việc của feature đó, tách ra từ feature và sau khi review OK sẽ merge PR lại từ nhánh task → feature.
Ngoài ra, có thể định nghĩa một số nhánh bổ sung. Ví dụ cùng các nhánh cùng level như:
- feature, hotfix
- task, bugfix, chore, cicd
Trước khi release một feature lên các môi trường staging hoặc production, nên tạo các nhánh tạm phục vụ release ngày hôm đó có suffix YYYYMMDD. Mục đích tạo các nhánh này để merge các feature cần release vào chung với nhau và xử lý resolve conflict nếu có tại chính nhánh tạm này. Không nên để khi merge vào main mới resolve conflict.

III. Một số lệnh git
Ở hình trên cũng có mô tả một số lệnh cơ bản khi làm việc với git. Ngoài ra, có thêm một số lệnh có thể hữu ích trong một số trường hợp như dưới đây:
Đang ở nhánh A, đồng đội push code lên nhánh origin nhánh B và muốn merge phần mới nhất của nhánh B vào
git checkout feature-a
git pull origin feature-b(thay vì phải checkout sang feature-b rồi pull về local rồi lại switch sang feature-a và chạy lệnh git merge feature-b)Muốn diff sourcce giữa commit hiện tại và một commit-X hoặc nhánh B
git diff --name-status HEAD~1 > diff.txt(diff với commit trước đó, và lấy tên các file thay đổi và status là ADD hay MODIFIED)
git diff --name-status commit-X > diff.txt(diff với commit-X, và lấy tên các file thay đổi và status là ADD hay MODIFIED)
git diff --numstat commit-X > diff.txt(diff với commit-X, và lấy số lượng Line of Codes)
git diff --name-only commit-X > diff.txt(diff với commit-X, và chỉ lấy tên files)
git diff --name-only --diff-filter=A commit-X > diff.txt(diff với commit-X, và chỉ lấy tên files được ADD)Đổi tên nhánh
git branch -m new_branch_name
git push origin :old_branch_name new_branch_nameXóa nhánh
git branch -D feature-X
git push origin --delete feature-XCopy source từ nhánh A sang nhánh B
git checkout feature-b(chuyển sang nhánh B)
git checkout feature-a -- .(Lệnh checkout này không chuyển sang nhánh A mà nó sẽ ở lại nhánh B và copy source từ nhánh A vào nhánh hiện tại. Nếu dùng git checkout mà không có--là sẽ nhảy sang nhánh mới. Dấu.là copy toàn bộ files, nếu muốn copy một file cố định thì dùnggit checkout feature-a -- file-1)
git commit -m "message"
git pushCopy chỉ những file khác nhau giữa 2 nhánh (từ nhánh A sang nhánh B)
git checkout feature-b
git checkout feature-a -- $(git diff --name-only feature-a feature-b)Revert một merged commit
git revert -m 1 commit_idRevert nhiều commits
commit_a ← commit_b ←commit_c ←commit_d ← HEAD
Cần revert các commit b,c,d
git reset --hard commit_a(Đưa con trỏ HEAD về commit_a)
git reset --mixed/soft commit_d(Đảo ngược các commit_b,c,d)
git commit -m “message”
git push