Các cam kết bí trong git có nghĩa là gì?


117

Squashing cam kết trong git có nghĩa là gì. Làm cách nào để thực hiện cam kết trong Github?

Tôi mới sử dụng Git và tôi đã yêu cầu được chỉ định một lỗi mới trong trình phân tích than. Tôi đã sửa lỗi và bây giờ tôi được yêu cầu xóa các cam kết của mình. Tôi phải làm nó như thế nào?


Xin chào @Lakshman, vui lòng chấp nhận câu trả lời được bình chọn cao nhất. Nó trả lời đúng câu hỏi của bạn.
Mostafiz Rahman

Câu trả lời:


180

Bạn có thể coi Git như một cơ sở dữ liệu nâng cao về các ảnh chụp nhanh của (các) thư mục làm việc của bạn.

Một tính năng rất hay của Git là khả năng viết lại lịch sử các cam kết.
Lý do chính để làm điều này là rất nhiều lịch sử như vậy chỉ liên quan đến nhà phát triển đã tạo ra nó, vì vậy nó phải được đơn giản hóa hoặc làm cho đẹp hơn, trước khi gửi nó vào một kho lưu trữ được chia sẻ.

Theo quan điểm thành ngữ, Squashing một commit có nghĩa là chuyển những thay đổi được đưa vào trong commit đã nói thành phần cha của nó để bạn kết thúc với một commit thay vì hai (hoặc nhiều hơn).
Nếu bạn lặp lại quá trình này nhiều lần, bạn có thể giảm n cam kết xuống một lần duy nhất.

Về mặt trực quan, nếu bạn bắt đầu công việc của mình tại Start được gắn thẻ cam kết , bạn muốn điều này

Git cam kết bóp méo

Bạn có thể nhận thấy rằng cam kết mới có màu xanh lam đậm hơn một chút. Đây là cố ý.

Trong Git , việc thu gọn được thực hiện với một Rebase , có dạng đặc biệt được gọi là Interactive Rebase .
Đơn giản hóa khi bạn căn cứ lại một tập hợp các cam kết vào một nhánh B , bạn áp dụng tất cả các thay đổi được giới thiệu bởi các cam kết đó khi chúng được thực hiện, bắt đầu từ B thay vì tổ tiên ban đầu của chúng.

Một manh mối trực quan

nhập mô tả hình ảnh ở đây

Lưu ý một lần nữa các sắc thái khác nhau của màu xanh lam.

Một rebase tương tác cho phép bạn chọn cách giảm giá cam kết. Nếu bạn chạy lệnh này:

 git rebase -i branch

Bạn sẽ có một tệp liệt kê các cam kết sẽ được giảm giá

 pick ae3...
 pick ef6...
 pick 1e0...
 pick 341...

Tôi không nêu rõ tên cam kết, nhưng bốn người đang dự định được các cam kết từ Bắt đầu đến Head

Điều tốt đẹp về danh sách này là nó có thể chỉnh sửa .
Bạn có thể bỏ qua các cam kết hoặc bạn có thể bỏ qua chúng .
Tất cả những gì bạn phải làm là thay đổi từ đầu tiên thành .

 pick ae3...
 squash ef6...
 squash 1e0...
 squash 341...

Nếu bạn đóng trình chỉnh sửa và không tìm thấy xung đột hợp nhất, bạn sẽ kết thúc với lịch sử này:

nhập mô tả hình ảnh ở đây

Trong trường hợp của bạn, bạn không muốn rebase vào một nhánh khác, mà là vào một cam kết trước đó.
Để chuyển đổi lịch sử như được hiển thị trong ví dụ đầu tiên, bạn phải chạy một cái gì đó như

git rebase -i HEAD~4

thay đổi "lệnh" để cho tất cả các cam kết ngoại trừ cái đầu tiên, và sau đó đóng soạn thảo của bạn.


Lưu ý về việc thay đổi lịch sử

Trong Git, các cam kết không bao giờ được chỉnh sửa. Chúng có thể được cắt tỉa, không thể tiếp cận, nhân bản nhưng không thay đổi.
Khi bạn rebase, bạn thực sự đang tạo các cam kết mới.
Những cái cũ không còn được tiếp cận bởi bất kỳ refs nào, vì vậy không được hiển thị trong lịch sử nhưng chúng vẫn ở đó!

Đây là những gì bạn thực sự nhận được cho một rebase:

nhập mô tả hình ảnh ở đây

Nếu bạn đã đẩy chúng đi đâu đó, viết lại lịch sử sẽ thực sự tạo ra một nhánh!


Tốt - điều gì sẽ xảy ra với các nhận xét cam kết ban đầu - liệu chúng có được kết hợp thành một nhận xét cam kết lớn duy nhất hay chúng bị mất?
Paul R

Từ man git rebase: Các đề nghị cam kết thông báo cho gấp cam kết là nối các cam kết thông điệp của các cam kết đầu tiên và những người có lệnh "bí"
Margaret Bloom

1
Đây là lời giải thích tốt nhất mà tôi từng thấy về sự phục hồi, cảm ơn bạn.
Kerry Jones

Giới thiệu về hiện tượng nhấp nháy trong hình ảnh đầu tiên của bạn: Bạn có thể làm một ví dụ trong đó HEAD có một thư mục làm việc khác nhau trước (xanh lam nhạt) và sau (xanh lam đậm) nhấp nháy không? Trong tất cả các ví dụ, tôi đã thử bóp méo có vẻ như nó vừa xóa ba cam kết giữa START và HEAD.
real_panda

@actual_panda Tôi không chắc mình theo dõi. HEAD là một giới thiệu cho một cam kết. Cam kết lưu trữ delta. Dir đang hoạt động là một tài sản của toàn bộ kho lưu trữ, nó phụ thuộc vào việc bạn đã kiểm tra cam kết nào. Nói chung, hai tham chiếu (như HEAD và START) luôn cung cấp hai trình tự làm việc khác nhau khi kiểm tra. Nếu bạn căn cứ lại bí trên cùng một nhánh, tác động là "nới lỏng" các cam kết trung gian nhưng trên thực tế, git đã tạo một cam kết mới với tất cả các đồng bằng. git diffcó thể giúp bạn chỉ ra những gì đã xảy ra.
Margaret Bloom

22

Lệnh rebase có một số tùy chọn tuyệt vời có sẵn trong chế độ --interactive(hoặc -i) của nó và một trong những cách được sử dụng rộng rãi nhất là khả năng xóa các cam kết. Điều này làm là thực hiện các cam kết nhỏ hơn và kết hợp chúng thành những cam kết lớn hơn, điều này có thể hữu ích nếu bạn đang hoàn thành công việc trong ngày hoặc nếu bạn chỉ muốn đóng gói các thay đổi của mình theo cách khác. Chúng ta sẽ xem xét cách bạn có thể làm điều này một cách dễ dàng.

Một lời cảnh báo: Chỉ thực hiện việc này đối với các cam kết chưa được đẩy ra kho lưu trữ bên ngoài. Nếu những người khác làm việc dựa trên các cam kết mà bạn sẽ xóa, nhiều xung đột có thể xảy ra. Chỉ cần không viết lại lịch sử của bạn nếu nó đã được chia sẻ với những người khác.

Vì vậy, giả sử bạn vừa thực hiện một vài cam kết nhỏ và bạn muốn thực hiện một cam kết lớn hơn trong số chúng. Lịch sử của kho lưu trữ của chúng tôi hiện như sau:

nhập mô tả hình ảnh ở đây

4 cam kết cuối cùng sẽ hạnh phúc hơn nhiều nếu chúng được kết hợp với nhau, vì vậy hãy thực hiện điều đó thông qua phục hồi tương tác:

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Vì vậy, một vài điều đã xảy ra ở đây. Trước hết, tôi đã nói với Git rằng tôi muốn căn cứ lại bằng cách sử dụng bốn cam kết cuối cùng từ vị trí HEAD với HEAD ~ 4. Git hiện đã đưa tôi vào một trình soạn thảo với văn bản trên trong đó và một chút giải thích về những gì có thể được thực hiện. Bạn có rất nhiều tùy chọn có sẵn cho bạn từ màn hình này, nhưng ngay bây giờ chúng tôi sẽ chỉ thu gọn mọi thứ vào một cam kết. Vì vậy, thay đổi bốn dòng đầu tiên của tệp này sẽ thực hiện thủ thuật:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

Về cơ bản, điều này yêu cầu Git kết hợp tất cả bốn cam kết vào cam kết đầu tiên trong danh sách. Khi điều này được thực hiện và được lưu, một trình chỉnh sửa khác sẽ xuất hiện với nội dung sau:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    # Explicit paths specified without -i nor -o; assuming --only paths...
    # Not currently on any branch.
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   new file:   LICENSE
    #   modified:   README.textile
    #   modified:   Rakefile
    #   modified:   bin/jekyll
    #

Vì chúng tôi đang kết hợp rất nhiều cam kết, nên Git cho phép bạn sửa đổi thông điệp của cam kết mới dựa trên phần còn lại của các cam kết liên quan đến quy trình. Chỉnh sửa tin nhắn khi bạn thấy phù hợp, sau đó lưu và thoát. Sau khi hoàn tất, các cam kết của bạn đã được xử lý thành công!

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
    Successfully rebased and updated refs/heads/master.

Và nếu chúng ta nhìn lại lịch sử… nhập mô tả hình ảnh ở đây

Vì vậy, điều này là tương đối dễ dàng cho đến nay. Nếu bạn gặp xung đột trong quá trình rebase, chúng thường khá dễ giải quyết và Git sẽ hướng dẫn bạn nhiều nhất có thể. Điều cơ bản của việc này là khắc phục xung đột được đề cập, git addtệp và sau đó git rebase --continuesẽ tiếp tục quá trình. Tất nhiên, thực hiện a git rebase --abortsẽ đưa bạn trở lại trạng thái trước đây nếu bạn muốn. Nếu vì lý do nào đó mà bạn bị mất cam kết trong rebase, bạn có thể sử dụng reflog để lấy lại.

Chi tiết có thể được tìm thấy liên kết này .


3
Cảm ơn bạn! Trong trường hợp bất kỳ ai không thoải mái với VIM như tôi ... khi bạn đến điểm bạn nhập các thao tác để chỉnh sửa, hãy nhấn 'i' để vào chế độ chỉnh sửa. Khi bạn thực hiện xong các thay đổi, hãy nhấn phím Escape rồi nhập ": wq" và nó sẽ đưa bạn về phía trước. (Mac)
Farasi78

+1 để biết sự thận trọng và bối cảnh khi nào thực hiện việc này. Theo kinh nghiệm cá nhân của tôi, thật tốt nếu bạn đang làm việc một mình trên một nhánh tính năng và có rất nhiều cam kết tầm thường như "đã cập nhật readme", "đã làm điều gì đó không ai quan tâm" và bạn đã sẵn sàng hợp nhất nhánh, có thể như cũng chỉ cần dồn tất cả vào một cam kết. Sẽ không ai muốn quay trở lại "đã làm điều gì đó mà không ai quan tâm" của bạn và nó làm ô nhiễm lịch sử cam kết
Adam Hughes

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.