2015-05-23 41 views
12

Tôi sử dụng một vài gói phần mềm (như gitlab) mà bạn cài đặt bằng cách nhân bản từ repo git của chúng. Họ thường đi kèm với một số config.example (dưới sự kiểm soát phiên bản), mà bạn sao chép vào tập tin config của riêng bạn (không thuộc quyền kiểm soát phiên bản hoặc thậm chí bị bỏ qua trong .gitignore) và thích ứng với nhu cầu của bạn.Tương tác hợp nhất các tệp được theo dõi bằng git và các tệp cục bộ không được theo dõi

Khi gói cập nhật được cập nhật và ví dụ thay đổi tùy chọn tệp cấu hình rõ ràng sẽ chỉ được phản ánh trong config.example.

Có một chuỗi lệnh git mà tôi đang thiếu có thể giúp tôi so sánh các thay đổi của config.example sang số mới trong upstream/HEAD và thậm chí có thể hợp nhất chúng tương tác vào tệp config cục bộ của tôi không?

Sẽ thật tuyệt vời nếu tôi có thể nhận được một cái gì đó giống như chế độ vá tương tác trong git add/commit --interactive.

Trả lời

2

git checkout --patch chọn hunks diff, đơn giản nhất ở đây có thể là để đưa nội dung của bạn tại đường dẫn phía thượng lưu, làm điều đó, và dọn dẹp sau:

cp config config.example 
git checkout -p upstream config.example 
mv config.example config 
git checkout @ config.example 

đó sẽ giúp bạn có được sự lựa chọn hunk hai diff từ git add --patch.

0

Để diff chỉ config.example trong repo địa phương của bạn với các tập tin tương ứng trong upstream/HEAD bạn có thể chạy:

git diff upstream/HEAD config.example 

Đáng tiếc là tôi không biết một cách để làm cho git trực tiếp áp dụng các thay đổi cho một tập tin mà git không theo dõi.

+0

vâng, tôi biết cách tìm khác biệt, nhưng bây giờ tương tác áp dụng cho 'config' là câu hỏi thực tế của tôi: -/ –

+0

Bạn đã thử sao chép tệp cấu hình đã cập nhật của mình qua config.example, kiểm tra điều đó bằng cách sử dụng tiêu chuẩn của bạn công cụ để hợp nhất từ ​​nguồn gốc, sau đó di chuyển nó trở lại cấu hình và đặt lại trước khi bạn cam kết thay đổi thành config.example? Nếu các tập tin không quá đồng bộ, bạn sẽ nhận được ít nhất một số trợ giúp sáp nhập chỉ là những gì đã thay đổi. – 1337joe

0

a tool called sdiff có thể làm những gì bạn muốn.

Gọi nó (trong trường hợp của bạn) với sdiff -o config config.example config

2
  • Bạn có thể sử dụng vim như một công cụ hợp nhất với vimdiff.
  • Emacs cũng có thể thực hiện việc này với ediff-mode.
0

Sau đây nên làm việc:

git diff <some-args> | perl -pe 's/path\/to\/changes\/file/path\/other/g' > t 
patch -p1 < t 
rm t 
1

Nếu bạn muốn git merge đầy đủ, bạn có thể nhận được git để làm điều đó với nội dung tùy ý bằng cách thiết lập một mục từ như git read-tree làm và sau đó gọi git bình thường hợp nhất trình điều khiển trên chỉ mục đó. Git đề cập đến các phiên bản nội dung khác nhau là "giai đoạn"; chúng là 1: bản gốc, 2: của bạn, 3: của chúng. Hợp nhất so sánh các thay đổi từ 1 đến 2 và từ 1 đến 3 và thực hiện điều đó. Để thiết lập, hãy sử dụng git update-index:

orig_example=  # fill in the commit with the config.example you based yours on 
new_upstream=  # fill in the name of the upstream branch 

(while read; do printf "%s %s %s\t%s\n" $REPLY; done \ 
| git update-index --index-info) <<EOD 
100644 $(git rev-parse $orig_example:config.example) 1 config 
100644 $(git hash-object -w config)     2 config 
100644 $(git rev-parse $new_upstream:config.example) 3 config 
EOD 

và bạn đã tổ chức hợp nhất nội dung tùy chỉnh cho đường dẫn đó. Bây giờ làm điều đó:

git merge-index git-merge-one-file -- config 

và nó sẽ hoặc là automerge hoặc rời khỏi phân xung đột thông thường, sửa chữa nó lên theo ý muốn và git rm --cached --ignore-unmatch (hoặc giữ) các chỉ mục nếu bạn muốn.

Tên đường dẫn bạn đặt trong chỉ mục ("cấu hình" trong cả ba mục ở đây), nhân tiện, không phải tồn tại hoặc có liên quan đến bất kỳ thứ gì. Bạn có thể đặt tên là "wip" hoặc "deleteme" hoặc bất kỳ thứ gì bạn muốn. Hợp nhất là id nội dung trong mục nhập chỉ mục.

Tôi nghĩ điều đó có khả năng làm những gì bạn muốn ở đây. Nếu bạn thực sự muốn chọn và chọn từ các thay đổi ngược dòng, bạn có thể đặt nội dung của riêng bạn tại cấu hình.ví dụ và làm git checkout -p upstream -- config.example, điều đó làm ngược lại của git add -p, sau đó đặt mọi thứ ngược lại theo cách của chúng.

+0

Tôi chủ yếu thích câu trả lời này cho đoạn cuối cùng của nó (phần còn lại có vẻ hơi quá giống với ma thuật đen đối với tôi). Với ý tưởng từ đoạn cuối, tôi chỉ có thể làm 'cp config config.example; git checkout -p upstream - config.ví dụ' sau đó tương tác quyết định cách hợp nhất các thay đổi và cuối cùng chạy 'mv config.example config && git reset config.example && git checkout - config.example' để đặt mọi thứ trở lại. Nếu bạn chia đoạn cuối thành một câu trả lời riêng biệt, tôi sẽ chấp nhận nó cho sự rõ ràng và đơn giản của nó. –

+1

OK, xong. Cảm ơn. – jthill

2

Bạn có thể tiếp cận vấn đề này theo nhiều cách. Tôi có thể nghĩ về hai: git-merge-file và cũ tốt patch. Phương pháp git-merge-file cung cấp một số tương tác, trong khi phương pháp patch không cung cấp.

Giải pháp với git-merge-file

phép nói rằng bạn có một tập tin gốc config.example mà bạn sử dụng để tạo ra một tập tin không phiên bản địa phương, config.local. Bây giờ khi cập nhật ngược dòng config.example, bạn có thể thực hiện theo một số bước như sau để hợp nhất bất kỳ thay đổi mới nào.

$ git fetch 
$ git show master:config.example > config.example.base 
$ git show origin/master:config.example > config.example.latest 
$ git merge-file config.local config.example.base config.example.latest 

này sẽ cập nhật config.local với các dấu hiệu xung đột thông thường, sau đó bạn sẽ phải giải quyết với công cụ hợp nhất mà bạn yêu thích (ediff trong Emacs là tốt đẹp, tôi chắc chắn rằng có những phương thức tương tự cho Vim). Ví dụ, ba tập tin sau đây,

config.example.base:

Original: 
      some config 

config.example.latest:

Original: 
      some config 

Upstream: 
      new upstream config 

config.local:

Original: 
      some config 

My changes: 
      some other config 

sẽ được sáp nhập như thế này:

Original: 
      some config 

<<<<<<< config.local 
My changes: 
      some other config 
======= 
Upstream: 
      new upstream config 
>>>>>>> config.example.latest 

Bạn có thể có lẽ kịch bản này mà không cần nhiều nỗ lực. Btw, git-merge-file có thể hoạt động trên bất kỳ 3 tệp nào, chúng không cần phải được kiểm soát phiên bản theo git. Điều đó có nghĩa là người ta có thể sử dụng nó để hợp nhất bất kỳ ba tập tin nào!

Giải pháp với patch:

Giả sử tên cùng một tập tin, config.localconfig.example, sau đây nên làm việc.

$ git fetch 
$ git diff master..origin/master -- config.example | sed -e 's%\(^[-+]\{3\}\) .\+%\1 config.local%g' > /tmp/mypatch 
$ patch < /tmp/mypatch 
+0

Tôi thích câu trả lời này cho 3-cách-hợp nhất, nhưng thật đáng buồn nó không phải ở tất cả các tương tác như 'git add -p', có nghĩa là tôi không thể thực sự xem xét các tùy chọn cấu hình mới. Nó có upvote của tôi tuy nhiên, vì đây có thể là cách để đi cho người khác. –

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