Chỉ thêm các thay đổi không phải khoảng trắng


343

Tôi có trình soạn thảo văn bản của mình để tự động cắt khoảng trắng theo sau khi lưu tệp và tôi đang đóng góp cho một dự án nguồn mở có vấn đề nghiêm trọng với khoảng trắng theo dõi.

Mỗi lần tôi cố gắng gửi một bản vá, trước tiên tôi phải bỏ qua tất cả các thay đổi chỉ có khoảng trắng bằng tay, để chỉ chọn thông tin có liên quan. Không chỉ vậy, nhưng khi tôi chạy git rebasetôi thường gặp phải một số vấn đề vì chúng.

Vì vậy, tôi muốn chỉ có thể thêm vào chỉ mục các thay đổi không phải khoảng trắng, theo cách tương tự git add -p, nhưng không phải tự mình chọn tất cả các thay đổi.

Có ai biết cách để làm điều này không?

EDIT: Tôi không thể thay đổi cách thức hoạt động của dự án và họ đã quyết định, sau khi thảo luận về nó trong danh sách gửi thư, để bỏ qua điều này.

Câu trả lời:


395

Giải pháp @Frew không hoàn toàn là những gì tôi cần, vì vậy đây là bí danh tôi đã tạo cho cùng một vấn đề:

alias.addnw=!sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero -'

Hoặc bạn chỉ có thể chạy:

git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

Cập nhật

Đã thêm tùy chọn -U0--unidiff-zerotương ứng với các vấn đề phù hợp với bối cảnh, theo nhận xét này .

Về cơ bản, nó áp dụng bản vá sẽ được áp dụng addmà không thay đổi khoảng trắng. Bạn sẽ nhận thấy rằng sau git addnw your/fileđó vẫn sẽ có những thay đổi chưa được thực hiện, đó là khoảng trắng còn lại.

Không - không có màu nhưng vì tôi luôn đặt màu, tôi phải sử dụng màu đó. Dù sao, tốt hơn an toàn hơn xin lỗi.


7
Điều này làm việc tốt cho tôi, tuy nhiên tôi phải sử dụng git apply --ignore-whitespacenếu không bản vá sẽ không áp dụng vì những lý do rõ ràng.
jupp0r

106
Thực sự nên có một tùy chọn để git add, như thế git add -wđã làm điều này.
Jarl

7
Điều này cho tôi vấn đề với patch does not applyerror while searching for... Bất kỳ ý tưởng?
DTI-Matt

18
không làm việc cho tôi. Có một patch does not applylỗi.
Jerry Saravia

13
Nếu bạn nhận được 'bản vá lỗi' do khoảng trắng trong ngữ cảnh như @bronson chỉ ra, lệnh được sửa đổi này sẽ hoạt động (Nó tạo ra một bản vá không có ngữ cảnh) : git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero. Điều này không có rủi ro vì chỉ số đã được cập nhật nhất có thể, vì vậy đây là cơ sở đáng tin cậy cho bản vá.
void.pulum

36

Điều này làm việc cho tôi:

Nếu bạn muốn giữ một stash xung quanh, điều này hoạt động

git stash && git stash apply && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

Tôi không thích các stash, nhưng tôi đã gặp phải một lỗi trong git + cygwin khi tôi mất các thay đổi, vì vậy để đảm bảo rằng các công cụ đó đã đi đến reflog ít nhất là tôi đã thiết lập như sau:

git add . && git commit -am 'tmp' && git reset HEAD^ && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

Về cơ bản, chúng tôi tạo ra một khác biệt không bao gồm các thay đổi không gian, hoàn nguyên tất cả các thay đổi của chúng tôi và sau đó áp dụng khác biệt.


1
+1. Bạn có thể muốn thực hiện git stashthay vì thanh toán, để có bản sao lưu các thay đổi của mình, ít nhất là cho đến khi thử nghiệm.
Paŭlo Ebermann

1
Bạn sẽ kết thúc với rất nhiều stash và về cơ bản, bạn không thực sự cần phải làm tất cả những điều này. Nó hoạt động nhưng tôi nghĩ nó hơi lộn xộn
Colin Hebert

3
Tôi đồng ý với Colin. Nếu kịch bản hoạt động, thì không cần phải tạo stash. Những gì có thể là tốt để xem xét mặc dù sẽ là chạy stash, sau đó stash pop. Stash popped có thể được phục hồi nếu cần thiết, nhưng bạn sẽ không kết thúc với rất nhiều stash khác. Điều này cũng để lại một tập tin bổ sung nằm xung quanh
Casebash

Làm thế nào về việc bỏ qua các tệp nhị phân? Khi thử áp dụng đoạn mã trên, tôi gặp lỗi rằng bản vá có thể được áp dụng mà không có dòng chỉ mục đầy đủ! Điều làm tôi thất vọng là tôi thậm chí không chạm vào những tệp / nhị phân này ngay từ đầu!
tver3305

1
Tôi nghĩ ở cuối lệnh đầu tiên "git rm foo.patch" chỉ nên là "rm foo.patch". Nếu không thì rất hữu ích cảm ơn.
Jack Casey

33

Tạo một tệp vá chỉ chứa các thay đổi thực sự (không bao gồm các dòng chỉ có thay đổi khoảng trắng), sau đó làm sạch không gian làm việc của bạn và áp dụng tệp vá đó:

git diff> sao lưu
git diff -w> thay đổi
thiết lập lại git -
bản vá lỗi <thay đổi

Xem lại sự khác biệt còn lại, sau đó addcommitnhư bình thường.

Tương đương với Mercurial là làm điều này:

hg diff> backup
hg diff -w> thay đổi
hg Revert --all
hg nhập --no-commit thay đổi


Một câu hỏi được bảo vệ của người Viking là gì? tôi cũng trả lời. Tôi không nghĩ rằng điều này thậm chí đủ điều kiện là một câu trả lời của tôi vì nó xuất hiện câu hỏi được đưa ra khỏi không khí mỏng ...
jww

4
@jww Cốt lõi của câu hỏi ban đầu của người gửi bài là "làm thế nào để tránh cam kết không gian trắng chỉ thay đổi thành kiểm soát nguồn". OP tình cờ sử dụng Git, nhưng điều này cũng áp dụng cho mọi hệ thống kiểm soát nguồn mà tôi từng sử dụng. Câu trả lời này cho thấy quy trình chính xác nếu ai đó tình cờ sử dụng Mercurial. Tôi có thể tưởng tượng người khác cũng có thể đóng góp một giải pháp cho những người sử dụng Sublesion, v.v.
Steve

1
@jww và @ pagid: Tôi đã chỉnh sửa câu trả lời của mình để giải quyết cụ thể Git, sử dụng phương pháp tương tự như giải pháp của tôi cho Mercurial. Theo quan điểm của tôi, StackOverflow không chỉ là một diễn đàn Q + A khác - nó còn có vai trò là kho lưu trữ kiến ​​thức. Những người không phải là người đăng ban đầu có thể được hưởng lợi từ các câu trả lời được đưa ra, và hoàn cảnh của họ khác nhau. Đó là lý do tại sao tôi tin rằng các câu trả lời chuyển tải một nguyên tắc chung là hợp lệ, thay vì chỉ nhắm mục tiêu vào một tình huống cụ thể.
Steve Pitchers

@Steve - "Tôi đã chỉnh sửa câu trả lời của mình để giải quyết cụ thể Git ..." - tại sao bạn không hỏi một câu hỏi mới trong bối cảnh đồng bóng, và sau đó thêm câu trả lời của riêng bạn cho câu hỏi mới ???
jww

8
Đây thực sự là cách sạch nhất, dễ hiểu nhất và không thể phá vỡ nhất trong các phương pháp mà tôi đã thấy.
Kzqai

12

Câu trả lời được bình chọn hàng đầu không hoạt động trong mọi trường hợp, do khoảng trắng trong ngữ cảnh vá theo người dùng trong các nhận xét.

Tôi đã sửa đổi lệnh như sau:

$ git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero

Điều này tạo ra một bản vá không có ngữ cảnh. Không nên là một vấn đề vì các bản vá là ngắn hạn.

Bí danh tương ứng, một lần nữa sửa đổi những gì đã được cung cấp bởi người dùng khác:

addw = !sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero' -

Để chỉ bỏ qua những thay đổi thụt đầu dòng, tôi phải sử dụng --ignore-space-changethay vì -w. git diff -U0 --ignore-space-change --no-color | git apply --cached --unidiff-zero
Andy

Một lời cảnh báo không sử dụng thủ thuật bối cảnh đáng yêu này với --ignore-blank-linesngười khác, bạn sẽ thấy các khối khác nhau được vá ở các độ lệch không chính xác nếu một số thay đổi 'khoảng trắng' mà bạn đang tìm cách bỏ qua là các bổ sung / xóa dòng trống.
elbeardmorez

12

Thêm phần sau vào .gitconfig:

anw = !git diff -U0 -w --no-color -- \"$@\" | git apply --cached --ignore-whitespace --unidiff-zero "#"

Cảm ơn câu trả lời của @Colin Herbert cho cảm hứng.

Giải thích cú pháp

Cuối cùng #phải được trích dẫn để nó không được coi là một nhận xét bên trong .gitconfig, mà thay vào đó được chuyển qua và được coi là một nhận xét bên trong vỏ - nó được chèn vào giữa phần cuối của các git applyđối số do người dùng cung cấp gittự động đặt tại cuối dòng lệnh. Các đối số này không muốn ở đây - chúng tôi không muốn git applysử dụng chúng, do đó, ký tự nhận xét trước. Bạn có thể muốn chạy lệnh này GIT_TRACE=1 git anwđể thấy điều này trong hành động.

Các --tín hiệu kết thúc các đối số và cho phép trường hợp bạn có một tệp có tên -whoặc một cái gì đó trông giống như một chuyển đổi git diff.

Các trích dẫn kép đã thoát $@được yêu cầu để duy trì mọi đối số được trích dẫn do người dùng cung cấp. Nếu "ký tự không được thoát, nó sẽ được .gitconfigtrình phân tích cú pháp sử dụng và không đến được vỏ.

Lưu ý: .gitconfigalias phân tích cú pháp không công nhận đơn dấu ngoặc kép như bất cứ điều gì đặc biệt - nhân vật duy nhất đặc biệt của nó là ", \, \n, và ;(bên ngoài của một "chuỗi -quoted). Đây là lý do tại sao "phải luôn luôn được thoát, ngay cả khi có vẻ như nó nằm trong một chuỗi trích dẫn duy nhất (mà git hoàn toàn không biết về).

Điều này rất quan trọng, vd. nếu bạn có một bí danh tiện dụng để thực thi một bashlệnh trong thư mục gốc của cây làm việc. Công thức không chính xác là:

sh = !bash -c '"$@"' -

Trong khi cái đúng là:

sh = !bash -c '\"$@\"' -

Thông minh. Điều này cho phép tôi thêm một tệp cùng một lúc. Khác với việc thêm một thư mục gốc cho một đối số, có cách nào để làm cho công việc này như 'git add -A' không?
Chucky

7

Làm thế nào về những điều sau đây:

git add `git diff -w --ignore-submodules |grep "^[+][+][+]" |cut -c7-`

Lệnh bên trong backquotes lấy tên của các tệp có thay đổi không phải khoảng trắng.


2
hoặc chỉ git add `git diff -w |grep '^+++' |cut -c7-`khi các mô hình con không được sử dụng
karmakaze 23/12/13

-1

Trước tiên bạn nên xem xét nếu khoảng trắng theo sau là cố ý. Nhiều dự án, bao gồm nhân Linux, Mozilla, Drupal và Kerberos (để đặt tên cho một số từ trang Wikipedia về phong cách) cấm khoảng trắng theo dõi. Từ tài liệu nhân Linux:

Nhận một trình soạn thảo đàng hoàng và không để khoảng trắng ở cuối dòng.

Trong trường hợp của bạn, vấn đề là cách khác: các cam kết trước đó (và có thể là các cam kết hiện tại) đã không tuân theo hướng dẫn này.

Tôi muốn rằng không ai thực sự muốn khoảng trắng theo sau và khắc phục sự cố có thể là một thay đổi đáng hoan nghênh. Những người dùng khác cũng có thể gặp phải vấn đề tương tự như bạn. Cũng có khả năng những người đóng góp đang thêm khoảng trắng ở cuối không biết rằng họ đang làm như vậy.

Thay vì cố gắng cấu hình lại git để bỏ qua vấn đề hoặc vô hiệu hóa chức năng mong muốn khác trong trình soạn thảo của bạn, tôi sẽ bắt đầu với một bài đăng vào danh sách gửi thư dự án giải thích vấn đề. Nhiều trình soạn thảo (và chính git) có thể được cấu hình để đối phó với khoảng trắng ở cuối.


16
Điều đó không có chủ ý, nhưng tôi không thể thay đổi cách suy nghĩ của hơn 100 người đóng góp cho dự án. Họ không quan tâm đến điều đó và sẽ không chấp nhận các bản vá với hơn 1000 thay đổi chỉ liên quan đến khoảng trắng ở cuối. Họ biết về vấn đề này và đã quyết định bỏ qua nó. Cuộc thảo luận này đã xảy ra trong danh sách và đã bị đóng cửa. Trong trường hợp này, chính tôi là người cần thích nghi với chúng.
Edu Felipe

19
Sau đó định cấu hình trình soạn thảo của bạn sao cho nó không cắt khoảng trắng theo sau khi làm việc với mã của dự án này.
jamessan

-2

Tôi tìm thấy một hook pre-commit hook loại bỏ khoảng trắng trailing . Tuy nhiên, nếu bạn không thể khiến người khác sử dụng nó, thì đó có thể không phải là một giải pháp hợp lệ.

  #!/bin/sh

  if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
     against=HEAD
  else
     # Initial commit: diff against an empty tree object
     against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
  fi
  # Find files with trailing whitespace
  for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
     # Fix them!
     sed -i 's/[[:space:]]*$//' "$FILE"
  done
  exit

4
Câu hỏi này là hỏi làm thế nào để duy trì khoảng trắng theo dõi.
Douglas

@Doumund: người ta có thể sử dụng câu trả lời này để tạo ra một cam kết trên một nhánh tạm thời, cam kết bản vá thực sự ở đó và chỉ chọn khác biệt vào nhánh làm việc bằng cách nào đó ...
Tobias Kienzler
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.