Làm cách nào để xóa các mục nhật ký cam kết đã chọn khỏi kho Git trong khi vẫn giữ các thay đổi của chúng?


241

Tôi muốn xóa các mục nhật ký cam kết đã chọn khỏi cây cam kết tuyến tính, để các mục nhập không hiển thị trong nhật ký cam kết.

Cây cam kết của tôi trông giống như:

R--A--B--C--D--E--HEAD

Tôi muốn xóa các mục B và C để chúng không hiển thị trong nhật ký cam kết, nhưng nên giữ nguyên các thay đổi từ A thành D. Có thể bằng cách giới thiệu một cam kết duy nhất, để B và C trở thành BC và cây trông như thế nào.

R--A--BC--D--E--HEAD

Hoặc, lý tưởng nhất là sau khi A đến trực tiếp. D 'đại diện cho các thay đổi từ A đến B, B đến C và C sang D.

R--A--D'--E--HEAD

Điều này có thể không? nếu có, làm thế nào?

Đây là một dự án khá mới vì vậy hiện tại không có chi nhánh, do đó cũng không có sự hợp nhất nào.


@ xk0der: "cam kết" là thuật ngữ đúng ở đây. rebasecó thể loại bỏ cũ / tạo các cam kết mới. Tôi không biết "cam kết mục nhập" nghĩa là gì.
jfs

@JFSebastian Tôi không thấy vấn đề với "nhật ký cam kết" - Nhật ký của tất cả các cam kết. Và tôi muốn xóa một vài mục từ nhật ký - trong khi vẫn giữ những thay đổi thực tế (các cam kết).
xk0der

@ xk0der: cam kết git là địa chỉ nội dung, nghĩa là, nếu bạn thay đổi bất cứ điều gì trong một cam kết, ví dụ, thông điệp tường trình của nó; bạn tạo một cam kết mới. Bạn có thể đọc cam kết của git mà không cần git và tự mình xem .
jfs

@JFSebastian - Cảm ơn các liên kết - Tôi biết điều đó - Nhưng liệu kỹ thuật đó có thực sự thay đổi vấn đề tôi đang gặp phải và cách tôi đưa ra? Tôi đoán là không. Cuối cùng: Tôi muốn xóa "thông điệp nhật ký cam kết" - mà không xóa "thay đổi cam kết" - Vui lòng đọc lại câu hỏi của tôi - đặc biệt là đoạn thứ hai. Để thêm nhiều hơn git loghiển thị "nhật ký cam kết" git-scm.com/docs/git-log . Và tôi muốn thoát khỏi hai mục từ nhật ký đó - không phải là những thay đổi.
xk0der

Câu trả lời:


273

git-rebase (1) thực hiện chính xác điều đó.

$ git rebase -i HEAD~5

git awsome-ness [git rebase - interactive] chứa một ví dụ.

  1. Không sử dụng git-rebasetrên các cam kết công khai (từ xa).
  2. Hãy chắc chắn rằng thư mục làm việc của bạn sạch sẽ ( commithoặc stashnhững thay đổi hiện tại của bạn).
  3. Chạy lệnh trên. Nó ra mắt của bạn $EDITOR.
  4. Thay thế picktrước CDbởi squash. Nó sẽ kết hợp C và D thành B. Nếu bạn muốn xóa một cam kết thì chỉ cần xóa dòng của nó.

Nếu bạn bị mất, gõ:

$ git rebase --abort  

Cảm ơn đã trả lời nhanh chóng. Vì vậy, tôi có kiểm tra A và thực hiện một rebase, một cái gì đó như thế git rebase -i D [A]nào?
xk0der


3
Làm thế nào chúng ta có thể làm điều đó trên repos từ xa?
Xóa

6
@Eray: chỉ là push -fnhững thay đổi của bạn. Đừng làm điều đó nếu bạn không làm việc một mình.
jfs

2
@ ripper234: Tôi đã sửa các liên kết đến điểm git-rebasethủ công và máy quay ngược lại cho bài đăng trên blog.
jfs

75
# detach head and move to D commit
git checkout <SHA1-for-D>

# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>

# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>

# Re-apply everything from the old D onwards onto this new place 
git rebase --onto HEAD <SHA1-for-D> master

Điều này cũng hoạt động và giúp tôi hiểu thế nào là thiết lập lại mềm. Cấp, câu trả lời "hàng đầu" là đúng và ngắn hơn, nhưng cảm ơn cho câu trả lời này là tốt.
cgp

41

Đây là một cách để loại bỏ một id xác nhận cụ thể chỉ biết id xác nhận mà bạn muốn xóa.

git rebase --onto commit-id^ commit-id

Lưu ý rằng điều này thực sự loại bỏ thay đổi đã được đưa ra bởi cam kết.


7
Đầu thêm vào trong lệnh này sẽ khiến cho cuộc nổi loạn kết thúc với một 'ĐẦU tách rời', điều không mong muốn. Nó nên được thông báo.
Frosty

3
Điều này hoàn nguyên các thay đổi được giới thiệu id-id của tôi, OP muốn giữ lại các thay đổi, chỉ cần xóa các xác nhận.
CB Bailey

1
-1 bởi vì nó không làm những gì OP yêu cầu (thay vào đó nó phá hủy thứ mà anh ta rõ ràng muốn giữ lại).
Emil Styrke

1
Mặc dù nó không làm những gì OP yêu cầu, nhưng đó chính xác là những gì tôi cần, vì vậy +1 cho câu trả lời hữu ích.
Evins

20

Để mở rộng câu trả lời của JF Sebastian:

Bạn có thể sử dụng git-rebase để dễ dàng thực hiện tất cả các loại thay đổi đối với lịch sử cam kết của mình.

Sau khi chạy git rebase - tương tác, bạn nhận được những điều sau trong $ EDITOR của mình:

pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

Bạn có thể di chuyển các dòng để thay đổi thứ tự cam kết và xóa các dòng để xóa cam kết đó. Hoặc bạn có thể thêm một lệnh để kết hợp (squash) hai lần xác nhận vào một lần xác nhận (lần xác nhận trước đó là lần xác nhận ở trên), chỉnh sửa cam kết (đã thay đổi) hoặc điều chỉnh lại thông điệp cam kết.

Tôi nghĩ rằng chọn chỉ có nghĩa là bạn muốn để lại cam kết một mình.

(Ví dụ là từ đây )



3

Một cách nữa,

git rebase -i ad0389efc1a79b1f9c4dd6061dca6edc1d5bb78a (C's hash)
and
git push origin master  -f

chọn hàm băm mà bạn muốn sử dụng làm cơ sở và lệnh trên sẽ làm cho nó tương tác để bạn có thể xóa tất cả các thông điệp hàng đầu (bạn cần để lại bản cũ nhất)


2

Tôi thấy quá trình này an toàn và dễ hiểu hơn nhiều bằng cách tạo một nhánh khác từ SHA1 của A và chọn các thay đổi mong muốn để tôi có thể chắc chắn rằng mình hài lòng với giao diện của nhánh mới này. Sau đó, thật dễ dàng để loại bỏ chi nhánh cũ và đổi tên chi nhánh mới.

git checkout <SHA1 of A>
git log #verify looks good
git checkout -b rework
git cherry-pick <SHA1 of D>
....
git log #verify looks good
git branch -D <oldbranch>
git branch -m rework <oldbranch>

nếu bạn làm điều này bạn cũng sẽ mất cam kết E, phải không? Theo tôi hiểu, bạn xóa master và đổi tên làm lại thành master (coi luồng ABCDE là nhánh master).
Renan Bandeira

1

Chỉ cần thu thập tất cả câu trả lời của mọi người: (m mới để git plz sử dụng nó để tham khảo)

git rebase để xóa bất kỳ cam kết

nhật ký git

-first check from which commit you want to rebase

git rebase -i ĐẦU ~ 1

-Here i want to rebase on the second last commit- commit count starts from '1')
-this will open the command line editor (called vim editor i guess)

Sau đó, màn hình sẽ trông giống như thế này:

chọn 0c2236d Đã thêm dòng mới.

Rebase 2a1cd65..0c2236d vào 2a1cd65 (1 lệnh)

#

Các lệnh:

p, chọn = sử dụng cam kết

r, tuaord = sử dụng cam kết, nhưng chỉnh sửa thông điệp cam kết

e, chỉnh sửa = sử dụng cam kết, nhưng dừng để sửa đổi

s, squash = sử dụng cam kết, nhưng kết hợp thành cam kết trước đó

f, fixup = like "squash", nhưng loại bỏ thông điệp tường trình của cam kết này

x, exec = run lệnh (phần còn lại của dòng) bằng shell

d, drop = xóa cam kết

#

Những dòng này có thể được đặt hàng lại; chúng được thực hiện từ trên xuống dưới.

#

Nếu bạn xóa một dòng ở đây, thì CAM KẾT SILL ĐƯỢC MẤT.

#

Tuy nhiên, nếu bạn loại bỏ mọi thứ, rebase sẽ bị hủy bỏ.

#

Lưu ý rằng các cam kết trống được nhận xét ~ ~

~
~
~
~
~
~
~
~
~ ~

Ở đây thay đổi dòng đầu tiên theo nhu cầu của bạn (sử dụng các lệnh được liệt kê ở trên tức là 'thả' để xóa cam kết, v.v.) Sau khi thực hiện chỉnh sửa, nhấn ': x' để lưu và thoát trình chỉnh sửa (chỉ dành cho trình soạn thảo vim)

Và sau đó

đẩy git

Nếu nó có vấn đề thì bạn cần đẩy mạnh các thay đổi sang điều khiển từ xa (ITS RẤT CẦN THIẾT: không ép buộc nếu bạn đang làm việc trong nhóm)

git đẩy -f nguồn gốc


-1

Bạn có thể sử dụng git cherry-pick cho việc này. 'cherry-pick' sẽ áp dụng một cam kết lên chi nhánh của bạn ngay bây giờ.

sau đó làm

git rebase --hard <SHA1 of A>

sau đó áp dụng các cam kết D và E.

git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>

Điều này sẽ bỏ qua cam kết B và C. Đã nói rằng có thể không thể áp dụng cam kết D cho chi nhánh mà không có B, vì vậy YMMV.


2
OP muốn kết hợp các cam kết B, C, D, không xóa các thay đổi của chúng.
jfs

3
Tôi nghĩ bạn có nghĩa là reset --hard, không rebase --hard(không tồn tại)
Mauricio Scheffer
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.