Tôi có thể chia một hunk đã chia bằng git không?


204

Gần đây tôi đã phát hiện ra patchtùy chọn của git cho addlệnh và tôi phải nói rằng nó thực sự là một tính năng tuyệt vời. Tôi cũng phát hiện ra rằng một khối lớn có thể được chia thành các khối nhỏ hơn bằng cách nhấn sphím, điều này làm tăng thêm độ chính xác của cam kết. Nhưng điều gì sẽ xảy ra nếu tôi muốn độ chính xác cao hơn nữa, nếu phần tách không đủ nhỏ?

Ví dụ, hãy xem xét hunk đã chia này:

@@ -34,12 +34,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

Làm cách nào tôi có thể thêm loại bỏ nhận xét CSS vào lần xác nhận tiếp theo? Các stùy chọn là không có sẵn nữa!

Câu trả lời:


253

Nếu bạn đang sử dụng git add -pvà thậm chí sau khi chia tách s, bạn không có một thay đổi đủ nhỏ, bạn có thể sử dụng eđể chỉnh sửa bản vá trực tiếp.

Điều này có thể hơi khó hiểu, nhưng nếu bạn cẩn thận làm theo các hướng dẫn trong cửa sổ soạn thảo sẽ được mở sau khi nhấn ethì bạn sẽ ổn thôi. Trong trường hợp bạn đã trích dẫn, bạn sẽ muốn thay thế -bằng một khoảng trắng ở đầu những dòng này:

-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {

... Và xóa dòng sau, tức là dòng bắt đầu bằng +. Nếu sau đó bạn lưu và thoát trình soạn thảo của mình, chỉ cần xóa bình luận CSS sẽ được tổ chức.


9
Giải pháp tuyệt vời! Tôi đã thấy điều đó nhưng hiểu lầm ... Tôi mặc dù những thay đổi cũng sẽ bị xóa khỏi cây làm việc.
greg0ire

7
Thật vậy, nó không rõ ràng từ văn bản trợ giúp. Thật ra, tôi thấy mình sử dụng nó rất nhiều, vì tôi nghĩ git thực sự khuyến khích bạn thực hiện từng cam kết chính xác và đẹp nhất có thể :)
Mark Longair

27
Lưu ý rằng bạn thực sự phải thay thế nó bằng một khoảng trắng . Tôi đã thử nó cho thấy tôi chỉ có thể xóa các -ký tự và Git phàn nàn rằng bản vá của tôi không áp dụng.
Ryan Lundy

3
Tôi đoán lý do bạn xóa các dòng bằng '-' và thay thế '+' bằng một khoảng trắng là sau đó bạn đang tạo một bản vá trong đó các dòng có dấu '-' đã bị xóa và các dòng có dấu ' + đã được thêm vào (trong mắt của bản vá). Hoặc một cách khác để xem xét, bạn có thực sự thực hiện hành động mà các ký tự đó (-, +) thể hiện (thêm một dòng hoặc xóa nó). Chỉ các dòng còn lại có '-'s và' + 'được ghi lại dưới dạng thay đổi và phần còn lại là "chỉ là cách tệp".
nguyên tử

3
@Filype: Tôi không biết tại sao điều đó lại xảy ra, tôi sợ - nếu bạn đang chạy git add -pvà chỉnh sửa một đoạn với eđiều đó chỉ ảnh hưởng đến những gì được dàn dựng chứ không phải cây làm việc của bạn.
Đánh dấu Longair

60

Hãy nói rằng bạn example.csstrông như thế này:

.classname {
  width: 440px;
}

/*#field_teacher_id {
  display: block;
} */

form.table-form #field_teacher + label,
form.table-form #field_producer_distributor + label {
  width: 300px;
}

.another {
  width: 420px;
}

Bây giờ, hãy thay đổi các bộ chọn kiểu ở khối giữa và trong khi chúng ta đang ở đó, hãy xóa một số kiểu nhận xét cũ mà chúng ta không cần nữa.

.classname {
  width: 440px;
}

#user-register form.table-form .field-type-checkbox label {
  width: 300px;
}

.another {
  width: 420px;
}

Điều đó thật dễ dàng, bây giờ hãy cam kết. Nhưng chờ đã, tôi muốn duy trì sự phân tách hợp lý các thay đổi trong kiểm soát phiên bản để xem xét mã theo từng bước đơn giản và để nhóm của tôi và tôi có thể dễ dàng tìm kiếm lịch sử cam kết để biết chi tiết cụ thể.

Xóa mã cũ tách biệt về mặt logic với thay đổi bộ chọn kiểu khác. Chúng ta sẽ cần hai cam kết riêng biệt, vì vậy hãy thêm hunk cho một bản vá.

git add --patch
diff --git a/example.css b/example.css
index 426449d..50ecff9 100644
--- a/example.css
+++ b/example.css
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

Stage this hunk [y,n,q,a,d,/,e,?]?

Rất tiếc, có vẻ như các thay đổi quá gần, vì vậy git đã kết hợp chúng lại với nhau.

Ngay cả khi cố gắng tách nó bằng cách nhấn scũng có kết quả tương tự vì sự phân tách không đủ chi tiết cho những thay đổi chính xác của chúng tôi. Các dòng không thay đổi được yêu cầu giữa các dòng thay đổi để git có thể tự động phân chia các bản vá.

Vì vậy, hãy chỉnh sửa thủ công bằng cách nhấne

Stage this hunk [y,n,q,a,d,/,e,?]? e

git sẽ mở các bản vá trong trình soạn thảo của chúng tôi lựa chọn.

# Manual hunk edit mode -- see bottom for a quick guide
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging. If it does not apply cleanly, you will be given
# an opportunity to edit again. If all lines of the hunk are removed,
# then the edit is aborted and the hunk is left unchanged.

Hãy xem lại mục tiêu:

Làm cách nào tôi có thể thêm loại bỏ nhận xét CSS vào lần xác nhận tiếp theo?

Chúng tôi muốn chia điều này thành hai cam kết:

  1. Cam kết đầu tiên liên quan đến việc xóa một số dòng (xóa bình luận).

    Để xóa các dòng nhận xét, chỉ cần để chúng một mình, chúng đã được đánh dấu để theo dõi việc xóa trong kiểm soát phiên bản như chúng ta muốn.

    -/*#field_teacher_id {
    - display: block;
    -} */

  2. Cam kết thứ hai là một thay đổi, được theo dõi bằng cách ghi lại cả xóa và bổ sung:

    • Xóa (dòng chọn cũ đã bị xóa)

      Để giữ các dòng chọn cũ (không xóa chúng trong lần xác nhận này), chúng tôi muốn ...

      Để xóa các dòng '-', tạo chúng ''

      ... nghĩa đen là thay thế trừ -dấu hiệu với một không gian nhân vật.

      Vì vậy, ba dòng ...

      -
      -form.table-form #field_teacher + label,
      -form.table-form #field_producer_distributor + label {

      ... sẽ trở thành ( chú ý khoảng trống duy nhất ở đầu tiên của cả 3 dòng):


      form.table-form #field_teacher + label,
      form.table-form #field_producer_distributor + label {

    • Bổ sung (thêm dòng chọn mới)

      Để không chú ý đến dòng bộ chọn mới được thêm vào trong lần xác nhận này, chúng tôi muốn ...

      Để xóa các dòng '+', hãy xóa chúng.

      ... có nghĩa đen là xóa toàn bộ dòng:

      +#user-register form.table-form .field-type-checkbox label {

      (Phần thưởng: Nếu bạn tình cờ sử dụng vim làm trình chỉnh sửa của mình, hãy nhấn ddđể xóa một dòng. Người dùng Nano nhấn Ctrl+ K)

Trình chỉnh sửa của bạn sẽ trông như thế này khi bạn lưu:

# Manual hunk edit mode -- see bottom for a quick guide
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */

 form.table-form #field_teacher + label,
 form.table-form #field_producer_distributor + label {
   width: 300px;
 }

# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging. If it does not apply cleanly, you will be given
# an opportunity to edit again. If all lines of the hunk are removed,
# then the edit is aborted and the hunk is left unchanged.

Bây giờ hãy cam kết.

git commit -m "remove old code"

Và để chắc chắn, chúng ta hãy xem những thay đổi từ lần cam kết cuối cùng.

git show
commit 572ecbc7beecca495c8965ce54fbccabdd085112
Author: Jeff Puckett <jeff@jeffpuckett.com>
Date:   Sat Jun 11 17:06:48 2016 -0500

    remove old code

diff --git a/example.css b/example.css
index 426449d..d04c832 100644
--- a/example.css
+++ b/example.css
@@ -2,9 +2,6 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */

 form.table-form #field_teacher + label,
 form.table-form #field_producer_distributor + label {

Hoàn hảo - bạn có thể thấy rằng chỉ có các thao tác xóa được đưa vào cam kết nguyên tử đó. Bây giờ hãy hoàn thành công việc và cam kết phần còn lại.

git add .
git commit -m "change selectors"
git show
commit 83ec3c16b73bca799e4ed525148cf303e0bd39f9
Author: Jeff Puckett <jeff@jeffpuckett.com>
Date:   Sat Jun 11 17:09:12 2016 -0500

    change selectors

diff --git a/example.css b/example.css
index d04c832..50ecff9 100644
--- a/example.css
+++ b/example.css
@@ -2,9 +2,7 @@
   width: 440px;
 }

-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

Cuối cùng, bạn có thể thấy cam kết cuối cùng chỉ bao gồm các thay đổi của bộ chọn.


1
Phần thưởng số 2: Nếu bạn tình cờ sử dụng VIM làm trình chỉnh sửa của mình, bạn phải nhấn "d" hai lần trên bàn phím để xóa một dòng: D
Alexxus

3
Ngoài ra, thay vì xóa các dòng bạn đã thêm mà bạn không muốn thêm, bạn có thể thay thế +bằng #. Kết quả là như nhau, nhưng có thể bạn không thoải mái với việc xóa (và không thể hoàn nguyên) hoặc bạn muốn thử nghiệm trước khi lưu.
ob-ivan

Và điều đó, đối với vim là r #hơn xD
aksh1618

Mục tiêu là "Làm cách nào tôi có thể thêm loại bỏ nhận xét CSS vào lần xác nhận tiếp theo?", Nhưng các bước thực sự khó hiểu về những gì nó đang thực hiện. (chúng tôi muốn "thêm" chỉ "loại bỏ" một vài dòng cho lần xác nhận tiếp theo.) Vì vậy, chỉ cần nói loại bỏ hoặc thêm là rất khó hiểu. Nói rõ những gì đã hoàn thành ở mỗi bước sẽ giúp làm rõ.
ahnbizcad

9

Nếu bạn có thể sử dụng git gui, nó cho phép bạn thay đổi từng giai đoạn theo từng dòng. Thật không may, tôi không biết làm thế nào để thực hiện nó từ dòng lệnh - hoặc thậm chí nếu có thể.

Một tùy chọn khác mà tôi đã sử dụng trong quá khứ là khôi phục một phần của thay đổi (giữ cho trình chỉnh sửa mở), cam kết các bit tôi muốn, hoàn tác và lưu lại từ trình chỉnh sửa. Không thanh lịch lắm, nhưng hoàn thành công việc. :)


EDIT (sử dụng git-gui):

Tôi không chắc chắn nếu git-gui giống nhau trong các phiên bản msysgit và linux, tôi chỉ sử dụng phiên bản msysgit. Nhưng giả sử nó giống nhau, khi bạn chạy nó, có bốn khung: ngăn trên cùng bên trái là thư mục làm việc của bạn thay đổi, phía dưới bên trái là các giai đoạn của bạn thay đổi, trên cùng bên phải là khác biệt cho tệp được chọn (có thể là thư mục hoạt động hoặc dàn dựng), và phía dưới bên phải là để mô tả về cam kết (Tôi nghi ngờ bạn sẽ không cần nó). Khi bạn bấm vào một tệp ở phía trên bên phải, bạn sẽ thấy khác. Nếu bạn nhấp chuột phải vào dòng khác, bạn sẽ thấy menu ngữ cảnh. Hai tùy chọn cần lưu ý là "giai đoạn hunk cho cam kết" và "giai đoạn cho cam kết". Bạn tiếp tục chọn "giai đoạn cho cam kết" trên các dòng bạn muốn cam kết và bạn đã hoàn thành. Bạn thậm chí có thể chọn một số dòng và giai đoạn chúng nếu bạn muốn.

Đối với cam kết, bạn có thể sử dụng công cụ gui hoặc dòng lệnh.


Đề xuất thứ hai của bạn khá rõ ràng, nhưng điều đầu tiên là thú vị, bạn có thể nói chi tiết hơn một chút không? Tôi đã cài đặt git-guinhưng tôi không biết làm thế nào để đạt được những gì bạn đang mô tả.
greg0ire

xe tăng rất nhiều! Những công việc này! Tôi thậm chí có thể chọn các dòng tôi muốn tạo giai đoạn và lập chỉ mục chúng bằng một cú nhấp chuột.
greg0ire

0

Một cách để làm điều đó là bỏ qua phần này, git addbất cứ thứ gì bạn cần, và sau đó chạy git addlại. Nếu đây là đoạn duy nhất, bạn sẽ có thể chia nó.

Nếu bạn lo lắng về thứ tự cam kết, chỉ cần sử dụng git rebase -i.


Đây là những gì tôi đã thử, và hunk trong câu hỏi của tôi là người duy nhất khi tôi chạy git add -plại, nhưng tôi không thể tách nó ra. Tôi nhận được điều này: Stage this hunk [y,n,q,a,d,/,e,?]?và sau đó nhấn 's' in trợ giúp. Ý bạn là gì add patch, phải không patch add? Hoặc là có mộtgit patch plugin tôi nên cài đặt?
greg0ire

Bạn đã phạm phải những kẻ săn mồi dàn dựng trước khi bạn chạy lại điều này? Và không, Mercurial có plugin, Git thì không.
Abizern

Không, tôi không muốn, tôi muốn họ ở cùng một cam kết (nhưng tôi đoán nếu giải pháp của bạn hoạt động, tôi có thể sử dụng --amend để đạt được điều này). Tôi sẽ thử.
greg0ire

Như câu trả lời của tôi đã nói → git rebase -i. Cái nào linh hoạt hơncommit --amend
Abizern
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.