- vừa được xem lúc

Git dành cho sinh viên đại học (phần 2)

0 0 1

Người đăng: TuanNQ

Theo Viblo Asia

phần 1 mình nói về Git versioning, ở phần 2 này mình sẽ nói về Git branch.

Git branch giải quyết vấn đề gì?

Hãy quay về ví dụ làm slide thuyết trình cho một project nhóm.

Để giải quyết vấn đề có ai đó vô tình chỉnh sửa file chung của nhóm, mình có thể làm thế này:

  • Tạo ra một bản copy của file chung đó
  • Chỉnh sửa ở file copy chứ không chỉnh sửa trên file chung
  • Leader sẽ review file copy này
  • Chỉ khi leader đồng ý thì mới merge những thay đổi của file copy này vào file chung của nhóm

Theo cách trên, ai muốn chỉnh sửa cái gì phải tạo ra một bản copy của file chung. Với Git, điều đó sẽ là mỗi người tạo ra một branch mới.

Mình có chút thắc mắc, bạn hỏi. Giả sử chỉ có 1 người tạo một bản copy, chỉnh sửa trên đó, rồi leader upload file đó lên Google Drive thành file chung thì ok, nhưng nếu 3 người làm việc đó cùng một lúc thì giải quyết thế nào?

Chẳng lẽ leader của nhóm phải xem lần lượt từng file mỗi file thay đổi những gì, copy paste những thay đổi đó thành một file mới, rồi mới upload lên Google Drive chung của nhóm hay sao?

Ở trong lập trình, đừng lo, Git sẽ giải quyết vấn đề đó cho bạn!

Chỉ cần dùng git merge và Git sẽ tự động merge những thay đổi cho bạn!

Giả sử nếu 2 người vô tình chỉnh sửa cùng một dòng trong cùng một file, đó sẽ là "conflict".

Túm cái váy lại từ ví dụ của mình:

  • Tạo một bản copy mới = Tạo một nhánh (branch) mới
  • Merge thành 1 file = Merge nhánh
  • 2 người chỉnh sửa cùng một chỗ = conflict (rồi tiếp theo sẽ phải resolve conflict)

Hãy cùng học cách dùng Git để làm tất cả những việc trên!

Workflow cơ bản khi bạn nhận task mới

Ở phần này, mình sẽ giải thích workflow cơ bản khi bạn nhận một task mới như thế nào.

Mặc định, khi bạn git init (tức là bảo Git bắt đầu quản lý version của một thư mục), bạn ở branch master. Bạn hãy tưởng tượng nhánh master như kiểu file chung cho cả nhóm vậy.

Nếu bạn có một task mới, bạn cần thực hiện những bước này:

  • Tạo một nhánh mới (= tạo một file copy mới)
  • Chỉnh sửa trên nhánh đó rồi git addgit commit -m (= tạo một version mới)
  • Merge vào nhánh master (= merge vào file chung của nhóm)

Hãy áp dụng nó vào project mà mình đã tạo ra ở phần 1.

View, create, merge branch

Đây là project của mình ở phần 1:

Để xem mình đang ở nhánh nào, bạn có thể sử dụng lệnh sau

git branch

Đây là kết quả của mình

 * master

Điều này có nghĩa mình đang ở nhánh master.

Bây giờ tưởng tượng bạn có một task mới: thêm vào index.js console.log("bye there").

Theo "đúng quy trình", đây là các bước bạn cần phải thực hiện:

  • Tạo một nhánh mới (= copy ra một file mới)
  • Thêm console.log("bye there") vào index.js (thực hiện task đó)
  • git add rồi git commit -m (= tạo một version mới)
  • Merge vào nhánh master (= merge vào file chung của nhóm)

Đầu tiên, hãy tạo một nhánh mới. Để tạo một nhánh mới, hãy sử dụng git checkout -b [branch-name].

Ví dụ mình tạo nhánh mới tên là feature/bye_there thì sẽ dùng lệnh sau:

git checkout -b feature/bye_there

Khi mới dùng Git, bạn có thể rất dễ quên mình đang ở nhánh nào. Vì thế hãy tạo thói quen tốt mỗi lần chuyển nhánh hay làm gì, hãy kiểm tra mình ở nhánh nào:

git branch

Đây là kết quả của mình

* feature/bye_there master

Điều này có nghĩa là mình có 2 nhánh masterfeature/bye_there và mình đang ở nhánh feature/bye_there.

Ở trong index.js, hãy thêm console.log("bye there"):

console.log("hello there");
console.log("bye there");

Sau khi hoàn thành task, hãy tạo một version mới:

git add index.js

rồi

git commit -m "[feature] add bye there"

Đây là hình vẽ minh họa giải thích những gì mình vừa làm:

Tiếp theo, hãy merge nó vào nhánh master. Có 2 bước để làm việc này:

  • Chuyển sang nhánh master: git checkout master
  • Merge nhánh feature/bye_there vào master: git merge feature/bye_there

Đầu tiên, hãy chuyển sang nhánh master:

git checkout master

Tiếp theo, hãy merge nhánh feature/bye_there vào master:

git merge feature/bye_there

Ok vậy là mình đã merge thành công nhánh feature/bye_there vào master. Dưới đây mình sẽ giải thích kỹ hơn một chút điều gì vừa xảy ra khi mình gọi git merge.

Khi bạn bảo git merge nhánh feature/bye_there vào master, git sẽ merge tất cả những thay đổi ở nhánh feature/bye_there vào master.

Nhánh feature/bye_there thay đổi những gì so với nhánh master? Đó là:

  • Ở file index.js ở line 2 viết console.log("bye there")

Vậy git sẽ làm thế này:

  • Apply những thay đổi vào nhánh master: ở file index.js ở line 2 viết console.log("bye there")
  • Tự động tạo một version mới ở nhánh master (add and commit)

Tóm tắt lại, có 5 bước bạn phải làm khi nhận một task mới:

  • git checkout -b [new branch]
  • git add [file name]
  • git commit -m [message]
  • git checkout master
  • git merge [new branch]

Conflict và resolve conflict

Bây giờ bạn đã hiểu một workflow đơn giản khi nhận một task mới bạn phải làm thế nào, tiếp đến ở phần này hãy giải thích về conflict. Khi nào thì conflict xảy ra và làm sao để resolve conflict?

Tưởng tượng có 2 người nhận 2 task mới cùng một lúc:

  • Task #1: Thêm console.log(1) vào file main.js
  • Task #2: Thêm console.log(2) vào file main.js

Cả 2 người này sẽ tạo 2 nhánh mới xuất phát từ cùng một điểm trên nhánh master. Mình có hình minh họa dưới đây giải thích làm các task lần lượt khác với nhiều người làm các task cùng lúc khác nhau như thế nào.

Để giả sử mình là 2 người làm 2 task một lúc, mình sẽ làm thế này. Đầu tiên mình sẽ tạo nhánh feature/print_1 rồi git addgit commit -m trên đó, nhưng tiếp theo chưa merge ngay vào nhánh master, mà từ nhánh master tạo tiếp nhánh feature/print_2 rồi git addgit commit -m xong nhánh đó, rồi mới merge cả 2 nhánh feature/print_1feature/print_2 vào master.

Nếu bạn thấy ở trên mình nói hơi... khó hiểu, dưới đây là hình vẽ minh họa mình sẽ làm gì:

Đầu tiên hãy hoàn thành task #1. Theo "đúng quy trình", mình sẽ phải làm thế này:

  • Tạo một nhánh mới
  • Tạo file main.js mới và thêm vào đó console.log(1)
  • Tạo một version mới: git add rồi git commit -m

Đầu tiên, hãy kiểm tra mình đang ở nhánh nào:

git branch

Đây là kết quả của mình:

 feature/bye_there
* master

Điều này có nghĩa mình đang ở nhánh master. Hãy đảm bảo rằng mình đang ở nhánh master trước khi tiếp tục.

Tiếp theo, hãy tạo nhánh feature/print_1.

git checkout -b feature/print_1

Bây giờ hãy cùng kiểm tra xem mình đang ở nhánh nào:

git branch

Đây là kết quả của mình

 feature/bye_there
* feature/print_1 master

Điều này có nghĩa là mình có 3 nhánh và mình đang ở nhánh feature/print_1.

Hãy hoàn thành task #1 bằng cách tạo file main.js với console.log(1):

console.log(1)

Tiếp đến, hãy tạo một version mới trên nhánh này:

git add main.js

rồi

git commit -m "[feature] add console log 1"

Bình thường bước cuối cùng sẽ là merge feature/print_1 vào master nhưng vì mình đang giả sử 2 người làm 2 task cùng lúc, mình sẽ chưa merge ngay vội.

Tiếp theo, hãy hoàn thành task #2.

Theo "đúng quy trình", mình sẽ làm theo các bước này:

  • Chuyển về nhánh master
  • Tạo một nhánh mới là feature/print_2
  • Làm task #2 trên nhánh này: tạo file main.js mới với console.log(2)

Đầu tiên, hãy chuyển về nhánh master:

git checkout master

Bạn sẽ thấy file main.js biến mất tại vì ở nhánh master thì file đó còn chưa tồn tại.

Bây giờ hãy tạo nhánh feature/print_2:

git checkout -b feature/print_2

Hãy tạo một thói quen tốt kiểm tra mình đang ở trên nhánh nào:

git branch

Đây là kết quả của mình:

 feature/bye_there feature/print_1
* feature/print_2 master

Điều này có nghĩa project hiện tại của mình có 4 nhánh và mình đang ở nhánh feature/print_2

Bây giờ hãy làm task #2 bằng cách tạo file main.js với nội dung như sau:

console.log(2)

Tiếp theo, hãy tạo một version mới trên nhánh feature/print_2 này:

git add main.js

rồi

git commit -m "[feature] add console log 2"

Ok vậy là mình hoàn thành task #2 rồi!

Bây giờ hãy merge nhánh feature/print_1 and feature/print_2 vào master.

Bước đầu tiên là chuyển về nhánh master:

git checkout master

Đầu tiên hãy merge nhánh feature/print_1 vào master:

git merge feature/print_1

Tiếp theo, hãy merge nhánh feature/print_2 vào master:

git merge feature/print_2

Và... conflict xảy ra! Khi gõ lệnh merge bên trên bạn sẽ nhìn thấy git thông báo conflict:

Auto-merging main.js
CONFLICT (add/add): Merge conflict in main.js
Automatic merge failed; fix conflicts and then commit the result.

Mình có conflict ở file main.js. Nếu bạn mở file main.js, bạn sẽ nhìn thấy như sau:

<<<<<<< HEAD
console.log(1);
=======
console.log(2);
>>>>>>> feature/print_2

Nếu bạn sử dụng VSCode, đây sẽ là cái mà bạn nhìn thấy:

Git đánh dấu chỗ nào có conflict bằng cách dùng <<<< HEAD, ======, >>>>> feature/print_2. Bây giờ nhiệm vụ của mình sẽ là resolve conflict.

Nhưng trước tiên hãy giải thích tại sao conflict lại xảy ra ở main.js, HEAD (current change) và incoming change mà VSCode hiển thị nghĩa là gì.

Một cách ngắn gọn, conflict xảy ra vì ở cả 2 nhánh feature/print_1feature/print_2 đều có file main.js mà ở cùng một dòng lại khác nhau (chính xác hơn là chỉnh sửa một cách khác nhau). Ở feature/print_1console.log(1). Ở feature/print_2console.log(2).

HEAD chỉ mình đang ở nhánh nào: master, trong khi "Incoming change" chỉ đến nhánh mà mình muốn merge vào master: feature/print_2.

Nếu bạn muốn mình giải thích kỹ hơn một chút, bạn có thể đọc tiếp dưới đây.

Đầu tiên, khi mình merge nhánh feature/print_1 vào master, git sẽ merge những thay đổi ở nhánh feature/print_1 vào master:

  • Tạo file main.js mới
  • Ở file main.js ở dòng 1 viết console.log(1)
  • Add và commit (trên nhánh master)

Tiếp theo, khi mình merge nhánh feature/print_2 vào master, git sẽ merge những thay đổi ở nhánh feature/print_2 vào master. Vậy git sẽ làm thế này:

  • Tạo file main.js mới (file đã có!)
  • Ở file main.js ở dòng 1 viết console.log(2)
  • Add and commit (trên nhánh master)

Tuy nhiên ở bước thứ hai thì file main.js ở dòng 1 đã là console.log(1). Đây là lý do conflict xảy ra.

Vậy làm sao để mình resolve conflict này? Trong trường hợp này, vì mình phải hoàn thành cả 2 task nên mình sẽ giữ cả 2 cái console.log.

main.js xóa những cái git thêm vào để đánh dấu conflict xảy ra ở đâu <<<<< HEAD, =====, >>>>> feature/print_2:

console.log(1);
console.log(2);

Bây giờ ở file main.js có cả 2 dòng console.log, có nghĩa là mình đã làm cả task #1 và task #2. Sau khi resolve conflict thành công, hãy add và commit file main.js:

git add main.js

rồi

git commit -m "Merge branch 'feature/print_2'"

Ok vậy là mình resolve conflict xong rồi! Đó là cách mình resolve conflict!

Giải thích các command ở phần 1

Ở phần 1, mình nói là 2 command git checkout mastergit switch -c mình sẽ giải thích ở phần này sau khi nói về nhánh. Bây giờ mình sẽ giải thích nó.

Có lẽ bây giờ bạn đã biết git checkout master là để chuyển về nhánh master. Nhưng ngoài việc bạn có thể dùng nó để chuyển nhánh bạn còn có thể dùng nó để thoát khỏi "preview mode" nữa. Nếu bạn đang ở nhánh feature/print_1 chẳng hạn và dùng git checkout [version hash] để xem các version trước, bạn có thể dùng git checkout feature/print_1 để thoát khỏi preview mode đó!

Lệnh tiếp theo git switch -c là để tạo ra một nhánh mới từ commit đó và chuyển sang nhánh mới đó. Với lệnh này, bạn không phải dùng git reset --hard [version-hash] (bạn sẽ không xem lại được những version sau đó nữa).

A fun thought experiment

Vậy là phần 2 kết thúc ở đây. Chúc mừng bạn đã học được những lệnh cơ bản về version và nhánh của Git! Bây giờ bạn có thể tự thưởng cho mình một ván game sau khi đã học hành vất vả!

Nhưng cho phần kết mình có "bài tập" vui nho nhỏ để giúp bạn quen thuộc hơn về khái niệm về nhánh và những lệnh cơ bản của git.

Bạn đã bao giờ thấy cái ảnh hài này chưa?

Bạn đã bao giờ nghe các bạn làm designer phàn nàn về việc khách hàng suốt ngày thay đổi thiết kế chưa? Kiểu các bạn ấy bỏ 1 tiếng ra chỉnh sửa thiết kế theo ý khách hàng, chỉ để khách hàng bảo hãy làm lại như ban đầu đi. Mà nữa, nhiều khi các bạn ấy phải edit lại về ban đầu vì nó đã quá giới hạn bấm Ctrl + Z.

Bây giờ bạn đã biết dùng Git, bạn sẽ làm gì khi gặp tình huống này:

  • Khách hàng muốn bạn chỉnh sửa ảnh cho cô ấy
  • Khách hàng muốn bạn thêm chút tương phản và ánh sáng cho bức ảnh
  • Rồi khách hàng muốn bạn dùng Liquidfy để nhìn cô ấy cho thon hơn
  • Rồi cô ấy hơi... hối hận và bảo bạn revert lại như ban đầu (nhìn trông ảo quá!)
  • Rồi cô ấy bảo bạn có cách nào cho tóc cô ấy thành màu hồng không
  • Xong cô ấy lại bảo bạn thử chỉnh tóc cô ấy thành màu xanh nước biển xem có xinh hơn không
  • Xong cô ấy muốn tóc hồng
  • Xong cô ấy muốn làm cho mắt cô ấy to hơn chút
  • Tuyệt vời! Cô ấy cảm ơn bạn.

Nếu bạn không biết Liquidfy trong Photoshop làm gì, mình có bức ảnh này giải thích cho bạn:

Ok sau khi bạn đã hiểu về "chi tiết kỹ thuật" Liquidfy là gì, bây giờ mình sẽ giải thích mình có thể dùng git như thế nào trong tình huống này.

Đây là hình vẽ giải thích mình sẽ làm thế nào:

Giả sử mình làm việc trên file cute-photo.psd:

  • Khách hàng muốn bạn chỉnh sửa ảnh cho cô ấy
    • git init
    • git add cute-photo.psd
    • git commit -m "initial commit"
  • Khách hàng muốn bạn thêm chút tương phản và ánh sáng cho bức ảnh
    • git checkout -b feature/dramatic_lighting
    • git add cute-photo.psd
    • git commit -m "[feature] add dramatic lighting"
    • git checkout master
    • git merge feature/dramatic_lighting
  • Rồi khách hàng muốn bạn dùng Liquidfy để nhìn cô ấy cho thon hơn
    • git checkout -b feature/liquidfy
    • git add cute-photo.psd
    • git commit -m "[feature] liquidfy thinner"
    • git checkout master
    • git merge feature/liquidfy
  • Rồi cô ấy hơi... hối hận và bảo bạn revert lại như ban đầu (nhìn trông ảo quá!)
    • git reset --hard [commit-hash]
  • Rồi cô ấy bảo bạn có cách nào cho tóc cô ấy thành màu hồng không
    • git checkout -b feature/hair_pink
    • git add cute-photo.psd
    • git commit -m "[feature] change hair to pink"
  • Xong cô ấy lại bảo bạn thử chỉnh tóc cô ấy thành màu xanh nước biển xem có xinh hơn không
    • git checkout master
    • git checkout -b feature/hair_blue
    • git add cute-photo.psd
    • git commit -m "[feature] change hair to blue
  • Xong cô ấy muốn tóc hồng
    • git checkout master
    • git merge feature/hair_pink
  • Xong cô ấy muốn làm cho mắt cô ấy to hơn chút
    • git checkout -b feature/eyes_bigger
    • git add cute-photo.psd
    • git commit -m "[feature] make eyes bigger"
    • git checkout master
    • git merge feature/eyes_bigger
  • Tuyệt vời! Cô ấy cảm ơn bạn.

Bạn đã bao giờ thắc mắc tại sao người ta không sử dụng Git khi làm việc với Photoshop, Illustrator, Blender, Maya,... chưa? Chẳng lẽ Git chỉ dùng được với code thôi hả?

Không phải. Bạn hoàn toàn có thể dùng Git để quản lý version những file .psd hay .ai,... Nếu bạn thử chạy những lệnh git add, git commit -m,... nó hoạt động hoàn toàn bình thường! Lý do mà người ta không làm việc này là vì khi conflict xảy ra, bạn không thể fix được. Những file Photoshop, Illustrator, Blender,... là binary file, nghĩa là bên trong nó toàn là 0 với 1, bạn còn không thể đọc được chứ đừng nói là resolve conflict.

Kết luận

Hãy cùng tóm tắt lại những gì mình đã học trong bài viết này:

  • git branch: xem mình đang ở branch nào
  • git checkout [branch name]: chuyển sang một branch khác
  • git checkout -b [new branch]: tạo một branch mới
  • git merge [branch name]: merge một branch khác vào branch hiện tại mình đang ở
  • Conflict và làm sao để resolve conflict

Ở phần 3 mình sẽ nói tiếp đến làm sao để làm việc với remote repository như là Github, Gitlab: git push, git pull, git clone,...

Credits

Nếu bạn thích con cá mà mình sử dụng, hãy xem: https://thenounproject.com/browse/collection-icon/stripe-emotions-106667/.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Những lệnh Git cơ bản cần nhớ

1. Cơ bản vê Git.

0 0 44

- vừa được xem lúc

5 Chiêu thức luyện công cùng Git

Khởi động. Để chuẩn bị tốt cho các chiêu thức sắp được trình bày, chúng ta cùng khởi động, ôn luyện một chút nhé.

0 0 57

- vừa được xem lúc

Một số trường hợp khi sử dụng git

Giới thiệu. Ở bài viết trước, mình đã giới thiệu các lệnh cơ bản thường dùng trong git.

0 0 36

- vừa được xem lúc

Git và những điều cơ bản bạn cần biết?

Những điều cơ bản về Git. Làm thế nào để xoá một branch ở phía local, làm thế nào để xoá một branch remote.

0 0 41

- vừa được xem lúc

[GIT] Làm việc với Git như một Senior

Khai niệm. . Git được hiểu đơn giản là một Version quản lý source-code. Hiện tại git được sử dụng rộng rãi trong quy trình phát triển phần mềm.

0 0 45

- vừa được xem lúc

Một số lưu ý, kinh nghiệm khi sử dụng Git

Chỉ là một chút kinh nghiệm cá nhân tự note để xem lại nên đa phần mình viết để gợi nhớ lại cho bản thân, để có thể đọc lại khi cần . .

0 0 41