Làm cách nào để chỉnh sửa thông báo cam kết không chính xác trong git (mà tôi đã đẩy)?


152

Tôi muốn sửa đổi một thông điệp cam kết sâu hơn trong lịch sử và tôi đã đẩy nhiều cam kết mới.

Làm cách nào để thay đổi thông điệp cam kết? Có thể không?

Câu trả lời:


125

Thông điệp từ Linus Torvalds có thể trả lời câu hỏi của bạn:

Sửa đổi / chỉnh sửa tin nhắn cam kết cũ

Câu trả lời ngắn: bạn không thể (nếu bị đẩy).


trích xuất (Linus gọi BitKeeper là BK):

Lưu ý bên lề, chỉ vì lợi ích lịch sử: trong BK bạn có thể.

Và nếu bạn đã quen với nó (như tôi) thì nó thực sự khá thiết thực. Tôi sẽ áp dụng một quả bom vá từ Andrew, nhận thấy có gì đó không ổn và chỉ cần chỉnh sửa nó trước khi đẩy nó ra.

Tôi có thể đã làm điều tương tự với git. Nó đã đủ dễ dàng để làm cho thông điệp cam kết không phải là một phần của tên, và vẫn đảm bảo rằng lịch sử không bị ảnh hưởng, và cho phép điều "sửa chữa bình luận sau".

Nhưng tôi đã không làm thế.

Một phần của nó hoàn toàn là "tính nhất quán nội bộ". Git đơn giản là một hệ thống sạch hơn nhờ mọi thứ được bảo vệ SHA1 và tất cả các đối tượng đều được đối xử như nhau, bất kể loại đối tượng. Vâng, có bốn loại đối tượng khác nhau và chúng đều thực sự khác nhau và chúng không thể được sử dụng theo cùng một cách, nhưng đồng thời, ngay cả khi mã hóa của chúng có thể khác nhau trên đĩa, về mặt khái niệm chúng đều hoạt động chính xác giống nhau.

Nhưng tính nhất quán nội bộ không thực sự là một lý do cho việc không linh hoạt, và rõ ràng nó sẽ rất linh hoạt nếu chúng ta có thể sửa chữa sai lầm sau khi chúng xảy ra. Vì vậy, đó không phải là một cuộc tranh luận thực sự mạnh mẽ.

Các thực lý do git không cho phép bạn thay đổi các cam kết thông báo kết thúc lên được rất đơn giản: đó là bằng cách nào, bạn có thể tin tưởng vào thông điệp. Nếu bạn cho phép mọi người thay đổi chúng sau đó, các tin nhắn vốn dĩ không đáng tin lắm.


Để hoàn thành, bạn có thể viết lại lịch sử cam kết cục bộ của mình để phản ánh những gì bạn muốn, như được đề xuất bởi sykora (với một số rebase và thiết lập lại - xin chào, thở hổn hển!)

Tuy nhiên, khi bạn xuất bản lịch sử sửa đổi của bạn một lần nữa (với một git push origin +master:master, các +dấu hiệu buộc push to xảy ra, ngay cả khi nó không dẫn đến một "tua" cam) ... bạn có thể nhận được vào một số rắc rối .

Trích từ câu hỏi SO khác này:

Tôi thực sự đã từng bị đẩy với - Force vào kho git.git và bị Linus BIG TIME mắng. Nó sẽ tạo ra rất nhiều vấn đề cho người khác. Một câu trả lời đơn giản là "đừng làm điều đó".


câu trả lời tốt. Bạn có biết nếu bây giờ bạn có thể thay đổi các thông điệp cam kết đã được đẩy trong các phiên bản mới hơn của git không? Có bất cứ điều gì thay đổi kể từ khi điều này được đăng trong '09?
David West

@DavidWest giữ nguyên tắc tương tự: bạn có thể viết lại lịch sử của mình và đẩy mạnh.
VonC

2
Để làm cho mọi thứ cụ thể hơn, nếu bạn sửa đổi / rebase cam kết, số nhận dạng cam kết của chúng (băm thập lục phân trong chỉ số git) chắc chắn sẽ thay đổi; điều đó có nghĩa là các xác nhận đã chỉnh sửa được xử lý khác với các cam kết cũ của chúng trong lịch sử git VCS. Điều đó nói rằng, nếu các thành viên nhóm phát triển của bạn không may rút được các cam kết cũ, họ có nghĩa vụ phải rút các cam kết mới, đã chỉnh sửa và thực hiện hợp nhất giữa bản cũ và bản mới trong bản sao làm việc tại địa phương của họ.
Shigerello

1
Tốt hơn hết là bạn nên chỉnh sửa cam kết một lần nữa để thuận tiện cho đồng nghiệp của mình, do đó, tốt nhất là loại bỏ nhu cầu hợp nhất trong các bản sao làm việc của đồng nghiệp.
Shigerello

28

Hiện tại một thay thế git có thể làm thủ thuật.

Cụ thể: Tạo một nhánh làm việc tạm thời

git checkout -b temp

Đặt lại cam kết để thay thế

git reset --hard <sha1>

Sửa đổi cam kết với thông điệp phù hợp

git commit --amend -m "<right message>"

Thay thế cam kết cũ bằng cam kết mới

git replace <old commit sha1> <new commit sha1>

trở lại chi nhánh nơi bạn đã ở

git checkout <branch>

loại bỏ chi nhánh tạm thời

git branch -D temp

đẩy

guess

làm xong.


11
@Jonah: Tôi nhận được thông báo "Mọi thứ cập nhật" khi tôi cố gắng đẩy đến chi nhánh từ xa
Simon Kagwi

1
Như đã đề cập trong một câu trả lời khác: sử dụng rebase -i với tua. Và nó sẽ viết lại lịch sử.
Sylvain

Cảm ơn bạn cho giải pháp, mà tôi đang tìm kiếm. Bạn tiết kiệm thời gian của tôi!
Tomasz Kuter

1
@Jonah - Tôi có một vấn đề ... giải pháp của bạn đã cập nhật nhật ký cam kết của tôi cục bộ, nhưng không phải từ xa. Làm thế nào để đẩy chúng ở đó?
Tomasz Kuter

1
@TomaszKuter, tôi cũng gặp vấn đề tương tự như bạn. Tin nhắn cam kết của tôi không được cập nhật từ xa. Tôi đã giải quyết nó bằng cách sử dụng trợ giúp sau từ GitHub: help.github.com/articles/changing-a-commit-message . Thực hiện theo: Sửa đổi tin nhắn của phần cũ hoặc nhiều tin nhắn cam kết. Về cơ bản, đây là câu trả lời từ bên dưới được đưa ra bởi user987419 Nếu bạn đã thay đổi thông điệp cam kết, bạn có thể thực hiện chọn và lưu mà không phải thay đổi lại.
evaldeslacasa

19

Bạn có thể sử dụng git rebase -i(đối với chi nhánh bạn phân nhánh từ) 'i' để tương tác.

Thay thế pickbên cạnh nhận xét cam kết bạn muốn thay đổi bằng r(hoặc reword), lưu và thoát và sau khi thực hiện, bạn sẽ có thể thực hiện chỉnh sửa.

git push một lần nữa và bạn đã hoàn tất


1
Điều này không cho phép một người chỉnh sửa tin nhắn trên các cam kết hợp nhất. Có thể với một số biến thể của lệnh này?
Andrew Mao

1
Hãy thử -plập luận về rebaseviệc pdự trữ hợp nhất.
Xương rồng

3
Tôi thích thủ tục này, nhưng ban đầu tôi không hiểu câu trả lời. Trong trường hợp ai đó cần giúp đỡ với nó, trang Trợ giúp Githulb cung cấp thông tin tốt về nó: help.github.com/articles/changing-a-commit-message
evaldeslacasa 4/11/2015

15

Giả sử bạn có một cái cây như thế này:

dd2e86 - 946992 - 9143a9 - a6fd86 - 5a6057 [master]

Đầu tiên, checkoutmột nhánh tạm thời:

git checkout -b temp

Trên tempnhánh, reset --hardvới một cam kết mà bạn muốn thay đổi thông điệp của nó (ví dụ: cam kết đó là 946992):

git reset --hard 946992

Sử dụng amendđể thay đổi tin nhắn:

git commit --amend -m "<new_message>"

Sau đó, cây sẽ trông như thế này:

dd2e86 - 946992 - 9143a9 - a6fd86 - 5a6057 [master]
           \
            b886a0 [temp]

Sau đó, cherry-pick tất cả các cam kết đó là trước 946992từ masterđể tempvà cam kết họ, sử dụng amendnếu bạn muốn thay đổi thông điệp của họ cũng như:

git cherry-pick 9143a9
git commit --amend -m "<new_message>
...
git cherry-pick 5a6057
git commit --amend -m "<new_message>

Cây bây giờ trông như thế này:

dd2e86 - 946992 - 9143a9 - a6fd86 - 5a6057 [master]
               \
                b886a0 - 41ab2c - 6c2a3s - 7c88c9 [temp]

Bây giờ buộc đẩy nhánh tạm thời vào điều khiển từ xa:

git push --force origin temp:master

Bước cuối cùng, xóa chi nhánh mastertrên địa phương,git fetch origin để kéo chi nhánh masterkhỏi máy chủ, sau đó chuyển sang chi nhánh mastervà xóa chi nhánh temp.

Bây giờ cả địa phương và từ xa của bạn sẽ có tất cả các tin nhắn được cập nhật.


5

Tại cửa hàng của chúng tôi, tôi đã giới thiệu quy ước thêm các thẻ chú thích có tên dễ nhận biết để cam kết với các thông báo không chính xác và sử dụng chú thích làm thay thế.

Mặc dù điều này không giúp những người chạy các lệnh "git log" thông thường, nhưng nó cung cấp cho chúng tôi cách khắc phục các tham chiếu theo dõi lỗi không chính xác trong các nhận xét và tất cả các công cụ xây dựng và phát hành của tôi đều hiểu quy ước.

Đây rõ ràng không phải là một câu trả lời chung chung, nhưng nó có thể là điều mà mọi người có thể chấp nhận trong các cộng đồng cụ thể. Tôi chắc chắn nếu điều này được sử dụng ở quy mô lớn hơn, một số loại hỗ trợ bằng sứ cho nó có thể mọc lên, cuối cùng ...


3
"Ghi chú git" có thể phục vụ một mục đích tương tự
Christian Goetze

2

(Từ http://git.or.cz/gitwiki/GitTips#head-9f87cd21bcdf081a61c29985604ff4be35a5e6c0 )

Làm thế nào để thay đổi cam kết sâu hơn trong lịch sử

Vì lịch sử trong Git là bất biến, nên sửa bất cứ thứ gì ngoại trừ lần xác nhận gần đây nhất (cam kết không phải là chi nhánh) yêu cầu lịch sử được viết lại từ cam kết đã thay đổi và chuyển tiếp.

Bạn có thể sử dụng StGIT cho điều đó, khởi tạo chi nhánh nếu cần thiết, không tham gia vào cam kết bạn muốn thay đổi, bật lên nếu cần, thực hiện thay đổi sau đó làm mới bản vá (với tùy chọn -e nếu bạn muốn sửa thông báo cam kết), sau đó đẩy tất cả mọi thứ và stg cam kết.

Hoặc bạn có thể sử dụng rebase để làm điều đó. Tạo nhánh tạm thời mới, tua lại thành cam kết bạn muốn thay đổi bằng cách sử dụng git reset --hard, thay đổi cam kết đó (nó sẽ là đỉnh của đầu hiện tại), sau đó rebase nhánh trên đỉnh của cam kết đã thay đổi, sử dụng git rebase --onto.

Hoặc bạn có thể sử dụng git rebase - tương tác, cho phép sửa đổi khác nhau như sắp xếp lại bản vá, thu gọn, ...

Tôi nghĩ rằng nên trả lời câu hỏi của bạn. Tuy nhiên, lưu ý rằng nếu bạn đã đẩy mã đến một kho lưu trữ từ xa và mọi người đã lấy từ đó, thì điều này sẽ làm rối loạn lịch sử mã của họ, cũng như công việc họ đã làm. Vì vậy, làm điều đó một cách cẩn thận.


Câu trả lời hay về lý thuyết, nguy hiểm trong thực tế: xem stackoverflow.com/questions/253055#432518
VonC

0

Nếu bạn đang sử dụng Tiện ích mở rộng Git: đi vào màn hình Cam kết, sẽ có một hộp kiểm có nội dung "Sửa đổi cam kết" ở phía dưới, như có thể thấy bên dưới:

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


@KrunalPandya có, hoặc chỉ cần nhấn commit & đẩy
batsheva
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.