Một vài câu hỏi về Git

Giới thiệu

Có thể nói rằng khi bạn đã là một lập trình viên, dù là newbie hay developer,...chắc chắn bạn đã từng nghe hay thậm chí còn đang sử dụng Git. Vậy Git là gì và tại sao Git hay được nhắc đến trong các bài viết liên quan đến lập trình đến thế? Git có cần thiết cho bạn, lập trình viên thường xuyên tham gia các dự án không? Trong bài viết này, chúng ta sẽ cùng tìm hiểu và trả lời một số câu hỏi về Git để hiểu và mạnh dạn ứng dụng Git khi cần thiết.

Mục Lục

  • Thế nào là repository, branch.
  • Làm thế nào để xoá một branch ở phía local, làm thế nào để xoá một branch remote
  • Làm thế nào để push một branch ở local lên remote dưới một cái tên khác
  • Thế nào là git rebase. Phân biệtrebase với merge
  • Thế nào là git fetch. Phân biệt fetch với pull
  • Thế nào là git stash
  • Làm thế nào xoá bỏ trạng thái của một vài commit gần đây
  • Làm thế nào để gộp một vài commit thành 1 commit duy nhất
  • Phân biệt git reset,git reset --hard,git reset –soft
  • Thế nào là cherry-pick, khi nào thì dùng cherry-pick
  • Git flow

Git là một trong những Hệ thống Quản lý Phiên bản Phân tán, được phát triển bởi Linus Torvalds vào năm 2005, vốn được phát triển nhằm quản lý mã nguồn (source code) của Linux. Trên Git, ta có thể lưu trạng thái của file dưới dạng lịch sử cập nhật. Vì thế, có thể đưa file đã chỉnh sửa một lần về trạng thái cũ hay có thể biết được file đã được chỉnh sửa chỗ nào.

1. Thế nào là repository, branch?

Repository: Repository (nhà kho) hay được gọi tắt là Repo đơn giản là nơi chứa/cơ sở dữ liệu (database) tất cả những thông tin cần thiết để duy trì và quản lý các sửa đổi và lịch sử của dự án.

Tất cả dữ liệu của Repository đều được chứa trong thư mục bạn đang làm việc dưới dạng folder ẩn có tên là .git Repository có hai loại: Remote repository: Là repository để chia sẻ giữa nhiều người và bố trí trên server chuyên dụng. Local repository: Là repository bố trí trên máy của bản thân mình, dành cho một người dùng sử dụng.

Bạn có thể có được một repository Git theo một trong hai cách sau:

  • Bạn có thể clone kho lưu trữ Git hiện có từ nơi khác.
  • Bạn tạo một thư mục local không thuộc quyền kiểm soát phiên bản và biến nó thành kho lưu trữ Git. Branch: Là phân nhánh ghi lại luồng thay đổi của lịch sử, các hoạt động trên mỗi branch sẽ không ảnh hưởng lên các branch khác nên có thể tiến hành nhiều thay đổi đồng thời trên một repository, giúp giải quyết được nhiều nhiệm vụ cùng lúc.
  • Khi đã phân nhánh thì các branch làm viêc độc lập, một branch thay đổi sẽ không ảnh hưởng đến branch khác trong cùng repo
  • Khi bạn tạo một repository thì Git sẽ thiết lập branch mặc định là master, nghĩa là nó sẽ tự tạo một branch master và mọi hoạt động của ban lúc này đều nằm trên branch master.
  • Khi làm việc để hợp các branch lại với nhau chúng ta thực hiện merge branch.

Local branch: Là nhánh ở local, tồn tại trên máy local của bạn và tất nhiên chỉ bạn mới có thể nhìn thấy. Local tracking branch: Là một nhánh local để theo dõi các nhánh khác. Điều này để cam kết rằng bạn có thể push lên/pull về các commit các nhánh khác. Remote branch: là branch lưu ở remote. Branch này có thể fetch về local nhưng không tạo thêm branch ở local. Remote tracking branch: là một bản sao cục bộ (local) của một nhánh remote

2. Làm thế nào để xoá một branch ở phía local, làm thế nào để xoá một branch remote?

Xóa một branch ở phía local: Cách 1:

$ git branch -d <branch_name>

Cách 2:

$ git branch -D <branch_name>

Cách 3:

$ git branch --delete <branch_name>

hoặc:

 $ git branch --delete --force <branch_name>

Xóa một branch remote:

$ git push --delete <ten_remote> <branch_name>

hoặc:

$ git push <ten_remote> --delete <branch_name>

3. Làm thế nào để push một branch ở local lên remote dưới một cái tên khác?

(Ví dụ như ở local tên branch là task#1, và muốn push lên branch develop ở remote ). Local và remote cùng tên banch:

 $ git push <remote_name> <branch_name>

Ví dụ: Bạn muốn push branch task#1 ở local lên branch task#1 trên remote

 $ git push origin task#1

Local và remote khác tên branch:

$ git push origin <local_branch>:<remote_branch>

​ Ví dụ: Bạn muốn push branch task#1 ở local lên branch develop trên remote

$ git push origin task#1:develop

4. Thế nào là git rebase. Phân biệt rebase với merge

Thế nào là git rebase? Git rebase là tích hợp các thay đổi từ nhánh này vào nhánh khác. Thực tế, git có hai cách chính để tích hợp các thay đổi từ nhánh này vào nhánh khác: đó là merge và rebase.

  • Chú ý vào rebase, mọi người sẽ thấy commit của rebase nằm phía trên commit mới nhất của nhánh. Còn ở merge, mọi người sẽ thấy commit của nhánh nằm phía trên commit mới nhất của merge, ngoài ra một commit Merge branch cũng được tạo ra.

Phân biệt rebase với merge

git rebase

Trước tiên bạn chuyển sang branch đang làm việc

$ git checkout <working_branch>

Thực hiện tích hợp branch <rebase_branch> vào branch trên.

$ git rebase <rebase_branch>

git merge

 $ git merge <merge_branch>

5. Thế nào là git fetch. Phân biệt fetch với pull

Thế nào là git fetch? Khi thực hiện pull, merge nội dung của remote repository sẽ tự động được tiến hành. Tuy nhiên, cũng có trường hợp chỉ đơn giản muốn kiểm tra nội dung của remote repository mà không muốn merge. Những lúc như vậy hãy sử dụng fetch.

Phân biệt fetch với pull

  • Khi bạn sử dụng fetch, Git thu thập bất kỳ commit từ các branch của remote không tồn tại ở branch hiện tại của bạn và lưu trữ chúng trong kho local của bạn. Tuy nhiên, nó không kết hợp chúng với branch hiện tại của bạn. Điều này đặc biệt hữu ích nếu bạn cần để giữ cho các kho lưu trữ của bạn đến nay, nhưng đang làm việc trên một cái gì đó có thể phá vỡ nếu bạn cập nhật các tập tin của bạn. Để tích hợp các commit vào branch tổng thể của bạn, bạn sử dụng kết hợp.
$ git fetch [<options>] [<repository> [<refspec>…​]]
$ git fetch [<options>] <group>
$ git fetch --multiple [<options>] [(<repository> | <group>)…​]
$ git fetch --all [<options>]

Ví dụ bạn muốn fetch từ branch develop remote về banch develop ở local của bạn

$ git fetch framgia develop:develop
  • Khi bạn sử dụng pull, Git cố gắng tự động làm công việc của bạn cho bạn. nó là bối cảnh nhạy cảm , Git sẽ kết hợp bất kỳ commit kéo vào các branch của bạn hiện đang làm việc. Pull tự động kết hợp các commit mà không để cho bạn xem lại đầu tiên. Nếu bạn không quản lý chặt chẽ các branch của bạn, bạn có thể gây mâu thuẫn giữa các commit.
  • Thực chất khi bạn sử dụng git pull là bạn đã sử dụng git fetchgit merge rồi.
$ git pull [options] [<repository> [<refspec>…​]]

Ví dụ bạn muốn pull từ branch remote về branch develop ở local của bạn

$ git pull framgia develop

6. Thế nào là git stash?

Git stash được sử dụng khi muốn lưu lại các thay đổi nhưng chưa commit, thường rất hữu dụng khi bạn muốn đổi sang 1 branch khác mà lại đang làm dở ở branch hiện tại. Một số lệnh với stash Xem danh sách stash:

$ git stash list [<options>]

Apply stash gần nhất và xóa stash đó:

 $ git stash pop

Apply stash:

$ git stash apply [email protected]{<index>} 

Xem nội dung stash:

$ git stash show [email protected]{<index>}

Xóa stash:

$ git stash drop [email protected]{<index>}

Xóa toàn bộ stash:

$ git stash clear

Lưu toàn bộ nội dung công việc đang làm dở, sử dụng lệnh:

$ git stash save

hoặc

 $ git stash

7. Làm thế nào xoá bỏ trạng thái của một vài commit gần đây

Có 2 cách để thực hiện công việc này:

Cách 1: Sử dụng git revert

 $ git revert <commit>

Lệnh này tạo commit đảo ngược commit có commit đã chọn, commit chỉ định bị xoá bỏ, các commit mới hơn vẫn được giữ nguyên. Cách 2: Sử dụng git reset --hard

$ git reset --hard <commit>

Lệnh này sẽ xoá toàn bộ các commit trước đó và đưa branch về trạng thái của commit có commit_id đã chọn.

8. Làm thế nào để gộp một vài commit thành 1 commit duy nhất?

Để gộp nhiều commit thành 1 commit duy nhất, ta có thể sử dụng câu lệnh:

 $ git rebase -i <commit_end>

hoặc

$ git rebase -i HEAD~<index>

<commit_end>: là id của commit cuối trong nhóm cần gộp. <index>: số commit cần gộp. Ta có các lựa chọn pick|squash|fixup các commit trước khi save.

9. Phân biệt git reset, git reset --hard, git reset --soft

Git reset

 $ git reset <commit>

Di chuyển con trỏ về vị trí commit reset và vẫn giữ nguyên tất cả các thay đổi của file, nhưng loại bỏ các thay đổi khỏi stage.

Git reset --hard

$ git reset --hard <commit>

Khi dùng --hard, commit sẽ được bỏ đi và bỏ cả những thay đổi chưa được commit trong working space. Khi này môi trường sẽ hoàn toàn "sạch sẽ" như thời điểm trước khi commit.

Git reset --soft

$ git reset --soft <commit>

Khi dùng --soft, commit sẽ được bỏ đi nhưng giữ nguyên những thay đổi chưa được commit trong working space. Lệnh này hữu dụng khi bạn muốn giữ lại những thay đổi chưa commit cho lần commit tiếp theo.

10 . Thế nào là cherry-pick, khi nào thì dùng cherry-pick

Giả sử bạn có 2 branches khác nhau cho 2 khách hàng khác nhau, tạm gọi là branch A và branch B. Và bạn đang fix một bug nghiêm trọng cùng tồn tại trên hệ thống của cả 2 khách hàng, bạn muốn chỉ commit một lần nhưng có thể apply vào luôn cả 2 branches.

Bạn có thể dùng lệnh cherry-pick của Git để giải quyết, như sau:

  • Đang ở branch A, commit những thay đổi đó
$ git add -A
$ git commit -m "Awesome Bug Fixed :("
  • Chuyển qua branch B và thực hiện lệnh cherry-pick
$ git checkout B
$ git cherry-pick A

cherry-pick sẽ lấy commit cuối cùng ở branch A merge vào branch B. Ngoài ra, bạn còn có thể chỉ định danh sách các commit cần "bốc" từ A để "bỏ" vào B nếu cần thiết.

11. Git Flow

) Git Flow là một tập các thao tác mở rộng của git nhằm cung cấp các thao tác repository (kho mã nguồn) ở mức cao dựa trên mô hình phân nhánh của Vincent Driessen.

  • Git flow cung cấp giao diện trợ giúp và đầu ra rất tuyệt vời. Hãy đọc chúng cẩn thận để xem điều kì diệu gì sẽ xảy ra =))
  • Git Client - Sourcetree là một Git Client có giao diện GUI rất tiện lợi và cũng hỗ trợ luôn git-flow trên giao diện.
  • Git-flow là một giải pháp dựa trên merge. Nó không rebase các nhánh tính năng.

Môi trường:

  • Bạn cần cài đặt git trước khi có thể cài git-flow.
  • Git flow có thể hoạt động trên OSX, Linux và Windows.

Khởi tạo: Sau khi di chuyển tới thư mục dự án, chạy lệnh sau để khởi tạo git-flow.

$ git flow init

Bạn sẽ cần trả lời một số câu hỏi cho việc thiết lập git-flow sau câu lệnh khởi tạo. Chúng tôi khuyên bạn nên sử dụng các giá trị [mặc định]. Các tính năng: Bắt đầu một tính năng Phát triển tính năng mới bắt đầu từ nhánh phát triển 'develop'. Ví dụ với tính năng MYFEATURE:

$ git flow feature start MYFEATURE

Lệnh này sẽ tạo ra một nhánh mới dựa trên nhánh 'develop' và chuyển sang nhánh mới này.

Kết thúc một tính năng Sau khi phát triển xong một tính năng, lệnh kết thúc tính năng sẽ thực hiện các thao tác:

  • Merge nhánh tính năng - MYFEATURE vào nhánh 'develop'
  • Xoá nhánh tính năng
  • Chuyển sang nhánh 'develop'
$ git flow feature finish MYFEATURE

Công bố tính năng Khi bạn làm việc với những người khác trên cùng một tính năng, bạn sẽ cần công bố phần mã nguồn của bạn cho tính năng đó lên remote để những người khác có thể cập nhập được.

$ git flow feature publish MYFEATURE

Lấy về tính năng Pull mã nguồn của tính năng được cập nhập bởi những thành viên khác.

$ git flow feature pull REMOTE_NAME MYFEATURE

Tạo một bản release

  • Hỗ trợ chuẩn bị cho bản release.
  • Cho phép sửa các lỗi nhỏ và chuẩn bị meta-data cho release.

Bắt đầu release Để bắt đầu release, sử dụng lệnh release của git flow. Lệnh này sẽ tạo ra nhánh 'release' từ nhánh 'develop'.

$ git flow release start RELEASE [BASE]

Tùy chọn [BASE] cho phép commit được một giá trị hash sha-1. Trường hợp không chỉ định tùy chọn này thì HEAD sẽ được sử dụng. Để công bố phần code 'release' của mình cho các thành viên khác, ta có thể làm tương tự như với công bố tính năng bằng lệnh sau:

$ git flow release publish RELEASE

Bạn có thể theo dấu remote 'release' bằng lệnh

git flow release track RELEASE

Kết thúc release

  • Kết thúc release là một bước lớn trong chiến lược phân nhánh git. Nó thực hiện các việc sau:
  • Merge nhánh 'release' vào nhánh 'master'
  • Gắn tag ở nhánh 'master' dành cho bản release
  • Merge lại nhánh 'release' vào nhánh 'develop'
  • Xóa bỏ nhánh 'release'

Sửa đổi nóng - hotfix Bắt đầu hotfix Giống như các lệnh khác của git flow, hotfix bắt đầu với:

$ git flow hotfix start VERSION [BASENAME]

Tham số VERSION ở đây chỉ định tên của phiên bản release hotfix này. Còn tham số tùy chọn basename sẽ chỉ định tên nhánh cơ bản thay cho hotfix thay vì nhánh 'master' Kết thúc hotfix Kết thúc hotfix sẽ merge lại nội dung thay đổi vào nhánh 'develop' và 'master'. Ở nhánh 'master' sẽ được gắn tag là phiên bản của hotfix.

$ git flow hotfix finish VERSION

Tổng hợp các lệnh

Kết luận

Qua bài viết chắc hẳn mọi người cũng phần nào hiểu thêm về git, và sẵn sàng dùng nó cho công việc của mình. Hy vọng bài viết mang lại cho mọi người nhiều kiến thức, cũng như kinh nghiệm bổ ích cho lập trình viên.