Git: git rebase

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Bài viết này sẽ thảo luận chuyên sâu về lệnh git rebase. Lệnh Rebase cũng đã được xem xét khi thiết lập kho lưu trữ và viết lại các trang lịch sử. Bài viết này sẽ xem xét chi tiết hơn về cấu hình và thực thi git rebase. Các trường hợp sử dụng Rebase phổ biến và cạm bẫy cũng sẽ được đề cập trong bài viết.

Rebase là một trong hai tiện ích Git chuyên tích hợp các thay đổi từ nhánh này sang nhánh khác. Tiện ích tích hợp thay đổi khác là git merge. Merge luôn là một bản ghi thay đổi chuyển tiếp. Ngoài ra, rebase có các tính năng viết lại lịch sử mạnh mẽ. Bản thân Rebase có 2 chế độ chính là chế độ "thủ công" và "tương tác".

git rebase là gì?

Rebasing là quá trình di chuyển hoặc kết hợp một chuỗi các xác nhận thành một commit cơ sở mới. Việc khởi động lại là hữu ích nhất và dễ hình dung nhất trong ngữ cảnh của quy trình phân nhánh tính năng. Quy trình chung có thể được hình dung như sau:

Hướng dẫn Git: Git rebase

Từ góc độ nội dung, việc khởi động lại đang thay đổi cơ sở của nhánh của bạn từ một commit này sang một commit khác làm cho nó có vẻ như thể bạn đã tạo nhánh của mình từ một commit khác. Về nội hàm, Git hoàn thành việc này bằng cách tạo các xác nhận mới và áp dụng chúng cho cơ sở đã chỉ định. Điều rất quan trọng là phải hiểu rằng mặc dù nhánh trông giống nhau nhưng nó bao gồm các commit hoàn toàn mới.

Cách sử dụng

Lý do chính để rebasing là để duy trì lịch sử dự án tuyến tính. Ví dụ, hãy xem xét tình huống mà nhánh chính đã phát triển kể từ khi bạn bắt đầu làm việc với nhánh tính năng. Bạn muốn nhận các bản cập nhật mới nhất cho nhánh chính trong nhánh tính năng của mình, nhưng bạn muốn giữ lịch sử nhánh của mình sạch để có vẻ như bạn đang làm việc trên nhánh chính mới nhất. Điều này mang lại lợi ích sau này của việc merge hoàn toàn nhánh tính năng của bạn trở lại nhánh chính. Tại sao chúng ta muốn duy trì một "lịch sử sạch"? Lợi ích của việc có một lịch sử sạch trở nên hữu hình khi thực hiện các thao tác Git để điều tra việc giới thiệu hồi quy. Một kịch bản trong thế giới thực hơn sẽ là:

  1. Một lỗi được xác định trong nhánh chính. Một tính năng đã hoạt động thành công hiện đã bị hỏng.
  2. Nhà phát triển kiểm tra lịch sử của nhánh chính bằng cách sử dụng git log vì "lịch sử sạch" nên nhà phát triển có thể nhanh chóng suy luận về lịch sử của dự án.
  3. Nhà phát triển không thể xác định thời điểm lỗi được giới thiệu bằng cách sử dụng git log để nhà phát triển thực thi tệp git bisect.
  4. Vì lịch sử git sạch, nên git bisect có một tập hợp các commit được tinh chỉnh để so sánh khi tìm kiếm hồi quy. Nhà phát triển nhanh chóng tìm thấy commit đã gây ra lỗi và có thể hành động tương ứng.

Bạn có hai tùy chọn để tích hợp tính năng của mình vào nhánh chính: hợp nhất trực tiếp hoặc khởi động lại và sau đó hợp nhất. Tùy chọn trước dẫn đến merge 3 chiều và merge commit, trong khi tùy chọn sau dẫn đến hợp nhất chuyển tiếp nhanh và lịch sử tuyến tính hoàn hảo. Sơ đồ sau đây minh họa cách khởi động lại nhánh chính tạo điều kiện merge nhanh về phía trước.

Git rebase: Nhánh lên master

Khởi động lại là một cách phổ biến để tích hợp các thay đổi ngược dòng vào kho lưu trữ cục bộ của bạn. Kéo theo các thay đổi ngược dòng với merge Git dẫn đến một merge commit không cần thiết mỗi khi bạn muốn xem dự án đã tiến triển như thế nào. Mặt khác, rebasing giống như nói, "Tôi muốn thay đổi dựa trên những gì mọi người đã làm."

Không rebase lịch sử công khai

Như chúng ta đã thảo luận trước đây trong phần viết lại lịch sử, bạn không bao giờ nên rebase các commit khi chúng đã được đẩy lên kho lưu trữ công cộng. Việc rebase sẽ thay thế các commit cũ bằng các commit mới và có vẻ như phần đó trong lịch sử dự án của bạn đột ngột biến mất.

Git Rebase Standard so với Git Rebase Interactive

Tương tác Git rebase là khi git rebase chấp nhận một đối số -- i. Đối số i là viết tắt của "Interactive". Nếu không có bất kỳ đối số nào, lệnh sẽ chạy ở chế độ tiêu chuẩn. Trong cả hai trường hợp, giả sử chúng ta đã tạo một nhánh tính năng riêng biệt.

# Create a feature branch based off of main 
git checkout -b feature_branch main
# Edit files 
git commit -a -m "Adds new feature"

Git rebase ở chế độ tiêu chuẩn sẽ tự động nhận các xác nhận trong nhánh làm việc hiện tại của bạn và áp dụng chúng cho phần đầu của nhánh đã thông qua.

git rebase <base>

Thao tác này sẽ tự động đặt lại nhánh hiện tại vào <base>, có thể là bất kỳ loại tham chiếu commit nào (ví dụ: ID, tên nhánh, thẻ hoặc tham chiếu tương đối đến HEAD).

Chạy git rebase với cờ -i bắt đầu phiên khởi động lại tương tác. Thay vì di chuyển một cách mù quáng tất cả các commit sang cơ sở mới, việc khởi động lại tương tác mang đến cho bạn cơ hội để thay đổi các commit riêng lẻ trong quy trình. Điều này cho phép bạn dọn sạch lịch sử bằng cách xóa, chia nhỏ và thay đổi một loạt các commit hiện có. Nó giống như Git commit --amend trên steroid.

git rebase --interactive <base>

Điều này khởi động lại nhánh hiện tại <base>nhưng sử dụng phiên khởi động lại tương tác. Thao tác này sẽ mở một trình chỉnh sửa nơi bạn có thể nhập các lệnh (được mô tả bên dưới) cho mỗi commit sẽ bị hủy bỏ. Các lệnh này xác định cách các commit riêng lẻ sẽ được chuyển sang cơ sở mới. Bạn cũng có thể sắp xếp lại danh sách commit để tự thay đổi thứ tự của các commit. Khi bạn đã chỉ định các lệnh cho mỗi lần xác nhận trong quá trình rebase, Git sẽ bắt đầu phát lại các lần xác nhận áp dụng các lệnh rebase. Các lệnh chỉnh sửa rebasing như sau:

pick 2231360 some old commit
pick ee2adc2 Adds new feature

# Rebase 2cf755d..ee2adc2 onto 2cf755d (9 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

Các lệnh rebase bổ sung

Như đã trình bày chi tiết trong trang lịch sử viết lại, việc khởi động lại có thể được sử dụng để thay đổi các lần xác nhận cũ hơn và nhiều lần xác nhận, các tệp đã commit và nhiều thông báo. Mặc dù đây là những ứng dụng phổ biến nhất nhưng git rebase cũng có các tùy chọn lệnh bổ sung có thể hữu ích trong các ứng dụng phức tạp hơn.

  • git rebase -- d : có nghĩa là trong khi phát lại, commit sẽ bị loại bỏ khỏi khối commit kết hợp cuối cùng.
  • git rebase -- p : để nguyên commit. Nó sẽ không sửa đổi thông báo hoặc nội dung của commit và sẽ vẫn là một commit riêng lẻ trong lịch sử nhánh.
  • git rebase -- x : trong khi phát lại sẽ thực thi tập lệnh shell script trên mỗi lần xác nhận được đánh dấu. Một ví dụ hữu ích là chạy bộ kiểm tra cơ sở mã của bạn trên các lần xác nhận cụ thể, điều này có thể giúp xác định các hồi quy trong quá trình khởi động lại.

Tóm tắt lại

Rebasing tương tác cung cấp cho bạn toàn quyền kiểm soát lịch sử dự án của bạn trông như thế nào. Điều này mang lại nhiều tự do cho các nhà phát triển, vì nó cho phép họ thực hiện một lịch sử "lộn xộn" trong khi họ tập trung vào viết mã, sau đó quay lại và dọn dẹp nó sau khi thực tế.

Hầu hết các nhà phát triển muốn sử dụng một rebasing tương tác để đánh bóng một nhánh tính năng trước khi hợp nhất nó vào cơ sở mã chính. Điều này mang lại cho họ cơ hội loại bỏ các commit không đáng kể, xóa những commit lỗi thời và đảm bảo mọi thứ khác theo thứ tự trước khi đưa vào lịch sử dự án “chính thức”. Đối với những phần khác, có vẻ như toàn bộ tính năng được phát triển trong một loạt các commit được lên kế hoạch tốt.

Sức mạnh thực sự của rebasing tương tác có thể được nhìn thấy trong lịch sử của nhánh chính kết quả. Đối với những phần khác, có vẻ như bạn là một nhà phát triển xuất sắc đã triển khai tính năng mới với số lượng commit hoàn hảo ngay lần đầu tiên. Đây là cách rebasing tương tác có thể giữ cho lịch sử của dự án rõ ràng và có ý nghĩa.

Tùy chọn cấu hình

Có một vài thuộc tính rebase có thể được thiết lập bằng cách sử dụng git config. Các tùy chọn này sẽ thay đổi git rebase look and feel.

  • rebase.stat: Một boolean được đặt thành false theo mặc định. Tùy chọn chuyển đổi hiển thị nội dung khác biệt trực quan hiển thị những gì đã thay đổi kể từ lần rebase cuối cùng.
  • rebase.autoSquash: Một giá trị boolean chuyển đổi hành vi --autosquash.
  • rebase.missingCommitsCheck: Có thể được đặt thành nhiều giá trị thay đổi hành vi rebase xung quanh các lần xác nhận bị thiếu.
warn In đầu ra cảnh báo ở chế độ tương tác cảnh báo về các commit đã xóa

error

Dừng rebase và in các thông báo cảnh báo commit đã xóa

ignore

Đặt theo mặc định, điều này sẽ bỏ qua mọi cảnh báo commit bị thiếu
  • rebase.instructionFormat: Một chuỗi định dạng git log sẽ được sử dụng để định dạng hiển thị rebase tương tác

Ứng dụng rebase nâng cao

Đối số dòng lệnh --onto có thể được truyền đến git rebase. Khi ở chế độ --onto git rebase, lệnh sẽ mở rộng thành: 

git rebase --onto <newbase> <oldbase>

Lệnh --onto kích hoạt một biểu mẫu hoặc rebase mạnh mẽ hơn cho phép chuyển các giới thiệu cụ thể thành mẹo của một rebase.

Giả sử chúng ta có một repo ví dụ với các nhánh như:

o---o---o---o---o  main
     \
      o---o---o---o---o  featureA
           \
            o---o---o  featureB

featureB dựa trên featureA, tuy nhiên, ta nhận thấy featureB không phụ thuộc vào bất kỳ thay đổi nào trong featureA và chỉ có thể được phân nhánh main.

git rebase --onto main featureA featureB

featureA là <oldbase>main trở thành <newbase>và featureB là tham chiếu cho HEAD của <newbase> trỏ đến. Kết quả sau đó là:

                  o---o---o  featureB
                 /
o---o---o---o---o  main
 \
  o---o---o---o---o  featureA

Cần nắm được sự nguy hiểm của rebase

Một lưu ý cần cân nhắc khi làm việc với Git Rebase là xung đột merge có thể trở nên thường xuyên hơn trong quy trình làm việc rebase. Điều này xảy ra nếu bạn có một nhánh tồn tại lâu đã đi lạc khỏi nhánh main. Cuối cùng, bạn sẽ muốn khởi động lại chính và tại thời điểm đó, nó có thể chứa nhiều xác nhận mới mà các thay đổi nhánh của bạn có thể xung đột. Điều này có thể dễ dàng khắc phục bằng cách khởi động lại nhánh của bạn thường xuyên so với nhánh chính và thực hiện các commit thường xuyên hơn. Các đối số dòng lệnh --continue và --abort có thể được truyền đến git rebase để nâng cấp hoặc đặt lại cơ sở dữ liệu khi xử lý xung đột.

Một cảnh báo rebase nghiêm trọng hơn là các commit bị mất do viết lại lịch sử tương tác. Chạy rebase trong chế độ tương tác và thực thi các lệnh con như squash hoặc drop sẽ xóa các xác nhận khỏi nhật ký tức thì của nhánh của bạn. Thoạt nhìn, điều này có vẻ như các commit đã biến mất vĩnh viễn. Sử dụng git reflog thì các commit này có thể được khôi phục và toàn bộ quá trình rebase có thể được hoàn tác.

Bản thân Git Rebase không nguy hiểm nghiêm trọng. Các trường hợp nguy hiểm thực sự phát sinh khi thực hiện lịch sử viết lại các cơ sở tương tác và buộc đẩy kết quả đến một nhánh từ xa được chia sẻ bởi những người dùng khác. Đây là mẫu nên tránh vì nó có khả năng ghi đè lên công việc của những người dùng từ xa khác khi họ kéo.

Phục hồi từ rebase ngược dòng

Nếu một người dùng khác đã khởi động lại và buộc đẩy đến nhánh mà bạn đang commit, thì git pull sau đó sẽ ghi đè lên bất kỳ commit nào bạn đã thực hiện dựa trên nhánh trước đó bằng mẹo đã được đẩy. May mắn thay, sử dụng git reflog bạn có thể nhận được reflog của nhánh từ xa. Trên reflog của nhánh từ xa, bạn có thể tìm thấy một ref trước khi nó bị rebase. Sau đó, bạn có thể khởi động lại nhánh của mình dựa trên tham chiếu từ xa đó bằng cách sử dụng tùy chọn --onto như đã thảo luận ở trên trong phần Ứng dụng Rebase Nâng cao.

Tóm tắt

Trong bài viết này, chúng ta đã đề cập đến việc sử dụng git rebase. Chúng ta đã thảo luận về các trường hợp sử dụng cơ bản và nâng cao cũng như các ví dụ nâng cao hơn. Một số điểm thảo luận chính là:

  • git rebase tiêu chuẩn so với chế độ tương tác
  • tùy chọn cấu hình git rebase
  • git rebase --onto
  • git rebase bị mất commit

Chúng ta cũng đã xem xét việc sử dụng git rebase với các công cụ khác như git refloggit fetch và git push.

« Trước: Git Bash
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!