Chỉ cam kết một phần của tệp trong Git


2764

Khi tôi thực hiện thay đổi đối với tệp trong Git, làm cách nào tôi chỉ có thể cam kết một số thay đổi?

Ví dụ: làm thế nào tôi có thể cam kết chỉ 15 dòng trong số 30 dòng đã được thay đổi trong một tệp?


3
liên quan stackoverflow.com/q 432609924/52074 : nếu bạn cần chia một phần lớn thành các phần nhỏ hơn.
Trevor Boyd Smith

Tóm tắt: về khả năng: git gui= git add -e> git add -i -p; về mặt tiện theo dõi: git gui> git add -i -p> git add -e. Vì vậy: chọn git guikhi bạn có quyền truy cập vào X. chọn git add -i -pcho những thứ đơn giản và khi bạn không có hoặc muốn sử dụng X. git add -eđể dàn dựng phức tạp mà không có X.
Penghe Geng

Câu trả lời:


3687

Bạn có thể sử dụng git add --patch <filename>(hoặc -pviết tắt) và git sẽ bắt đầu chia nhỏ tệp của bạn thành những gì nó cho là "hunk" hợp lý (các phần của tệp). Sau đó nó sẽ nhắc bạn với câu hỏi này:

Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]?

Dưới đây là mô tả của từng tùy chọn:

  • y giai đoạn hunk này cho cam kết tiếp theo
  • n không tạo ra hunk này cho lần cam kết tiếp theo
  • qbỏ việc; không giai đoạn hunk này hoặc bất kỳ hunk còn lại
  • a giai đoạn hunk này và tất cả các hunk sau này trong tập tin
  • d không giai đoạn hunk này hoặc bất kỳ hunk sau này trong tập tin
  • g chọn một hunk để đi đến
  • / tìm kiếm một hunk phù hợp với regex đã cho
  • j rời khỏi hunk này chưa quyết định, xem hunk chưa quyết định tiếp theo
  • J rời khỏi hunk này chưa quyết định, xem hunk tiếp theo
  • k rời khỏi hunk này chưa quyết định, xem hunk chưa quyết định trước
  • K rời khỏi hunk này chưa quyết định, xem hunk trước
  • s chia hunk hiện tại thành hunk nhỏ hơn
  • e tự chỉnh sửa hunk hiện tại
  • ? in hunk giúp

Nếu tệp chưa có trong kho lưu trữ, trước tiên bạn có thể làm git add -N <filename>. Sau đó bạn có thể tiếp tục với git add -p <filename>.

Sau đó, bạn có thể sử dụng:

  • git diff --staged để kiểm tra xem bạn đã dàn dựng các thay đổi chính xác chưa
  • git reset -p để unstage nhầm hunk thêm
  • git commit -v để xem cam kết của bạn trong khi bạn chỉnh sửa thông điệp cam kết.

Lưu ý rằng điều này khác xa so với git format-patchlệnh, mục đích của nó là phân tích dữ liệu cam kết vào một .patchtệp.

Tham khảo cho tương lai: Công cụ Git - Dàn dựng tương tác


83
Nó có thể hữu ích để lưu ý rằng đó -p/--patchlà một phím tắt cho hành động vá bên trong -i/--interactivelệnh khởi tạo chế độ Tương tác hữu ích .
tutuDajuju

5
> Điều gì xảy ra nếu tập tin đó đã được dàn dựng? Nó sẽ chỉ hiển thị những thay đổi không có căn cứ. Tương tự như git diffvậy.
Eugen Konkov

3
Làm thế nào tôi có thể chỉnh sửa hunk hiện tại bằng tay? Tôi không biết phải làm gì sau khi tôi gõ e.
Hunsu

23
Sau khi nhấn e, Bạn có thể chỉnh sửa hunk bằng tay bằng cách thay thế +hoặc -bằng#
veksen

1
Điều này thật tuyệt nhưng bây giờ làm thế nào để tôi thực sự đẩy nó? nếu tôi làm git pushnó nói đã cập nhật. và nếu tôi làm git difftôi thấy những người đàn ông mà tôi nói n. nếu tôi làm git diff --stagedtôi thấy cam kết tôi muốn đẩy. Giả sử tôi có thể đẩy cam kết, làm cách nào để xóa các khối mà tôi đã nói no?
chovy

250

Bạn có thể sử dụng git add --interactivehoặc , và sau đó ( không ); xem Chế độ tương tác trong trang chủ git-add hoặc chỉ cần làm theo hướng dẫn.git add -p <file>git commit git commit -a

Modern Git cũng có git commit --interactive(và git commit --patch, là phím tắt để vá tùy chọn trong cam kết tương tác).

Nếu bạn thích làm điều đó từ GUI, bạn có thể sử dụng git-gui . Bạn chỉ có thể đánh dấu các đoạn mà bạn muốn có trong cam kết. Cá nhân tôi thấy nó dễ hơn sử dụng git add -i. Các GUI git khác, như QGit hoặc GitX, cũng có thể có chức năng này.


1
Thật thú vị, windows.github.com đã hỗ trợ cho các cam kết một phần tệp nhưng dường như đã bỏ nó gần đây ..
Juri

1
@Juri Tôi nghĩ rằng sự hỗ trợ cho các cam kết một phần của tập tin đã quay trở lại.
Ela782 24/2/2015

@Juri Bạn được chào đón. Tôi thực sự chưa bao giờ nhận thấy rằng nó đã ở đó trước đó - tôi đã thấy nó tuần trước và nghĩ "ồ, thật là một tính năng mới tuyệt vời"! :-)
Ela782 24/2/2015

1
Ngày nay, windows.github.com chuyển hướng đến Máy tính để bàn GitHub được đổi thương hiệu đẹp hơn GUI Git và hỗ trợ các cam kết một phần ... nhưng không hỗ trợ ký cam kết. Thở dài.

147

git gui cung cấp chức năng này dưới chế độ xem khác. Chỉ cần nhấp chuột phải vào (các) dòng bạn quan tâm và bạn sẽ thấy mục trình đơn "giai đoạn dòng này để cam kết".


13
Đối với các bản vá phức tạp, đây thường là cách tiếp cận nhanh nhất đối với tôi.
hochl

7
Đây là một cách rất hiệu quả và trực quan để thêm các thay đổi vào khu vực tổ chức một cách chi tiết. Ngoài ra nhiều dòng có thể được chọn và tất cả các thay đổi trong lựa chọn đó sẽ được thêm vào.
Jox

Lưu ý rằng điều này không phải gitk, nhưng nó được bao gồm trong Git Bash cho Windows; bạn nên có một mục menu bắt đầu cho nó hoặc có thể bắt đầu nó bằng lệnh git gui. Ngoài ra còn stage this hunkcó ích hơn stage this line. Có thể là mới vì câu trả lời này đã được tạo ra 10 năm trước.
Chris

82

Tôi tin rằng đó git add -e myfilelà cách dễ nhất (ít nhất là sở thích của tôi) vì nó chỉ đơn giản là mở trình soạn thảo văn bản và cho phép bạn chọn dòng nào bạn muốn trình bày và dòng nào bạn không chọn. Về các lệnh chỉnh sửa:

thêm nội dung:

Nội dung được thêm được thể hiện bằng các dòng bắt đầu bằng "+". Bạn có thể ngăn chặn bất kỳ dòng bổ sung bằng cách xóa chúng.

đã xóa nội dung:

Nội dung bị xóa được thể hiện bằng các dòng bắt đầu bằng "-". Bạn có thể ngăn chặn việc loại bỏ chúng bằng cách chuyển đổi "-" thành "" (dấu cách).

nội dung sửa đổi:

Nội dung được sửa đổi được thể hiện bằng các dòng "-" (xóa nội dung cũ) theo sau là dòng "+" (thêm nội dung thay thế). Bạn có thể ngăn chặn việc sửa đổi bằng cách chuyển đổi các dòng "-" thành "" và xóa các dòng "+". Coi chừng việc sửa đổi chỉ một nửa của cặp có khả năng đưa ra các thay đổi khó hiểu cho chỉ mục.

Mọi chi tiết về git addđều có sẵn trêngit --help add


7
Điều này sẽ hữu ích hơn nếu có một lời giải thích rõ ràng ở đâu đó về cách thực sự chọn những dòng đó (tức là các lệnh thực tế để nhập). Tôi không thể tìm thấy một trong các tài liệu. Bạn có thể thêm một tài liệu tham khảo?
Alex

4
Đối với những người không thích các tùy chọn tốc ký, -e--edit.
Kolyunya

2
@Alex Các trích dẫn tham khảo được thêm bởi theFreedomBanana là từ phần EDITING PATCHES ingit --help add
Randall

8
Đây là câu trả lời duy nhất (chỉ yêu cầu git) giải quyết vấn đề thêm / xóa dòng một cách khôn ngoan khi bạn không thể làm cho khối lớn hơn strong chế độ vá tương tác.
cdosborn

3
Có thể hữu ích để hiểu rằng lệnh này ( git add -e) * không * thay đổi nội dung tệp trên đĩa. Nó chỉ chuyển một phần của các thay đổi từ không theo giai đoạn sang giai đoạn (chỉ mục).
Penghe Geng

44

Nếu bạn đang sử dụng vim, bạn có thể muốn thử plugin tuyệt vời có tên fugitive .

Bạn có thể thấy sự khác biệt của một tệp giữa bản sao làm việc và chỉ mục với :Gdiff, sau đó thêm các dòng hoặc khối vào chỉ mục bằng cách sử dụng các lệnh vim diff cổ điển như dp. Lưu các sửa đổi trong chỉ mục và cam kết với :Gcommit, và bạn đã hoàn thành.

Screencasts giới thiệu rất tốt ở đây (xem phần 2 ).


Cảm ơn bạn rất nhiều vì liên kết này. Chính xác những gì tôi cần. Đặc biệt là :diffget/:diffputtrong chế độ trực quan, nơi tôi có thể chọn các dòng cụ thể mà tôi muốn đặt lại / cam kết. Vì vậy, hãy chắc chắn một lần nữa: vim là tuyệt vời.
goodniceweb

30

Tôi thực sự khuyên bạn nên sử dụng SourceTree từ Atlassian. (Nó miễn phí.) Nó làm cho chuyện nhỏ này. Bạn có thể tạo các đoạn mã riêng lẻ hoặc từng dòng mã riêng lẻ một cách nhanh chóng và dễ dàng.

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


1
Tôi đồng ý rằng SourceTree là một công cụ tốt cho mục đích này, bởi vì nó cung cấp cho bạn quyền kiểm soát chi tiết hơn so với những gì có thể thông qua dòng lệnh.

19
@cupdding Tôi sẽ tranh luận ngược lại, khi thấy rằng SourceTree có thể sử dụng các lệnh thực thi git dòng lệnh đó, vốn dĩ sẽ luôn có thể thực hiện các hành động chi tiết tương tự (hoặc hơn) thông qua "dòng lệnh".
tutuDajuju

2
Bất kể các hạt mịn luận Tôi rất muốn khuyên SourceTree như hunks dàn và đường dây cá nhân là siêu dễ dàng: i.imgur.com/85bNu4C.png
Mars Robertson

1
@tutuDajuju Trong trường hợp này, tôi không chắc đó là sự thật. SourceTree có khả năng chọn những gì phần đến giai đoạn từng dòng . Bạn không cần phải tạo ra toàn bộ một hunk; bạn có thể giai đoạn 2 dòng ở giữa một hunk. Tôi không biết làm thế nào nó hoàn thành điều đó, mặc dù. (Hiện tại, tôi đang cố gắng khắc phục sự cố không thể tạo ra các dòng cụ thể của SourceTree cho một tệp không bị theo dõi. Tôi đã đến đây để tìm cách khắc phục, chỉ để thấy rằng git dường như không cung cấp khả năng theo từng dòng ít nhất. Ít nhất là không theo cách đơn giản.)
jpmc26

1
@Sun bạn có thể nhấp vào dòng 50 và shift + nhấp vào dòng 100 sau đó giai đoạn. Bạn có thể dễ dàng tạo giai đoạn 50-100 trong Sourcetree :)
ryan123 17/12/18

26

Đáng lưu ý rằng để sử dụng git add --patchcho một tệp mới, trước tiên bạn cần thêm tệp vào chỉ mục với git add --intent-to-add:

git add -N file
git add -p file

23

Khi tôi có nhiều thay đổi và cuối cùng sẽ tạo ra một vài cam kết từ các thay đổi, sau đó tôi muốn lưu điểm xuất phát của mình tạm thời trước khi dàn dựng mọi thứ.

Như thế này:

$ git stash -u
Saved working directory and index state WIP on master: 47a1413 ...
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 1st commit"
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 2nd commit"
$ git stash pop

Câu trả lời của Whymarrh là những gì tôi thường làm, ngoại trừ đôi khi có rất nhiều thay đổi và tôi có thể nói rằng tôi có thể mắc lỗi trong khi dàn dựng mọi thứ, và tôi muốn một trạng thái cam kết tôi có thể quay lại để vượt qua lần thứ hai.


12

Nếu bạn sử dụng emacs, hãy xem Magit , cung cấp giao diện git cho emacs. Nó hỗ trợ dàn dựng (phần của tập tin) khá tốt.


Tôi thường vấp phải một lệnh git muốn mở trình soạn thảo, khi tôi chạy nó từ cửa sổ shell Mx. Liệu pháp sư có ngăn chặn sự điên rồ đó, và chỉ mở một bộ đệm mới cho điều đó? (xin vui lòng không có gợi ý nền-emacs-daemon; dù sao cũng cảm ơn nhưng cuộc sống quá ngắn).
dùng2066657

Không, theo như tôi có thể nói nó không chặn điều này. Nhưng đừng hiểu ý tôi vì (1) Tôi hầu như không bao giờ sử dụng cửa sổ shell trong Emacs và (2) Tôi thường sử dụng emacsclient. Phải nói rằng, nếu emacsclient một tùy chọn cho bạn, thì ít nhất nó đã ngăn một cửa sổ bổ sung với các emacs được mở và bộ đệm "COMMIT_EDITMSG" đã được mở trong cửa sổ Emacs hiện tại của tôi.
Mark van Chay

10

Intellij IDEA (và tôi đoán tất cả các sản phẩm khác của bộ) đã được xây dựng để hỗ trợ cho các cam kết một phần kể từ v2018.1

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


9

Đối với những người sử dụng Tiện ích mở rộng Git :

Trong cửa sổ Cam kết, chọn tệp bạn muốn cam kết một phần, sau đó chọn văn bản bạn muốn cam kết trong khung bên phải, sau đó nhấp chuột phải vào lựa chọn và chọn 'Giai đoạn được chọn' từ menu ngữ cảnh.


2
Phím tắt trong Git Tiện ích mở rộng cho 'Dòng được chọn trong giai đoạn' là s- rất hữu ích để sắp xếp nhanh các phần của tệp cho một cam kết.
Nhà giả kim

8

Giống như câu trả lời của jdsumsion, bạn cũng có thể bỏ công việc hiện tại của mình nhưng sau đó sử dụng một công cụ khác như meld để lấy các thay đổi được chọn từ stash. Bằng cách đó, bạn thậm chí có thể chỉnh sửa các hunk thủ công rất dễ dàng, điều này hơi khó khăn khi vào git add -p:

$ git stash -u
$ git difftool -d -t meld stash
$ git commit -a -m "some message"
$ git stash pop

Sử dụng phương thức stash cung cấp cho bạn cơ hội để kiểm tra, nếu mã của bạn vẫn hoạt động, trước khi bạn cam kết.


Điều này hoạt động tốt, nhưng nếu bạn sử dụng git commit --amend, có vẻ như bạn không thể bật stash sau đó, hoặc có cách nào để làm điều này?
Đánh dấu

7

Thêm vào câu trả lời trước, nếu bạn thích sử dụng dòng lệnh, việc nhập git add -e myfilesẽ cho bạn lựa chọn chọn từng dòng theo những gì bạn muốn cam kết vì lệnh này sẽ mở một trình soạn thảo với sự khác biệt, như vậy:

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

Như bạn có thể biết các dòng bắt đầu bằng +nghiện, các dòng bắt đầu bằng -là xóa. Vì thế:

  • Để không giai đoạn bổ sung chỉ cần xóa dòng đó.
  • Để không giai đoạn xóa chỉ cần thay thế -bằng không gian .

Đây là những gì git add -hnói về việc thêm tệp theo cách này (vá tệp):

nội dung đã thêm Nội dung được thêm được thể hiện bằng các dòng bắt đầu bằng "+". Bạn có thể ngăn chặn bất kỳ dòng bổ sung bằng cách xóa chúng.

nội dung bị xóa: Nội dung bị xóa được thể hiện bằng các dòng bắt đầu bằng "-". Bạn có thể ngăn chặn việc loại bỏ chúng bằng cách chuyển đổi "-" thành "" (dấu cách).

nội dung được sửa đổi: Nội dung được sửa đổi được thể hiện bằng các dòng "-" (xóa nội dung cũ) theo sau là các dòng "+" (thêm nội dung thay thế). Bạn có thể ngăn chặn việc sửa đổi bằng cách chuyển đổi các dòng "-" thành "" và xóa các dòng "+". Coi chừng việc sửa đổi chỉ một nửa của cặp có khả năng đưa ra các thay đổi khó hiểu cho chỉ mục.

Chú ý: không thay đổi nội dung của tệp, đây không phải là nơi tốt để làm như vậy. Chỉ cần thay đổi các toán tử của dòng bị xóa hoặc thêm.


Câu trả lời trước là gì? Câu trả lời được lưu trữ dựa trên số điểm họ có. Vì vậy, câu trả lời của bạn bây giờ ở một nơi khác so với khi bạn viết nó so với các câu trả lời khác.
KulaGGin

Tôi tin rằng câu trả lời được tham chiếu là từ @theFreedomBanana
K. Biểu tượng

6

Plugin vim-gitgutter có thể tạo giai đoạn hunk mà không cần rời khỏi trình chỉnh sửa vim bằng cách sử dụng

:GitGutterStageHunk

Bên cạnh đó, nó cung cấp các tính năng thú vị khác như cột dấu hiệu khác như trong một số IDE hiện đại

Nếu chỉ là một phần của hunk nên được dàn dựng vim-fugitive

:Gdiff

cho phép lựa chọn phạm vi hình ảnh sau đó :'<,'>diffputhoặc :'<,'>diffgetgiai đoạn / hoàn nguyên các thay đổi dòng riêng lẻ.



4

Với TortoiseGit:

nhấp chuột phải vào tập tin và sử dụng Context Menu → Restore after commit. Điều này sẽ tạo ra một bản sao của tập tin như nó là. Sau đó, bạn có thể chỉnh sửa tệp, ví dụ như trong TortoiseGitMerge và hoàn tác tất cả các thay đổi bạn không muốn cam kết. Sau khi lưu những thay đổi đó, bạn có thể cam kết tập tin.


4

Đã 10 năm kể từ khi câu hỏi này được hỏi. Và tôi hy vọng câu trả lời này sẽ hữu ích cho ai đó. Như đã đề cập trong câu trả lời ở đây , trong đó GUI không phải là một tùy chọn, phần mở rộng crecord của Andrew Shadura giúp mang đến một cửa sổ ncurses trong đó chúng ta có thể chọn các dòng để cam kết.

Thiết lập tiện ích mở rộng như sau:

git clone https://github.com/andrewshadura/git-crecord
cd git-crecord
./setup.py install
ln -s $PWD/git-crecord ~/.local/bin/git-crecord

cd vào git repo của bạn và gọi nó như sau:

git crecord

Điều này sẽ đưa ra giao diện ncurses có thể được sử dụng như hiển thị bên dưới. Nhấn các phím sau trong cửa sổ ncurses sẽ thực hiện một số hành động nhất định:

f       hunk toggle fold (arrow keys can also be used)
space   toggle hunk selection
a       toggle commit or amend
c       confirm and open commit window

Screencast hiển thị cách sử dụng mẫuThí dụ


3

Đối với người dùng Atom , gói github bao gồm dàn tương tác, theo kiểu git gui. Để biết các phím tắt, xem tài liệu của gói .

Sử dụng Atom cho phép làm việc với một chủ đề có nền tối (theo mặc định, git guicó nền trắng).



2

git-meld-index - trích dẫn từ trang web:

git-meld-index chạy meld - hoặc bất kỳ git Difftool nào khác (kdiff3, khuếch tán, v.v.) - để cho phép bạn thay đổi giai đoạn tương tác với chỉ số git (còn được gọi là khu vực dàn git).

Điều này tương tự như chức năng của git add -p và git add - tương tác. Trong một số trường hợp, meld dễ sử dụng / nhanh hơn so với git add -p. Đó là vì meld cho phép bạn, ví dụ, để:

  • xem thêm bối cảnh
  • xem khác biệt nội dòng
  • chỉnh sửa bằng tay và xem các bản cập nhật khác nhau 'trực tiếp' (được cập nhật sau mỗi lần nhấn phím)
  • điều hướng đến một thay đổi mà không nói 'n' với mọi thay đổi bạn muốn bỏ qua

Sử dụng

Trong kho git, chạy:

git meld-index

Bạn sẽ thấy meld (hoặc git Difftool được cấu hình của bạn) bật lên với:

TRÁI : thư mục tạm thời chứa các tệp được sao chép từ cây làm việc của bạn

RIGHT : thư mục tạm thời với nội dung của chỉ mục. Điều này cũng bao gồm các tệp chưa có trong chỉ mục nhưng được sửa đổi hoặc không bị theo dõi trong bản sao làm việc - trong trường hợp này bạn sẽ thấy nội dung tệp từ HEAD.

Chỉnh sửa chỉ mục (bên tay phải) cho đến khi hạnh phúc. Nhớ lưu lại khi cần.

Khi bạn hoàn tất, đóng meld và git-meld-index sẽ cập nhật chỉ mục để khớp với nội dung của thư mục tạm thời ở phía bên phải của meld mà bạn vừa chỉnh sửa.


2

Nếu đó là trên Windowsnền tảng, theo tôi git guilà công cụ rất tốt để stage/ commitvài dòng từ unstagedtệp

1. Hunk khôn ngoan:

  • Chọn tệp từ unstagged Changesphần
  • Nhấp chuột phải vào đoạn mã cần được dàn dựng
  • Lựa chọn Stage Hunk for commit

2. Dòng khôn ngoan:

  • Chọn tệp từ unstagged Changesphần
  • Chọn dòng / dòng sẽ được dàn dựng
  • Nhấp chuột phải và chọn Stage Lines for commit

3. Nếu bạn muốn tạo tập tin hoàn chỉnh trừ vài dòng:

  • Chọn tệp từ unstagged Changesphần
  • nhấn Ctrl+T (Stage file to commit)
  • Tập tin được chọn bây giờ chuyển đến Staged ChangesPhần
  • Chọn dòng / dòng được dàn dựng
  • Nhấp chuột phải và chọn UnStage Lines for commit

1

Như một câu trả lời ở trên cho thấy, bạn có thể sử dụng git add --patch filename.txt

hoặc dạng ngắn git add -p filename.txt

... nhưng đối với các tệp đã có trong kho lưu trữ của bạn, có, tốt hơn hết là sử dụng cờ --patch trên lệnh commit (nếu bạn đang sử dụng một phiên bản git đủ gần đây): git commit --patch filename.txt

... hoặc, một lần nữa, dạng ngắn git commit -p filename.txt

... Và sau đó sử dụng các khóa được đề cập, (y / n, v.v.), để chọn các dòng được đưa vào cam kết.


Điều gì mang lại cho bạn hơn " git add -p filename.txt" ngoài việc có ít lỗi hơn? Nếu bạn làm hỏng thay đổi tập tin một phần, việc hoàn tác một add sẽ tốt hơn là hoàn tác một cam kết.
CTMacUser

Tôi không biết tại sao, nhưng khi tôi nói 'n' thì dòng được bao gồm .... và khi tôi nói 'y' trên hunk thứ 2, nó cũng được đưa vào.
chovy

1

git-cola là một GUI tuyệt vời và cũng có tính năng này tích hợp sẵn. Chỉ cần chọn các dòng để giai đoạn và nhấn S. Nếu không có lựa chọn nào được thực hiện, hunk hoàn chỉnh được dàn dựng.

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.