Làm cách nào để tìm khác biệt cùng một tệp giữa hai lần xác nhận khác nhau trên cùng một nhánh?


1144

Trong Git, làm cách nào tôi có thể so sánh cùng một tệp giữa hai cam kết khác nhau (không liền kề) trên cùng một nhánh (ví dụ chính)?

Tôi đang tìm kiếm một tính năng so sánh như tính năng trong Visual SourceSafe (VSS) hoặc Team Foundation Server (TFS).
Có thể trong Git?

Câu trả lời:


1476

Từ git-difftrang hướng dẫn:

git diff [--options] <commit> <commit> [--] [<path>...]

Ví dụ, để xem sự khác biệt cho một tệp "main.c" giữa bây giờ và hai lần xác nhận lại, đây là ba lệnh tương đương:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c

43
Điều ..này không thực sự cần thiết, mặc dù nó sẽ hoạt động với nó (ngoại trừ trong các phiên bản khá cũ, có thể). Bạn cũng có thể sử dụng git loghoặc gitkđể tìm SHA1 để sử dụng, nếu hai cam kết cách nhau rất xa. gitkcũng có "diff select -> this" và "diff this -> select" trong menu ngữ cảnh của nó.
Cascabel

17
Điều này sẽ hoạt động ngay cả khi tên tệp đã được sửa đổi giữa 2 lần xác nhận?
reubenjohn

26
Vậy mục đích của "-"
user64141

29
@ user64141 Điều --này rất hữu ích, ví dụ như khi bạn có một tệp có tên -p. Tốt để sử dụng trong các kịch bản, chỉ trong trường hợp hiếm hoi cần thiết trong thực tế.
Palec

13
Lưu ý: bạn cần sử dụng các đường dẫn liên quan đến thư mục gốc của repo. Các đường dẫn liên quan đến thư mục làm việc hiện tại sẽ không hoạt động.
Kevin Wheeler

281

Bạn cũng có thể so sánh hai tệp khác nhau trong hai phiên bản khác nhau, như sau:

git diff <revision_1>:<file_1> <revision_2>:<file_2>


25
lưu ý rằng có vẻ như nếu <file_1><file_2>nằm trong thư mục hiện tại, không phải trên thư mục được quản lý git cấp cao nhất, người ta phải trả trước ./cho Unix:<revision_1>:./filename_1
Andre Holzner

7
<revision>: có thể bị hủy bỏ, do đó bạn có thể tìm khác với một tệp chưa được cam kết.
Yaroslav Nikitenko

2
Lưu ý rằng trên Windows người ta phải sử dụng '/' cho đường dẫn tệp chứ không phải '\'.
np8

88

Nếu bạn đã cấu hình "Difftool", bạn có thể sử dụng

git difftool revision_1:file_1 revision_2:file_2

Ví dụ: So sánh một tệp từ cam kết cuối cùng của nó với cam kết trước đó trên cùng một nhánh: Giả sử rằng nếu bạn đang ở trong thư mục gốc của dự án

$git difftool HEAD:src/main/java/com.xyz.test/MyApp.java HEAD^:src/main/java/com.xyz.test/MyApp.java

Bạn nên có các mục sau trong tệp ~ / .gitconfig hoặc trong tệp dự án / .git / config. Cài đặt p4merge [Đây là công cụ tìm và hợp nhất ưa thích của tôi]

[merge]
    tool = p4merge
    keepBackup = false
[diff]
    tool = p4merge
    keepBackup = false
[difftool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
[mergetool]
    keepBackup = false
[difftool]
    keepBackup = false
[mergetool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
    cmd = p4merge.exe \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"

50

Kiểm tra $ git log, sao chép ID SHA-1 của hai cam kết khác nhau và chạy git difflệnh với các ID đó. ví dụ:

$ git diff (sha-id-one) (sha-id-two)

18
Nếu bạn muốn tìm khác biệt cho một tệp cụ thể, hãy thêm đường dẫn đến nó ở cuối lệnh.
hBrent

Đồng thời thực hiện "git pull" để tải xuống thông tin cây đầy đủ nếu hai cam kết nằm trên các nhánh khác nhau. Nếu không, bạn sẽ gặp lỗi "fatal: bad object".
user238607

4
git diff (sha-id-one) (sha-id-two) -- filename.ext không có tên tệp, nó sẽ liệt kê các khác biệt của tất cả các tệp trong hai cam kết đó.
SherylHohman

40

Nếu bạn muốn xem tất cả các thay đổi đối với tệp giữa hai lần xác nhận trên cơ sở cam kết, bạn cũng có thể thực hiện

git log -u $start_commit..$end_commit -- path/to/file


"$ Start_commit" và "$ end_commit" là gì? Họ có nghĩa đen, hoặc nếu không, bạn có thể cung cấp một ví dụ?
Peter Mortensen

Đó là các biến shell chứa bản sửa đổi bắt đầu và kết thúc, thay vào đó có thể là sha1
nghĩa đen

21

Dưới đây là tập lệnh Perl in ra các lệnh Git diff cho một tệp đã cho như được tìm thấy trong lệnh ghi nhật ký Git.

Ví dụ

git log pom.xml | perl gldiff.pl 3 pom.xml

Sản lượng:

git diff 5cc287:pom.xml e8e420:pom.xml
git diff 3aa914:pom.xml 7476e1:pom.xml
git diff 422bfd:pom.xml f92ad8:pom.xml

mà sau đó có thể được cắt và dán trong một phiên cửa sổ vỏ hoặc đường ống đến /bin/sh.

Ghi chú:

  1. số (3 trong trường hợp này) chỉ định số lượng dòng cần in
  2. tệp (pom.xml trong trường hợp này) phải đồng ý ở cả hai nơi (bạn có thể gói nó trong hàm shell để cung cấp cùng một tệp ở cả hai vị trí) hoặc đặt nó trong thư mục nhị phân dưới dạng tập lệnh shell

Mã số:

# gldiff.pl
use strict;

my $max  = shift;
my $file = shift;

die "not a number" unless $max =~ m/\d+/;
die "not a file"   unless -f $file;

my $count;
my @lines;

while (<>) {
    chomp;
    next unless s/^commit\s+(.*)//;
    my $commit = $1;
    push @lines, sprintf "%s:%s", substr($commit,0,6),$file;
    if (@lines == 2) {
        printf "git diff %s %s\n", @lines;
        @lines = ();
    }
    last if ++$count >= $max *2;
}

14

Nếu bạn muốn tạo khác biệt với nhiều hơn một tệp, với phương thức được chỉ định bởi @mipadi:

Ví dụ: diff giữa HEADvà của bạn master, để tìm tất cả .coffeecác tệp:

git diff master..HEAD -- `find your_search_folder/ -name '*.coffee'`

Điều này sẽ đệ quy tìm kiếm của bạn your_search_folder/cho tất cả .coffeecác tệp và tạo sự khác biệt giữa chúng và các masterphiên bản của chúng .


13

Nếu bạn có một số tệp hoặc thư mục và muốn so sánh các cam kết không liên tục, bạn có thể làm điều này:

Tạo một nhánh tạm thời ( "sửa đổi" trong ví dụ này)

git checkout -b revision

Tua lại mục tiêu cam kết đầu tiên

git reset --hard <commit_target>

Cherry hái trên những cam kết quan tâm

git cherry-pick <commit_interested> ...

Áp dụng khác

git diff <commit-target>^

Khi bạn làm xong

git branch -D revision

2
Cảm ơn giải pháp này. Nó hoạt động tốt cho trường hợp sử dụng của tôi. Điều duy nhất tôi sẽ cập nhật là khi bạn hoàn thành, bạn không thể xóa chi nhánh cho đến khi bạn tắt nó.
Steven Dix

9

Chỉ là một cách khác để sử dụng sự tuyệt vời của Git ...

git difftool HEAD HEAD@{N} /PATH/FILE.ext

Tôi đã xác định một bí danh từ câu trả lời này hoạt động với bash:difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #"
blueogive

2

Nếu bạn muốn so sánh trực quan đơn giản trên Windows, chẳng hạn như bạn có thể truy cập vào Visual SourceSafe hoặc Team Foundation Server (TFS), hãy thử điều này:

  • nhấn chuột phải vào tệp trong File Explorer
  • chọn 'Lịch sử Git'

Lưu ý: Sau khi nâng cấp lên Windows 10, tôi đã mất các tùy chọn menu ngữ cảnh Git. Tuy nhiên, bạn có thể đạt được điều tương tự bằng cách sử dụng 'gitk' hoặc 'tên tệp gitk' trong cửa sổ lệnh.

Khi bạn gọi 'Lịch sử Git', công cụ Git GUI sẽ bắt đầu, với lịch sử của tệp ở khung trên cùng bên trái. Chọn một trong những phiên bản bạn muốn so sánh. Sau đó nhấp chuột phải vào phiên bản thứ hai và chọn một trong hai

Khác biệt này -> đã chọn

hoặc là

Khác biệt được chọn -> này

Sự khác biệt được mã hóa màu sẽ xuất hiện trong khung bên trái phía dưới.


Lưu ý đối với downvoters: đây là một giải pháp đơn giản, dễ thực hiện và giải quyết vấn đề của OP. Nó hoạt động trên Windows mà OP đang sử dụng rõ ràng (xem tài liệu tham khảo về TFS và VSS trong câu hỏi).
Tài nguyên
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.