2013-06-20 28 views
7

Tôi đang sử dụng Git trong một thời gian dài, nhưng gần đây phải đối mặt với mẹo thú vị cho phép bạn hoàn nguyên lịch sử thay đổi tệp trong quá trình hợp nhất. Dưới đây là các bước để tái tạo là:Git cho phép mất lịch sử thay đổi tập tin trong khi hợp nhất với xung đột

Tôi có kho git với hai tập tin và một cam kết:

$ git branch 
    * master 
$ git log --oneline 
    80c8d5a Initial commit 
$ git log --oneline -- README 
    80c8d5a Initial commit 
$ ls 
    README conflict_file 

tôi là tạo ra các chi nhánh thực nghiệm mới và thay đổi README và tập tin conflict_file:

$ checkout -b experiment 
    Switched to branch 'experiment' 
$ vim README 
$ vim conflict_file 
$ git commit -am "Experimental changes" 
    [experiment cdbc988] Experimental changes 
    2 files changed, 2 insertions(+) 
$ git log --oneline -- README 
    cdbc988 Experimental changes 
    80c8d5a Initial commit 

trở lại với chi nhánh tổng thể và chỉnh sửa conflict_file (có mâu thuẫn trong quá trình hợp nhất):

$ git checkout master 
    Switched to branch 'master' 
$ vim conflict_file 
$ git commit -am "Master changes" 
    [master ad8b68e] Master changes 
    1 file changed, 1 insertion(+) 

Tình trạng của kho lưu trữ của tôi trong những điều sau đây:

$ git log --oneline --decorate --graph --all 
    * ad8b68e (HEAD, master) Master changes 
    | * cdbc988 (experiment) Experimental changes 
    |/ 
    * 80c8d5a Initial commit 

Đang cố gắng để kết hợp với các chi nhánh thực nghiệm:

$ git merge experiment 
    Auto-merging conflict_file 
    CONFLICT (content): Merge conflict in conflict_file 
    Automatic merge failed; fix conflicts and then commit the result. 
$ git mergetool 
    <merging conflict in conflict_file> 

Dưới đây là mẹo:

$ git reset HEAD README 
    Unstaged changes after reset: 
    M  README 
$ git commit 
    [master 909139f] Merge branch 'experiment' 
$ git log --oneline -- README 
    80c8d5a Initial commit 

Tôi mất những thay đổi và lịch sử của README tệp đã được giới thiệu trong thử nghiệm chi tiết chi nhánh trong Thay đổi thử nghiệm cam kết. Ai có thể xin vui lòng bình luận làm thế nào nó tương quan với ý tưởng rằng Git biết về tất cả những thay đổi? Điều đó có thể tránh được tình huống này không? Nó có thể trở thành một vấn đề trong công ty của chúng tôi, bởi vì hợp nhất được cho phép hoạt động cho các nhà phát triển, nhưng họ vô tình có thể loại bỏ những thay đổi của ai đó.

+1

Thử tùy chọn '--full-history' vào' git log'. Cũng đọc trang người đàn ông về _history simplification_: "Chế độ mặc định ... lịch sử đơn giản nhất giải thích trạng thái cuối cùng của cây". – chirlu

+0

Tại sao bạn ngạc nhiên rằng những thay đổi đối với tệp 'README' đã biến mất? bạn đã yêu cầu rõ ràng điều đó xảy ra với 'git reset HEAD README'. – Chronial

+0

Gọi 'git log --follow - ' helpen me – erkfel

Trả lời

7

Không có lịch sử nào bị mất: Thay đổi thành README được thực hiện trên nhánh thử nghiệm vẫn được chứa trong cam kết 210fdc1.Rằng nó không phải là một phần của cam kết hợp nhất 909139f là chỉ vì bạn hoàn toàn hoàn nguyên nó trước khi hoàn tất việc hợp nhất.

Bạn không nói những gì bạn mong đợi xảy ra, vì vậy tôi chỉ có thể đoán chính xác những gì bạn ngạc nhiên ở đây. Tôi sẽ chỉ ra hai ứng viên có khả năng.

  1. Cam kết hợp nhất không giới hạn chỉ sửa đổi tệp được chạm từ cơ sở hợp nhất hoặc thậm chí chỉ các tệp có thay đổi xung đột. Trong thực tế, nó có thể hoàn toàn khác với tất cả các bậc cha mẹ của nó.

    "Hoàn toàn khác" tất nhiên không phải là điều bạn nên giới thiệu, bởi vì nó sẽ phá vỡ giả định của mọi người về việc hợp nhất làm gì. Tuy nhiên, nó có thể có ý nghĩa hoàn hảo để mở rộng các tệp tài liệu trong cam kết hợp nhất và giải quyết xung đột nhất định nhất định có thể yêu cầu thay đổi các tệp bổ sung.

  2. Khi bạn gọi git log -- some_path, quá trình được gọi là đơn giản hóa lịch sử được gọi. Khi trang người dùng mô tả nó, git log sẽ cố gắng chỉ hiển thị những cam kết đó "đủ để giải thích cách các tệp phù hợp với các đường dẫn được chỉ định đến". Trong trường hợp của bạn, cam kết ban đầu là đủ để giải thích trạng thái hiện tại của README (vì README vẫn còn, hoặc một lần nữa, cùng một nội dung), do đó, đó là tất cả những gì được hiển thị.

    Bạn có thể muốn sử dụng --full-history, có thể cùng với --simplify-merges hoặc một số tùy chọn đơn giản hóa lịch sử khác. Họ, cũng như các quy tắc chính xác để bao gồm các cam kết (phức tạp hơn ngụ ý ở trên), là described in the git log man page, với một ví dụ mở rộng.

+0

Tôi dựa trên kỳ vọng của tôi về ý tưởng rằng mỗi thay đổi phải được theo dõi và lưu trong lịch sử của các sửa đổi tập tin, kỳ vọng của tôi là có 3 thay đổi trong tệp README trong 909139f. Hành vi tương tự nếu bạn đang sử dụng một nhánh và khi bạn thực hiện một số thay đổi và sau đó hoàn tác những thay đổi này, sẽ có 2 cam kết khác nhau mà không sử dụng '--amend' và chúng sẽ được hiển thị cho bạn trong' git log'. – erkfel

+0

Chúng tôi đang cố gắng giới thiệu Git trong tổ chức của chúng tôi, các nhà phát triển đang sử dụng IDE để commit/merge/push và Gerrit/GitHub để truy cập mã bằng UI, chúng tôi có các chính sách sử dụng Git như push force force, branch feature… Git và chúng tôi nhận được phàn nàn rằng rất dễ dàng để mất những thay đổi. – erkfel

+0

Sau khi điều tra, chúng tôi thấy rằng đó là kết quả của việc hợp nhất không chính xác như trong ví dụ của tôi, khi mọi người làm điều gì đó sai trái trong khi xung đột hợp nhất và vô tình đặt lại (và sau đó xóa) thay đổi. Khi họ đề cập đến biến mất của một số thay đổi họ đi đến Gerrit/GitHub, kiểm tra lịch sử tập tin và không thấy rằng những thay đổi thậm chí không được giới thiệu. Điều này rất khó hiểu. Chỉ những điều tra sâu mới giúp tìm ra sự hợp nhất không chính xác. – erkfel

1

Bạn chưa thực sự mất những thay đổi, bạn chỉ cần chưa đăng ký trong những thay đổi để nộp README, vì vậy họ không nằm trong bất kỳ cam kết thể hiện bởi git log lệnh của bạn:

* 9b8ede8 (HEAD, master) Merge branch 'experiment' 
|\ 
| * 210fdc1 (experiment) Experimental 
* | d0c1637 Master changes 
|/ 
* b558d42 Initial commit 

(SHA tôi dĩ nhiên là khác nhau) và:

$ git status 
# On branch master 
# Changes not staged for commit: 
# (use "git add <file>..." to update what will be committed) 
# (use "git checkout -- <file>..." to discard changes in working directory) 
# 
# modified: README 
# 
# Untracked files: 
# (use "git add <file>..." to include in what will be committed) 
# 
# conflict_file.orig 
no changes added to commit (use "git add" and/or "git commit -a") 

Như @Chronial lưu ý trong các ý kiến, bạn nói một cách rõ ràng git để làm một git reset --mixed (--mixed là mặc định) của tập tin README đến số điện thoại sau đó- HEAD, là (trong trường hợp của bạn) ad8b68e.

Đã bạn chạy git status ở giữa kết hợp mâu thuẫn của bạn (trước git mergetool), bạn sẽ thấy điều này:

$ git status 
# On branch master 
# You have unmerged paths. 
# (fix conflicts and run "git commit") 
# 
# Changes to be committed: 
# 
# modified: README 
# 
# Unmerged paths: 
# (use "git add <file>..." to mark resolution) 
# 
# both modified:  conflict_file 
# 

Bước git mergetool giải quyết các xung đột, di chuyển conflict_file vào cùng ready-to-cam ghi là README ở trên - nhưng sau khi số reset --mixed, README chuyển từ "thay đổi được cam kết" thành "thay đổi không được dàn xếp cho cam kết".

+0

Cảm ơn bạn đã trả lời, vui lòng kiểm tra nhận xét của tôi cho câu trả lời "chirlu". – erkfel

Các vấn đề liên quan