2016-08-18 18 views
8

Tôi muốn đè bẹp một số cam kết với nhau ở giữa một chi nhánh mà không sửa đổi các cam kết trước và sau.Git squash cam kết ở giữa một chi nhánh

tôi có:

A -- B -- C -- D -- E -- F -- G 
|        | 
master      dev 
origin/master 

Tôi muốn bí đó vào

A -- H -- E -- F -- G 
|     | 
master    dev 
origin/master 

đâu H tương đương với B -- C -- D. Và tôi muốn có thể chỉ định thông điệp cam kết của H. A là cam kết cuối cùng đã được đẩy để tất cả các cam kết sau đó có thể được viết lại mà không làm hỏng máy chủ. Ý tưởng là để làm sạch lịch sử trước khi tôi chuyển tiếp nhanh master.

Tôi có thể làm như thế nào?

PS: Lưu ý rằng trong trường hợp của tôi, tôi thực sự có nhiều hơn 3 cam kết để bíp ở giữa, nhưng nếu tôi có thể làm điều đó với 3, tôi sẽ có thể làm điều đó với nhiều hơn nữa.

PPS: Ngoài ra, nếu có thể, tôi muốn có giải pháp trong đó E, FG vẫn không bị ảnh hưởng (chủ yếu liên quan đến ngày cam kết).

+0

Bản sao có thể có của [Kết hợp nhiều lần commit trước khi đẩy vào Git] (http://stackoverflow.com/questions/6934752/combining-multiple-commits-before-pushing-in-git) –

Trả lời

13

Bạn có thể thực hiện thao tác rebase tương tác và chọn thủ công mà bạn muốn đánh số. Điều này sẽ viết lại lịch sử của chi nhánh dev của bạn, nhưng vì bạn chưa đẩy các cam kết này, nên không có bất kỳ hậu quả tiêu cực nào từ việc này ngoài những gì có thể xảy ra trên máy tính của riêng bạn.

Bắt đầu với những điều sau đây:

git checkout dev 
git rebase -i HEAD~6 

này nên mang lên một cửa sổ hiển thị cho bạn danh sách sau đây của 7 cam kết, sẽ trở lại 6 bước từ HEAD của chi nhánh dev của bạn:

pick 07c5abd message for commit A 
pick dl398cn message for commit B 
pick 93nmcdu message for commit C 
pick lst28e4 message for commit D 
pick 398nmol message for commit E 
pick 9kml38d message for commit F 
pick 02jmdmp message for commit G 

Cam kết đầu tiên được hiển thị (A ở trên) là cũ nhất và lần cuối cùng là lần commit gần đây nhất. Bạn có thể thấy rằng theo mặc định, tùy chọn cho mỗi cam kết là pick. Nếu bạn đã hoàn thành việc rebase ngay bây giờ, bạn sẽ chỉ giữ lại mỗi cam kết như nó là, đó là hiệu quả một no-op. Nhưng kể từ khi bạn muốn bí ẩn một số cam kết trung gian nhất định, hãy chỉnh sửa và thay đổi danh sách thành:

pick 07c5abd message for commit A 
pick dl398cn new commit message for "H" goes here 
squash 93nmcdu message for commit C 
squash lst28e4 message for commit D 
pick 398nmol message for commit E 
pick 9kml38d message for commit F 
pick 02jmdmp message for commit G 

Lưu ý cẩn thận những gì đang xảy ra ở trên. Bằng cách nhập squash, bạn đang yêu cầu Git hợp nhất cam kết đó vào một ở trên, đó là cam kết xuất hiện ngay lập tức trước. Vì vậy, điều này nói để bí quyết cam kết D ngược lại vào cam kết C và sau đó để squash C thành B, chỉ để lại cho bạn một cam kết cho cam kết B, CD. Các cam kết khác vẫn như cũ.

Lưu tệp (: wq trên Git Bash trong Windows) và quá trình rebase hoàn tất. Hãy nhớ rằng bạn có thể nhận được xung đột hợp nhất từ ​​điều này như bạn có thể mong đợi, nhưng không có gì đặc biệt về giải quyết chúng và bạn có thể tiếp tục như bạn làm với bất kỳ rebase hoặc hợp nhất thường xuyên nào.

Nếu bạn kiểm tra chi nhánh sau khi rebase, bạn sẽ nhận thấy rằng các cam kết E, FG hiện có các băm, ngày mới, v.v. Điều này là do các cam kết này thực sự đã được thay thế bằng các cam kết mới. Lý do cho điều này là bạn viết lại lịch sử, và do đó các cam kết nói chung có thể không còn giống như trước đây.

+0

Làm việc như một sự quyến rũ, cảm ơn! Tôi đã không mong đợi điều này là dễ dàng. Tuy nhiên, có cách nào để làm điều tương tự mà không cần viết lại 3 lần commit cuối cùng không? Tôi nhận thấy git đã tạo 3 commit mới (với ngày cam kết là ngày hiện tại). – deadbeef

+1

@deadbeef Nếu bạn suy ngẫm câu hỏi của mình một lúc, bạn sẽ nhận ra tại sao câu trả lời phải là không. Vì bạn đã viết lại những gì đã xảy ra trước các cam kết 'E',' F' và 'G', ba commit này được viết lại và thực sự là commit _new_. –

+0

Tôi đã cân nhắc một lúc và nhận ra rằng có lẽ không thể có :-). Tuy nhiên tôi tìm thấy 'git rebase --committer-date-is-author-date' mà về cơ bản làm những gì tôi muốn (giữ ngày cam kết ban đầu). – deadbeef

Các vấn đề liên quan