No menu items!
No menu items!
More

    [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.

    Bài viết gần đây

    spot_img

    Related Stories

    Leave A Reply

    Please enter your comment!
    Please enter your name here

    Đăng ký nhận thông tin bài viết qua email