Git: Làm thế nào để hoàn nguyên 2 tệp bị kẹt cứng ở "Đã thay đổi nhưng không được cam kết"?


84

Tôi có một repo có hai tệp được cho là tôi đã thay đổi cục bộ.

Vì vậy, tôi bị mắc kẹt với điều này:

$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   dir1/foo.aspx
#       modified:   dir2/foo.aspx
#
no changes added to commit (use "git add" and/or "git commit -a")

Làm git diffnói rằng toàn bộ nội dung tệp đã thay đổi, ngay cả khi nhìn vào mắt nó dường như không đúng sự thật (dường như có những dải dòng phổ biến mà sự khác biệt dường như không nhìn thấy).

Điều thú vị là tôi không nhớ đã thay đổi cục bộ các tệp này. Repo này được sử dụng với một repo từ xa (riêng tư, tại GitHub.com, FWIW).

Bất kể tôi đã thử gì, tôi không thể hủy những thay đổi cục bộ này. Tôi đã thử tất cả:

$ git checkout -- .
$ git checkout -f
$ git checkout -- dir1/checkout_receipt.aspx
$ git reset --hard HEAD
$ git stash save --keep-index && git stash drop
$ git checkout-index -a -f

Nói cách khác, tôi đã thử mọi thứ được mô tả trong Làm cách nào để loại bỏ các thay đổi chưa phân giai đoạn trong Git? thêm nữa. Nhưng 2 tệp vẫn bị kẹt là "đã thay đổi nhưng không được cam kết".

Cái quái gì sẽ khiến hai tệp bị kẹt như thế này và dường như "un-revert-table" ??

PS Trong danh sách ở trên hiển thị các lệnh tôi đã thử, tôi đã viết nhầm git revertkhi có ý git checkout. Tôi xin lỗi và cảm ơn những người trong số các bạn đã trả lời rằng tôi nên thử checkout. Tôi đã chỉnh sửa câu hỏi để sửa nó. Tôi chắc chắn đã thử checkout.


git diff --ignore-space-changehoặc git diff --ignore-all-spacetạo ra sự khác biệt trong đầu ra của git diff?
jdd

@jermiahd Có! Với một trong hai lá cờ, git diffcho biết các tệp giống hệt nhau.
Greg Hendershott

2
Bản sao có thể có của stackoverflow.com/questions/2016404/… . Tôi thích câu trả lời được chấp nhận ở đó tốt hơn, đó là đặt git config --global core.autocrlf falsethay vì 'đúng'.
Johann

2
Câu trả lời [ở đây] [1] hiệu quả với tôi và nhiều người khác. [1]: stackoverflow.com/questions/2016404/…
Mike K

2
Điều này cũng xảy ra khi kho chứa 2 hoặc nhiều tệp trong cùng một thư mục với các trường hợp khác nhau được kiểm tra trong hệ thống tệp không phân biệt chữ hoa chữ thường. Xóa hoặc đổi tên một trong các tệp để giải quyết vấn đề.
465544

Câu trả lời:


33

Kết thúc dòng trong tệp là gì? Tôi cá là họ CRLF. Nếu có, hãy xem hướng dẫn này: http://help.github.com/line-endings/

Tóm lại, bạn cần đảm bảo rằng git được thiết lập để chuyển đổi phần cuối dòng thành LF khi cam kết, và sau đó cam kết các tệp đó. Các tệp trong repo phải luôn là LF, các tệp được kiểm tra phải là tệp gốc của hệ điều hành, giả sử bạn đặt git chính xác.


1
Cảm ơn. Tôi đã có git config --global core.autocrlf truevà bên kia cũng đẩy đến repo trên GitHub.
Greg Hendershott

1
Sau đó, bạn chỉ cần thực hiện các bit trong <pre>khối cuối cùng của hướng dẫn đó để sửa các tệp trong repo.
Tekkub

5
Tôi không đồng ý rằng kết thúc dòng phải luôn là LF trong repo (đặc biệt nếu ai đó đã cam kết CRLF) và hệ điều hành cũng phải luôn là bản địa. Môi trường và trình soạn thảo Windows của tôi (chủ yếu cho PHP, HTML, CSS, v.v.) đối phó hoàn toàn tốt với phần cuối dòng LF.
Simon East

Một câu trả lời thiên tài, tôi đã quên rằng gần đây tôi đã sử dụng gitattributes để buộc LF trong các tệp repo và không mong đợi git sẽ tự động thay đổi tệp. Chúng tôi có sự kết hợp giữa các nhà phát triển Windows và Linux và điều đó khiến chúng tôi phát điên khi các biên tập viên trên các nền tảng khác nhau liên tục chuyển đổi các trình kết thúc dòng, một khi sự thay đổi xảy ra, tất cả điều này sẽ biến mất.
Oliver Dungey

120

Tôi đã dành hàng giờ để giải quyết một vấn đề tương tự - một nhánh từ xa mà tôi đã kiểm tra, nó hiển thị bốn tệp là 'Đã thay đổi nhưng chưa cập nhật', ngay cả khi xóa tất cả các tệp và chạy git checkout -flại (hoặc các biến thể khác từ bài đăng này)!

Bốn tệp này là cần thiết, nhưng chắc chắn đã không được tôi sửa đổi. Giải pháp cuối cùng của tôi - thuyết phục Git rằng chúng không bị thay đổi. Các thao tác sau đây phù hợp với tất cả các tệp đã kiểm xuất, hiển thị trạng thái 'đã sửa đổi' - hãy đảm bảo rằng bạn đã cam kết / lưu trữ bất kỳ tệp nào thực sự đã được sửa đổi !:

git ls-files -m | xargs -i git update-index --assume-unchanged "{}"

Trên Mac OSX, tuy nhiên xargs hoạt động hơi khác một chút (thx Daniel cho nhận xét):

git ls-files -m | xargs -I {} git update-index --assume-unchanged {}

Tôi đã thêm phần này làm trình giữ chỗ cho bản thân vào lần sau, nhưng tôi hy vọng nó cũng giúp ích cho người khác.

-Al


9
Tôi có một vài tệp cứng và chạy lệnh này, trạng thái git hiện không có gì thay đổi, nhưng khi tôi cố gắng thay đổi nhánh git vẫn cho tôi biết tôi không thể thay đổi nhánh vì hai tệp đó có các thay đổi cục bộ. Không chắc mình đã làm gì sai nhưng có vẻ như nó chỉ che đậy vấn đề hơn là sửa chữa nó? Tôi cũng không thể xác nhận các tệp sau khi chạy lệnh đó. Giải pháp cho tôi là xóa chúng, cam kết và hoán đổi các nhánh.
RodH257

5
cảm ơn! Tôi đã thử TẤT CẢ các thủ thuật được đề cập trong mọi câu trả lời khác mà tôi có thể tìm thấy - không có hiệu quả nào. trên máy Mac không thể sử dụng dòng như hiện tại, chỉ chạy git update-index --assume-changes <filename> trên mỗi tệp và điều này đã làm cho vấn đề biến mất.
Yonatan Karni

2
Không phải tùy chọn "- số lượng không thay đổi" được sử dụng khi bạn muốn các sửa đổi cục bộ trên tệp này KHÔNG BAO GIỜ được cam kết? Giống như khi bạn kiểm tra tệp cấu hình trang web mẫu và cập nhật tệp đó bằng các thông tin nhạy cảm không được lưu trữ trong kho lưu trữ?
Maxime Rossini

6
Đây chính xác là những gì tôi cần, mặc dù xargs trên mac có vẻ hoạt động hơi khác (tôi đang chạy 10.10 Yosemite). Điều này cuối cùng đã làm việc cho tôi:git ls-files -m | xargs -I {} git update-index --assume-unchanged {}
Daniel

3
Để hoàn nguyên hiệu lực của lệnh:git ls-files -v|grep '^h' | cut -c3- | xargs -i git update-index --no-assume-unchanged "{}"
Marinos An

20

đây là cách tôi đã khắc phục sự cố tương tự trong trường hợp của tôi: mở .gitattributes change:

* text=auto

đến:

#* text=auto

lưu và đóng, sau đó hoàn nguyên hoặc đặt lại, cảm ơn @Simon East về gợi ý


1
Việc xóa text=autocài đặt trong .gitattributes có hiệu quả với tôi và sau đó, sau khi tôi git reset --hardđặt lại cài đặt đó, các tệp không còn hiển thị là đã sửa đổi nữa!
ErikE

1
Rõ ràng là có gì đó sai với text=autocài đặt này . Tôi đang làm việc trong các repo với các cam kết từ nhiều hệ điều hành và tôi vẫn chưa tìm ra nguyên nhân khiến tôi gặp nhiều vấn đề hơn: giữ hay bỏ nó.
Marinos An

1
@MarinosAn có, cụ thể là git cho phép bạn để lại các tệp văn bản hiện có với phần cuối dòng sai khi bạn thêm cài đặt này lần đầu tiên. Điều đó chỉ sai và trừ khi bạn nhớ tự làm điều đó, cuối cùng bạn sẽ gặp phải một trong những thay đổi không thể hoàn nguyên này.
Roman Starkov

12

Một khả năng khác là sự khác biệt (ngăn bạn hoàn nguyên các tệp này bằng lệnh kiểm tra) là một trong chế độ tệp. Đây là những gì xảy ra với tôi. Trên phiên bản git của tôi, bạn có thể khám phá điều này bằng cách sử dụng

git diff dir1 / foo.aspx

Và nó sẽ hiển thị cho bạn các thay đổi chế độ tệp. Tuy nhiên, nó vẫn không cho phép bạn hoàn nguyên chúng. Để sử dụng

git config core.filemode false

hoặc thay đổi git .config của bạn trong trình soạn thảo văn bản của bạn bằng cách thêm

[cốt lõi]

filemode = false

Sau khi làm điều này, bạn có thể sử dụng

git đặt lại HEAD dir1 / foo.aspx

và tệp sẽ biến mất.

(Tôi đã hiểu tất cả những điều này từ câu trả lời cho Làm cách nào để thực hiện thay đổi chế độ git bỏ qua (chmod)? )


1
Nếu bạn đang ở trên Windows, Eyal của chẩn đoán / giải pháp nên đoán đầu tiên của bạn
AlcubierreDrive

Đặc biệt cẩn thận không bao giờ sử dụng cygwin git từ cmd.exe. Nếu bạn muốn git trong cmd.exe, hãy cài đặt msysgit.
AlcubierreDrive

Chỉ để xác nhận rằng đây thực sự là vấn đề trên Windows.
Dejan Marjanović

Đối với tôi trên Windows, đây không phải là vấn đề ( core.filemodeđã được đặt thành sai). Trong trường hợp của tôi, cách khắc phục / cách giải quyết là một trong câu trả lời của Alan Forsyth .
Venryx

3

Cố gắng hoàn nguyên các thay đổi cục bộ :

git checkout -- dir1/foo.aspx
git checkout -- dir2/foo.aspx

Tôi đã "hoàn nguyên" trên não và tôi muốn viết checkout. Tôi đã thử checkout. Cảm ơn bạn dù sao cho câu trả lời của bạn. Đó là một câu trả lời tốt cho câu hỏi ban đầu của tôi vì vậy tôi sẽ ủng hộ.
Greg Hendershott

3

Tôi có một số tệp thay đổi ảo được hiển thị là đã sửa đổi, nhưng thực sự giống hệt nhau.

Chạy lệnh này đôi khi hoạt động:
(Tắt các chuyển đổi kết thúc dòng "thông minh" nhưng thường không hữu ích của git)

git config --local core.autocrlf false

Nhưng trong một trường hợp khác, tôi phát hiện ra đó là do một .gitattributestệp trong thư mục gốc có một số cài đặt kết thúc dòng, đang cố gắng áp dụng autocrlfcho một số tệp nhất định ngay cả khi nó đã bị tắt. Điều đó thực sự không hữu ích, vì vậy tôi đã xóa .gitattributes, cam kết và tệp không còn hiển thị là đã sửa đổi.


Việc xóa text=autocài đặt trong .gitattributes có hiệu quả với tôi và sau đó, sau khi tôi git reset --hardđặt lại cài đặt đó, các tệp không còn hiển thị là đã sửa đổi nữa!
ErikE

2
git checkout dir1/foo.aspx
git checkout dir2/foo.aspx

Tôi đã "hoàn nguyên" trên não và tôi muốn viết checkout. Tôi đã thử checkout. Cảm ơn bạn dù sao cho câu trả lời của bạn. Đó là một câu trả lời tốt cho câu hỏi ban đầu của tôi vì vậy tôi sẽ ủng hộ.
Greg Hendershott

2

Bạn cũng có thể gặp sự cố liên quan đến các trường hợp chữ cái đặt tên thư mục. Một số đồng nghiệp của bạn có thể đã thay đổi tên của thư mục từ myHandler thành MyHandler . Nếu sau này bạn đẩy và kéo một số tệp của thư mục gốc, bạn sẽ có 2 thư mục riêng biệt trên kho lưu trữ từ xa VÀ chỉ một thư mục trên máy cục bộ của bạn vì trên Windows bạn chỉ có thể có một. Và bạn đang gặp rắc rối.

Để kiểm tra xem có đúng như vậy không, chỉ cần xem liệu kho lưu trữ từ xa có cấu trúc kép hay không.

Để khắc phục điều này, hãy tạo một bản sao lưu của thư mục mẹ bên ngoài repo, sau đó xóa thư mục mẹ, đẩy nó. Thực hiện một lần kéo (đây là khi cái thứ hai được đánh dấu là đã xóa sẽ xuất hiện trên trạng thái) và đẩy lại. Sau đó, tạo lại toàn bộ cấu trúc từ bản sao lưu của bạn và đẩy lại các thay đổi.


2

Tôi nghĩ sẽ hữu ích nếu cung cấp gợi ý về cách tái tạo vấn đề , để hiểu rõ hơn vấn đề:

$ git init
$ echo "*.txt -text" > .gitattributes
$ echo -e "hello\r\nworld" > 1.txt
$ git add 1.txt 
$ git commit -m "committed as binary"
$ echo "*.txt text" > .gitattributes
$ echo "change.." >> 1.txt

# Ok let's revert now

$ git checkout -- 1.txt
$ git status
 modified:   1.txt

# Oooops, it didn't revert!!


# hm let's diff:

$ git diff
 warning: CRLF will be replaced by LF in 1.txt.
 The file will have its original line endings in your working 
 directory.
 diff --git a/1.txt b/1.txt
 index c78c505..94954ab 100644
 --- a/1.txt
 +++ b/1.txt
 @@ -1,2 +1,2 @@
 -hello
 +hello
  world

# No actual changes. Ahh, let's change the line endings...

$ file 1.txt 
 1.txt: ASCII text, with CRLF line terminators
$ dos2unix 1.txt
 dos2unix: converting file 1.txt to Unix format ...
$ git diff
 git diff 1.txt
 diff --git a/1.txt b/1.txt
 index c78c505..94954ab 100644
 --- a/1.txt
 +++ b/1.txt
 @@ -1,2 +1,2 @@
 -hello
 +hello
  world

# No, it didn't work, file is still considered modified.

# Let's try to revert for once more:
$ git checkout -- 1.txt
$ git status
 modified:   1.txt

# Nothing. Let's use a magic command that prints wrongly committed files.

$ git grep -I --files-with-matches --perl-regexp '\r' HEAD

HEAD:1.txt

Cách thứ 2 để tái tạo: Trong đoạn script trên, hãy thay thế dòng này:
echo "*.txt -text" > .gitattributes
bằng
git config core.autocrlf=false
và giữ nguyên các dòng còn lại


Tất cả những điều trên nói lên điều gì? Một tệp văn bản có thể (trong một số trường hợp) được cam kết với CRLF, (ví dụ: -texttrong .gitattributes/ hoặc core.autocrlf=false).

Sau này, khi chúng ta muốn xử lý cùng một tệp là văn bản ( -text-> text), nó sẽ cần phải được cam kết lại.
Tất nhiên bạn có thể tạm thời hoàn nguyên nó (như trả lời chính xác của Abu Assar ). Trong trường hợp của chúng ta:

echo "*.txt -text" > .gitattributes
git checkout -- 1.txt
echo "*.txt text" > .gitattributes

Câu trả lời là : bạn có thực sự muốn làm điều đó không, bởi vì nó sẽ gây ra cùng một vấn đề mỗi khi bạn thay đổi tệp.


Đối với hồ sơ:

Để kiểm tra tệp nào có thể gây ra sự cố này trong repo của bạn, hãy thực hiện lệnh sau (git phải được biên dịch bằng --with-libpcre):

git grep -I --files-with-matches --perl-regexp '\r' HEAD

Bằng cách cam kết (các) tệp (giả sử rằng bạn muốn coi chúng là văn bản), cũng giống như thực hiện những gì được đề xuất trong liên kết này http://help.github.com/line-endings/ để khắc phục các sự cố như vậy . Tuy nhiên, thay vì bạn xóa .git/indexvà thực hiện reset, bạn chỉ có thể thay đổi (các) tệp, sau đó thực hiện git checkout -- xyz zyfvà sau đó cam kết.


2

Tôi đã gặp vấn đề tương tự, với sự bổ sung thú vị là các tệp đã bị thay đổi trên windows, nhưng không phải khi xem chúng từ WSL. Không thể thay đổi kết thúc dòng, đặt lại, v.v.

Cuối cùng, tôi đã tìm ra giải pháp trong câu trả lời này . Sau đây là văn bản để thuận tiện:


Tôi đã giải quyết vấn đề này bằng cách sử dụng các bước sau

1) Xóa mọi tệp khỏi chỉ mục của Git.

git rm --cached -r .

2) Viết lại chỉ mục Git để chọn tất cả các kết thúc dòng mới.

git reset --hard

Giải pháp là một phần của các bước được mô tả trên trang web git https://help.github.com/articles/dealing-with-line-endings/



1

Vấn đề này cũng có thể là do git coi sự khác biệt về cách viết hoa là các tệp khác nhau nhưng windows lại coi chúng là cùng một tệp. Nếu tên tệp chỉ thay đổi cách viết hoa thì mọi người dùng windows của repo đó sẽ gặp phải tình huống này.

Giải pháp là xác nhận nội dung tệp là chính xác và sau đó gửi lại. Chúng tôi đã phải hợp nhất nội dung hai tệp với nhau vì chúng khác nhau. Sau đó kéo và sẽ có xung đột hợp nhất mà bạn có thể giải quyết bằng cách xóa tệp trùng lặp. Gửi lại độ phân giải hợp nhất và bạn trở lại trạng thái ổn định.

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.