Làm cho git tự động xóa khoảng trắng theo dõi trước khi cam kết


220

Tôi đang sử dụng git với nhóm của mình và muốn xóa các thay đổi khoảng trắng khỏi các khác biệt, nhật ký, sáp nhập, v.v. Tôi giả sử rằng cách dễ nhất để làm điều này là để git tự động xóa khoảng trắng theo dõi (và các lỗi khoảng trắng khác ) từ tất cả các cam kết khi chúng được áp dụng.

Tôi đã cố gắng thêm các mục sau vào ~/.gitconfigtệp nhưng nó không làm gì khi tôi cam kết. Có lẽ nó được thiết kế cho một cái gì đó khác nhau. Giải pháp là gì?

[core]
    whitespace = trailing-space,space-before-tab
[apply]
    whitespace = fix

Tôi đang sử dụng ruby ​​trong trường hợp bất cứ ai có ý tưởng cụ thể về ruby. Định dạng mã tự động trước khi cam kết sẽ là bước tiếp theo, nhưng đó là một vấn đề khó khăn và không thực sự gây ra vấn đề lớn.


Nếu chỉ thị core.whitespace không khắc phục được sự cố của bạn, bạn cũng có thể thay đổi hook pre-commit (.git / hook / pre-commit) để tìm và sửa chúng cho bạn. Xem bài đăng này để mô tả chi tiết.
ROLA

2
Tôi đã nản lòng với các lỗi khoảng trắng tương tự và các giải pháp một phần, và đã viết một tiện ích linh hoạt và khá đầy đủ tính năng có thể sửa hoặc đơn giản là báo cáo các lỗi khoảng trắng mà các hệ thống kiểm soát phiên bản bedevil: Whitespace Total Fixer trên Github (xin lỗi nếu điều này quá tự quảng cáo)
Dan Lenski

Câu trả lời:


111

Những cài đặt đó ( core.whitespaceapply.whitespace) không có ở đó để xóa khoảng trắng theo sau mà là:

  • core.whitespace: phát hiện chúng và đưa ra lỗi
  • apply.whitespace: và tước chúng, nhưng chỉ trong khi vá, không "luôn tự động"

Tôi tin rằng git hook pre-commitsẽ làm một công việc tốt hơn cho điều đó (bao gồm xóa khoảng trắng theo sau)


Lưu ý rằng tại bất kỳ thời điểm nào bạn cũng có thể chọn không chạy pre-commithook:

  • một cách tạm thời: git commit --no-verify .
  • vĩnh viễn: cd .git/hooks/ ; chmod -x pre-commit

Cảnh báo: theo mặc định, pre-committập lệnh (như tập lệnh này ), không phải là tính năng "xóa dấu vết", mà là tính năng "cảnh báo" như:

if (/\s$/) {
    bad_line("trailing whitespace", $_);
}

Tuy nhiên, bạn có thể xây dựng một pre-commithook tốt hơn , đặc biệt là khi bạn xem xét rằng:

Việc cam kết trong Git chỉ với một số thay đổi được thêm vào khu vực tổ chức vẫn dẫn đến một bản sửa đổi nguyên tử của Vương mà không bao giờ tồn tại như một bản sao làm việc và có thể không hoạt động .


Chẳng hạn, ông già đề xuất trong một câu trả lời khác là một pre-commitcái móc phát hiện và loại bỏ khoảng trắng.
Vì hook đó lấy tên tệp của mỗi tệp, tôi khuyên bạn nên cẩn thận đối với một số loại tệp nhất định: bạn không muốn xóa khoảng trắng theo sau trong .mdcác tệp (đánh dấu )!


1
Hóa ra git có thể bị thuyết phục để sửa khoảng trắng trong bản sao làm việc của bạn thông qua apply.whitespace, bằng cách lừa git xử lý các thay đổi bản sao làm việc của bạn như một bản vá. Xem câu trả lời của tôi dưới đây .
ntc2

> "bạn không muốn xóa khoảng trắng theo sau trong các tệp .md (markdown)" - Tại sao vậy? Mục đích của dấu cách khoảng trắng trong các tệp markdown là gì? Tôi nhận thấy một số .editorconfigtập tin có một quy tắc cụ thể cho điều đó.
Friederbluemle

5
@friederbluemle tùy thuộc vào loại đánh dấu, không gian kép kéo dài biểu thị <br>: github.com/FriendsOfPHP/PHP-CS-Fixer/issues/iêu
VonC

Thiết core.whitespaceđến trailing-spacevới git configkhông gây lỗi khi cam kết trong git2.5.0.
Karl Richter

43

Bạn có thể lừa Git để sửa chữa khoảng trắng cho bạn, bằng cách lừa Git coi các thay đổi của bạn là một bản vá. Ngược lại với các giải pháp "hook pre-commit", các giải pháp này thêm các lệnh sửa lỗi khoảng trắng vào Git.

Vâng, đây là những hack.


Giải pháp mạnh mẽ

Các bí danh Git sau đây được lấy từ của tôi~/.gitconfig .

"Mạnh mẽ", ý tôi là những bí danh này chạy không có lỗi, làm đúng, bất kể cây hay chỉ mục có bị bẩn hay không. Tuy nhiên, chúng không hoạt động nếu một tương tác git rebase -iđã được tiến hành; hãy xem phần kiểm tra bổ sung của tôi~/.gitconfig nếu bạn quan tâm đến trường hợp góc này, trong đó git add -emẹo được mô tả ở cuối sẽ hoạt động.

Nếu bạn muốn chạy chúng trực tiếp trong shell, mà không tạo bí danh Git, chỉ cần sao chép và dán mọi thứ giữa các dấu ngoặc kép (giả sử shell của bạn giống Bash).

Sửa chỉ mục nhưng không phải cây

fixwsBí danh Git sau đây sửa tất cả các lỗi khoảng trắng trong chỉ mục, nếu có, nhưng không chạm vào cây:

# Logic:
#
# The 'git stash save' fails if the tree is clean (instead of
# creating an empty stash :P). So, we only 'stash' and 'pop' if
# the tree is dirty.
#
# The 'git rebase --whitespace=fix HEAD~' throws away the commit
# if it's empty, and adding '--keep-empty' prevents the whitespace
# from being fixed. So, we first check that the index is dirty.
#
# Also:
# - '(! git diff-index --quiet --cached HEAD)' is true (zero) if
#   the index is dirty
# - '(! git diff-files --quiet .)' is true if the tree is dirty
#
# The 'rebase --whitespace=fix' trick is from here:
# https://stackoverflow.com/a/19156679/470844
fixws = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git stash save FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git stash pop && \
    git reset --soft HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

Ý tưởng là chạy git fixwstrước git commitnếu bạn có lỗi khoảng trắng trong chỉ mục.

Sửa chỉ mục và cây

fixws-global-tree-and-indexBí danh Git sau đây sửa tất cả các lỗi khoảng trắng trong chỉ mục và cây, nếu có:

# The different cases are:
# - dirty tree and dirty index
# - dirty tree and clean index
# - clean tree and dirty index
#
# We have to consider separate cases because the 'git rebase
# --whitespace=fix' is not compatible with empty commits (adding
# '--keep-empty' makes Git not fix the whitespace :P).
fixws-global-tree-and-index = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~2 && \
    git reset HEAD~ && \
    git reset --soft HEAD~ ; \
  elif (! git diff-files --quiet .) ; then \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git reset HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

Để sửa lỗi khoảng trắng trong các tệp không đảo ngược, hãy làm

git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index

Giải pháp đơn giản nhưng không mạnh mẽ

Các phiên bản này dễ sao chép và dán hơn, nhưng chúng không làm đúng nếu điều kiện phụ của chúng không được đáp ứng.

Sửa cây con gốc ở thư mục hiện tại (nhưng đặt lại chỉ mục nếu nó không trống)

Sử dụng git add -eđể "chỉnh sửa" các bản vá với trình chỉnh sửa danh tính ::

(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset

Khắc phục và bảo quản chỉ mục (nhưng không thành công nếu cây bị bẩn hoặc chỉ mục trống)

git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~

Sửa cây và chỉ mục (nhưng đặt lại chỉ mục nếu nó không trống)

git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~

Giải thích về export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .mánh khóe

Trước khi tôi biết về git rebase --whitespace=fixthủ thuật từ câu trả lời này, tôi đã sử dụng git addthủ thuật phức tạp hơn ở mọi nơi.

Nếu chúng tôi làm bằng tay:

  1. Đặt apply.whitespacethành fix(bạn chỉ phải thực hiện việc này một lần):

    git config apply.whitespace fix
    

    Điều này nói với Git để sửa khoảng trắng trong các bản vá .

  2. Thuyết phục Git để coi những thay đổi của bạn như một bản vá :

    git add -up .
    

    Nhấn a+ enterđể chọn tất cả các thay đổi cho mỗi tệp. Bạn sẽ nhận được cảnh báo về việc Git sửa các lỗi khoảng trắng của bạn.
    ( git -c color.ui=auto difftại thời điểm này cho thấy các thay đổi không được lập chỉ mục của bạn chính xác là các lỗi khoảng trắng).

  3. Xóa các lỗi khoảng trắng khỏi bản sao làm việc của bạn:

    git checkout .
    
  4. Mang lại những thay đổi của bạn (nếu bạn chưa sẵn sàng cam kết chúng):

    git reset
    

Các GIT_EDITOR=:phương tiện để sử dụng :như là trình soạn thảo, và như một lệnh :là danh tính.


1
Tôi vừa thử nghiệm nó trong Windows: nó chỉ hoạt động tốt trong dấu nhắc lệnh của DOS: set VISUAL= && git add -ue . && git checkout .Lưu ý ' .' được sử dụng với git add: đó là vì git1.8.3
VonC

@VonC Sẽ không hủy cài đặt VISUAL vĩnh viễn, điều này có thể gây ra git commitviệc sử dụng trình chỉnh sửa sai sau đó? Tôi gói VISUAL=phần trong một subshell trong phiên bản unix của tôi ở trên để tránh điều này, nhưng tôi không biết liệu DOS có subshell hay không.
ntc2

1
Cảm ơn vì hack tuyệt vời! FYI, nếu bạn đã core.editorđặt thì xuất VISUALkhông có hiệu lực vì cài đặt cấu hình được ưu tiên mỗi man git-var. Để ghi đè điều này, bạn cần xuất GIT_EDITOR=:thay thế.
Nick Feel

1
Ngoài ra, tôi đã điều chỉnh phiên bản của fixwsmình để thất bại nhanh nếu bạn đã ở trong một cuộc nổi loạn tương tác vì nếu không nó sẽ chết ở git rebase --whitespace=fixdòng và khiến bạn rơi vào trạng thái kỳ lạ. Tôi đã mượn từ câu hỏi này và chỉ cần thêm một trường hợp bổ sung trước nếu: fixws = !"\ if test -d $(git rev-parse --git-dir)/rebase-merge ; then \ echo 'In rebase - cannot fixws' ; \ elif (! git diff-files --quiet .) && \ (! git diff-index --quiet --cached HEAD) ; then \ ...
Nick Feel

1
fyi: Tôi đã điều chỉnh nó thành một cái móc trước khi giao kết
Ian Kelling

29

Tôi tìm thấy một hook pre-commit hook loại bỏ khoảng trắng trailing .

#!/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"
   git add "$FILE"
done
exit

3
Lệnh thứ hai sed( sed -r 's/:[0-9]+:.*//') có thể được thay thế bằng cut -f1 -d:. Điều này sẽ hoạt động giống nhau trên cả nền tảng dựa trên Linux và BSD.
Ihor Kaharlichenko

2
@IhorKaharlichenko: thực sự, việc sử dụng cutkhông an toàn như lần thứ hai sed: cắt sẽ thất bại trong trường hợp (rất khó xảy ra) của tên tệp có chứa ":". Bạn có thể sử dụng awk 'NF>2{NF-=2}1'để an toàn
MestreLion

1
BTW, Nếu bạn đang sử dụng Windows (msysgit) và sử dụng core.autocrlf=true, bạn có thể muốn thêm dos2unix -D "$FILE"vào bên trong vòng lặp for, sau sed. Nếu không, nó sẽ thay đổi tất cả các CRLF thành các LF bằng cách chỉ phát hành sed.
jakub.g

49
Làm git addtrong một cái móc cam kết có vẻ khá xấu xa đối với tôi. Điều gì nếu bạn đang thực hiện một phần / cam kết của một tập tin? Bạn không muốn tập tin đầy đủ được cam kết sau lưng, phải không?
Stefaan

19

Trên Mac OS (hoặc, có thể, bất kỳ BSD nào), các tham số lệnh sed phải khác nhau một chút. Thử cái này:

#!/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 -E 's/:[0-9]+:.*//' | uniq` ; do
    # Fix them!
    sed -i '' -E 's/[[:space:]]*$//' "$FILE"
    git add "$FILE"
done

Lưu tệp này dưới dạng .git/hooks/pre-commit- hoặc tìm tệp đã có ở đó và dán phần dưới cùng vào đâu đó bên trong tệp. Và nhớ chmod a+xnó quá.

Hoặc để sử dụng toàn cầu (thông qua Git commit hook - cài đặt toàn cầu ), bạn có thể đặt nó vào $GIT_PREFIX/git-core/templates/hooks( trong đó GIT_PREFIX là / usr hoặc / usr / local hoặc / usr / share hoặc / opt / local / share) và chạy git initbên trong các repos hiện có của bạn.

Theo git help init:

Chạy git init trong kho lưu trữ hiện có là an toàn. Nó sẽ không ghi đè lên những thứ đã có. Lý do chính cho việc khởi chạy lại git init là chọn các mẫu mới được thêm vào.


7
Không phải cái móc này sửa đổi tệp làm việc và ghi đè chỉ mục bằng tệp làm việc đã sửa đổi? Nếu bạn đã 'git add -p' để xây dựng chỉ mục của mình, hook hook này sẽ thổi bay điều đó.
Matthew Dutton

2
Vâng, bạn có thể đúng. Ai đó có thể phải viết lại tập lệnh này để sử dụng git hash-object -wgit update-indexđể (chèn lại) tệp được trộn trực tiếp vào chỉ mục. Có người rất dũng cảm.
AlexChaffee

11

Tôi muốn để lại nhiệm vụ này cho biên tập viên yêu thích của bạn.

Chỉ cần đặt lệnh để xóa dấu cách khi lưu.


2
Trong vim bạn có thể làm điều này với: autocmd BufWritePre .cpp, .c, *. H:% / \ s \ + $ // e
Robert Massaioli

3
Xin lỗi, tôi đã đưa ra nhận xét trên trước khi kiểm tra nó. Có một "s" bị thiếu sau dấu phần trăm và nó sẽ di chuyển con trỏ xung quanh nếu khoảng trắng được tìm thấy và nó sẽ xóa mẫu tìm kiếm cuối cùng. Xem vim.wikia.com/wiki/Remove_unwocate_spaces để biết các lựa chọn thay thế tốt hơn.
Seth Johnson

1
Trong emacs đó là Mx xóa dấu vết-khoảng trắng.
Mauvis Ledford

2
Vẫn tốt hơn, đối với emacs, đặt một hook để xóa khoảng trắng theo dõi trước khi lưu bằng cách thêm (add-hook 'before-save-hook 'delete-trailing-whitespace)vào .emacstệp của bạn . Thủ thuật khoảng trắng của Emacs
Duncan Parkes

1
Tôi sử dụng (add-hook 'before-save-hook' whitespace-cleanup) cũng chuyển đổi các tab thành khoảng trắng.
Nils Fagerburg

10

Sử dụng thuộc tính git và thiết lập bộ lọc với cấu hình git

OK, đây là một cách mới để giải quyết vấn đề này Cách tiếp cận của tôi là không sử dụng bất kỳ hook nào, mà là sử dụng các bộ lọc và thuộc tính git. Điều này cho phép bạn làm, là thiết lập, trên mỗi máy bạn phát triển, một bộ các bộ lọc sẽ loại bỏ khoảng trắng ở cuối và thêm các dòng trống ở cuối tệp trước khi thực hiện chúng. Sau đó, thiết lập tệp .gitattribut cho biết loại tệp nào mà bộ lọc sẽ được áp dụng. Các bộ lọc có hai giai đoạn, cleanđược áp dụng khi thêm tệp vào chỉ mục và smudgeđược áp dụng khi thêm chúng vào thư mục làm việc.

Nói với git của bạn để tìm một tệp thuộc tính toàn cầu

Trước tiên, hãy cho cấu hình toàn cầu của bạn sử dụng tệp thuộc tính toàn cầu:

git config --global core.attributesfile ~/.gitattributes_global

Tạo bộ lọc toàn cầu

Bây giờ, tạo bộ lọc:

git config --global filter.fix-eol-eof.clean fixup-eol-eof %f
git config --global filter.fix-eol-eof.smudge cat
git config --global filter.fix-eol-eof.required true

Thêm ma thuật kịch bản sed

Cuối cùng, đặt đoạn fixup-eol-eofscript ở đâu đó trên đường dẫn của bạn và làm cho nó có thể thực thi được. Kịch bản sử dụng sed để thực hiện một số thao tác chỉnh sửa (loại bỏ khoảng trắng và khoảng trống ở cuối dòng và các dòng trống bên ngoài ở cuối tệp)

fixup-eol-eof sẽ giống như thế này:

#!/bin/bash
sed -e 's/[  ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1

ý chính của tôi về điều này

Nói cho git biết loại tệp nào sẽ áp dụng bộ lọc mới tạo của bạn cho

Cuối cùng, tạo hoặc mở ~ / .gitattribut_global trong trình chỉnh sửa yêu thích của bạn và thêm các dòng như:

pattern attr1 [attr2 [attr3 […]]]

Vì vậy, nếu chúng tôi muốn khắc phục sự cố khoảng trắng, đối với tất cả các tệp nguồn c của chúng tôi, chúng tôi sẽ thêm một dòng giống như sau:

*.c filter=fix-eol-eof

Thảo luận về bộ lọc

Bộ lọc có hai giai đoạn, giai đoạn sạch sẽ được áp dụng khi mọi thứ được thêm vào chỉ mục hoặc được kiểm tra và giai đoạn nhoè khi git đưa công cụ vào thư mục làm việc của bạn. Ở đây, smudge của chúng tôi chỉ chạy nội dung thông qua catlệnh sẽ không thay đổi chúng, ngoại trừ có thể thêm một ký tự dòng mới nếu không có một ký tự ở cuối tệp. Lệnh sạch là bộ lọc khoảng trắng mà tôi đã ghép lại với nhau từ các ghi chú tại http://sed.sourceforge.net/sed1line.txt . Có vẻ như nó phải được đưa vào một tập lệnh shell, tôi không thể tìm ra cách tiêm lệnh sed, bao gồm cả việc vệ sinh các dòng phụ ngoại lai ở cuối tập tin trực tiếp vào tập tin git-config. (Bạn CÓ THỂtuy nhiên, loại bỏ các khoảng trống theo sau mà không cần một tập lệnh sed riêng biệt, chỉ cần đặt thành filter.fix-eol-eofmột cái gì đó giống như sed 's/[ \t]*$//' %fnơi \tcó một tab thực tế, bằng cách nhấn tab.)

Yêu cầu = true gây ra lỗi được nêu ra nếu có sự cố xảy ra, để tránh cho bạn khỏi rắc rối.

Xin vui lòng tha thứ cho tôi nếu ngôn ngữ của tôi liên quan đến git là không chính xác. Tôi nghĩ rằng tôi đã nắm bắt khá tốt các khái niệm nhưng vẫn đang học thuật ngữ.


Cách tiếp cận thú vị. +1
VonC

Cảm ơn @VonC! Tôi cũng muốn nhân cơ hội này để chỉ ra rằng các thuộc tính git có thể được cấu hình theo cơ sở mỗi lần lặp lại trong .gitthư mục chứ không phải trên toàn cầu, điều này có thể có ý nghĩa hơn.
zbeekman

9

Tôi đã viết hook hook pre-commit này, nó chỉ loại bỏ khoảng trắng theo sau khỏi các dòng bạn đã thay đổi / thêm vào, vì các đề xuất trước đó có xu hướng tạo ra các cam kết không thể đọc được nếu các tệp mục tiêu có quá nhiều khoảng trắng ở cuối.

#!/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

IFS='
'

files=$(git diff-index --check --cached $against -- | sed '/^[+-]/d' | perl -pe 's/:[0-9]+:.*//' | uniq)
for file in $files ; do
    diff=$(git diff --cached $file)
    if test "$(git config diff.noprefix)" = "true"; then
        prefix=0
    else
        prefix=1
    fi
    echo "$diff" | patch -R -p$prefix
    diff=$(echo "$diff" | perl -pe 's/[ \t]+$// if m{^\+}')
    out=$(echo "$diff" | patch -p$prefix -f -s -t -o -)
    if [ $? -eq 0 ]; then
        echo "$diff" | patch -p$prefix -f -t -s
    fi
    git add $file
done

1
Hấp dẫn. +1. Xem câu trả lời khác của tôi để tính toán cây trống.
VonC

1
Ý tưởng tốt, đây là chính xác những gì tôi muốn. Tuy nhiên, hãy cẩn thận khi sử dụng này! Đối với tôi trên OSX và git phiên bản 2.3.5, nó sẽ thổi bay mọi thay đổi bổ sung nhưng không được cam kết mà tôi đã dàn dựng. Tôi vẫn sẽ quan tâm đến một giải pháp làm việc cho việc này mặc dù.
Casper

9

Vui lòng thử tôi cam kết trước móc , nó có thể tự động phát hiện trailing khoảng trắng và loại bỏ nó . Cảm ơn bạn!

nó có thể làm việc theo GitBash(windows), Mac OS X and Linux!


Ảnh chụp nhanh:

$ git commit -am "test"
auto remove trailing whitespace in foobar/main.m!
auto remove trailing whitespace in foobar/AppDelegate.m!
[master 80c11fe] test
1 file changed, 2 insertions(+), 2 deletions(-)

1
Hấp dẫn. +1. Tôi đã tham chiếu móc của bạn trong câu trả lời của riêng tôi
VonC

@VonC Cảm ơn sự khẳng định của bạn! Đối với '.md', tôi chỉ tìm thấy git commit -no-verify, có loại đường nào không?
ông già

Tôi thà làm cho hook có thể phát hiện .mdtệp và không xóa các khoảng trắng, thay vì yêu cầu người dùng cuối thêm một --no-verifytùy chọn trên git commit.
VonC

Thất bại nếu cam kết một tệp / thư mục bắt đầu bằng +hoặc-
Rody Oldenhuis

6

Đây là phiên bản tương thích ubfox + mac os x:

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

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]+:.*//' > /dev/null 2>&1 || sed -E 's/:[0-9]+:.*//') | uniq` ; do
  # Fix them!
  (sed -i 's/[[:space:]]*$//' "$FILE" > /dev/null 2>&1 || sed -i '' -E 's/[[:space:]]*$//' "$FILE")
  git add "$FILE"
done

# Now we can commit
exit

Chúc vui vẻ


Có vẻ như sự khác biệt duy nhất giữa bạn và tôi là bạn kiểm tra xem sed sẽ thực sự thay thế thứ gì đó trước khi viết lại tập tin ... Tôi không chắc vấn đề đó vì git không cam kết thay đổi mà không thực sự thay đổi gì. Tôi cho rằng nó an toàn hơn một chút, nhưng cũng chậm hơn một chút và tôi thích sự rõ ràng của việc không lặp lại các biểu thức hai lần trên một dòng. De gustibus non disputandum est!
AlexChaffee

không có sự khác biệt là phiên bản đang sử dụng cú pháp ubfox trước và (nếu thất bại) sau đó là phiên bản osx.
sdepold

1
Tôi đã chỉnh sửa bài đăng của sdepold, nó cũng có thể cho phép khoảng trắng trong tên tệp bây giờ.
imme

5

Đã suy nghĩ về điều này ngày hôm nay. Đây là tất cả những gì tôi đã làm cho một dự án java:

egrep -rl ' $' --include *.java *  | xargs sed -i 's/\s\+$//g'

3

Đối với người dùng văn bản tuyệt vời .

Đặt đúng theo cấu hình của bạn Cài đặt người dùng .

"trim_trailing_white_space_on_save": true


1
Đây có phải là một cách để thiết lập điều này theo loại tập tin? Tôi có *.md(đánh dấu) các tệp dựa vào "" (dấu cách hai dấu cách) để đánh dấu đơn giản <br />và cài đặt đó dường như áp dụng cho tất cả các tệp, kể cả những tệp tôi không muốn xóa dấu cách.
VonC

@VonC Có sự phân cấp về cách cấu hình được áp dụng chi tiết hơn ở đây, stackoverflow.com/questions/16983328/ Hy vọng nó sẽ giúp
Haris Krajina

2

vòng lặp for cho các tệp sử dụng biến shell $ IFS. trong tập lệnh đã cho, tên tệp có ký tự nằm trong biến $ IFS sẽ được xem là hai tệp khác nhau trong vòng lặp for. Kịch bản lệnh này khắc phục nó: công cụ sửa đổi chế độ đa dòng như được đưa ra theo hướng dẫn sử dụng sed dường như không hoạt động theo mặc định trên hộp ub Ubuntu của tôi, vì vậy tôi đã tìm kiếm một sự bổ sung khác và tìm thấy nó với nhãn lặp, về cơ bản nó sẽ chỉ bắt đầu thay thế trên dòng cuối cùng của tập tin nếu tôi đã hiểu đúng.

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

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

SAVEIFS="$IFS"
# only use new-line character as seperator, introduces EOL-bug?
IFS='
'
# Find files with trailing whitespace
for FILE in $(
    git diff-index --check --cached $against -- \
    | sed '/^[+-]/d' \
    | ( sed -r 's/:[0-9]+:.*//' || sed -E 's/:[0-9]+:.*//' ) \
    | uniq \
)
do
# replace whitespace-characters with nothing
# if first execution of sed-command fails, try second one( MacOSx-version)
    (
        sed -i ':a;N;$!ba;s/\n\+$//' "$FILE" > /dev/null 2>&1 \
        || \
        sed -i '' -E ':a;N;$!ba;s/\n\+$//' "$FILE" \
    ) \
    && \
# (re-)add files that have been altered to git commit-tree
#   when change was a [:space:]-character @EOL|EOF git-history becomes weird...
    git add "$FILE"
done
# restore $IFS
IFS="$SAVEIFS"

# exit script with the exit-code of git's check for whitespace-characters
exec git diff-index --check --cached $against --

[1] mẫu phụ đề sed: Làm cách nào tôi có thể thay thế một dòng mới (\ n) bằng sed? .


2

Điều này không tự động xóa khoảng trắng trước khi cam kết, nhưng nó khá dễ thực hiện. Tôi đặt tập lệnh perl sau vào một tệp có tên git-wsf (git khoảng trắng sửa lỗi) trong một thư mục trong $ PATH để tôi có thể:

git wsf | sh

và nó loại bỏ tất cả các khoảng trắng chỉ từ dòng file báo cáo git như một diff.

#! /bin/sh
git diff --check | perl -x $0
exit

#! /usr/bin/perl

use strict;

my %stuff;
while (<>) {
    if (/trailing whitespace./) {
        my ($file,$line) = split(/:/);
        push @{$stuff{$file}},$line;
    }
}

while (my ($file, $line) = each %stuff) {
    printf "ex %s <<EOT\n", $file;
    for (@$line) {
        printf '%ds/ *$//'."\n", $_;
    }
    print "wq\nEOT\n";
}

0

Hơi muộn nhưng vì điều này có thể giúp ai đó ngoài kia, nên đi đây.

Mở tệp trong VIM. Để thay thế các tab bằng khoảng trắng, hãy nhập dòng lệnh sau trong vim

:%s#\t#    #gc

Để thoát khỏi các khoảng trắng khác

:%s#\s##gc

Điều này khá nhiều đã làm điều đó cho tôi. Thật tẻ nhạt nếu bạn có nhiều tập tin cần chỉnh sửa. Nhưng tôi thấy nó dễ dàng hơn các hook pre-commit và làm việc với nhiều biên tập viên.


Nếu nó trở nên tẻ nhạt - và nếu bạn có một bản sao lưu những gì bạn sắp chỉnh sửa - thì tôi thường chỉ sử dụng sed để thay đổi các tab thành khoảng trắng: sed -i 's|\t| |g' filenames(khoảng trắng ở vị trí thay thế). Lưu ý rằng bạn có thể sử dụng find để lấy tên tệp của mình. Nếu bạn chưa nghĩ đến cách lấy bản sao lưu đó, tôi thường chỉ cam kết mọi thứ và sau đó 'hoàn tác' cam kết với thiết lập lại mềm trở lại nơi tôi đang ở; đôi khi tôi thêm mọi thứ vào cây nhưng không cam kết và đôi khi tôi sử dụng stash / áp dụng (không phải pop!). Nếu tôi cảm thấy lo lắng, tôi sẽ đưa toàn bộ cây của mình đến một vị trí an toàn trước khi can thiệp ...
hiền nhân

0

Để xóa khoảng trắng ở cuối dòng trong một tệp có thể di chuyển, sử dụng ed:

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file

-1

Điều này có thể sẽ không trực tiếp giải quyết vấn đề của bạn, nhưng bạn có thể muốn đặt chúng thông qua git-config trong không gian dự án thực tế của mình, nó chỉnh sửa ./.git/config trái ngược với ~ / .gitconfig. Rất vui được giữ các thiết lập nhất quán giữa tất cả các thành viên dự án.

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"

3
afaik, cài đặt bên trong .git không được chia sẻ với bất kỳ ai khác; chúng cụ thể cho repo địa phương của bạn
AlexChaffee
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.