Chỉnh sửa cam kết gốc trong Git?


328

Có nhiều cách để thay đổi tin nhắn từ các lần xác nhận sau:

git commit --amend                    # for the most recent commit
git rebase --interactive master~2     # but requires *parent*

Làm thế nào bạn có thể thay đổi thông điệp cam kết của lần xác nhận đầu tiên (không có cha mẹ)?



Cụ thể: việc sử dụng biến môi trường GIT_COMMIT trong tập lệnh củagit filter-branch --msg-filter
fork0

Câu trả lời:


285

Giả sử rằng bạn có một cây làm việc sạch sẽ, bạn có thể làm như sau.

# checkout the root commit
git checkout <sha1-of-root>

# amend the commit
git commit --amend

# rebase all the other commits in master onto the amended root
git rebase --onto HEAD HEAD master

23
Tôi tin rằng điều này nên được git rebase --onto HEAD <sha1-of-root> master.
Andrew

5
Đúng, nhưng bạn muốn cam kết gốc ban đầu cho <ngược dòng> của git rebase. git rebaseáp dụng các cam kết trong <nhánh> ( master) không nằm trong <ngược dòng>; HEADkhông có trong master, vì vậy phiên bản của bạn cố gắng áp dụng tất cả master.
Andrew

7
Vâng, hãy chắc chắn rằng đó là git rebase --onto HEAD <sha1-of-root>chủ, nơi <sha1-of-root>được sử dụng tương tự git checkout <sha1-of-root>. Nếu không, bạn sẽ có 2 first commit's.
Andy

2
@Cupdding: Bạn đã kiểm tra phiên bản cũ của lệnh chưa? Nó sẽ hoạt động tốt. Việc sửa đổi chỉ thay đổi thông điệp cam kết để các xác nhận gốc cũ và mới giới thiệu chính xác các thay đổi tương tự để cam kết gốc cũ được tự động bỏ qua. Thứ hai HEADđảm bảo rằng tất cả các xác nhận được xem xét và chúng ta có thể sử dụng hai phiên bản tham số của rebase để quay trở lại chủ. Xin lưu ý rằng câu trả lời này có trước sự tồn tại của --roottùy chọn để rebase.
CB Bailey

9
Câu trả lời của ecdpalma dưới đây dễ dàng và đơn giản hơn nhiều và có nhiều phiếu bầu hơn, hãy cuộn xuống mọi người!
Flimm

567

Kể từ phiên bản Git 1.7.12 , bây giờ bạn có thể sử dụng

git rebase -i --root

Tài liệu


2
Có thể khởi động lại root của tất cả các nhánh bằng lệnh này không? Có vẻ như điều này sẽ tách nhánh hiện tại lên gốc mới và tất cả các nhánh khác sẽ ở lại gốc cũ
woojoo666 22/03/2015

@ woojoo666 bạn sẽ phải rebase các nhánh lên root mới rồi. như thường lệ.
berkus

@Atcold nó không hoạt động nếu không có root ngược dòng
Kai

Cảnh báo: Tôi đã giả định sai điều này sẽ làm gốc của nhánh đã kiểm tra của tôi, nhưng phải mất một thời gian để tải tất cả các cam kết, sau đó khởi động lại tất cả.
Leo

2
@Leo bình luận của bạn có ý nghĩa gì? Tôi không thể thấy liên kết giữa phần đầu tiên và phần thứ hai - phải mất một thời gian để làm gì với nó?
boycy

66

Để mở rộng câu trả lời của ecdpalma , bây giờ bạn có thể sử dụng --roottùy chọn để nói rebaserằng bạn muốn viết lại root / cam kết đầu tiên:

git rebase --interactive --root

Sau đó, cam kết gốc sẽ hiển thị trong danh sách TODO rebase và bạn có thể chọn chỉnh sửa hoặc điều chỉnh lại nó:

reword <root commit sha> <original message>
pick <other commit sha> <message>
...

Đây là lời giải thích --roottừ các tài liệu rebase Git (nhấn mạnh của tôi):

Rebase tất cả các cam kết có thể truy cập từ <branch>, thay vì giới hạn chúng với một <upstream>. Điều này cho phép bạn khởi động lại (các) cam kết gốc trên một nhánh .


12

Chỉ để cung cấp một thay thế cho các câu trả lời được đánh giá cao hơn:

Nếu bạn đang tạo một repo và biết trước rằng bạn sẽ nổi loạn lên trên cam kết thực sự "đầu tiên" của nó trong tương lai, bạn có thể tránh vấn đề này hoàn toàn bằng cách thực hiện một cam kết trống rõ ràng ngay từ đầu:

git commit --allow-empty -m "Initial commit"

và chỉ sau đó bắt đầu thực hiện các cam kết "thực sự". Sau đó, bạn có thể dễ dàng khởi động lại trên đó cam kết theo cách tiêu chuẩn, ví dụgit rebase -i HEAD^


4
Điều này không có nghĩa là, để điều này hoạt động, bạn cần có tầm nhìn xa (hoặc là nhà ngoại cảm) để thực hiện một cam kết trống ngay khi bắt đầu dự án của bạn ? Điều này dường như là cực kỳ tình huống , với tôi, và nói chung là không thực tế . Bạn nghĩ sao? Điều gì xảy ra nếu tôi đã thực hiện 100 lần xác nhận và đột nhiên tôi cần chỉnh sửa cam kết gốc. Điều này sẽ vẫn hoạt động, trong trường hợp đó, nếu tôi không thực hiện cam kết trống đó khi bắt đầu?

2
Chỉnh sửa thông điệp của cam kết gốc có lẽ không phải là điều bạn sẽ làm sau khi có 100 trong số chúng. Thỉnh thoảng tôi tình cờ chỉ muốn có một repo git, thực hiện một số cam kết rác rưởi, biết rằng một khi tôi đạt được trạng thái có thể sử dụng được, tôi sẽ ép chúng thành một ví dụ và điều chỉnh lại tin nhắn. Dù sao, bây giờ tôi đã thay đổi ý định và tôi nghĩ rằng điều hoàn toàn hữu ích nhất cho lần cam kết đầu tiên sẽ là đặt .gitattributestệp thay vì thực hiện một cam kết trống.
jakub.g

4

Bạn có thể sử dụng git filter-branch:

cd test
git init

touch initial
git add -A
git commit -m "Initial commit"

touch a
git add -A
git commit -m "a"

touch b
git add -A
git commit -m "b"

git log

-->
8e6b49e... b
945e92a... a
72fc158... Initial commit

git filter-branch --msg-filter \
"sed \"s|^Initial commit|New initial commit|g\"" -- --all

git log
-->
c5988ea... b
e0331fd... a
51995f1... New initial commit

Tôi đang sử dụng nhánh lọc thay đổi tác giả / committer và -- --alltùy chọn thực sự là chìa khóa trong trường hợp này để có thể xử lý cam kết gốc.
sschuberth
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.