Saturday, January 18, 2025

[Git] Phần 9 – Nhánh trong git, tạo và quản lý nhánh, gộp nhánh với git merge

-

1. Lý thuyết.

Nhánh (Branch) trong Git: Nhánh trong Git là một con đường độc lập chứa một chuỗi commit. Nó được sử dụng để phát triển các tính năng độc lập mà không ảnh hưởng đến các nhánh khác.

Tạo và chuyển nhánh: Để tạo một nhánh mới, bạn sử dụng lệnh git branch <branch-name>. Để chuyển đến một nhánh khác, bạn sử dụng lệnh git checkout <branch-name> hoặc git switch <branch-name>.

git branch new-feature
git checkout new-feature

Con trỏ HEAD: HEAD là một con trỏ đến commit hiện tại (hoặc nhánh hiện tại) mà bạn đang làm việc. Khi bạn chuyển nhánh, HEAD thay đổi để trỏ đến commit cuối cùng của nhánh mới.

Quản lý nhánh: Để xóa một nhánh, bạn sử dụng lệnh git branch -d <branch-name>.

git branch -d new-feature

Gộp nhánh với git merge: Để gộp nhánh, bạn sử dụng lệnh git merge <branch-name>. Điều này sẽ gộp nhánh được chỉ định vào nhánh hiện tại.

git merge new-feature

Xử lý xung đột khi gộp nhánh: Khi gộp nhánh, có thể xảy ra xung đột nếu cùng một phần của file được thay đổi trên cả hai nhánh. Git sẽ đánh dấu các phần của file có xung đột và yêu cầu bạn giải quyết chúng trước khi hoàn tất việc gộp.

2. Thực hành.

Tạo project thực hành.

shell> mkdir myproject
shell> echo 'Noi dung 0' > 0.txt
shell> git init
Initialized empty Git repository in /Users/hoanghd/My Drive/git/.git/

Tạo commit đầu tiên.

shell> git add .
shell> git commit -m"C0"
[main (root-commit) 9e77d92] C0
 1 file changed, 1 insertion(+)
 create mode 100644 0.txt

Tạo commit thứ 2.

shell> echo 'Noi dung 1' > 1.txt
shell> git add .
shell> git commit -m"C1"
[main deb5dfe] C1
 1 file changed, 1 insertion(+)
 create mode 100644 1.txt

Tạo commit thứ 3.

shell> echo 'Noi dung 2' > 2.txt
shell> git add .
shell> git commit -m"C2"
[main d781dd7] C2
 1 file changed, 1 insertion(+)
 create mode 100644 2.txt

Xác minh lại, bạn sẽ có 3 commit như dưới.

shell> git log --oneline
d781dd7 (HEAD -> main) C2
deb5dfe C1
9e77d92 C0

Kiểm tra danh sách các nhánh.

Kiểm tra nhánh chúng ta sẽ có một nhánh mặc định Git sẽ tạo tự động cho bạn, có thể tên nó là nhánh master hoặc là main.

shell> git branch
* main

Các nhánh trong Git giống như một cơ sở dữ liệu để lưu code cho luồng phát triển nào đó cho dự án nào đó. Code của chúng ta sẽ phát triển trên nhiều nhánh khác nhau và sau này có thể gộp lại.

Con trỏ đang đứng ở commit C2 ở nhánh main, nếu khởi tạo nhánh từ vị trí này thì nó sẽ tạo ra nhanh alpha sẽ bắt đầu rẽ nhánh từ commit C2 (tức là nó được kế thừa các commit C0, C1 và C2 của nhánh main).

Tạo nhánh.

Để tạo thêm nhánh mới, bạn sử dụng lệnh git branch <tên nhánh tự đặt cần tạo> như sau:

shell> git log --oneline
d781dd7 (HEAD -> main) C2
deb5dfe C1
9e77d92 C0

git branch alpha

Giờ đây nếu sử dụng lệnh git branch bạn nhận được 2 nhánh alpha và main và hiện giờ con trỏ vẫn đang trỏ vào nhành main (tức là chúng ta vẫn đang làm việc với Commit C3 ở nhánh main).

shell> git branch
  alpha
* main

Chuyển nhánh.

Để chuyển qua làm việc ở nhánh alpha chúng ta sử dụng lệnh git checkout hoặc git switch.

shell> git checkout alpha
Switched to branch 'alpha'

Bây giờ nếu sử dụng lệnh git branch bạn sẽ thấy con trỏ đang đứng ở nhánh alpha hoặc sử dụng lệnh git log --oneline bạn cũng thấy con trỏ HEAD đang chỉ vào Commit thứ 2 của nhánh alpha và nhánh alpha được kết thừa các commit C0, C1 và C2 từ nhánh main, commit C2 là điểm chung rẽ nhánh của nhánh main và alpha.

shell> git branch
* alpha
  main

shell> git log --oneline
d781dd7 (HEAD -> alpha, main) C2
deb5dfe C1
9e77d92 C0

Ví dụ chuyển nhánh bằng lệnh git switch.

shell> git switch main
Switched to branch 'main'

shell> git branch
  alpha
* main

Kiểm tra lịch sử commit bạn sẽ thấy con trỏ đang trỏ ở commit C2 của nhánh main.

shell> git log --oneline
d781dd7 (HEAD -> main, alpha) C2
deb5dfe C1
9e77d92 C0

Tạo commit mới ở nhánh Alpha.

Tạo nội dung Noi dung 3 ghi vào file 3.txt tiến hành chuyển qua nhánh alpha và tạo commit C3 như sau:

shell> echo 'Noi dung 3' > 3.txt

shell> git status
On branch alpha
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        3.txt

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

shell> git add 3.txt 

shell> git commit -m"C3"
[alpha 495c530] C3
 1 file changed, 1 insertion(+)
 create mode 100644 3.txt

Sử dụng lệnh git log –oneline xem lịch sử commit bạn thấy con trỏ đang chỉ vào commit C3 của nhánh alpha.

shell> git log --oneline
495c530 (HEAD -> alpha) C3
d781dd7 (main) C2
deb5dfe C1
9e77d92 C0

Giờ đây nếu bạn chuyển qua nhánh main, file 3.txt cùng với commit C3 đã được commit ở nhánh alpha sẽ biến mất.

shell>git checkout main
Switched to branch 'main'

shell> git log --oneline
d781dd7 (HEAD -> main) C2
deb5dfe C1
9e77d92 C0

shell> ls -al
total 24
drwx------   7 hoanghd  staff   224 Feb  2 11:01 .
drwx------@ 36 hoanghd  staff  1152 Feb  2 09:38 ..
drwxr-xr-x  13 hoanghd  staff   416 Feb  2 11:01 .git
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:30 0.txt
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:31 1.txt
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:31 2.txt
drwxr-xr-x   2 hoanghd  staff    64 Feb  2 10:30 myproject

Bây giờ nếu bạn quay lại nhánh alpha, bạn sẽ thấy file 3.txt cùng với commit C3 đã được commit ở nhánh alpha sẽ xuất hiện trở lại.

shell> git switch alpha
Switched to branch 'alpha'

shell> git log --oneline
495c530 (HEAD -> alpha) C3
d781dd7 (main) C2
deb5dfe C1
9e77d92 C0

shell> ls -al
total 32
drwx------   8 hoanghd  staff   256 Feb  2 11:02 .
drwx------@ 36 hoanghd  staff  1152 Feb  2 09:38 ..
drwxr-xr-x  13 hoanghd  staff   416 Feb  2 11:02 .git
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:30 0.txt
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:31 1.txt
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:31 2.txt
-rw-r--r--   1 hoanghd  staff    11 Feb  2 11:02 3.txt
drwxr-xr-x   2 hoanghd  staff    64 Feb  2 10:30 myproject

Trường hợp gộp nhánh không có xung đột.

Chỉnh sửa nội dung file 1.txt.

echo -e "\n- Lenh git checkout, git branch" >> 1.txt

shell> cat 1.txt 
Noi dung 1
- Lenh git checkout, git branch

Tiến hành thêm commit thứ 4 như sau:

shell> git add .
shell> git commit -m"C4"
[alpha 2325b37] C4
 1 file changed, 1 insertion(+)

Lúc này chúng ta đã có 1 commit C4 tại nhánh alpha.

shell> git log --oneline
2325b37 (HEAD -> alpha) C4
495c530 C3
d781dd7 (main) C2
deb5dfe C1
9e77d92 C0

Chuyển sang nhánh main.

shell> git checkout main
Switched to branch 'main'

shell> ls -al
total 24
drwx------   7 hoanghd  staff   224 Feb  2 11:07 .
drwx------@ 36 hoanghd  staff  1152 Feb  2 09:38 ..
drwxr-xr-x  13 hoanghd  staff   416 Feb  2 11:07 .git
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:30 0.txt
-rw-r--r--   2 hoanghd  staff    11 Feb  2 11:07 1.txt
-rw-r--r--   1 hoanghd  staff    11 Feb  2 10:31 2.txt
drwxr-xr-x   2 hoanghd  staff    64 Feb  2 10:30 myproject

Thay đổi nội dung file 0.txt.

echo -e "\n- Hoc git" >> 0.txt

shell> cat 0.txt 
Noi dung 0
- Hoc git

Tạo file 3.txt.

echo 'Noi dung 3' > 3.txt

Kiểm tra trạng thái bạn thấy tại nhánh main có file 0.txt đã được chỉnh sửa và file 3.txt được tạo mới nhưng đang ở ngoài vùng staged không được theo dõi.

shell> git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   0.txt

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

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

Tiến hành thêm 2 file này vào vùng staged và tạo commit C5.

shell> git add .
shell> git commit -m"C5"
[main e0a52db] C5
 2 files changed, 2 insertions(+)
 create mode 100644 3.txt

Kiểm tra lại lịch sử commit của nhánh main bạn thấy nhánh main hiện tại đang có 4 commit như dưới.

shell> git log --oneline
e0a52db (HEAD -> main) C5
d781dd7 C2
deb5dfe C1
9e77d92 C0

Tiếp theo đừng từ commit C5 của nhánh main mình tạo một nhánh mới tên là sualoigap sau đó mình chuyển sang nhánh mới tạo này.

shell> git branch sualoigap
shell> git branch
  alpha
* main
  sualoigap

shell> git checkout sualoigap
Switched to branch 'sualoigap'

Bạn sẽ thấy con trỏ đang đứng ở vị trí commit C5 được kết thừa từ nhánh main.

shell> git log --oneline
e0a52db (HEAD -> sualoigap, main) C5
d781dd7 C2
deb5dfe C1
9e77d92 C

Tiếp theo mình chỉnh sửa file 1.txt.

shell> echo -e '\nSua loi ABC' >> 1.txt
shell> cat 1.txt 
Noi dung 1
Sua loi ABC

Kiểm tra trạng thái bạn thấy file 1.txt đã được chỉnh sửa và chưa được theo dõi.

shell> git status
On branch sualoigap
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   1.txt

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

Tiến hành thêm nó vào vùng staged và tạo commit C6.

shell> git add .

shell> git commit -m"C6"
[sualoigap 9562b6f] C6
 1 file changed, 1 insertion(+)

Lúc này bạn đã thấy con trỏ đang đứng tại commit C6 của nhánh sualoigap.

shell> git log --oneline
9562b6f (HEAD -> sualoigap) C6
e0a52db (main) C5
d781dd7 C2
deb5dfe C1
9e77d92 C0

Tiếp theo mình chỉnh sửa file 2.txt.

shell> echo -e '\nSua loi tren 2.txt' >> 2.txt
shell> cat 2.txt 
Noi dung 2
Sua loi tren 2.txt

Kiểm tra trạng thái và đưa nó vào vùng staged, tạo commit C7.

shell> git status
On branch sualoigap
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   2.txt

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

shell> git add .
shell> git commit -m"C7"
[sualoigap 1ab1cc7] C7
 1 file changed, 1 insertion(+)

Giờ đây bạn đã thấy có thêm 1 commit C7 đang ở nhánh sualoigap.

shell> git log --oneline
1ab1cc7 (HEAD -> sualoigap) C7
9562b6f C6
e0a52db (main) C5
d781dd7 C2
deb5dfe C1
9e77d92 C0

Giờ chúng ta sẽ tiến hành merge nhánh sualoigap với nhánh main. Để tiến hành gộp nhanh sualoigap với nhánh main chúng ta hãy quay về nhánh main trước.

shell> git checkout main
Switched to branch 'main'

Để đảm bảo tránh bị xung đột chúng ta cần đảm bảo nhánh main cần phải ở trạng thái working tree clean.

shell> git status
On branch main
nothing to commit, working tree clean

Kiểm tra lịch sử commit của nhánh main chúng ta thấy có 5 commit và con trỏ đang đứng ở commit C5.

shell> git log --oneline
e0a52db (HEAD -> main) C5
d781dd7 C2
deb5dfe C1
9e77d92 C0

Đứng từ nhánh main tiến hành gõ lệnh git merge <tên nhánh cần gộp với nhánh hiện tại>.

Khi chúng ta tiến hành gộp nhánh như thế này thì Git sẽ kiểm tra sự sửa đổi của commit C5 của nhánh main và commit cuối của nhánh sualoigap để so sánh sự khác nhau để tiến hành gộp dữ liệu.

Sau thời điểm commit C5 thì nhánh main không thực hiện thêm một commit nào nên nó không gây ra sự xung đột nào cả, vậy nên khi chúng ta gộp nhánh thì chúng ta sẽ gộp được ngay mà không gặp lỗi nào cả.

shell> git merge sualoigap
Updating e0a52db..1ab1cc7
Fast-forward
 1.txt | 1 +
 2.txt | 1 +
 2 files changed, 2 insertions(+)

Lệnh git merge được sử dụng để kết hợp các thay đổi từ một nhánh khác vào nhánh hiện tại. Trong trường này chúng ta đã kết hợp nhánh sualoigap vào nhánh hiện tại.

Output của lệnh cho bạn biết những gì đã xảy ra trong quá trình merge:

  • Updating e0a52db..1ab1cc7: Đây là commit hash của hai commit: commit cuối cùng trên nhánh hiện tại trước khi merge (e0a52db) và commit cuối cùng trên nhánh sualoigap (1ab1cc7). Git đã cập nhật nhánh hiện tại từ commit e0a52db lên 1ab1cc7.
  • Fast-forward: Điều này cho biết rằng git đã thực hiện một “fast-forward merge”. Điều này có nghĩa là, thay vì tạo một commit merge mới, git chỉ đơn giản di chuyển con trỏ HEAD của nhánh hiện tại lên commit cuối cùng của nhánh sualoigap. Điều này chỉ có thể xảy ra khi không có thay đổi nào trên nhánh hiện tại kể từ khi nhánh sualoigap được tách ra.
  • 1.txt | 1 + và 2.txt | 1 +: Đây là danh sách các file đã thay đổi trong quá trình merge, cùng với số lượng dòng đã được thêm (+) hoặc xóa (-). Trong trường hợp này, một dòng đã được thêm vào cả hai file 1.txt và 2.txt.
  • 2 files changed, 2 insertions(+): Tổng cộng, hai file đã thay đổi, với hai dòng được thêm vào.

Kiểm tra lịch sử commit của nhánh main chúng ta sẽ thấy commit C6 và C7 của nhánh sualoigap đã được thêm vào nhánh main.

shell> git log --oneline
1ab1cc7 (HEAD -> main, sualoigap) C7
9562b6f C6
e0a52db C5
d781dd7 C2
deb5dfe C1
9e77d92 C0

Xóa nhánh sửa lỗi gấp.

Sáu khi gộp nhánh thành công thì chúng ta có thể không cần tới nhánh sualoigap nữa nên mình sẽ xóa nhánh này đi.

Để xóa nhánh sualoigap sử dụng lệnh git branch -d <tên nhánh cần xóa>.

shell> git branch -d sualoigap
Deleted branch sualoigap (was 1ab1cc7).

shell> git branch
  alpha
* main

Trường hợp gộp nhánh có xung đột sử dụng công cụ có sẵn trên Visual Studio Code.

Giả sử chúng ta tiến hành gộp nhánh alpha vào nhánh main. Đứng từ nhánh main tiến hành sử dụng lệnh git merge alpha để gộp nhánh.

shell> git merge alpha
Auto-merging 1.txt
CONFLICT (content): Merge conflict in 1.txt
Automatic merge failed; fix conflicts and then commit the result.

Lệnh git merge được sử dụng để kết hợp các thay đổi từ một nhánh khác vào nhánh hiện tại. Trong trường hợp này chúng ta đã cố gắng kết hợp nhánh alpha vào nhánh hiện tại.

Khi bạn cố gắng merge hai nhánh có các thay đổi khác nhau đối với cùng một phần của một file, Git sẽ không biết bạn muốn giữ thay đổi nào và sẽ tạo ra một xung đột merge.

Output của lệnh cho biết những gì đã xảy ra trong quá trình merge:

  • Auto-merging 1.txt: Git đã cố gắng tự động hợp nhất các thay đổi từ nhánh alpha vào file 1.txt trên nhánh hiện tại.
  • CONFLICT (content): Merge conflict in 1.txt: Tuy nhiên, có một xung đột trong quá trình hợp nhất. Cụ thể, có một xung đột nội dung trong file 1.txt, có nghĩa là cùng một phần của file đã được thay đổi trên cả hai nhánh.
  • Automatic merge failed; fix conflicts and then commit the result.: Do có xung đột, quá trình hợp nhất tự động đã thất bại. Git yêu cầu bạn giải quyết xung đột (bằng cách chỉnh sửa file, chọn giữa các thay đổi từ nhánh hiện tại hoặc nhánh alpha, và sau đó lưu file) và sau đó commit kết quả.

Để giải quyết xung đột, sử dụng lệnh git status sẽ cung cấp thông tin về trạng thái hiện tại của repository. Trong trường hợp này, output cho thấy bạn đang trong quá trình merge và có một xung đột chưa được giải quyết, trạng thái both modified của file 1.txt sinh ra do quá trình gộp nhánh.

  • On branch main: Bạn đang làm việc trên nhánh main.
  • You have unmerged paths.: Có một hoặc nhiều file có xung đột không được giải quyết trong quá trình merge.
  • (fix conflicts and run "git commit"): Đây là hướng dẫn để giải quyết xung đột: bạn cần chỉnh sửa các file có xung đột, thêm chúng vào vùng staging với git add, và sau đó commit chúng với git commit.
  • (use "git merge --abort" to abort the merge): Nếu bạn không muốn tiếp tục quá trình merge, bạn có thể hủy nó với lệnh git merge --abort.
  • Unmerged paths:: Phần này liệt kê các file có xung đột chưa được giải quyết.
  • both modified: 1.txt: File 1.txt đã được sửa đổi trên cả hai nhánh đang được merge, dẫn đến xung đột.
  • no changes added to commit (use "git add" and/or "git commit -a"): Hiện tại, không có thay đổi nào được thêm vào vùng staging để commit. Sau khi bạn giải quyết xung đột, bạn cần sử dụng git add để thêm các thay đổi vào vùng staging, và sau đó sử dụng git commit để commit chúng.

Bạn có thể mở file 1.txt và tìm kiếm các đánh dấu xung đột (<<<<<<<=======, và >>>>>>>). Các dòng giữa <<<<<<< và ======= là thay đổi từ nhánh hiện tại, và các dòng giữa ======= và >>>>>>> là thay đổi từ nhánh alpha. Bạn cần quyết định thay đổi nào sẽ được giữ lại.

Nhìn vào nội dung của file 1.txt ở dưới đây chúng ta thấy kết quả như sau:

  • <<<<<<< HEAD bắt đầu phần của xung đột merge. Tất cả nội dung sau đây cho đến ======= là nội dung từ nhánh hiện tại (nhánh mà bạn đang cố gắng merge vào, thường được gọi là nhánh “HEAD”).
  • Sua loi ABC là thay đổi từ nhánh hiện tại.
  • ======= đánh dấu kết thúc của thay đổi từ nhánh hiện tại và bắt đầu của thay đổi từ nhánh khác.
  • - Lenh git checkout, git branch là thay đổi từ nhánh khác (nhánh mà bạn đang cố gắng merge từ, trong trường hợp này là nhánh “alpha”).
  • >>>>>>> alpha kết thúc phần của xung đột merge.

Để giải quyết xung đột này, bạn cần quyết định giữa Sua loi ABC (thay đổi từ nhánh hiện tại) hoặc - Lenh git checkout, git branch (thay đổi từ nhánh “alpha”). Bạn chỉnh sửa file để nó chỉ chứa nội dung bạn muốn giữ, sau đó thêm file vào vùng staging với git add và commit nó với git commit.

Khi bạn gặp phải một xung đột merge trong Visual Studio Code, IDE sẽ cung cấp cho bạn một số tùy chọn để giải quyết xung đột đó:

  • Accept Current Change: Chọn tùy chọn này sẽ giữ lại thay đổi từ nhánh hiện tại (nhánh mà bạn đang cố gắng merge vào, thường được gọi là nhánh “HEAD”) và loại bỏ thay đổi từ nhánh khác. Trong trường hợp này, nếu bạn chọn tùy chọn này, “Sua loi ABC” sẽ được giữ lại và “- Lenh git checkout, git branch” sẽ bị loại bỏ.
  • Accept Incoming Change: Chọn tùy chọn này sẽ giữ lại thay đổi từ nhánh khác (nhánh mà bạn đang cố gắng merge từ) và loại bỏ thay đổi từ nhánh hiện tại. Trong trường hợp này, nếu bạn chọn tùy chọn này, “- Lenh git checkout, git branch” sẽ được giữ lại và “Sua loi ABC” sẽ bị loại bỏ.
  • Accept Both Changes: Chọn tùy chọn này sẽ giữ lại cả hai thay đổi. Trong trường hợp này, nếu bạn chọn tùy chọn này, cả “Sua loi ABC” và “- Lenh git checkout, git branch” đều sẽ được giữ lại.
  • Compare Changes: Chọn tùy chọn này sẽ mở một cửa sổ so sánh bên cạnh, cho phép bạn xem cả hai thay đổi bên cạnh nhau. Điều này có thể giúp bạn quyết định thay đổi nào nên giữ lại.

Mình chọn Accept Both Changes để lấy cả 2 phiên bản.

Nội dung file 1.txt sẽ như sau:

shell> git commit -m"C8 - gop nhanh alpha"
[main 27186cc] C8 - gop nhanh alpha

Giờ kiểm tra lịch sử commit của nhánh main bạn sẽ thấy chúng ta đã gộp nhánh thành công.

shell> git log --oneline
27186cc (HEAD -> main) C8 - gop nhanh alpha
1ab1cc7 C7
9562b6f C6
e0a52db C5
2325b37 (alpha) C4
495c530 C3
d781dd7 C2
deb5dfe C1
9e77d92 C0

Hoặc bạn có thể sử dụng lệnh git log kèm thêm tham số --graph, đây là một cách trực quan để xem lịch sử commit của bạn.

shell> git log --oneline --graph
*   27186cc (HEAD -> main) C8 - gop nhanh alpha
|\  
| * 2325b37 (alpha) C4
| * 495c530 C3
* | 1ab1cc7 C7
* | 9562b6f C6
* | e0a52db C5
|/  
* d781dd7 C2
* deb5dfe C1
* 9e77d92 C0
  • Mỗi dòng bắt đầu bằng một * đại diện cho một commit.
  • Mã hash ngắn của mỗi commit (ví dụ: 27186cc) được hiển thị ngay sau *.
  • Tên của commit (ví dụ: C8 - gop nhanh alpha) được hiển thị sau mã hash.
  • (HEAD -> main) cho biết con trỏ HEAD hiện đang trỏ đến commit này trên nhánh main.
  • (alpha) cho biết commit cuối cùng trên nhánh alpha.
  • Các dấu |\/ và * tạo thành một đồ thị cho thấy cách các nhánh và commit liên quan đến nhau. Các commit trên cùng một dòng đại diện cho các commit trên cùng một nhánh. Các dòng kẻ dọc (|) và chéo (\ hoặc /) cho thấy nhánh tách ra hoặc được gộp lại.

Trong trường hợp này, bạn có thể thấy rằng nhánh main và alpha đã tách ra sau commit C2, mỗi nhánh có các commit riêng của mình (C3 và C4 trên alphaC5C6, và C7 trên main) và sau đó được gộp lại trong commit C8.

Giả sử tôi quay về commit C7 với mã hash là 1ab1cc7.

shell> git checkout 1ab1cc7
Note: switching to '1ab1cc7'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 1ab1cc7 C7

Thông báo này từ Git cho biết bạn đã chuyển sang một commit cụ thể, không phải một nhánh, bằng cách sử dụng lệnh git checkout. Trạng thái này được gọi là ‘detached HEAD’.

Trong trạng thái ‘detached HEAD’, bạn có thể thực hiện thay đổi và commit chúng mà không ảnh hưởng đến bất kỳ nhánh nào. Nếu bạn muốn lưu lại các commit bạn tạo ra, bạn có thể tạo một nhánh mới bằng cách sử dụng lệnh git switch -c <new-branch-name>.

Nếu bạn muốn quay lại trạng thái trước đó, bạn có thể sử dụng lệnh git switch -.

Cuối cùng, thông báo này cũng cho biết rằng bạn có thể tắt lời khuyên này bằng cách thiết lập biến cấu hình advice.detachedHead thành false.

“HEAD is now at 1ab1cc7 C7” cho biết bạn đang ở commit có mã hash là 1ab1cc7 và mô tả commit là C7.

Dưới đây là nội dung file 1.txt ở commit C7.

shell> cat 1.txt 
Noi dung 1
Sua loi ABC

Giả sử tôi quay về commit C4 với mã hash là 2325b37, tôi sẽ có nội dung file 1.txx khác với commit C7 ở trên như dưới.

shell> git checkout 2325b37
Previous HEAD position was 1ab1cc7 C7
HEAD is now at 2325b37 C4

shell> cat 1.txt 
Noi dung 1
- Lenh git checkout, git branch

Dưới đây là ví dụ khi tôi chuyển về nhánh main, kết quả file 1.txt sẽ là gộp nội dung của commit C7 và commit C4.

shell> git checkout main
Previous HEAD position was 2325b37 C4
Switched to branch 'main'

shell> cat 1.txt 
Noi dung 1
Sua loi ABC
- Lenh git checkout, git branch

Trường hợp gộp nhánh có xung đột sử dụng công cụ tích hợp trong Git.

Đầu tiên mình sẽ tạo sự xung đột để demo trường hợp này bằng cách như sau:

Sửa đổi và thêm commit mới tại nhánh main.

Tại nhánh main mình thêm nội dung Sua doi main vào 0.txt.

echo -e "\nSua doi main" >> 0.txt

Sử dụng lệnh git status cho thấy chúng ta đang đứng ở nhánh main và file 0.txt đang ở trạng thái modified chưa được theo dõi.

shell> git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   0.txt

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

Tiến hành commit nó theo quy trình dưới.

shell> git add .
shell> git commit -m"C9"
[main 6f24339] C9
 1 file changed, 2 insertions(+), 1 deletion(-)

Kết quả chúng ta đã có thêm commit C9 ở nhánh main.

shell> git log --oneline
6f24339 (HEAD -> main) C9
27186cc C8 - gop nhanh alpha
1ab1cc7 C7
9562b6f C6
e0a52db C5
2325b37 (alpha) C4
495c530 C3
d781dd7 C2
deb5dfe C1
9e77d92 C0

Sửa đổi và thêm commit mới tại nhánh alpha.

Tiếp tục thực hiện y chang như ở nhánh main đối với nhánh alpha.

Đầu tiên chúng ta chuyển qua nhánh alpha.

shell> git switch alpha
Switched to branch 'alpha'

Tại nhánh alpha mình thêm nội dung Sua doi alpha vào 0.txt.

echo -e "\nSua doi alpha" >> 0.txt

Sử dụng lệnh git status cho thấy chúng ta đang đứng ở nhánh main và file 0.txt đang ở trạng thái modified chưa được theo dõi.

shell> git status
On branch alpha
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   0.txt

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

Tiến hành commit nó theo quy trình dưới.

shell> git add .
shell> git commit -m"C10"
[alpha dbc4b2e] C10
 1 file changed, 2 insertions(+)

Kết quả chúng ta đã có thêm commit C9 ở nhánh main.

shell> git log --oneline
dbc4b2e (HEAD -> alpha) C10
2325b37 C4
495c530 C3
d781dd7 C2
deb5dfe C1
9e77d92 C0

Giờ chúng ta chuyển qua nhánh main để tiến hành gộp nhánh alpha vào.

shell> git checkout main
Switched to branch 'main'

Và kết quả khi gộp nhánh alpha vào main sẽ bị CONFLICT như dưới.

shell> git merge alpha
Auto-merging 0.txt
CONFLICT (content): Merge conflict in 0.txt
Automatic merge failed; fix conflicts and then commit the result.

Nếu chúng ta sử dụng Visual Studio Code bạn sẽ thấy kết quả như dưới.

Khi bạn thực hiện một thao tác merge trong git và gặp một xung đột, bạn có thể sử dụng lệnh git mergetool để giúp giải quyết xung đột đó thay cho Visual Studio Code.

shell> git mergetool

This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff tortoisemerge emerge vimdiff nvimdiff
Merging:
0.txt

Normal merge conflict for '0.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (opendiff): 

Trong trường hợp này, git đang thông báo rằng bạn chưa cấu hình một công cụ merge cụ thể nào ('merge.tool' is not configured). Git sẽ cố gắng sử dụng một trong những công cụ mà nó biết, bao gồm opendiff, tortoisemerge, emerge, vimdiff, và nvimdiff.

Tiếp theo, git thông báo rằng có một xung đột merge thông thường cho file ‘0.txt’. Cả phiên bản local (phiên bản hiện tại trên nhánh bạn đang làm việc) và phiên bản remote (phiên bản từ nhánh bạn đang cố gắng merge vào) đều đã sửa đổi file này, và git không thể tự động giải quyết xung đột.

Cuối cùng, git đang chờ bạn nhấn enter để bắt đầu sử dụng công cụ merge resolution (trong trường hợp này là opendiff) để giải quyết xung đột.

shell> git mergetool

This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff tortoisemerge emerge vimdiff nvimdiff
Merging:
0.txt

Normal merge conflict for '0.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (opendiff): 
xcode-select: error: tool 'opendiff' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
0.txt seems unchanged.
Was the merge successful [y/n]?

Để cài đặt Xcode trên macOS, bạn có thể làm theo các bước sau:

  • Mở App Store trên máy Mac của bạn.
  • Tìm kiếm “Xcode” trong thanh tìm kiếm.
  • Khi Xcode xuất hiện trong kết quả tìm kiếm, nhấp vào “Get” hoặc “Install” để bắt đầu quá trình cài đặt.
  • Bạn có thể cần nhập mật khẩu Apple ID của mình để xác nhận việc cài đặt.
  • Sau khi cài đặt, bạn có thể mở Xcode từ Launchpad hoặc Spotlight.

Lưu ý rằng Xcode có thể mất một thời gian để tải xuống và cài đặt do kích thước lớn của nó.

Nhưng do phiên bản MacOS của mình đang là phiên bản thấp nên không cài được Xcode nên mình sẽ không demo được mergetool cho các bạn.

Nhưng mình sẽ nói sơ qua một số tùy chọn của mergetool như sau, sẽ có 3 tùy chọn chính.

diffg LO, diffg RE và diffg BA là các lệnh trong vimdiff, một công cụ so sánh và merge file được sử dụng trong vi/vim editor. Vimdiff được sử dụng như một công cụ merge trong git.

  • diffg LO: Lệnh này lấy các thay đổi từ “bên trái” (LO = left side) và áp dụng chúng vào cửa sổ hiện tại. Trong ngữ cảnh của git, “bên trái” thường là phiên bản của bạn (local version).
  • diffg RE: Lệnh này lấy các thay đổi từ “bên phải” (RE = right side) và áp dụng chúng vào cửa sổ hiện tại. Trong ngữ cảnh của git, “bên phải” thường là phiên bản từ nhánh bạn đang cố gắng merge vào (remote version).
  • diffg BA: Nếu bạn sử dụng diffg BA trong vimdiff nó sẽ lấy nội dung từ cả hai nhánh (HEAD và alpha) và ghép chúng lại. Lưu ý rằng diffg BA không tự động loại bỏ các dấu đánh dấu xung đột (<<<<<<<=======>>>>>>>). Bạn sẽ cần phải loại bỏ chúng thủ công sau khi sử dụng diffg BA.

Trong trường hợp của mình, nếu mình đang sử dụng vimdiff để giải quyết xung đột merge, mình có thể sử dụng diffg LO để giữ lại thay đổi “- Hoc git\nSua doi main” hoặc diffg RE để giữ lại thay đổi “Sua doi alpha” hoặc diffg BA để lấy cả 2.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories