Skip to main content

2.5. Essential Commands: SSL/TLS certificate và quản lý source code với Git

Mục lục​


1. SSL hay TLS và certificate dùng để làm gì?​

Cần một lời làm rõ trước đã. Thứ được gọi là SSL trong quá khứ thì ngày nay thực chất là TLS, nhưng người ta vẫn gọi nó bằng cái tên cũ đã không còn đúng nữa.

SSL viết tắt của Secure Sockets Layer, TLS viết tắt của Transport Layer Security. Vì sao vẫn dùng tên cũ sai? Vì SSL được dùng trong một thời gian rất dài, và cái tên đó bám lại trong nhiều tool và nhiều tài liệu, kể cả sau khi phần lớn certificate đã chuyển sang TLS. Có thể coi TLS là một bản nâng cấp của SSL: SSL có nhiều vấn đề bảo mật, và TLS vá lại khá nhiều lỗ hổng đó.

Certificate tồn tại để xử lý hai vấn đề. Nghĩ tới lúc nhập password trên một website, hoặc nhập thông tin thẻ tín dụng:

  1. Không có gì bảo đảm dữ liệu đó đang được gửi tới website hợp pháp, thay vì tới một bản clone do kẻ tấn công dựng lên.
  2. Không có gì bảo đảm không ai lấy được những thông tin đó trong lúc chúng đi qua network.

Certificate xử lý cả hai: nó authenticate website, và nó encrypt network traffic giữa user và website.

Authentication nghĩa là website chứng minh được bằng mật mã học với browser rằng nó là thật. Nó chứng minh nó đúng là kodekloud.com chứ không phải một bản clone. Certificate cũng được dùng để làm kết nối giữa user và kodekloud.com trở thành riêng tư: mọi dữ liệu trao đổi với website đều được mã hoá.

What a TLS certificate doesAuthenticationThe site proves cryptographicallythat it really is kodekloud.comand not a clone of itEncryptionEverything exchanged with thesite travels encrypted, so nobodycan steal a password on the wayopenssl reqmakes key.pemand req.pemSend the CSRto a certificateauthorityThe CA signs itwith its ownprivate keyBrowserscheck thatsignatureSelf-signing skips the CA: useful inside an office network whereevery machine can be configured to trust the local certificatesx509 is the certificate format used for this on websites

2. Định hướng trong OpenSSL bằng chính command line​

Utility thường dùng trên Linux để tạo và quản lý TLS certificate tên là OpenSSL. Đây lại là một chỗ nữa cái tên SSL cũ còn bám lại: tool tên là OpenSSL nhưng thứ tạo ra bằng nó là TLS certificate.

Tra manual của nó:

man openssl

Tài liệu chỉ ra rằng utility này làm được nhiều việc hơn là chỉ certificate: nó xử lý được rất nhiều phép toán liên quan tới cryptography. Phần cần ở đây là tạo x509 certificate, loại certificate dùng trên website để làm authentication và encryption đã nói ở mục trên.

Rắc rối là lệnh openssl hỗ trợ một số lượng subcommand và option rất lớn, khó nhớ chính xác phải gõ gì cho một task cụ thể. May là có vài mẹo để tự định hướng ngay trên command line.

Trước tiên, xem các subcommand được hỗ trợ:

openssl help

Gõ openssl không kèm gì cũng cho ra cùng output. Chú ý phần đầu có tiêu đề Standard Commands: trong đó có hai subcommand là req và x509, đúng hai thứ cần dùng.

Vì OpenSSL là một tool phức tạp, nó có nhiều manual, mỗi subcommand quan trọng một manual. Xem danh sách manual có sẵn bằng cách gõ man openssl rồi nhấn Tab hai lần:

man openssl<Tab><Tab>

Muốn xem manual của subcommand req thì gõ một trong hai dạng sau, cả hai cho ra cùng một thứ:

man openssl req
man openssl-req

Manual này cho thấy ngay rằng lệnh để sinh certificate có thể phức tạp đến mức nào. Với người mới, rất khó bắt đầu chỉ bằng cách đọc manual và toàn bộ option mà subcommand req hỗ trợ. Nhưng vẫn lấy được vài mẹo hữu ích từ đó: nhấn / rồi gõ EXAMPLES toàn chữ hoa để nhảy tới phần ví dụ, nơi có thể học cách bắt đầu.

Trong phần đó có hai lệnh đáng ghi nhớ, vì hai lệnh đó sẽ được chỉnh lại để sinh certificate signing request và tạo self-signed certificate ở hai mục dưới. Thoát manual bằng q.

Quy trình đúng y như vậy áp dụng được để xem các lệnh của openssl x509.


3. Private key và certificate signing request​

Subcommand req làm việc với Certificate Signing Request. Lý do cần nó: bản thân digital certificate dùng để bảo vệ traffic của website là chưa đủ.

example.com dùng được một certificate để bảo vệ web traffic giữa user và website, chuyện đó không vấn đề gì. Nhưng khi một user truy cập example.com, browser của họ còn cần tin certificate đó. Nó cần một cách để biết chắc certificate là thật, không phải bản giả do kẻ tấn công tạo ra. Cách của nó là kiểm tra xem certificate của example.com có được một certificate authority ký hay không.

Quy trình: certificate được sinh ra ở local rồi gửi tới một công ty làm certificate authority. Họ dùng một private key đặc biệt để ký certificate đó. Khi certificate đã được ký, bất kỳ browser nào cũng kiểm tra được signature và thấy rằng certificate authority đã xác nhận nó, nên nó hợp pháp.

Certificate thường được dùng kèm một secret key. Cả private key và certificate signing request được sinh ra trong một lệnh duy nhất, chính là lệnh thấy trong man page ở mục trên:

openssl req -newkey rsa:2048 -keyout key.pem -out req.pem

Giải thích từng option:

  • -newkey rsa:2048 chỉ thị cho OpenSSL sinh một key thuộc loại RSA trên 2048 bit.
  • -keyout key.pem bảo utility lưu private key vào một file tên key.pem.
  • -out req.pem lưu certificate signing request, tức CSR, vào một file tên req.pem.

Lệnh chạy sẽ hỏi vài câu. Đầu tiên là chọn một password để bảo vệ và mã hoá file private key. Sau đó là một vài chi tiết sẽ được đưa vào signing request: ở bước này đang nói với certificate authority rằng muốn họ ký cái gì, ví dụ một certificate cho một công ty tên KodeKloud, địa điểm ở New York, cùng các thông tin tương tự.

Hai file được tạo ra. Xem nội dung file key:

cat key.pem

# Output (rút gọn):
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQ...
-----END ENCRYPTED PRIVATE KEY-----

Nội dung được encode Base64 nên đọc không ra nghĩa gì. Nhưng dòng đầu và dòng cuối cho biết đây là một private key, và nó đang được mã hoá.

Xem nội dung CSR:

cat req.pem

# Output (rút gọn):
-----BEGIN CERTIFICATE REQUEST-----
MIIC4TCCAckCAQAwgZcxCzAJBgNVBAYTAlVTMREwDwYDVQQI...
-----END CERTIFICATE REQUEST-----

Cũng là Base64, là chính CSR vừa sinh ra. Nhìn vào hai file này ít nhất biết được chúng đại diện cho cái gì.

Ở thế giới thật, file CSR này được gửi tới một certificate authority. Họ kiểm tra và xác minh các chi tiết đã khai, bên gửi chứng minh danh tính của mình, trả một khoản phí, rồi nhận về certificate.


4. Self-signed certificate​

Khi muốn cả thế giới xác thực và tin certificate của mình thì cần tới dịch vụ của một certificate authority. Nhưng còn những tình huống khác. Ví dụ chỉ cần dùng certificate nội bộ trong network của văn phòng, và mọi máy tính trong đó đều cấu hình được để tin các certificate nội bộ của tổ chức. Trường hợp đó làm cái gọi là self-signing certificate: bỏ qua bước sinh CSR và gửi nó tới certificate authority, tự sinh luôn certificate đã được ký.

Lệnh dùng thêm vài option nữa, cũng là để làm ví dụ cho việc tinh chỉnh certificate:

openssl req -x509 -nodes -newkey rsa:4096 -days 365 -keyout myprivate.key -out mycert.pem

Các option được dùng ở đây là -x509, -nodes, -newkey rsa:4096, -days 365 và -keyout.


5. Vì sao cần một version control system như Git?​

Ở thời điểm hiện tại, một project software thường do những đội lớn phát triển, và chuyện đó kéo theo một tập vấn đề riêng.

Hình dung mười developer làm cùng một project. Mỗi người thêm, xóa, sửa code ở những chỗ ngẫu nhiên. Sáng ra, bật máy tính lên, sẵn sàng làm việc: làm sao biết 24 giờ qua có gì thay đổi? Những việc có thể đã diễn ra trong khoảng thời gian đó:

  • Đội testing báo một bug. Một developer đã sửa code ở sáu file để vá bug đó.
  • Một developer khác thêm một feature mới: ba file mới được thêm vào, hai file được sửa.
  • Một người nữa bỏ một feature sẽ không cần ở version tiếp theo của project: hai file bị xóa, một file được sửa.

Đó là một lượng thay đổi khá lớn trong thời gian ngắn, và rất khó theo dõi hết. Các developer có thể thông báo cho nhau qua chat về việc họ đã làm, nhưng cách đó nhanh chóng trở nên lộn xộn, dồn vào mỗi người một đống thông tin phải ghi nhớ.

Nên khi bắt đầu làm việc, cần một cách nhanh để nắm toàn bộ những thay đổi đó: file nào được thêm, bị xóa hay bị sửa, dòng code nào thay đổi, ai sửa những dòng đó, và vì sao họ sửa. Nói ngắn gọn: cần biết phần còn lại của đội đã làm gì. Và khi tự mình sửa, cũng cần một cách thông báo cho đội về việc đã sửa gì và vì sao. Có một phương pháp làm việc đó, cả đội mới cùng làm trên cùng một đoạn code mà vẫn luôn biết chuyện gì đã xảy ra từ lần đăng nhập trước.

Giải pháp là dùng một distributed version control system như Git. Cốt lõi công việc của Git là cho phép một nhóm người lớn cùng làm trên một project software.

Local repository và remote repository​

Trong Git có khái niệm repository: nơi code được lưu, kèm thông tin về từng thay đổi. Là một thành viên trong đội thì thường có hai repository: một local repository và một remote repository.

Local repository là của riêng từng người. Remote repository nằm ở một vị trí trung tâm dùng chung cho cả đội. Khi code trên máy của mình thì làm việc với local repository; khi hài lòng với kết quả thì upload những thay đổi mới nhất lên remote repository.

Ai từng vào GitHub đều đã thấy rất nhiều remote repository: mỗi project ở đó về cơ bản là một remote Git repository. Upload lên remote repository là cách từng thành viên cập nhật project ở một vị trí trung tâm; download từ remote repository là cách từng thành viên thấy được những gì người khác đã làm, nhờ đó cả đội cùng được cập nhật.

💡 Hình dung: remote repository là chỗ cả đội tụ lại và lắp các mảnh ghép mà từng người đang làm. Mỗi thay đổi nhỏ từ các local repository được gom về và tích hợp vào đó.

Muốn cập nhật remote repository bằng những thay đổi mới nhất thì push code từ local lên remote. Muốn lấy những thay đổi mới nhất của đồng đội thì pull từ remote repository về local. Tên lệnh cho hai hành động này khá trực quan.


6. Cấu hình Git và khởi tạo repository​

Git thường có sẵn trên phần lớn các bản Linux hiện đại. Nếu chưa có thì cài:

sudo apt install git

# Output (rút gọn):
git is already the newest version (1:2.34.1-1ubuntu1.10).

Việc đầu tiên sau khi cài là đặt username và email:

git config --global user.name "Aaron"
git config --global user.email "[email protected]"

Đây không phải thông tin đăng nhập. Nó chỉ là thông tin hữu ích cho các thành viên khác: khi có thay đổi trên project và có commit, họ sẽ thấy username và email này và biết ai sửa cái gì.

Tham số --global đặt giá trị ở phạm vi toàn hệ thống, áp dụng cho mọi local Git repository sẽ tạo trên máy này về sau. Bỏ --global đi thì username và email được đặt theo từng repository: repository này dùng một email identity, repository khác dùng một identity khác hẳn.

git init​

Giả sử code của project sẽ nằm trong một directory tên project:

mkdir project
cd project

Giờ cần nói với Git rằng project sẽ nằm ở đây. Bảo nó bắt đầu theo dõi mọi thứ diễn ra trong directory này:

git init

# Output:
Initialized empty Git repository in /home/aaron/project/.git/

init là dạng viết ngắn của initialize. Trong output thấy nó đã tạo một directory ẩn tên .git. Xem nhanh nội dung bên trong:

ls .git

# Output (minh họa):
branches config description HEAD hooks info objects refs

Git lưu toàn bộ thông tin của repository ở đây, từ setting của repository cho tới dữ liệu nó dùng để theo dõi thay đổi code.

Username và email đặt lúc trước được đặt ở phạm vi global. Muốn chọn một identity khác tại chính repository này, không global, thì bỏ tham số --global đi. Thông tin đó được lưu bên trong directory .git tại một file tên config, nên xem setting của local repository rất nhanh và dễ:

cat .git/config

# Output (minh họa):
[core]
repositoryformatversion = 0
filemode = true
[user]
name = Aaron

Hai file code đầu tiên​

Bắt đầu viết code trong directory project: tạo hai file, file1 và file2, mỗi file chứa một dòng text, coi như đây là hai dòng code đầu tiên.

echo "this is the line of code in file1" > file1
echo "this is the line of code in file2" > file2

Về sau, hai dòng text này cho thấy Git giúp theo dõi thay đổi code trong từng file ra sao.

Một ghi chú quan trọng: Git không liên tục theo dõi mọi thay đổi trong directory của project. Mỗi lần có thay đổi, phải tự thông báo cho Git rằng có chuyện vừa xảy ra.


7. Working area staging area và commit​

Có ba bước để sửa code rồi theo dõi thay đổi bằng Git: sửa trong working area, thêm những thay đổi muốn theo dõi vào staging area, rồi commit chúng.

Three steps to track a change in Git1. Working areaThe project directorywhere files are editedGit does not watch iton its owngit add2. Staging areaTell Git which changesbelong in the nextcommit, and git resettakes one back outgit commit -m3. CommitGit takes a snapshot ofthe staged files at thatpoint in time, and git loglists every snapshotStaging is like pointing a phone camera: the shot is framedbut nothing is captured until the shutter button is pressedgit status prints what changed and suggests the next command.git rm deletes a file and stages that removal in one go.

Bước một đã xong rồi: working area chính là directory của project đang đứng, và thay đổi đã được tạo ra lúc thêm hai file cùng text bên trong. Mỗi lần sửa gì trong directory của project là đã sửa working area.

Vì sao cần staging area?​

Bước hai là cách nói với Git về những thay đổi đã tạo ra trên project, cụ thể hơn là những thay đổi nào muốn nó theo dõi trong commit tiếp theo. Vì sao Git không tự kiểm tra working area rồi theo dõi hết mọi thay đổi một cách tự động?

Một lý do là Git không biết được lúc nào thì công việc sửa đã xong. Ví dụ hôm nay thêm 50 dòng code vào một file, nhưng mai mới thêm 50 dòng nữa để hoàn tất. Vậy không muốn Git theo dõi thay đổi dở dang ở mốc 50 phần trăm tiến độ; cần đợi tới lúc thêm xong hết các dòng code.

Lý do nữa: khi sửa 10 file khác nhau, không muốn Git theo dõi thành 10 giai đoạn riêng cho từng file. Mười file đó có thể được sửa chỉ để thêm một feature mới vào project, nên cần theo dõi tất cả như một thay đổi duy nhất trong vòng đời của project, không phải 10 thay đổi riêng lẻ.

git status và git add​

Với project chỉ có hai file thì dễ biết đã sửa gì và cần stage gì. Nhưng project phức tạp thì khác: thêm một feature mới và phải sửa 16 file, vài giờ sau đã quên mất mình sửa những file nào. Git có lệnh cho biết chính xác những gì đã sửa:

git status

# Output (minh họa):
On branch master

No commits yet

Untracked files:
(use "git add <file>..." to include in what will be committed)
file1
file2

nothing added to commit but untracked files present (use "git add" to track)

Nó đã nhận ra cái gì thay đổi, và còn in ra luôn lệnh tiếp theo cần dùng. Thêm hai file vào staging area:

git add file1 file2
git status

# Output (minh họa):
On branch master

No commits yet

Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1
new file: file2

Giờ Git đã sẵn sàng cho bước thứ ba là commit. file1 và file2 đang nằm trong staging area: đã nói với Git rằng đây là những file đã thay đổi và muốn theo dõi, nhưng chưa có gì được theo dõi cho tới khi staging area này thực sự được commit.

💡 Hình dung: stage một thứ trong Git giống như chĩa camera điện thoại vào vật gì đó. Khung ảnh đã được canh, nhưng chưa có gì được chụp. Chỉ khi bấm nút chụp, một tấm ảnh mới được tạo và lưu vào bộ nhớ máy. Git làm đúng việc đó lúc commit staging area: nó chụp lại hình dạng của các file đã stage ở một thời điểm nhất định.

Trong output git status ở trên còn thấy cách unstage một file. Nhưng không nên dùng lệnh git rm cho việc này vì nó có thể gây hậu quả ngoài ý muốn: quên thêm tham số --cached thì có thể xóa luôn file khỏi project thay vì chỉ bỏ nó khỏi staging area. Cách unstage an toàn:

git reset file2

Ở trường hợp này mọi thứ đang ổn nên không chạy lệnh đó, chỉ ghi nhớ là có lựa chọn này khi cần.

Stage nhiều file cùng lúc​

Một số project khá phức tạp, gõ tay tên của hàng chục hay hàng trăm file thì mất rất nhiều thời gian. Có vài lối tắt để stage nhiều file.

Thêm chỉ những file có phần mở rộng HTML trong current directory:

git add '*.html'

Phải dùng dấu nháy trong trường hợp này, để shell Bash không expand ký tự dấu sao và dẫn tới kết quả ngoài ý muốn.

Git cũng stage được trọn subdirectory. Ví dụ muốn thêm một subdirectory tên products trong current directory:

git add products/

Mọi file và subdirectory bên trong directory đó cũng được stage theo. Thêm chỉ những file có phần mở rộng HTML từ subdirectory products:

git add 'products/*.html'

Vẫn dùng ký tự dấu sao nên vẫn cần dấu nháy, vì đúng lý do vừa nói. Ghi nhớ trong đầu: luôn dùng dấu nháy khi dùng ký tự dấu sao.

Những mẹo tương tự cũng dùng được để bỏ nhiều file cùng lúc khỏi staging area, nên một lệnh như sau cũng hợp lệ:

git reset 'products/*.html'

Commit​

Nhiều thành viên trong đội có thể đang làm trên code của project, nên cần giúp họ đỡ việc khi họ xem lại những thay đổi đã tạo ra. Vì mục đích đó, thông lệ chuẩn là thêm một comment cho từng commit, giải thích ngắn gọn vì sao thay đổi được thực hiện. Thêm comment vào commit bằng option -m, viết tắt của message:

git commit -m "add file1 and file2 with the first lines of code"

# Output (minh họa):
[master (root-commit) 9f2c1ab] add file1 and file2 with the first lines of code
2 files changed, 2 insertions(+)
create mode 100644 file1
create mode 100644 file2

Message phải nằm trong dấu nháy, nếu không shell Bash sẽ nhầm: thay vì nhiều từ cách nhau bằng dấu cách, nó tưởng đó là nhiều command-line argument cho option -m. Bọc message trong dấu nháy là cách nói với Bash rằng đây là một argument duy nhất.

Git làm gì lúc commit? Nó xem những gì đã được thêm vào staging area rồi tạo một kiểu snapshot. Nhờ vậy nó hiểu được cái gì thay đổi giữa lần project được sửa trước đó và lần này.

Đây là cơ chế làm nên thứ như trang GitHub của Linux kernel: sau khi một Git commit được tạo ở local repository rồi upload lên remote repository, những người khác thấy chính xác cái gì đã thay đổi. Họ thấy danh sách file được sửa, bao nhiêu dòng được thêm, bao nhiêu dòng bị xóa, và những dòng thay đổi được highlight: màu đỏ là phần bị bỏ đi, tức nội dung cũ, màu xanh là phần được thêm vào, tức nội dung mới.

Với project ở đây, Git nhận ra rằng project đi từ một directory rỗng thành một directory có hai file chứa các dòng text.

Nhắc lại ba bước: sửa working area, tức directory lưu project ở local; nói với Git những thay đổi nào muốn theo dõi bằng cách thêm file và directory vào staging area; và khi đã chuẩn bị xong, bảo Git commit toàn bộ những thay đổi đã thêm vào staging area. Nói cách gọn hơn: bảo Git theo dõi đúng trạng thái này của project, để nó nhớ được mọi trạng thái, tức mọi commit, mà project đã đi qua.

Xóa file và theo dõi việc xóa​

Phần trên chỉ bàn một loại thay đổi là thêm file mới, nhưng còn những loại khác. Ví dụ một project có thể cần xóa bỏ những file không cần thiết.

Tạo file thứ ba rồi stage và commit nó:

echo "this is a buggy feature in file3" > file3
git add file3
git commit -m "add a new feature in file3"

Tới đây hình dung ra rằng feature này nhiều bug và không đáng sửa, nên quyết định bỏ hẳn nó khỏi project. Lúc này project có ba file. Bảo Git bỏ file đó khỏi project:

git rm file3

# Output:
rm 'file3'

Lệnh này làm hai việc. Nó bỏ file khỏi repository, tức khỏi cái gọi là working tree, và liệt kê current directory sẽ thấy file đã biến mất. Nhưng git rm cũng stage luôn thay đổi này cho commit sắp tới: nó stage việc xóa file khỏi project. Xem được việc đó bằng git status, và thay đổi đã sẵn sàng để commit:

git status
git commit -m "remove the buggy feature in file3"

Hai loại thay đổi đã theo dõi được: thêm file mới và xóa file khỏi project. Còn một loại nữa là sửa file cũ, nghĩa là Git theo dõi những dòng code nào thay đổi trong các file. Loại thay đổi đó mở đường sang một feature khác của Git: branch.


8. Branch và lịch sử commit​

Lúc chạy git status và lúc commit, trong output có một dòng kiểu On branch master. Branch là gì?

Project có thể có nhiều version. Giả sử version 1.0 đã được giao cho người dùng, và một phần của đội đang liên tục sửa bug trong version 1.0, nên họ làm trên branch 1.0. Nhưng cùng lúc, đội cũng muốn xây feature mới vào software, nên một phần khác của đội làm trên version 1.1, trên một branch hoàn toàn khác. Nhờ vậy người ta làm được trên hai version, hai branch, mà không chen vào nhau, và Git theo dõi từng branch riêng biệt.

💡 Hình dung: branch là những con đường phát triển khác nhau. Chúng đi theo những hướng gần giống nhau nhưng hơi lệch, và đôi khi chúng được nhập lại với nhau, việc nhập lại đó trong thuật ngữ Git gọi là merging.

Branch master là branch mặc định Git làm việc với. Có thể dùng nó để theo dõi version ổn định của project, version được giao thẳng ra công chúng. Dùng nó thế nào thì tuỳ người.

Giả sử branch master đang theo dõi version 1.0, chứa file1 và file2, và mọi thứ đang ổn. Nhưng cần chuẩn bị một version 1.1 mới và tốt hơn, nên bắt đầu cải thiện code. Không muốn sửa thẳng vào branch master, mà muốn tạo một branch mới. Branch đó cũng không đặt tên là 1.1, mà đặt là 1.1-testing: tên đó nói với cả đội rằng branch 1.1 này còn chưa chốt, đang sửa code và có ý định test software mới trước khi phát hành ra công chúng.

Branches are parallel development roadsmasteradd file1and file2remove buggyfeaturemerge commitHEADgit branch 1.1-testing1.1-testingimprove the line of codein file2git merge 1.1-testinggit branch --list marks the current branch with an asterisk.HEAD points at a commit, and that commit is what the working area shows.

Tạo, liệt kê và xóa branch​

git branch 1.1-testing

Nếu cần xóa một branch:

git branch --delete 1.1-testing

Xem mọi branch có sẵn:

git branch --list

# Output (minh họa):
* master
1.1-testing

Gõ git branch không kèm gì cũng cho ra cùng danh sách. Trong output thấy hiện tại vẫn đang ở trong branch master: dấu sao đánh dấu branch đang được chọn.

Nhưng mục tiêu là thêm feature mới và theo dõi chúng trong branch 1.1-testing, không phải trong master. Chuyển sang branch 1.1-testing:

git checkout 1.1-testing

Sửa code trong branch mới​

Mở file2 bằng editor, nhấn i để bắt đầu nhập text, sửa dòng code, rồi nhấn Escape và gõ :wq để write và quit:

vi file2

Dòng code được đổi thành this is the improved line of code in file2. Sau đó:

git status

# Output (minh họa):
On branch 1.1-testing
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: file2

no changes added to commit (use "git add" and/or "git commit -a")

Git đã nhận ra file2 bị sửa. Trong output còn một gợi ý hữu ích: lệnh git commit -a, nghĩa là bỏ qua hẳn bước git add file2 và nhảy thẳng tới commit:

git commit -a -m "improve the line of code in file2"

Nhưng để tạo thói quen tốt và tránh sai sót về sau khi còn là người mới, cứ đi theo trình tự thường lệ: thêm file2 vào staging area rồi commit thay đổi.

git add file2
git commit -m "improve the line of code in file2"

Giờ đang ở branch 1.1-testing, nên mọi developer trong đội xem branch này sẽ thấy các thay đổi mới nhất. Branch master về cơ bản không bị sửa, vẫn chứa đoạn code sạch và đã test kỹ như trước.

git log​

Tới đây đã làm khá nhiều việc trong Git repository này. Tuần sau có thể không còn nhớ hết các thay đổi đã thực hiện, và khi nhiều thành viên tham gia thì càng khó biết người khác đã sửa gì trong quá khứ. Lệnh để xem lại hoạt động đã qua là git log:

git log

# Output (minh họa):
commit 7b3e9d2f1a4c8e6b5d0f2a9c3e7b1d4f6a8c2e0b (HEAD -> 1.1-testing)
Author: Aaron <[email protected]>
Date: Fri Oct 24 10:40:00 2026 +0700

improve the line of code in file2

commit 4a1c8e6b5d0f2a9c3e7b1d4f6a8c2e0b7b3e9d2f
Author: Aaron <[email protected]>
Date: Fri Oct 24 10:32:00 2026 +0700

remove the buggy feature in file3

Output rất nhiều chi tiết, giúp nhìn nhanh ra các thành viên khác đã làm gì trong project. Muốn biết đúng những file nào bị thay đổi thì thêm --raw:

git log --raw

Trong output có những dòng cho biết commit đã thêm hai file, file1 và file2, và chữ A mang nghĩa đó. Chữ D chỉ những file bị xóa trong một commit, chữ M báo file bị sửa.

Còn một chuỗi text lạ cạnh mỗi commit, gọi là commit hash, nó định danh duy nhất từng entry. Muốn đi sâu hơn và xem những dòng code nào đã thay đổi trong một commit thì dùng vài ký tự đầu của hash đó:

git show 7b3e9d2

Text màu đỏ có dấu trừ phía trước là nội dung cũ đã bị bỏ, text màu xanh có dấu cộng phía trước là nội dung mới được thêm vào. Nhờ đó thấy được đúng phần đã sửa trong commit đó khi text trong file được edit.

HEAD và chuyện du hành thời gian​

Liệt kê commit lại sẽ để ý hai chuyện. Thứ nhất, branch master đang chậm hơn một commit, vì danh sách được sắp từ cũ nhất tới mới nhất: mới nhất ở trên cùng, cũ nhất ở dưới cùng. Thay đổi cải thiện code chỉ được commit trong branch 1.1-testing, nên chuyện này là đúng như trông đợi.

Thứ hai là một từ bí ẩn: HEAD. Nó nói lên điều gì? Hiện tại HEAD trỏ tới commit nơi code trong file2 được cải thiện, và xem file2 thì thấy dòng code đã được cải thiện trong đó.

Chuyển về branch master rồi xem log lại:

git checkout master
git log

Có vài khác biệt. Thứ nhất, giờ chỉ còn thấy ba commit thay vì bốn như trước. Commit cuối ở đây là lúc bỏ feature nhiều bug; commit cải thiện code không có mặt. Chuyện đó hợp lý vì thay đổi đó không được commit trong branch master, chỉ trong branch 1.1-testing.

Thứ hai, HEAD giờ trỏ tới commit nơi feature nhiều bug bị bỏ, trước đó nó trỏ tới commit cải thiện code. Kiểm tra file2 lần nữa:

cat file2

# Output:
this is the line of code in file2

Nó hiện nội dung cũ của file. Giải thích: HEAD đang trỏ tới một commit cũ hơn, lúc feature nhiều bug bị bỏ, và trong commit đó file2 có đúng nội dung gốc này. Vậy HEAD trỏ tới một commit nhất định, không nhất thiết là commit cuối cùng đã làm trong project. Và thứ HEAD trỏ tới chính là trạng thái project sẽ thấy trong working area. Trỏ HEAD sang một commit khác là du hành thời gian được, xem lại trạng thái project đúng như lúc đó. Đây là một điểm hay nữa của Git: nó cho phép thăm lại các giai đoạn khác nhau trong vòng đời của một project software.

Merge branch​

Những thay đổi mới nhất trong file2 không có trong branch master. Theo thuật ngữ Git, branch master đang ở phía sau branch 1.1-testing.

Giả sử việc cải thiện code đã xong và đã test hết trong branch 1.1-testing, tới lúc phát hành sản phẩm mới. Cách làm là đem mọi thay đổi từ branch 1.1-testing vào branch master, và việc đó gọi là merging branch. Một branch phụ được merge vào branch hiện tại, nên muốn merge vào master thì phải chắc chắn master đang là branch hiện tại.

git branch --list
git merge 1.1-testing
cat file2

# Output:
this is the improved line of code in file2

Branch master cuối cùng đã bao gồm mọi thay đổi code mới nhất được đem về từ branch 1.1-testing.


9. Remote repository push pull và clone​

Tới đây mọi việc chỉ diễn ra trên local repository. Nhưng là một phần của đội lớn, cần định kỳ làm cho những thay đổi code của mình có sẵn cho mọi người khác. Cách dễ nhất là upload tiến độ từ local repository lên một remote repository. Ai từng dùng GitHub hay GitLab đều đã thấy hai ví dụ về platform host được remote repository.

Nhưng upload thay đổi lên remote repository chỉ là một nửa câu chuyện. Các thành viên khác cũng đang làm trên project này, nên cần thấy được những thay đổi họ đã làm. Hai khái niệm tương ứng: upload thay đổi lên remote repository gọi là push, download thay đổi về gọi là pull. Thứ được download và upload là toàn bộ các commit mà Git biết: pull là lấy về mọi commit có sẵn từ remote repository, push là đẩy mọi commit của mình lên remote repository. Cách nào thì cả đội cũng được giữ đồng bộ với các thay đổi code mới nhất.

Local repository and remote repositoryLocal repositoryA personal copy, with thehidden .git directoryholding the config andall of the commitsgit push origin masterRemote repositoryA shared central placesuch as GitHub or GitLabwhere the whole teamassembles its commitsgit pull origin mastergit remote -v lists the configured remotesgit remote add origin plus the connection string registers onegit clone plus that string creates a ready-made local repositorySSH keys from ssh-keygen let the push happen without a password

Tạo repository trên GitHub​

GitHub là platform phổ biến nhất cho remote Git repository, nên đây là các bước cần đi qua ở đó. Sau khi đăng nhập vào account, vào tab Repositories, bấm nút New để tạo một repository mới, chọn một cái tên (ở đây là kk-project), còn lại để nguyên setting mặc định.

Phần quan trọng tiếp theo là lấy connection string. Mặc định giao thức HTTPS được chọn. Khi có ý định thay đổi remote repository, phải chứng minh với GitHub rằng mình được phép làm việc đó. Dùng giao thức HTTPS thì có những cơ chế đăng nhập riêng, ví dụ dùng username kèm một access token. Nhưng ở đây bấm vào nút SSH để đăng nhập theo cách khác, dễ hơn trong trường hợp này vì đăng nhập được bằng SSH key. Copy connection string ở đó rồi quay lại terminal.

Đăng ký remote repository​

Git lưu mọi thông tin về local repository trong directory ẩn .git, và đó cũng là nơi nó lưu thông tin về các remote repository. Kiểm tra xem repository này đã gắn remote repository nào chưa:

git remote -v

-v là verbose, nghĩa là output chi tiết. Lệnh không in gì cả, vì chưa có remote repo nào được cấu hình. Thêm cái đầu tiên:

git remote add origin [email protected]:aaron/kk-project.git

Lệnh này nói với Git rằng cần dùng remote repository nào khi upload dữ liệu từ local repository này, hoặc khi download dữ liệu về nó.

origin là một alias: một cái tên tự chọn cho remote repository, vì gõ và nhớ origin dễ hơn gõ cả một connection string. Với các lệnh sau, chỉ cần bảo Git push hoặc pull từ origin, và nó biết origin trỏ tới connection string đó. Tên nào cũng được, nhưng thông lệ chuẩn là chọn đúng tên này cho remote repo mặc định.

Kiểm tra lại:

git remote -v

# Output (minh họa):
origin [email protected]:aaron/kk-project.git (fetch)
origin [email protected]:aaron/kk-project.git (push)

Hai dòng cho thấy một origin đã gắn với connection string cụ thể đó. Nó được cấu hình cho cả fetch, tức download từ remote repository, và push, tức upload lên đó.

Cấu hình SSH key​

Giờ cấu hình SSH key để đăng nhập được vào remote repo này. Sinh một cặp public key và private key:

ssh-keygen

Nhấn Enter ở từng prompt để chọn setting mặc định: private key được lưu ở vị trí mặc định, và dùng passphrase rỗng để không phải chọn password nào mã hoá private key.

Thứ cần là public key, được ghi rõ ở output là id_ed25519.pub. Hiển thị nội dung của nó rồi copy toàn bộ đoạn text:

cat ~/.ssh/id_ed25519.pub

Quay lại website GitHub, vào tab Settings, chọn SSH and GPG keys, bấm New SSH Key, điền một title rồi paste key vào. Ở đây có phân biệt giữa authentication key và signing key: cái cần là authentication key. Bấm Add SSH Key.

Push và pull​

Remote repository đang rỗng. Đưa nó lên trạng thái mới nhất bằng cách upload mọi commit đã làm ở local:

git push origin master

Lần đầu kết nối sẽ có một prompt, gõ yes. Lệnh này bảo Git push các commit ở local lên remote repository tên origin, và cũng chỉ rõ branch nào được upload, ở đây là branch tên master. Vào lại website github.com và mở repository sẽ thấy nó đã có nội dung.

Lấy về các commit mới nhất vào branch master cũng là một lệnh trực quan tương tự:

git pull origin master

git clone cho thành viên mới​

Tới đây vẫn giả định mọi thành viên trong đội đã có local repository. Nhưng khi một người mới vào thì họ chưa có local repository của project này, phải bắt đầu từ con số không.

Lệnh clone làm hết những việc cần thiết. Trước đó, SSH key của họ được dựng và public key của họ được upload vào project, rồi họ nhận connection string. Đặt mình vào vị trí của họ: thoát khỏi directory hiện tại, về home directory, tạo một directory tên work để chứa mọi project software họ sẽ làm, rồi vào đó.

cd ~
mkdir work
cd work
git clone [email protected]:aaron/kk-project.git

Lệnh clone tạo một local repository, và local repo này được cấu hình trước với các setting riêng của project: remote origin được thêm tự động, và toàn bộ file cùng commit của project cũng được download về.

ls

# Output:
kk-project

Directory kk-project được tạo ra, và xem bên trong sẽ thấy nó chứa toàn bộ file của project, cộng thêm directory ẩn .git chứa lịch sử commit và mọi dữ liệu khác Git theo dõi. Chuyển vào directory đó là dùng được đúng những lệnh như trước:

cd kk-project
git log

Thành viên mới giờ có cùng một repository trên máy họ như mọi thành viên khác đang làm. Lệnh clone là cách nhanh và gọn để bắt đầu từ con số không. Sau khi local repository đã được tạo thì phần còn lại của workflow giống y như đã làm ở các mục trên.

Phần trên bao trọn những bước thiết yếu cần biết khi làm việc với Git. Git là một tool rất phức tạp, làm được nhiều hơn rất nhiều so với những gì vừa xem. Khi cần, gõ git rồi một dấu cách rồi nhấn Tab hai lần để xem nhanh mọi subcommand dùng được, và xem help cho một subcommand bằng man, chữ git, rồi tên subcommand thấy trong danh sách đó:

git <Tab><Tab>
man git add

Nguồn tham khảo​

Nguồn gốc: Khóa "Prep Course - Linux Foundation Certified System Administrator (LFCS) Certification" — phần "Essential Commands" (SSL và TLS certificate, tra cứu OpenSSL ngay trên command line, tạo private key cùng certificate signing request và self-signed certificate, cùng phần quản lý source code với Git gồm staging, commit, branch và remote repository), nền tảng KodeKloud. Giảng viên: Jeremy Morgan và Alexandru Andrei.

Fact-check:

  • Transcript của lecture về SSL certificate bị cắt giữa câu, dừng ở -keyout nên không có tên file đích. Lệnh self-signed certificate trong tài liệu dựng theo dạng chuẩn mà openssl ghi nhận, chỉ dùng các option transcript có nêu tên; tên file myprivate.key và mycert.pem là tên minh họa, đổi tùy ý. Nguồn: man 1 openssl-req, 2026-10-24.
  • Bài giảng gốc dùng git checkout để đổi branch. Từ Git 2.23 có thêm git switch dành riêng cho việc này, còn git checkout vẫn hoạt động và vẫn nằm trong tài liệu chính thức. Nguồn: man 1 git-switch và man 1 git-checkout, 2026-10-24.
  • git init vẫn đặt tên branch đầu tiên là master (kiểm trên Git 2.43.0), nhưng tên này do cấu hình init.defaultBranch quyết định, nên trên máy khác hoặc trên repo tạo từ dịch vụ hosting thì tên branch mặc định có thể khác. Nguồn: man 1 git-init, 2026-10-24.