12/08/2018, 13:01
Một số thủ thuật nhỏ làm việc với GIT
Là một developer mới được tiếp xúc với GIT chưa lâu, mình thấy rõ được sự "kỳ diệu" của công cụ quản lý code này. GIT kỳ diệu như thế nào thì còn phải phân tích nhiều; nhưng ít ra, bạn có thể thoải mái code mà không lo ngại sẽ lỡ tay làm hỏng, hay là phá cả hủy hệ thống... =)). Tìm hiểu chi ...
Là một developer mới được tiếp xúc với GIT chưa lâu, mình thấy rõ được sự "kỳ diệu" của công cụ quản lý code này. GIT kỳ diệu như thế nào thì còn phải phân tích nhiều; nhưng ít ra, bạn có thể thoải mái code mà không lo ngại sẽ lỡ tay làm hỏng, hay là phá cả hủy hệ thống... =)). Tìm hiểu chi tiết ở đây
Một khái niệm cực kỳ quan trọng trong GIT đó là commit. Làm việc với GIT thì chắc là sẽ rất hay gặp. Bạn có thể đọc thêm ở bài viết này hoặc là chịu khó google search nhé
Bài viết này, mình xin chia sẻ một số thủ thuật nhỏ mà mình đã sử dụng trong dự án gần đây để thao tác với commit. Tất nhiên, nó sẽ không hoàn toàn phù hợp cho tất cả các trường hợp và cũng có thể không phải là cách tối ưu nhất, nhưng bạn có thể áp dụng cho một số trường hợp cụ thể
Thủ thuật được đề cập ở đây là cherry-pick với commit
Cherry-pick
1. Đặt vấn đề
Giả sử bạn phải làm việc trên nhánh base là master có 2 file với nội dung như sau
- ####File file1.txt origin content of file1
- ####File file2.txt origin content of file2
Mỗi khi tiến hành code một task mới (code trên file file2.txt) thì bạn cần phải thêm một đoạn code sau vào cuối file file1.txt. Nó là điều kiện để bạn có thể chạy được ứng dụng ở trên local
Tuy nhiên khi bạn đã code xong cho task, trước khi push code lên để tạo pull request thì bạn phải bỏ phần code điều kiện này đi, và chỉ để lại phần code cho task của bạn ở file file2.txt
Nếu chỉ như trên thì không có gì phải bàn luận, trường hợp mình muốn nói tới ở đây là, có nhiều task cùng cần một cái điều kiện như vậy (ở đây là đoạn code trong file file1.txt mình nhắc đến ở trên) thì sẽ giải quyết như thế nào?
Bạn có thể cứ mỗi khi tạo nhánh làm task mới thì bạn sẽ thêm điều kiện này vào một cách thủ công. Nhưng như thế thì rất bị động, và với phần điều kiện có nhiểu thay đổi thì rất bất tiện khi làm việc
Dưới đây là 2 cách thao tác với GIT có thể dùng để giải quyết được việc này
2. Giải quyết
C1. Cách cổ điển - rebase
Trước tiên, từ master, bạn tạo một nhánh mới để chứa phần code điều kiện. Ở đây mình tạo nhánh pre-run
Tiến hành code cho phần điều kiện ở trên nhánh pre-run. Giả sử sau khi thay đổi thì 2 file trên sẽ như sau
origin content of file1 content of prepare to run # new line ===================================== origin content of file2
commit để tổ chức phần code điều kiện này như bình thường. Khi đó, kiểm tra log ở nhánh này ta có như bên dưới
$ git log --oneline eead22b prepare to run 2879ed2 Improve the README and create test_file fb4a53b init repo
Tiếp đó, từ pre-run, tạo mới nhánh branch-1 và tiến hành code cho task của mình. 2 file đó sẽ thành
origin content of file1 content of prepare to run # new line ===================================== origin content of file2 content of branch-1 # new line
Ta cũng commit cho phần này và kiểm tra lại log
$ git log --oneline af8507b code for branch-1 eead22b prepare to run 2879ed2 Improve the README and create test_file fb4a53b init repo
Việc còn lại là chúng ta sẽ dùng câu lệnh rebase để đẩy branch-1 về ngay sau master mà không phải qua pre-run nữa. Ta dùng cấu trúc git rebase --onto target-branch source-branch và kiểm tra lại log
$ git rebase --onto master pre-run $ git log --oneline a6668fc code for branch-1 2879ed2 Improve the README and create test_file fb4a53b init repo
Bạn có thể xem kĩ hơn về rebase --onto tại đây
Thay đổi hiện tại của bạn sẽ là (1)
origin content of file1 ===================================== origin content of file2 content of branch-1 # new line
Hoàn thành. Việc còn lại là đẩy code lên remote thôi
Với task mới thì bước đầu tiên là sẽ rebase nhánh pre-run đã có về master (đã ở version mới tại thời điểm đó) và project sẽ trở về trạng thái như (1)
Tiếp đó, lại tạo nhánh mới để code và tiếp tục tiến hành như trên
C2. cherry-pick commit
Tạo ra nhánh new-pre-run chứa code điều kiện cho task mới
Bạn chỉ cần lần về trước, kiểm tra log để tìm xem commit nào chứa phần điều kiện. Ở đây, đó là commit có mã SHA rút gọn eead22b ở nhánh pre-run bên trên
Từ nhánh new-pre-run, chúng ta chỉ cần cherry-pick commit đó để đưa code điều kiện vào đây
$ git cherry-pick eead22b
Ta có thể hiểu đơn giản là nếu rebase và merge thao tác với các nhánh thì cherry-pick lại là câu lệnh chỉ thao tác với các commit. Bạn có thể xem thêm chi tiết ở đây hoặc dùng lệnh để đọc doc
$ git cherry-pick --help
Quay trở lại, câu lệnh này sẽ tiến hành sao chép những thay đổi trong commitcó mã eead22bở trên và tạo ra một 'commit' mới với nội dung hoàn toàn giống, chỉ khác nhau mã SHA. Mã commit mới này là 13b0749 Kiểm tra log
$ git log --oneline 13b0749 prepare to run 2879ed2 Improve the README and create test_file fb4a53b init repo
Đến đây thì nhánh new-pre-run đã nghiễm nhiên có toàn bộ phần code điều kiện để chúng ta làm việc. Chúng ta sẽ tiến hành code ngay trên nhánh new-pre-run này luôn với 2 file như sau
origin content of file1 content of prepare to run # new line ============================================== origin content of file2 content of branch-3 for cherry-pick # new line
Sau khi code xong thì cũng commit để tổ chức code như bình thường
$ git log --oneline 528a5bd code for cherry-pick test 13b0749 prepare to run 2879ed2 Improve the README and create test_file fb4a53b init repo
Đến đây, chúng ta lại về nhánh master và tiến hành cherry-pick commit 528a5bd và kiểm tra kết quả
$ git log --oneline 3f2092f code for cherry-pick test 2879ed2 Improve the README and create test_file fb4a53b init repo
Và ta lại có được phần code như mong muốn tương tự (1) . Với task mới thì cũng làm hoàn toàn tương tự
2. Lời kết
Với cách dùng rebase thì bạn có thể chỉ cần tạo ra một nhánh duy nhất chưa phần code điều kiện đó để dùng cho nhiều task
Còn với cách dùng cherry-pick thì mỗi task bạn tạo ra một nhánh trung gian để chứa phần code điều kiện, nhưng có thể tiến hành code ngay trên nhánh trung gian đó luôn. Rất tiện lợi
Tất nhiên, trong quá trình sử dụng cherry-pick cũng như rebase, bạn phải nhuần nhuyễn khái niệm fix conflict đấy. =))
Tài liệu
- https://viblo.asia/nguyen.van.ngoc/posts/n157G5NZvAje
- https://viblo.asia/tand/posts/w5WQvzBnvk3E
- https://git-scm.com/docs/git-cherry-pick
- http://makandracards.com/makandra/10173-git-how-to-rebase-your-feature-branch-from-one-branch-to-another