Làm thế nào để sửa đổi các thông điệp cam kết hiện có, chưa được đánh dấu?


7664

Tôi đã viết điều sai trong một thông điệp cam kết.

Làm thế nào tôi có thể thay đổi tin nhắn? Các cam kết chưa được đẩy.


868
Đối với những người hơi mới với git: Quan điểm của Laurie về việc chưa được đẩy là rất quan trọng. Giống như nổi loạn, điều này đang thay đổi lịch sử. Nếu ai đó đã nhân bản / kéo từ repo của bạn giữa lịch sử gốc và viết lại thì họ sẽ không thể kéo sau khi viết lại (cho nhánh đó).
Pat Notz

Câu trả lời:


16132

Sửa đổi tin nhắn cam kết gần đây nhất

git commit --amend

sẽ mở trình soạn thảo của bạn, cho phép bạn thay đổi thông báo cam kết của lần xác nhận gần đây nhất. Ngoài ra, bạn có thể đặt thông báo cam kết trực tiếp trong dòng lệnh với:

git commit --amend -m "New commit message"

Tuy nhiên, điều này có thể làm cho các thông điệp cam kết nhiều dòng hoặc chỉnh sửa nhỏ trở nên cồng kềnh hơn để nhập.

Hãy chắc chắn rằng bạn không có bất kỳ thay đổi bản sao nào được thực hiện trước khi thực hiện việc này nếu không chúng cũng sẽ được cam kết. ( Những thay đổi chưa được thực hiện sẽ không được cam kết.)

Thay đổi thông báo của một cam kết mà bạn đã đẩy đến chi nhánh từ xa của mình

Nếu bạn đã đẩy cam kết của mình lên chi nhánh từ xa, thì - sau khi sửa đổi cam kết của bạn cục bộ (như được mô tả ở trên) - bạn cũng sẽ cần phải đẩy cam kết với:

git push <remote> <branch> --force
# Or
git push <remote> <branch> -f

Cảnh báo: lực đẩy sẽ ghi đè lên nhánh từ xa với trạng thái của địa phương . Nếu có các cam kết trên nhánh từ xa mà bạn không có trong chi nhánh địa phương của mình, bạn sẽ mất các cam kết đó.

Cảnh báo: thận trọng về việc sửa đổi các cam kết mà bạn đã chia sẻ với người khác. Sửa đổi các cam kết về cơ bản viết lại chúng để có các ID SHA khác nhau , điều này đặt ra một vấn đề nếu người khác có các bản sao của cam kết cũ mà bạn đã viết lại. Bất cứ ai có một bản sao của cam kết cũ sẽ cần phải đồng bộ hóa công việc của họ với cam kết mới được viết lại của bạn, điều này đôi khi có thể khó khăn, vì vậy hãy đảm bảo bạn phối hợp với những người khác khi cố gắng viết lại lịch sử cam kết được chia sẻ hoặc chỉ cần tránh viết lại các cam kết được chia sẻ hoàn toàn.


Thực hiện một rebase tương tác

Một lựa chọn khác là sử dụng rebase tương tác. Điều này cho phép bạn chỉnh sửa bất kỳ tin nhắn nào bạn muốn cập nhật ngay cả khi đó không phải là tin nhắn mới nhất.

Để thực hiện bí đao Git, hãy làm theo các bước sau:

// n is the number of commits up to the last commit you want to be able to edit
git rebase -i HEAD~n

Khi bạn thực hiện các cam kết của mình - chọn phần e/rchỉnh sửa tin nhắn:

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

Lưu ý quan trọng về rebase tương tác

Khi bạn sử dụng git rebase -i HEAD~ncó thể có nhiều hơn n cam kết. Git sẽ "thu thập" tất cả các cam kết trong n lần xác nhận cuối cùng và nếu có một sự hợp nhất ở đâu đó trong phạm vi đó, bạn cũng sẽ thấy tất cả các cam kết, vì vậy kết quả sẽ là n +.

Mẹo tốt:

Nếu bạn phải làm điều đó cho nhiều hơn một chi nhánh và bạn có thể phải đối mặt với xung đột khi sửa đổi nội dung, hãy thiết lập git rererevà để Git tự động giải quyết những xung đột đó cho bạn.


Tài liệu


257
Tuy nhiên git commit --amendkhông mạnh mẽ như git rebase -i.
Jeffrey Jose

76
@jeffjose, Nó chắc chắn không cần phải như vậy. Ngoài ra, git commit --amendcó thể sửa lỗi (a?) Cam kết chính.
strager

116
Nếu bạn đã đẩy, chỉ cần đẩy lại:git push -f origin branchname
hughes

177
@hughes không git push -fnguy hiểm một chút nếu người khác đang sử dụng cùng một kho lưu trữ?
Armand

91
Nếu bạn không muốn viết lại toàn bộ thông điệp cam kết, hãy tiếp tục git commit --amend -c HEAD. Điều này sẽ mở trình soạn thảo được điền trước bằng thông điệp cam kết cũ của bạn, vì vậy bạn có thể thay đổi nó.
Sam

2506
git commit --amend -m "your new message"

7
Tôi đã thực hiện git commit --amend -m "Tin nhắn mới", nhưng việc đẩy lên Github đã tạo ra "Hợp nhất các thay đổi từ xa trước khi đẩy lại". Sau khi kéo, cam kết --amend và đẩy lại, thông báo mới sẽ không xuất hiện. Thay vào đó, tôi có "Hợp nhất chi nhánh 'chủ nhân của github.com:[myrepo]"
Dave Everitt

8
@DaveEveritt rất có thể bạn đã đẩy cam kết của mình ngược dòng trước khi cố gắng sửa nó.
Thorbjørn Ravn Andersen

12
@Kyralessa không đúng. Trong bash, bạn có thể dễ dàng soạn tin nhắn cam kết nhiều dòng bằng cách không đóng trích dẫn cho đến khi bạn hoàn thành (nhấn return ở cuối mỗi dòng trong dấu ngoặc kép).
hobs

32
Tôi không hiểu làm thế nào một câu trả lời trông giống như ý chính của câu trả lời đã được viết cách đây hai năm và câu trả lời được chấp nhận lại nhận được rất nhiều phiếu bầu. Lạ thật. (không có gì sai với câu trả lời)
coder hạnh phúc

7
@AmalMurali, tốt. Quan điểm của tôi không phải là quá nhiều về sự phổ biến của câu hỏi, cũng như tiện ích của câu trả lời. Nhưng câu trả lời đặc biệt này không phải là câu trả lời lâu đời nhất, cũng không cung cấp bất kỳ cái nhìn sâu sắc hơn nữa về câu trả lời được chấp nhận. Nó dường như là một bản sao của một phần của câu trả lời được chấp nhận. Đó là quan điểm của tôi. GIÁ RẺ!
coder hạnh phúc

2376

Nếu cam kết bạn muốn sửa không phải là cam kết gần đây nhất:

  1. git rebase --interactive $parent_of_flawed_commit

    Nếu bạn muốn sửa một số cam kết thiếu sót, hãy vượt qua cha mẹ của người già nhất trong số họ.

  2. Một biên tập viên sẽ đưa ra, với một danh sách tất cả các cam kết kể từ khi bạn đưa ra.

    1. Thay đổi pickthành reword(hoặc trên các phiên bản cũ của Git, thành edit) trước bất kỳ cam kết nào bạn muốn sửa.
    2. Khi bạn lưu, Git sẽ phát lại các cam kết được liệt kê.

  3. Đối với mỗi cam kết bạn muốn điều chỉnh lại , Git sẽ đưa bạn trở lại trình chỉnh sửa của mình. Đối với mỗi cam kết bạn muốn chỉnh sửa , Git thả bạn vào trình bao. Nếu bạn đang ở trong vỏ:

    1. Thay đổi cam kết theo bất kỳ cách nào bạn muốn.
    2. git commit --amend
    3. git rebase --continue

Hầu hết các chuỗi này sẽ được giải thích cho bạn bằng đầu ra của các lệnh khác nhau khi bạn đi. Nó rất dễ; bạn không cần phải ghi nhớ nó - chỉ cần nhớ rằng git rebase --interactivecho phép bạn sửa lỗi cho dù chúng đã tồn tại bao lâu.


Lưu ý rằng bạn sẽ không muốn thay đổi các cam kết mà bạn đã đẩy. Hoặc có thể bạn làm, nhưng trong trường hợp đó, bạn sẽ phải hết sức cẩn thận để liên lạc với tất cả những người có thể đã thực hiện các cam kết của bạn và thực hiện công việc trên đầu trang của họ. Làm cách nào để khôi phục / đồng bộ hóa lại sau khi ai đó đẩy rebase hoặc thiết lập lại thành một nhánh được xuất bản?


39
Người ta có thể thay đổi thông điệp của lần xác nhận đầu tiên (không có cha mẹ) không?
13ren

27
Điều này được đề cập trong một trong những câu trả lời khác nhưng tôi sẽ ghi chú lại ở đây. Vì git 1.6.6, bạn có thể sử dụng rewordthay thế pickthông báo nhật ký.
MitMaro

89
Ngẫu nhiên, $parent_of_flawed_committương đương với $flawed_commit^.
Peeja

67
Không bao giờ EVER làm điều này (hoặc rebase nói chung) nếu bạn đã đẩy ngược dòng!
Daniel Rinser

20
Sử dụng -p( --preserve-merges) nếu có một sự hợp nhất sau khi cam kết thiếu sót.
ahven

778

Để sửa đổi cam kết trước đó, hãy thực hiện các thay đổi bạn muốn và thực hiện các thay đổi đó, rồi chạy

git commit --amend

Điều này sẽ mở một tệp trong trình soạn thảo văn bản của bạn đại diện cho thông điệp cam kết mới của bạn. Nó bắt đầu được điền với văn bản từ tin nhắn cam kết cũ của bạn. Thay đổi thông điệp cam kết như bạn muốn, sau đó lưu tệp và thoát trình chỉnh sửa của bạn để hoàn tất.

Để sửa đổi cam kết trước đó và giữ cùng một thông điệp tường trình, hãy chạy

git commit --amend -C HEAD

Để sửa lỗi cam kết trước đó bằng cách xóa hoàn toàn, hãy chạy

git reset --hard HEAD^

Nếu bạn muốn chỉnh sửa nhiều hơn một tin nhắn cam kết, hãy chạy

git rebase -i HEAD~commit_count

(Thay thế commit_count bằng số lần xác nhận mà bạn muốn chỉnh sửa.) Lệnh này khởi chạy trình soạn thảo của bạn. Đánh dấu cam kết đầu tiên (cam kết mà bạn muốn thay đổi) là bản chỉnh sửa trực tuyến thay vì chọn Pick, sau đó lưu và thoát khỏi trình soạn thảo của bạn. Thực hiện thay đổi bạn muốn cam kết và sau đó chạy

git commit --amend
git rebase --continue

Lưu ý: Bạn cũng có thể "Thực hiện thay đổi bạn muốn" từ trình chỉnh sửa được mở bởi git commit --amend


18
git rebase -i HEAD~commit_countcũng sẽ cho phép bạn thay đổi các thông điệp cam kết của nhiều cam kết mà bạn chọn. Chỉ cần đánh dấu các cam kết đã chọn là "tua lại" thay vì "chọn".
Joe

2
Điều gì nếu bạn không muốn nổi loạn? Bạn chỉ muốn thay đổi một tin nhắn cũ?
SuperUberDuper

3
git reset --hardhủy bỏ những thay đổi không cam kết Hãy thay thế --hardbằng --soft.
lươn ghEEz

1
Đồng ý, git reset --hardlà một mệnh lệnh hoàn toàn hợp pháp, nhưng nó gây hiểu lầm cho câu hỏi. Bạn sử dụng --hardnếu bạn đã cam kết những thay đổi bạn muốn vứt đi, chứ không phải nếu bạn mắc lỗi đánh máy trong thông điệp cam kết!
Soren Bjornstad

398

Như đã đề cập, git commit --amendlà cách ghi đè lên cam kết cuối cùng. Một lưu ý: nếu bạn muốn ghi đè lên các tệp , lệnh sẽ là

git commit -a --amend -m "My new commit message"

4
Và nếu bạn không muốn để thêm tất cả mọi thứ, trước tiên bạn có thể làm git add file.extsau đó chỉ cầngit commit --amend
MalcolmOcean

358

Bạn cũng có thể sử dụng git filter-branchcho điều đó.

git filter-branch -f --msg-filter "sed 's/errror/error/'" $flawed_commit..HEAD

Nó không dễ như một thứ tầm thường git commit --amend, nhưng nó đặc biệt hữu ích, nếu bạn đã có một số sự hợp nhất sau thông điệp cam kết sai lầm của bạn.

Lưu ý rằng điều này sẽ cố gắng viết lại mọi cam kết giữa HEADvà cam kết thiếu sót, vì vậy bạn nên chọn msg-filterlệnh của mình thật khôn ngoan ;-)


4
Có phiên bản nào không thay đổi cam kết nếu regex không tìm thấy gì không?
sjakubowski

3
Chi nhánh bộ lọc AFAIK --msg-filter sẽ tạo các xác nhận mới trong mọi trường hợp. Tuy nhiên, bạn có thể kiểm tra trong bộ lọc thông điệp, nếu sed thành công và sử dụng thông tin này khi hoạt động của nhánh bộ lọc kết thúc để đặt lại cây của bạn thành refs / gốc.
Đánh dấu

4
@DavidHogue Điều này chỉ đúng khi sử dụng phương thức lọc nhánh. ID cam kết sau một cam kết đã sửa đổi sẽ không thay đổi nếu bạn sử dụng rebase tương tác.
Đánh dấu

6
@Mark Có họ làm, họ được yêu cầu. Id cam kết phụ thuộc vào các cam kết trước đó. Nếu họ không thay đổi, git sẽ vô dụng.
Miles Rout

2
Bạn cần $flawed_commit^..HEAD, không $flawed_commit..HEAD. như đã nêu trong trang man: « Lệnh sẽ chỉ viết lại các ref tích cực được đề cập trong dòng lệnh (ví dụ: nếu bạn vượt qua a..b, chỉ b sẽ được viết lại). »
Ángel

319

Tôi thích cách này:

git commit --amend -c <commit ID>

Nếu không, sẽ có một cam kết mới với ID cam kết mới.


7
Đối với tôi, sử dụng lệnh của bạn ở trên thực sự tạo ra một cam kết mới với ID cam kết mới cộng với một cam kết bổ sung có nội dung "hợp nhất chi nhánh" làm thông điệp cam kết mặc định.
Jan

46
Sửa đổi luôn tạo ra một cam kết mới với ID cam kết mới. ID cam kết là hàm băm SHA của nội dung của cam kết, bao gồm thông điệp cam kết và dấu thời gian được ủy quyền / cam kết. Đây là một tính năng của Git, chặn các va chạm băm, đảm bảo rằng hai lần xác nhận có cùng một ID là chính xác cùng một cam kết, với chính xác cùng một nội dung, lịch sử, v.v.
Emil Lundberg

7
Đồng ý với Emil. Ngoài ra, đọc tài liệu - có vẻ như tất cả "-c" đều nói với git rằng thông điệp cam kết sẽ sử dụng làm mặc định / mẫu cho cam kết mới của bạn..Thực sự nó sẽ thực hiện "-c <commit ID>" theo mặc định , vì vậy không cần chỉ định nó.
Gal

2
Việc -cnày có một vài điều. Nó sử dụng tin nhắn cũ theo mặc định, nhưng nó cũng sao chép thông tin quyền tác giả (người và thời gian). -Cthực hiện điều tương tự ngoại trừ việc nó không yêu cầu bạn chỉnh sửa tin nhắn.
Joseph K. Strauss

1
Giống như @SantanuDey, nó không hoạt động với tôi. Tôi đã nhậnfatal: Option -m cannot be combined with -c/-C/-F/--fixup.
Andrew Grimm

312

Nếu bạn đang sử dụng công cụ Git GUI, có một nút có tên Sửa đổi lần cam kết cuối cùng . Nhấp vào nút đó và sau đó nó sẽ hiển thị các tập tin và cam kết cuối cùng của bạn. Chỉ cần chỉnh sửa tin nhắn đó và bạn có thể cam kết nó với một tin nhắn cam kết mới.

Hoặc sử dụng lệnh này từ bàn điều khiển / thiết bị đầu cuối:

git commit -a --amend -m "My new commit message"

4
Câu trả lời này là theo nghĩa đen giống này một lớn hơn . Bạn đã kiểm tra câu trả lời hiện có trước khi cung cấp một câu trả lời khác?
Dan Dascalescu

284

Bạn có thể sử dụng Git rebasing . Ví dụ: nếu bạn muốn sửa đổi trở lại để xác nhận bbc643cd, hãy chạy

$ git rebase bbc643cd^ --interactive

Trong trình chỉnh sửa mặc định, sửa đổi 'chọn' thành 'chỉnh sửa' trong dòng có cam kết bạn muốn sửa đổi. Thực hiện các thay đổi của bạn và sau đó thực hiện chúng với

$ git add <filepattern>

Bây giờ bạn có thể sử dụng

$ git commit --amend

để sửa đổi cam kết và sau đó

$ git rebase --continue

để trở lại cam kết đầu trước.


1
Nếu bạn muốn chắc chắn rằng thay đổi của bạn git commit --amendđã ảnh hưởng đến bạn có thể sử dụng git showvà nó sẽ hiển thị thông báo mới.
Steve Tauber

279
  1. Nếu bạn chỉ muốn sửa đổi thông điệp cam kết cuối cùng của mình, thì hãy làm:

    git commit --amend
    

Điều đó sẽ thả bạn vào trình soạn thảo văn bản của bạn và cho phép bạn thay đổi thông điệp cam kết cuối cùng.

  1. Nếu bạn muốn thay đổi ba thông điệp cam kết cuối cùng hoặc bất kỳ thông điệp cam kết nào cho đến thời điểm đó, hãy cung cấp HEAD~3cho git rebase -ilệnh:

    git rebase -i HEAD~3
    

6
Câu trả lời trước đây đã nói rằng bạn có thể sử dụng git commit --amend, và nó cũng nói rằng bạn có thể sử dụng git rebase -i HEAD~commit_count, tất cả các bạn đã làm là cắm 3cho commit_count.

Downvote là tốt. Mọi người chỉ không bận tâm để đọc câu trả lời hiện có .
Dan Dascalescu

261

Nếu bạn phải thay đổi một thông điệp cam kết cũ trên nhiều chi nhánh (nghĩa là, cam kết với thông báo sai có mặt trong nhiều chi nhánh) bạn có thể muốn sử dụng:

git filter-branch -f --msg-filter \
'sed "s/<old message>/<new message>/g"' -- --all

Git sẽ tạo một thư mục tạm thời để viết lại và sao lưu thêm các tham chiếu cũ trong refs/original/.

  • -fsẽ thực thi việc thực hiện các hoạt động. Điều này là cần thiết nếu thư mục tạm thời đã có hoặc nếu đã có tài liệu tham khảo được lưu trữ bên dưới refs/original. Nếu đó không phải là trường hợp, bạn có thể thả cờ này.

  • -- tách các tùy chọn nhánh lọc khỏi các tùy chọn sửa đổi.

  • --allsẽ đảm bảo rằng tất cả các nhánhthẻ được viết lại.

Do sao lưu các tham chiếu cũ của bạn, bạn có thể dễ dàng quay lại trạng thái trước khi thực hiện lệnh.

Giả sử, bạn muốn khôi phục chủ của mình và truy cập vào chi nhánh old_master:

git checkout -b old_master refs/original/refs/heads/master

3
Câu trả lời này không giải quyết được câu hỏi của OP, vì họ hoàn toàn quan tâm đến việc sửa chữa một cam kết mà họ chỉ mới thực hiện. Tôi thường xuyên sử dụng git commit --amendđể sửa chữa lên ý kiến hoặc thêm các tập tin tôi quên git add, nhưng chỉ từng trước khi tôi đã git pushed. Tôi cũng sử dụng git filter-branchkhi tôi muốn hoàn toàn lộn xộn với lịch sử phiên bản, nhưng OP không muốn điều này, vì vậy câu trả lời này cần một cảnh báo lớn về sức khỏe - đừng thử điều này ở nhà, nhìn trộm !!
kbro

226

Sử dụng

git commit --amend

Để hiểu chi tiết, một bài viết xuất sắc là 4. Viết lại Lịch sử Git . Nó cũng nói về khi không sử dụng git commit --amend .


2
Có cách nào tốt để sửa các thông điệp cam kết đã được đẩy đến một kho lưu trữ công cộng không? Cho đến nay tôi đã đi đến kết luận rằng, một khi bị đẩy, lỗi chính tả và thông điệp của tôi phải sống mãi mãi.
stackunderflow

2
Nói một cách dễ hiểu! Không có cách TỐT để rút lại thứ bạn đã đẩy. Tất cả rút lại là BAD ở mức độ lớn hơn hoặc thấp hơn. Bạn cần áp dụng kỷ luật làm việc trong một chi nhánh trong kho lưu trữ riêng của mình, thực hiện nhiều cam kết khi bạn thêm một chút, kiểm tra một chút, điều chỉnh một chút. Sau đó, hợp nhất toàn bộ chi nhánh của bạn thành một cam kết duy nhất, viết một thông điệp cam kết mới mô tả sự thay đổi tổng thể, PROOFREAD nó và đẩy.
kbro

1
Chỉ cần chỉ ra một điều hiển nhiên là người ta không phải thực hiện một cam kết duy nhất khi quay trở lại từ một nhánh tính năng. Những gì nhiều người làm là rebase trên nhánh mục tiêu (để làm cho mọi thứ trông sạch sẽ) sau đó hợp nhất với tùy chọn để ngăn chặn chuyển tiếp nhanh. Đồng ý với quan điểm chính là cẩn thận trước khi bạn đẩy lên.
ShawnFumo

1
Câu git commit --amendtrả lời đã được đưa ra (nhiều lần) trước khi bạn viết. Tại sao bạn lại đăng nó? Nếu bạn muốn thêm một liên kết đến "Viết lại lịch sử Git", bạn có thể chỉnh sửa một trong những câu trả lời hiện có hoặc để lại nhận xét.
Dan Dascalescu

199

Sửa đổi

Bạn có một vài lựa chọn ở đây. Bạn có thể làm

git commit --amend

miễn là đó là cam kết cuối cùng của bạn.

Rebase tương tác

Mặt khác, nếu đó không phải là cam kết cuối cùng của bạn, bạn có thể thực hiện một cuộc nổi loạn tương tác,

git rebase -i [branched_from] [hash before commit]

Sau đó, bên trong rebase tương tác, bạn chỉ cần thêm chỉnh sửa cho cam kết đó. Khi nó xuất hiện, làm một git commit --amendvà sửa đổi thông điệp cam kết. Nếu bạn muốn quay lại trước điểm cam kết đó, bạn cũng có thể sử dụng git reflogvà chỉ cần xóa cam kết đó. Sau đó, bạn chỉ cần làm git commitlại.


191

Nếu đó là cam kết cuối cùng của bạn, chỉ cần sửa đổi cam kết:

git commit --amend -o -m "New commit message"

(Sử dụng cờ -o( --only) để đảm bảo bạn chỉ thay đổi thông điệp cam kết)


Nếu đó là một cam kết bị chôn vùi, hãy sử dụng rebase tương tác tuyệt vời :

git rebase -i @~9   # Show the last 9 commits in a text editor

Tìm cam kết bạn muốn, thay đổi pickthành r( reword), lưu và đóng tệp. Làm xong!



Hướng dẫn thu nhỏ Vim (hoặc, cách khởi động lại chỉ với 8 lần nhấn phím 3jcwrEscZZ):

  • Chạy vimtutornếu bạn có thời gian
  • hjkl tương ứng với các phím di chuyển
  • Tất cả các lệnh có thể được bắt đầu bằng một "phạm vi", ví dụ: 3jdi chuyển xuống ba dòng
  • i để vào chế độ chèn - văn bản bạn nhập sẽ xuất hiện trong tệp
  • Eschoặc Ctrlcđể thoát chế độ chèn và trở về chế độ "bình thường"
  • u trở lại
  • Ctrlr làm lại
  • dd, dw, dlXóa một dòng, văn bản, hoặc lá thư, tương ứng
  • cc, cw, clĐể thay đổi một dòng, văn bản, hoặc lá thư, tương ứng (giống như ddi)
  • yy, yw, ylSao chép ( "yank") một dòng, văn bản, hoặc lá thư, tương ứng
  • phoặc Pđể dán sau, hoặc trước vị trí hiện tại, tương ứng
  • :wEnter để lưu (ghi) một tập tin
  • :q!Enter bỏ mà không tiết kiệm
  • :wqEnterhoặc ZZđể lưu và thoát

Nếu bạn chỉnh sửa văn bản nhiều, sau đó chuyển sang bố trí bàn phím Dvorak , tìm hiểu kiểu chạm và tìm hiểu Vim. Có đáng nỗ lực không? Đúng.



ProTip ™: Đừng ngại thử nghiệm các lệnh "nguy hiểm" viết lại lịch sử * - Git không xóa các cam kết của bạn trong 90 ngày theo mặc định; bạn có thể tìm thấy chúng trong reflog:

$ git reset @~3   # Go back three commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* Coi chừng các tùy chọn như --hard--forcemặc dù - họ có thể loại bỏ dữ liệu. * Ngoài ra, không viết lại lịch sử trên bất kỳ chi nhánh nào bạn cộng tác.


3
Phần vim hoàn toàn ngoài chủ đề và thay vì khuyến khích người dùng dành thời gian học sử dụng trình soạn thảo phức tạp, tại sao không dạy họ một cái gì đó theo chủ đề, như cách thiết lập trình soạn thảo git mặc định để trở nên thân thiện với người dùng, như nano? Chúng ta đang nói về những sửa đổi tầm thường cần được thực hiện đối với một tệp văn bản, chứ không phải mã hóa cứng sẽ tạo ra một cuộc chiến rực lửa về trình soạn thảo văn bản "tốt nhất".
Dan Dascalescu

1
@DanDascalescu: Bởi vì học Vim nhanh hơn bằng cách sử dụng các hướng dẫn ở trên hơn là thực hiện một số cuộc nổi loạn bằng cách sử dụng nano. Toàn bộ lý do git mở trình soạn thảo văn bản chứ không phải giao diện riêng để khởi động lại là vì Vim tồn tại: nó nhẹ, được cài đặt mặc định trên hầu hết các hệ thống và rất dễ học đủ để thực hiện rebase một cách dễ dàng: ví dụ: ddjjpZZdi chuyển một cam kết xuống 2. Không có gì phức tạp về kiến ​​thức Vim cơ bản; phải mất 10 phút để trở nên thoải mái hơn với Vim so với nano.
Zaz

185

Nếu bạn đang sử dụng GUI Git, bạn có thể sửa đổi cam kết cuối cùng chưa được đẩy bằng:

Commit/Amend Last Commit

168

Tôi sử dụng GUI Git nhiều nhất có thể và điều đó cho bạn tùy chọn sửa đổi cam kết cuối cùng:

Đánh dấu vào ô đó

Ngoài ra, git rebase -i origin/masterlà một câu thần chú hay sẽ luôn mang đến cho bạn những cam kết bạn đã thực hiện trên đỉnh chính và cung cấp cho bạn tùy chọn để sửa đổi, xóa, sắp xếp lại hoặc squash. Không cần phải giữ băm đó trước.


4
Làm thế nào để tôi đến màn hình mà bạn đã hiển thị trong ví dụ của bạn?
Marwan مروان

2
Đó là phần dưới bên phải của Windows Git Gui. Chỉ cần chọn chuyển đổi 'Sửa đổi cam kết cuối cùng' và nó sẽ được cung cấp với thông tin cam kết gần đây nhất.
wbdarby

138

Wow, vì vậy có rất nhiều cách để làm điều này.

Tuy nhiên, một cách khác để làm điều này là xóa cam kết cuối cùng, nhưng hãy giữ các thay đổi của nó để bạn không bị mất việc. Sau đó, bạn có thể thực hiện một cam kết khác với thông báo đã sửa. Điều này sẽ trông giống như thế này:

git reset --soft HEAD~1
git commit -m 'New and corrected commit message'

Tôi luôn luôn làm điều này nếu tôi quên thêm một tập tin hoặc thay đổi.

Hãy nhớ chỉ định --softthay vì --hard, nếu không bạn mất hoàn toàn cam kết đó.


5
Điều này thực hiện chính xác tương tự như git commit --amendngoại trừ đó là một quá trình 2 bước.
Joseph K. Strauss

3
@ JosephK.Strauss Tôi tin rằng việc củng cố cam kết cũng giữ thông tin về tác giả và ngày cam kết ban đầu, có thông tin về người đi làm và thông tin ngày mới. Tôi không chắc cách tiếp cận này làm điều đó.
everton

4
@EvertonAgner Bạn đúng. --amendsẽ giữ thông tin tác giả, nhưng câu hỏi chỉ yêu cầu thay đổi tin nhắn.
Joseph K. Strauss

131

Đối với bất kỳ ai đang tìm kiếm GUI Windows / Mac để giúp chỉnh sửa các tin nhắn cũ hơn (không chỉ là tin nhắn mới nhất), tôi khuyên bạn nên sử dụng Sourcetree . Các bước để làm theo dưới đây.

Sourcetree rebase tương tác

Đối với các cam kết chưa được đẩy đến một điều khiển từ xa:

  1. Đảm bảo bạn đã cam kết hoặc lưu lại tất cả các thay đổi hiện tại (nghĩa là không có tệp nào được liệt kê trong tab "Trạng thái tệp") - nó sẽ không hoạt động theo cách khác.
  2. Trong tab "Nhật ký / Lịch sử", nhấp chuột phải vào mục nhập có dòng liền kề trong biểu đồ bên dưới (các) cam kết bạn muốn chỉnh sửa và chọn "Rebase con của <commit ref> tương tác ..."
  3. Chọn toàn bộ hàng cho một thông điệp cam kết bạn muốn thay đổi (nhấp vào cột "Tin nhắn") .
  4. Nhấp vào nút "Chỉnh sửa tin nhắn".
  5. Chỉnh sửa tin nhắn như mong muốn trong hộp thoại xuất hiện và sau đó nhấp OK.
  6. Lặp lại các bước 3-4 nếu có thông báo cam kết khác để thay đổi.
  7. Bấm OK: Rebasing sẽ bắt đầu. Nếu tất cả đều ổn, đầu ra sẽ kết thúc "Hoàn thành thành công". LƯU Ý: Đôi khi tôi đã thấy điều này thất bại Unable to create 'project_path/.git/index.lock': File exists.khi cố gắng sửa đổi nhiều thông điệp cam kết cùng một lúc. Không chắc chắn chính xác vấn đề là gì, hoặc liệu nó sẽ được khắc phục trong phiên bản tương lai của Sourcetree, nhưng nếu điều này xảy ra sẽ khuyên bạn nên loại bỏ chúng cùng một lúc (chậm hơn nhưng có vẻ đáng tin cậy hơn).

... Hoặc ... cho các cam kết đã được đẩy:

Thực hiện theo các bước trong câu trả lời này , tương tự như trên, nhưng yêu cầu một lệnh tiếp theo được chạy từ dòng lệnh ( git push origin <branch> -f) để buộc đẩy nhánh. Tôi khuyên bạn nên đọc tất cả và áp dụng sự thận trọng cần thiết!


ra khỏi tất cả các câu trả lời - điều này là thích hợp nhất cho tất cả người mới git ^^^ (sử dụng một chương trình SourceTree miễn phí và áp dụng "rebase trẻ em" trên một cam kết trước khi một trong những bạn muốn chỉnh sửa)
revelt

127

Nếu bạn chỉ muốn chỉnh sửa cam kết mới nhất, hãy sử dụng:

git commit --amend

hoặc là

git commit --amend -m 'one line message'

Nhưng nếu bạn muốn chỉnh sửa một số cam kết liên tiếp, bạn nên sử dụng rebasing thay thế:

git rebase -i <hash of one commit before the wrong commit>

Chỉnh sửa Git rebase

Trong một tệp, như ở trên, viết edit/ehoặc một trong các tùy chọn khác, và nhấn lưu và thoát.

Bây giờ bạn sẽ ở cam kết sai đầu tiên. Thực hiện thay đổi trong các tệp và chúng sẽ được tự động dàn dựng cho bạn. Kiểu

git commit --amend

Lưu và thoát khỏi đó và gõ

git rebase --continue

để chuyển sang lựa chọn tiếp theo cho đến khi hoàn thành với tất cả các lựa chọn của bạn.

Lưu ý rằng những điều này thay đổi tất cả băm SHA của bạn sau cam kết cụ thể đó.


2
git rebase -i <băm của một cam kết trước khi cam kết sai> hoạt động với tôi. cảm ơn.
Viraths

127

Nếu bạn chỉ muốn thay đổi tin nhắn cuối cùng của mình, bạn nên sử dụng --onlycờ hoặc lối tắt của nó -ovới commit --amend:

git commit --amend -o -m "New commit message"

Điều này đảm bảo rằng bạn không vô tình nâng cao cam kết của mình với các công cụ được dàn dựng. Tất nhiên tốt nhất là có một $EDITORcấu hình phù hợp . Sau đó, bạn có thể bỏ -mtùy chọn này và Git sẽ điền trước thông điệp cam kết với thông báo cũ. Bằng cách này, nó có thể dễ dàng chỉnh sửa.


1
Câu trả lời "hàng đầu" không trả lời câu hỏi. Nó chỉ đưa ra một giới thiệu chung về git commit --amend. Câu hỏi rất cụ thể, do đó lâu hơn! = Tốt hơn. Việc đề cập quyết định đến -ocờ có lẽ sẽ bị chôn vùi trong phần còn lại của thông tin. Tôi cũng không thoải mái khi chỉnh sửa một câu trả lời đã có rất nhiều phiếu bầu.
David Ongaro

2
Điều đó được nói rằng bạn có thể tự do chỉnh sửa câu trả lời hàng đầu, vì có một mối nguy hiểm thực sự mà mọi người đang sử dụng đó là câu trả lời "chính xác". Nó có thể dễ dàng xảy ra để sửa đổi cam kết của bạn với các công cụ được dàn dựng - nó đã xảy ra với tôi và thật sự rất khó chịu khi bạn tình cờ thúc đẩy điều đó. Tuy nhiên, số lượng không đảm bảo cho tính chính xác. Không có số lượng câu trả lời cũng như số lượng phiếu bầu.
David Ongaro

1
Tôi sẽ không đi xa để nói rằng câu trả lời hàng đầu là "không chính xác" và nó "không trả lời câu hỏi". Nó chắc chắn hoạt động và trả lời câu hỏi, bạn chỉ cần đảm bảo rằng bạn không có thay đổi theo giai đoạn khi bạn cố gắng sửa đổi. Nhưng tôi thấy quan điểm của bạn về việc phải cảnh báo mọi người về điều đó. Tôi sẽ chỉnh sửa nó sau nếu tôi có thời gian.

1
Công bằng mà nói: mặc dù --onlytùy chọn có --amendsẵn từ git 1.3.0 nhưng nó không hoạt động chính xác cho đến khi nó được sửa trong 1.7.11.3 ( ea2d4ed35902ce15959965ab86d80527731a177c ). Vì vậy, câu trả lời đúng trong năm 2008 có lẽ sẽ giống như : git stash; git commit --amend; git stash pop.
David Ongaro

103

Cập nhật thông báo cam kết sai cuối cùng của bạn với thông báo cam kết mới trong một dòng:

git commit --amend -m "your new commit message"

Hoặc, hãy thử thiết lập lại Git như dưới đây:

# You can reset your head to n number of commit
# NOT a good idea for changing last commit message,
# but you can get an idea to split commit into multiple commits
git reset --soft HEAD^

# It will reset you last commit. Now, you
# can re-commit it with new commit message.

Sử dụng thiết lập lại để phân chia các cam kết thành các cam kết nhỏ hơn

git reset cũng có thể giúp bạn chia một cam kết thành nhiều cam kết:

# Reset your head. I am resetting to last commits:
git reset --soft HEAD^
# (You can reset multiple commit by doing HEAD~2(no. of commits)

# Now, reset your head for splitting it to multiple commits
git reset HEAD

# Add and commit your files separately to make multiple commits: e.g
git add app/
git commit -m "add all files in app directory"

git add config/
git commit -m "add all files in config directory"

Ở đây bạn đã chia thành công cam kết cuối cùng của bạn thành hai lần cam kết.


3
Nếu tất cả những gì bạn muốn làm là chỉnh sửa thông báo về cam kết cuối cùng của bạn, sử dụng thiết lập lại mềm cho mục đích đó là quá mức . Chỉ cần sử dụng git commit --amend, chính xác như cách nó nói trong câu trả lời được bình chọn hàng đầu . Ngoài ra, git reset --soft HEAD^hoạt động giống hệt với thiết lập lại mềm trong câu trả lời trước đó , bởi vì cả hai đều đặt lại về cam kết cha mẹ đầu tiên.

3
Tôi chỉ bận tâm thêm git resetvào giải pháp chỉ để đưa ra một ý tưởng để chia một thông điệp cam kết thành nhiều thông điệp cam kết. Bởi vì, tôi đã phải đối mặt với vấn đề đó khi tôi bắt đầu sử dụng git. Đôi khi, điều này có thể thực sự hữu ích. :)
przbadu

87

Về câu hỏi này có rất nhiều câu trả lời, nhưng không ai trong số họ giải thích siêu chi tiết về cách thay đổi các thông điệp cam kết cũ hơn bằng Vim . Tôi đã bị mắc kẹt khi cố gắng tự làm điều này, vì vậy ở đây tôi sẽ viết chi tiết về cách tôi đã làm điều này đặc biệt đối với những người không có kinh nghiệm về Vim!

Tôi muốn thay đổi năm cam kết mới nhất của mình mà tôi đã đẩy lên máy chủ. Điều này khá 'nguy hiểm' bởi vì nếu ai đó đã rút từ điều này, bạn có thể làm mọi thứ rối tung lên bằng cách thay đổi các thông điệp cam kết. Tuy nhiên, khi bạn đang làm việc trên chi nhánh nhỏ của mình và chắc chắn không ai kéo nó, bạn có thể thay đổi nó như thế này:

Giả sử bạn muốn thay đổi năm cam kết mới nhất của mình và sau đó bạn nhập mã này vào thiết bị đầu cuối:

git rebase -i HEAD~5

* Trong đó 5 là số lượng tin nhắn cam kết bạn muốn thay đổi (vì vậy nếu bạn muốn thay đổi cam kết thứ 10 thành cam kết cuối cùng, bạn nhập 10).

Lệnh này sẽ đưa bạn vào Vim ở đó bạn có thể 'chỉnh sửa' lịch sử cam kết của mình. Bạn sẽ thấy năm cam kết cuối cùng của bạn ở đầu như thế này:

pick <commit hash> commit message

Thay vì pickbạn cần viết reword. Bạn có thể làm điều này trong Vim bằng cách gõ vào i. Điều đó làm cho bạn đi vào chế độ chèn . (Bạn thấy rằng bạn đang ở chế độ chèn bởi từ INSERT ở phía dưới.) Đối với các cam kết bạn muốn thay đổi, hãy nhập rewordthay vì pick.

Sau đó, bạn cần lưu và thoát khỏi màn hình này. Bạn làm điều đó bằng cách trước tiên vào 'chế độ lệnh' bằng cách nhấn Escnút (bạn có thể kiểm tra xem bạn đang ở chế độ lệnh nếu từ INSERT ở phía dưới đã biến mất). Sau đó, bạn có thể gõ một lệnh bằng cách gõ :. Lệnh để lưu và thoát là wq. Vì vậy, nếu bạn gõ :wqbạn đang đi đúng hướng.

Sau đó, Vim sẽ chuyển qua mọi thông điệp cam kết bạn muốn điều chỉnh lại và ở đây bạn thực sự có thể thay đổi các thông điệp cam kết. Bạn sẽ làm điều này bằng cách chuyển sang chế độ chèn, thay đổi thông báo cam kết, chuyển sang chế độ lệnh và lưu và thoát. Làm điều này năm lần và bạn ra khỏi Vim!

Sau đó, nếu bạn đã đẩy các cam kết sai của mình, bạn cần git push --forceghi đè lên chúng. Hãy nhớ rằng đó git push --forcelà một điều khá nguy hiểm để làm, vì vậy hãy chắc chắn rằng không ai rút khỏi máy chủ kể từ khi bạn đẩy sai phạm!

Bây giờ bạn đã thay đổi tin nhắn cam kết của bạn!

(Như bạn thấy, tôi không có kinh nghiệm về Vim, vì vậy nếu tôi sử dụng sai 'biệt ngữ' để giải thích những gì đang xảy ra, vui lòng sửa tôi!)


4
<nitpick>Không có "chủ đề" nào trên Stack Overflow, vì đây không phải là một diễn đàn thảo luận, chỉ có "câu hỏi", "câu trả lời" và "bài viết". </nitpick>. Ngoài ra, không phải tất cả các phiên bản của Vim đều giống nhau, không phải tất cả chúng đều cho phép bạn xóa các ký tự trong chế độ chèn (có ý nghĩa theo một cách nào đó, phải không?). Nếu bạn muốn luôn có thể xóa các ký tự trong Vim Xxsẽ làm điều đó (một ít xxóa các ký tự ở phía trước con trỏ, Xsẽ xóa phía sau). Nếu bạn mắc lỗi, bạn có thể sử dụng unhiều lần để hoàn tác. Cuối cùng, rlà tốc ký rewordtrong trình soạn thảo rebase tương tác.

1
Để thay đổi một từ trong vim được cwgõ vào đầu của nó (mặc dù câu hỏi không phải là về vim, tôi đồng ý).
Yaroslav Nikitenko

Bạn không cần phải sử dụng sự ghê tởm đó . Bạn có thể đặt trình soạn thảo git của mình thành một thứ gì đó lành mạnh và thân thiện với người dùng, như nanomcedit Midnight Commander.
Dan Dascalescu

79

Bạn có thể sử dụng git-rebase-tuaord

Nó được thiết kế để chỉnh sửa bất kỳ cam kết nào (không chỉ cuối cùng) theo cách tương tự như commit --amend

$ git rebase-reword <commit-or-refname>

Nó được đặt tên theo hành động tương tác rebase để sửa đổi một cam kết: "tua lại". Xem bài đăng này và chế độ tương tác người đàn ông-

Ví dụ:

$ git rebase-reword b68f560
$ git rebase-reword HEAD^

6
Điều này đòi hỏi phải cài đặt một chương trình bên ngoài. Theo tôi, sẽ tốt hơn nếu học cách sử dụng các công cụ và bí danh tích hợp hiệu quả hơn. Tôi sẽ gõ: g c; g rb -i @~9(cam kết và rebase), di chuyển cam kết mới đến nơi tôi muốn, thay đổi committhành f( fixup) và lưu. Nếu bạn muốn một cái gì đó nhanh hơn thế, bạn có thể bí danh git commit --fixup=<commit>; git rebase -i --autosquash <commit>^
Zaz

79

Tôi đã thêm các bí danh recirecmcho recommit (amend)nó. Bây giờ tôi có thể làm điều đó với git recmhoặc git recm -m:

$ vim ~/.gitconfig

[alias]

    ......
    cm = commit
    reci = commit --amend
    recm = commit --amend
    ......

57

Tôi nhận ra rằng tôi đã đẩy một cam kết với một lỗi đánh máy trong đó. Để hoàn tác, tôi đã làm như sau:

git commit --amend -m "T-1000, advanced prototype"
git push --force

Cảnh báo: buộc đẩy các thay đổi của bạn sẽ ghi đè lên nhánh từ xa bằng nhánh cục bộ của bạn. Hãy chắc chắn rằng bạn sẽ không ghi đè lên bất cứ thứ gì bạn muốn giữ. Ngoài ra, hãy thận trọng về việc buộc một cam kết sửa đổi (viết lại) nếu có ai khác chia sẻ chi nhánh với bạn, bởi vì họ sẽ cần phải viết lại lịch sử của chính họ nếu họ có bản sao cũ của cam kết mà bạn vừa viết lại.


7
Không có gì được "ghi đè" trong git. Trong trường hợp này, con trỏ nhánh sẽ được đặt thành cam kết mới của bạn và cam kết cũ sẽ bị cũ nếu không còn tham chiếu nào cho nó và nó có thể bị xóa sau vài tuần. (Cho đến lúc đó những người khác vẫn có thể tìm và tham khảo nó, ví dụ bằng cách xem qua phần giới thiệu.)
David Ongaro

51

Tôi thích sử dụng như sau:

  1. git status
  2. git add --all
  3. git commit -am "message goes here about the change"
  4. git pull <origin master>
  5. git push <origin master>

46

Nếu bạn chưa đẩy mã đến chi nhánh từ xa ( GitHub / Bitbucket ), bạn có thể thay đổi thông báo cam kết trên dòng lệnh như dưới đây.

 git commit --amend -m "Your new message"

Nếu bạn đang làm việc trên một chi nhánh cụ thể, hãy làm điều này:

git commit --amend -m "BRANCH-NAME: new message"

Nếu bạn đã đẩy mã với thông báo sai và bạn cần cẩn thận khi thay đổi tin nhắn. Đó là, sau khi bạn thay đổi thông điệp cam kết và thử đẩy nó một lần nữa, bạn sẽ gặp vấn đề. Để làm cho nó trơn tru, hãy làm theo các bước sau.

Xin vui lòng đọc toàn bộ câu trả lời của tôi trước khi làm điều đó.

git commit --amend -m "BRANCH-NAME : your new message"

git push -f origin BRANCH-NAME                # Not a best practice. Read below why?

Lưu ý quan trọng: Khi bạn sử dụng lực đẩy trực tiếp, bạn có thể gặp phải các vấn đề về mã mà các nhà phát triển khác đang làm việc trên cùng một chi nhánh. Vì vậy, để tránh những xung đột đó, bạn cần phải rút mã từ chi nhánh của mình trước khi thực hiện lực đẩy :

 git commit --amend -m "BRANCH-NAME : your new message"
 git pull origin BRANCH-NAME
 git push -f origin BRANCH-NAME

Đây là cách tốt nhất khi thay đổi thông điệp cam kết, nếu nó đã được đẩy.

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.