จะเลือกผสานหรือรับการเปลี่ยนแปลงจากสาขาอื่นใน Git ได้อย่างไร?


1450

ฉันใช้คอมไพล์ในโครงการใหม่ที่มีสองขนานกัน แต่ปัจจุบันกำลังทำการทดลอง - สาขาการพัฒนา:

  • master: นำเข้า codebase ที่มีอยู่บวกกับ mods เล็กน้อยที่โดยทั่วไปฉันแน่ใจ
  • exp1: สาขาทดลอง # 1
  • exp2: สาขาทดลอง # 2

exp1และexp2เป็นตัวแทนของสองแนวทางสถาปัตยกรรมที่แตกต่างกันมาก จนกว่าฉันจะไปได้ไกลกว่านั้นฉันก็ไม่รู้ว่าจะใช้อันไหน (ถ้ามี) เมื่อฉันก้าวหน้าในสาขาหนึ่งบางครั้งฉันก็มีการแก้ไขที่จะเป็นประโยชน์ในสาขาอื่นและต้องการที่จะรวมเฉพาะที่

วิธีที่ดีที่สุดในการรวมการเปลี่ยนแปลงแบบเลือกจากสาขาการพัฒนาหนึ่งไปยังอีกสาขาหนึ่งคืออะไรในขณะที่ทิ้งทุกอย่างอื่นไว้

แนวทางที่ฉันได้พิจารณา:

  1. git merge --no-commit ตามด้วย unstaging ด้วยตนเองของการแก้ไขจำนวนมากที่ฉันไม่ต้องการทำร่วมกันระหว่างสาขา

  2. การคัดลอกไฟล์ทั่วไปด้วยตนเองไปยังไดเรกทอรีชั่วคราวแล้วgit checkoutย้ายไปที่สาขาอื่นจากนั้นคัดลอกออกจากไดเรกทอรีชั่วคราวด้วยตนเองไปยังแผนผังการทำงาน

  3. ความแปรปรวนด้านบน ยกเลิกexpสาขาในตอนนี้และใช้ที่เก็บข้อมูลเพิ่มเติมในพื้นที่สองแห่งสำหรับการทดลอง ทำให้การคัดลอกไฟล์ด้วยตนเองทำได้ง่ายขึ้น

ทั้งสามวิธีการเหล่านี้ดูเหมือนน่าเบื่อและผิดพลาดได้ง่าย ฉันหวังว่าจะมีวิธีการที่ดีกว่า สิ่งที่คล้ายกับพารามิเตอร์พา ธ ตัวกรองที่จะทำให้git-mergeเลือกได้มากกว่า


5
หากมีการเปลี่ยนแปลงในสาขาการทดลองของคุณมีการจัดดีในการกระทำที่แยกจากกันจะดีกว่าที่จะคิดในแง่ของการรวมเลือกกระทำแทนการเลือกไฟล์ คำตอบส่วนใหญ่ด้านล่างถือว่าเป็นกรณีนี้
akaihola

2
การรวมกันของgit merge -s ours --no-commitบางคนgit read-treeจะไม่เป็นทางออกที่ดีสำหรับเรื่องนี้? ดูstackoverflow.com/questions/1214906/…
VonC

34
คำถามล่าสุดมีคำตอบหนึ่งบรรทัดเขียนดี: stackoverflow.com/questions/10784523/…
brahn

ชำระเงินบล็อกนี้สำหรับการรวมไฟล์เฉพาะjasonrudolph.com/blog/2009/02/25/…
Ashutosh Chamoli

คำตอบ:


475

คุณใช้คำสั่งcherry-pickเพื่อรับค่าคอมมิตจากแต่ละสาขา

หากมีการเปลี่ยนแปลง (s) ที่คุณต้องการไม่ได้อยู่ในกระทำของแต่ละบุคคลแล้วใช้วิธีการที่แสดงที่นี่เพื่อแยกการกระทำเข้ากระทำของแต่ละบุคคล การพูดโดยประมาณคุณใช้git rebase -iเพื่อให้ได้คอมมิตดั้งเดิมเพื่อแก้ไขจากนั้นgit reset HEAD^เลือกที่จะยกเลิกการเปลี่ยนแปลงจากนั้นเลือกที่git commitจะคอมมิตบิตนั้นเป็นคอมมิชชันใหม่ในประวัติศาสตร์

มีอีกวิธีที่ดีที่นี่ในนิตยสาร Red Hat ที่พวกเขาใช้git add --patchหรือเป็นไปได้git add --interactiveที่ช่วยให้คุณเพิ่มเพียงบางส่วนของก้อนใหญ่ถ้าคุณต้องการที่จะแยกการเปลี่ยนแปลงที่แตกต่างกันในแต่ละไฟล์ (ค้นหาในหน้านั้นสำหรับ "แยก")

เมื่อแยกการเปลี่ยนแปลงแล้วตอนนี้คุณสามารถเลือกเฉพาะสิ่งที่คุณต้องการได้


14
จากความเข้าใจของฉันนี่เป็นสิ่งที่ซับซ้อนกว่าคำตอบที่ได้รับการโหวตสูงกว่าโดยไม่จำเป็น
Alexander Bird

54
นี่คือเทคนิคคำตอบที่ถูกต้องคำตอบที่ถูกต้องจะปรากฏ "convoluted" --- คำตอบที่ได้รับการโหวตมากขึ้นเป็นเพียงคำตอบที่ "สกปรก" ซึ่งรวดเร็วและสกปรกซึ่งสำหรับคนส่วนใหญ่คือทั้งหมดที่พวกเขามีอยู่ (:
Jacob

3
@akaihola: HEAD ^ ถูกต้อง ดู man git-rev-parse: คำต่อท้าย ^ ถึงพารามิเตอร์ revision หมายถึงพาเรนต์แรกของการคอมมิทวัตถุนั้น คำนำหน้า ^ สัญกรณ์จะใช้ในการแยกการกระทำที่สามารถเข้าถึงได้จากการกระทำ
ไทเลอร์ริค

13
ฉันแค่อยากจะแบ่งปันวิธีการอื่นซึ่งดูเหมือนว่าจะสะอาดและน่าเชื่อถือน้อยที่สุดของพวกเขาทั้งหมด: jasonrudolph.com/blog/2009/02/25/…ความเรียบง่ายและน่าประทับใจโดยรวม
superuseroi

14
สับสนโดยการอภิปรายว่าวิธีการใดที่ 'ถูกต้อง'? พิจารณาความแตกต่างระหว่างไฟล์และกระทำ (ดูข้อสังเกตที่ด้านล่าง) OP ต้องการรวมไฟล์ & ไม่พูดถึงคอมมิชชัน คำตอบที่ได้รับการโหวตสูงกว่านั้นเฉพาะไฟล์ คำตอบที่ได้รับการยอมรับจะใช้ cherry-pick ซึ่งเฉพาะเจาะจงกับการกระทำ Cherry-pick อาจเป็นกุญแจสำคัญในการรวมการกระทำที่เลือกสรร แต่อาจเจ็บปวดมากสำหรับการย้ายไฟล์จากสาขาหนึ่งไปอีกสาขาหนึ่ง แม้ว่าความมุ่งมั่นเป็นหัวใจของความแข็งแกร่งของคอมไพล์ แต่อย่าลืมว่าไฟล์ยังคงมีบทบาท!
Kay V

970

ฉันมีปัญหาเดียวกันตามที่คุณกล่าวไว้ข้างต้น แต่ฉันพบนี้ที่ชัดเจนในการอธิบายคำตอบ

สรุป:

  • ชำระเงินเส้นทางจากสาขาที่คุณต้องการผสาน

    $ git checkout source_branch -- <paths>...
    

    คำแนะนำ: มันใช้งานได้โดยไม่--เหมือนที่เห็นในโพสต์ที่เชื่อมโยง

  • หรือเลือกผสานการล่าสัตว์

    $ git checkout -p source_branch -- <paths>...
    

    อีกวิธีหนึ่งคือการใช้การตั้งค่าแล้วเพิ่มที่มีตัวเลือก-p,

    $ git reset <paths>...
    $ git add -p <paths>...
    
  • ในที่สุดก็กระทำ

    $ git commit -m "'Merge' these changes"
    

9
บทความที่เชื่อมโยงของ Bart J เป็นวิธีที่ดีที่สุด ชัดเจนง่ายคำสั่งเดียว มันเป็นสิ่งที่ฉันจะใช้ :)
Pistos

256
นี่ไม่ใช่การผสานที่แท้จริง คุณกำลังเลือกการเปลี่ยนแปลงตามไฟล์แทนที่จะส่งและคุณจะสูญเสียข้อมูลการกระทำที่มีอยู่ (ผู้เขียนข้อความ) ได้รับสิ่งนี้เป็นสิ่งที่ดีถ้าคุณต้องการรวมการเปลี่ยนแปลงทั้งหมดในบางไฟล์และมันก็โอเคที่คุณจะต้องทำใหม่ทั้งหมด แต่ถ้าไฟล์มีทั้งการเปลี่ยนแปลงที่จะผสานและอื่น ๆ ที่จะละทิ้งหนึ่งในวิธีการที่ให้ไว้ในคำตอบอื่น ๆ จะให้บริการคุณดีขึ้น
akaihola

10
@mykhal และคนอื่น ๆ : ขั้นตอนนี้จะทำให้ไฟล์ในดัชนีโดยอัตโนมัติดังนั้นหากคุณชำระเงินแล้วให้เลิกfoo.cทำgit reset HEAD foo.cขั้นตอนที่ไฟล์นั้นและคุณสามารถกระจายมันได้ ฉันพบสิ่งนี้หลังจากลองแล้วกลับมาที่นี่เพื่อหาคำตอบสำหรับเรื่องนี้
michiakig

12
เพื่อดูการเปลี่ยนแปลงที่คุณสามารถใช้:git diff --cached
OderWat

9
ตามคำตอบ นี้git checkout -p <revision> -- <path>จะเหมือนกับการออกคำสั่งสามคำสั่งแรกที่คุณอธิบาย :)
7hi4g0

338

ในการเลือกรวมไฟล์จากสาขาหนึ่งเข้ากับสาขาอื่นให้เรียกใช้

git merge --no-ff --no-commit branchX

ซึ่งbranchXเป็นสาขาที่คุณต้องการผสานเข้าจากสาขาในปัจจุบัน

--no-commitตัวเลือกที่จะเวทีไฟล์ที่ได้รับการควบรวมกิจการโดย Git ไม่จริงพวกเขากระทำ นี่จะทำให้คุณมีโอกาสที่จะแก้ไขไฟล์ที่ถูกผสานอย่างไรก็ตามคุณต้องการและคอมมิทด้วยตัวคุณเอง

ขึ้นอยู่กับว่าคุณต้องการรวมไฟล์อย่างไรมีสี่กรณี:

1) คุณต้องการผสานที่แท้จริง

ในกรณีนี้คุณยอมรับไฟล์ที่ถูกผสานในลักษณะที่ Git รวมเข้าด้วยกันโดยอัตโนมัติ

2) มีไฟล์บางไฟล์ที่คุณไม่ต้องการรวม

ตัวอย่างเช่นคุณต้องการเก็บเวอร์ชันไว้ในสาขาปัจจุบันและไม่ต้องสนใจเวอร์ชันในสาขาที่คุณกำลังผสาน

หากต้องการเลือกเวอร์ชันในสาขาปัจจุบันให้รัน:

git checkout HEAD file1

สิ่งนี้จะดึงเวอร์ชันของfile1ในสาขาปัจจุบันและเขียนทับfile1automerged โดย Git

3) ถ้าคุณต้องการรุ่นใน branchX (และไม่ใช่ผสานจริง)

วิ่ง:

git checkout branchX file1

นี้จะเรียกรุ่นของfile1ในbranchXและเขียนทับfile1อัตโนมัติรวมโดย Git

4) file1กรณีสุดท้ายคือถ้าคุณต้องการที่จะเลือกการผสานเพียงเฉพาะใน

ในกรณีนี้คุณสามารถแก้ไขการแก้ไขfile1โดยตรงอัปเดตเป็นอะไรก็ได้ที่คุณต้องการให้เวอร์ชันfile1กลายเป็นแล้วคอมมิท

หาก Git ไม่สามารถรวมไฟล์โดยอัตโนมัติไฟล์นั้นจะรายงานว่าเป็น " unmerged " และสร้างสำเนาที่คุณจะต้องแก้ไขข้อขัดแย้งด้วยตนเอง



หากต้องการอธิบายเพิ่มเติมเกี่ยวกับตัวอย่างสมมติว่าคุณต้องการรวมbranchXเข้ากับสาขาปัจจุบัน:

git merge --no-ff --no-commit branchX

จากนั้นคุณเรียกใช้git statusคำสั่งเพื่อดูสถานะของไฟล์ที่แก้ไข

ตัวอย่างเช่น:

git status

# On branch master
# Changes to be committed:
#
#       modified:   file1
#       modified:   file2
#       modified:   file3
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      file4
#

ที่ไหนfile1, file2และfile3เป็นไฟล์ที่คอมไพล์ได้ประสบความสำเร็จอัตโนมัติรวม

สิ่งนี้หมายความว่าการเปลี่ยนแปลงในmasterและbranchXสำหรับทั้งสามไฟล์นั้นได้ถูกรวมเข้าด้วยกันโดยไม่มีข้อขัดแย้ง

คุณสามารถตรวจสอบวิธีการผสานที่ได้กระทำโดยการทำงานgit diff --cached;

git diff --cached file1
git diff --cached file2
git diff --cached file3

หากคุณพบว่าการรวมที่ไม่พึงประสงค์บางอย่างนั้นคุณทำได้

  1. แก้ไขไฟล์โดยตรง
  2. บันทึก
  3. git commit

หากคุณไม่ต้องการผสานfile1และต้องการเก็บเวอร์ชันไว้ในสาขาปัจจุบัน

วิ่ง

git checkout HEAD file1

หากคุณไม่ต้องการที่จะผสานfile2และต้องการรุ่นเท่านั้นbranchX

วิ่ง

git checkout branchX file2

หากคุณต้องการfile3ถูกผสานโดยอัตโนมัติอย่าทำอะไรเลย

Git ได้รวมตอนนี้


file4ด้านบนเป็นการรวมที่ล้มเหลวโดย Git ซึ่งหมายความว่ามีการเปลี่ยนแปลงทั้งสองสาขาที่เกิดขึ้นในบรรทัดเดียวกัน ที่นี่คุณจะต้องแก้ไขข้อขัดแย้งด้วยตนเอง คุณสามารถยกเลิกการผสานที่ทำได้โดยแก้ไขไฟล์โดยตรงหรือรันคำสั่งเช็คเอาต์สำหรับเวอร์ชันในสาขาที่คุณต้องการfile4เป็น


git commitสุดท้ายอย่าลืมให้


10
ระวังแม้ว่า: ถ้าgit merge --no-commit branchXเป็นเพียงการกรอไปข้างหน้าตัวชี้จะได้รับการอัปเดตและ --no-commit จะถูกเพิกเฉยดังนั้น
cfi

16
@cfi การเพิ่ม--no-ffเพื่อป้องกันพฤติกรรมนั้นเป็นอย่างไร
Eduardo Costa

5
ฉันแนะนำให้อัพเดทคำตอบนี้ด้วยตัวเลือก "--no-ff" ของ Eduardo ฉันอ่านทุกอย่าง (ซึ่งยอดเยี่ยมมาก) เพื่อให้การผสานของฉันได้รับการส่งต่ออย่างรวดเร็ว
Funktr0n

7
โซลูชันนี้ให้ผลลัพธ์ที่ดีที่สุดและมีความยืดหยุ่น
Thiago Macedo

20
ต่างจากคำตอบที่ได้รับการโหวตมากที่สุดวิธีนี้รักษาประวัติการผสานของฉันไว้ซึ่งสำคัญสำหรับฉันเมื่อฉันสานส่วนหนึ่งไปมาข้ามสาขา ฉันไม่ได้ลองวิธีแก้ปัญหาที่แนะนำอื่น ๆ ทั้งหมดดังนั้นบางคนก็ทำเช่นนี้เช่นกัน
ws_e_c421

107

ฉันไม่ชอบวิธีการข้างต้น การใช้ cherry-pick นั้นยอดเยี่ยมสำหรับการเลือกการเปลี่ยนแปลงเดี่ยว แต่มันเป็นความเจ็บปวดถ้าคุณต้องการนำการเปลี่ยนแปลงทั้งหมดยกเว้นการเปลี่ยนแปลงที่ไม่ดี นี่คือแนวทางของฉัน

ไม่มี--interactiveข้อโต้แย้งใด ๆ ที่คุณสามารถส่งไปยังคอมไพล์ผสาน

นี่คือทางเลือก:

คุณมีการเปลี่ยนแปลงบางอย่างใน 'ฟีเจอร์' ของสาขาและคุณต้องการนำบางส่วน แต่ไม่ทั้งหมดไปยัง 'มาสเตอร์' ในแบบที่ไม่เลอะเทอะ (เช่นคุณไม่ต้องการให้เชอร์รี่เลือกและกระทำแต่ละอัน)

git checkout feature
git checkout -b temp
git rebase -i master

# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change

# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

git checkout master
git pull . temp
git branch -d temp

ดังนั้นเพียงแค่ห่อมันในเชลล์สคริปต์เปลี่ยน master เป็น $ to และเปลี่ยนคุณสมบัติเป็น $ from และคุณพร้อมที่จะไป:

#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp

ฉันแก้ไขการจัดรูปแบบ - นี่เป็นวิธีที่ดีทีเดียวหากคุณต้องการเลือกคอมมิชชัน
ข้อมูล 1800

ฉันใช้เทคนิคนี้ในตอนนี้และดูเหมือนว่าจะทำงานได้ดีจริงๆ
dylanfm

4
คุณอาจต้องการเปลี่ยนgit rebase -i $toเป็นgit rebase -i $to || $SHELLเพื่อให้ผู้ใช้สามารถโทรgit --skipฯลฯ ได้ตามความจำเป็นหากการรีบูทล้มเหลว นอกจากนี้ยังควรผูกสายไว้ด้วยกัน&&แทนที่จะเป็นบรรทัดใหม่
sircolinton

2
น่าเสียดายที่ลิงค์ในคำตอบนั้นปรากฏขึ้น
ThomasW

ไม่เพียง แต่ลิงค์จะตาย แต่มันยังมีคำเตือนเรื่องชื่อเสียงที่แย่ ดังนั้นฉันจึงลบมัน
Jean-François Corbett

93

มีอีกวิธีที่จะไป:

git checkout -p

มันเป็นการผสมผสานระหว่างgit checkoutและgit add -pและอาจเป็นสิ่งที่คุณกำลังมองหา:

   -p, --patch
       Interactively select hunks in the difference between the <tree-ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree-ish> was specified, the index).

       This means that you can use git checkout -p to selectively discard
       edits from your current working tree. See the “Interactive Mode”
       section of git-add(1) to learn how to operate the --patch mode.

10
นี่เป็นวิธีที่ง่ายที่สุดและง่ายที่สุดตราบใดที่คุณมีการเปลี่ยนแปลงจำนวนที่จัดการได้เพื่อผสานเข้าด้วยกันฉันหวังว่าผู้คนจำนวนมากจะสังเกตเห็นคำตอบนี้และโหวตขึ้น ตัวอย่าง: git checkout --patch exp1 file_to_merge
Tyler Rick

1
คำตอบที่คล้ายกันโพสต์ในคำถามนี้: stackoverflow.com/a/11593308/47185
Tyler Rick

โอ้ฉันไม่ทราบว่าการชำระเงินมีการแก้ไข! ฉันเช็คเอาต์ / รีเซ็ต / เพิ่ม -p แทน
Daniel C. Sobral

2
เป็นวิธีที่ง่ายที่สุด git checkout -p ชื่อไฟล์ของคุณลักษณะ และสิ่งที่ดีที่สุดคือเมื่อรันคำสั่งมันจะให้ ay / n / e /? / ... ฯลฯ ตัวเลือกเพื่อตัดสินใจว่าจะรวมไฟล์อย่างไร ฉันลองกับ e และฉันสามารถแก้ไขแพตช์ก่อนที่จะใช้ ... มันเจ๋งแค่ไหน สายการบินหนึ่งที่แท้จริงสำหรับการรวมไฟล์ที่เลือกจากสาขาอื่น
infoclogged

55

ในขณะที่คำตอบเหล่านี้ค่อนข้างดีฉันรู้สึกเหมือนไม่มีใครตอบข้อ จำกัด ดั้งเดิมของ OP: การเลือกไฟล์เฉพาะจากสาขาเฉพาะ วิธีนี้แก้ไขได้ แต่อาจน่าเบื่อหากมีไฟล์จำนวนมาก

ช่วยบอกว่าคุณมีmaster, exp1และexp2สาขา คุณต้องการรวมไฟล์หนึ่งไฟล์จากแต่ละสาขาทดลองไปยังต้นแบบ ฉันจะทำสิ่งนี้:

git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b

# save these files as a stash
git stash
# merge stash with master
git merge stash

สิ่งนี้จะทำให้คุณแตกต่างในไฟล์สำหรับแต่ละไฟล์ที่คุณต้องการ ไม่มีอะไรเพิ่มเติม ไม่มีอะไรน้อย มีประโยชน์ที่คุณจะเปลี่ยนไฟล์ต่างกันอย่างสิ้นเชิงระหว่างเวอร์ชั่น - ในกรณีของฉันการเปลี่ยนแอพจาก Rails 2 เป็น Rails 3

แก้ไข : นี่จะรวมไฟล์ แต่จะรวมเข้าด้วยกัน ฉันไม่สามารถหาวิธีใช้วิธีการนี้เพื่อรับข้อมูล diff ในไฟล์ (อาจจะยังคงมีความแตกต่างอย่างมากน่ารำคาญสิ่งเล็ก ๆ น้อย ๆ เช่นช่องว่างได้รวมกลับเข้ามาเว้นแต่คุณจะใช้-s recursive -X ignore-all-spaceตัวเลือก)


4
หมายเหตุ: คุณสามารถทำไฟล์หลายไฟล์จากสาขาที่กำหนดทั้งหมดแบบอินไลน์เช่นgit checkout exp1 path/to/file_a path/to/file_x
EMiller

2
นี่คือสิ่งที่สวยงาม ฉันได้git checkout feature <path>/*รับกลุ่มของไฟล์
isherwood

ใช้งานได้ แต่เพิ่มวัตถุกระทำพิเศษสองรายการ ไม่ใช่เรื่องใหญ่โต แต่ยุ่งนิดหน่อย
MightyPork

@MightyPork คุณพูดถูก น่าเสียดายที่ตั้งแต่ฉันเขียนมานานแล้วฉันไม่แน่ใจว่าทำไมขั้นตอน "git stash" และ "git merge stash" อยู่ในนั้นแทนที่จะเป็น "git commit"
Eric Hu

2
โอ้นั่นชัดเจนฉันคิดว่า วิธีนี้จะรวมไฟล์เดียวไม่จำเป็นต้องเขียนทับการเปลี่ยนแปลงก่อนหน้านี้ในสาขาเป้าหมาย
MightyPork

48

คำตอบของข้อมูล 1800 ถูกต้องสมบูรณ์ ในฐานะที่เป็น noob คอมไพล์ "ใช้ git cherry-pick" ไม่เพียงพอสำหรับฉันที่จะคิดออกโดยไม่ต้องขุดบนอินเทอร์เน็ตอีกเล็กน้อยดังนั้นฉันคิดว่าฉันจะโพสต์คำแนะนำรายละเอียดเพิ่มเติมในกรณีที่คนอื่นอยู่ใน เรือที่คล้ายกัน

กรณีการใช้งานของฉันคือต้องการที่จะเลือกดึงการเปลี่ยนแปลงจากสาขา github ของคนอื่นเป็นของฉันเอง หากคุณมีสาขาในพื้นที่ที่มีการเปลี่ยนแปลงคุณต้องทำตามขั้นตอนที่ 2 และ 5-7

  1. สร้าง (ถ้าไม่ได้สร้าง) สาขาท้องถิ่นที่มีการเปลี่ยนแปลงที่คุณต้องการนำเข้า

    $ git branch mybranch <base branch>

  2. เปลี่ยนเป็นมัน

    $ git checkout mybranch

  3. ดึงการเปลี่ยนแปลงที่คุณต้องการจากบัญชีของบุคคลอื่น หากคุณยังไม่ได้เพิ่มคุณต้องการเพิ่มพวกเขาเป็นรีโมท

    $ git remote add repos-w-changes <git url>

  4. ดึงทุกอย่างจากสาขาของพวกเขา

    $ git pull repos-w-changes branch-i-want

  5. ดูบันทึกการกระทำเพื่อดูการเปลี่ยนแปลงที่คุณต้องการ:

    $ git log

  6. สลับกลับไปที่สาขาที่คุณต้องการดึงการเปลี่ยนแปลง

    $ git checkout originalbranch

  7. เชอร์รี่เลือกการกระทำของคุณทีละคนด้วยแฮช

    $ git cherry-pick -x hash-of-commit

เคล็ดลับหมวก: http://www.sourcemage.org/Git_Guide


3
เคล็ดลับ: ใช้git cherryคำสั่งก่อน (ดูด้วยตนเองก่อน) เพื่อระบุการกระทำที่คุณยังไม่ได้ผสาน
akaihola

งานนี้ .. 1. สร้างสาขาใหม่ 2. สร้างบางไฟล์ / ทำการเปลี่ยนแปลงบางอย่าง 3. ส่ง 4. ชำระเงินที่สาขาหลัก 5. เรียกใช้ git cherry-pick -x hash-of-commit และแก้ไขข้อขัดแย้งในการผสานคุณดี ไป.
RamPrasadBismil

ลิงก์ของคุณไม่ทำงานอีกต่อไป คุณช่วยอัพเดทได้มั้ย
creep3007

42

นี่คือวิธีที่คุณสามารถแทนที่Myclass.javaไฟล์ในmasterสาขาด้วยMyclass.javaในfeature1สาขา มันจะทำงานแม้ว่าไม่ได้อยู่ในMyclass.javamaster

git checkout master
git checkout feature1 Myclass.java

หมายเหตุสิ่งนี้จะเขียนทับ - ไม่รวม - และไม่สนใจการเปลี่ยนแปลงในเครื่องในสาขาหลักแทน


6
สิ่งนี้จะไม่รวม มันจะเขียนทับการเปลี่ยนแปลงของมาสเตอร์ด้วยการเปลี่ยนแปลงจากฟีเจอร์ 1
Skunkwaffle

3
อย่างสมบูรณ์แบบฉันกำลังมองหาการรวมชนิดนี้ที่theirsเขียนทับours=> +1 ไชโย;)
โอลิเบอร์

1
บางครั้งสิ่งที่คุณต้องทำคือแทนที่ไฟล์ทั้งหมดดังนั้นนี่คือสิ่งที่ฉันต้องการ แต่คุณต้องแน่ใจว่าคุณต้องการสูญเสียการเปลี่ยนแปลงทั้งหมดที่คุณทำกับไฟล์นี้
MagicLAMP

1
วิธีการแก้ปัญหาที่สะอาดที่สุดเนื่องจาก OP ต้องการเปลี่ยนไฟล์ทั้งหมดโดยเทียบเท่ากับสาขาอื่น:2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
Brent Faust

29

วิธีง่ายๆในการรวมไฟล์จากสองสาขาเข้าด้วยกันไม่ใช่แค่แทนที่ไฟล์เฉพาะกับไฟล์จากสาขาอื่น

ขั้นตอนที่หนึ่ง: แตกกิ่งก้านสาขา

git diff branch_b > my_patch_file.patch

สร้างไฟล์แพตช์ของความแตกต่างระหว่างสาขาปัจจุบันและ branch_b

ขั้นตอนที่สอง: ใช้โปรแกรมปะแก้กับไฟล์ที่ตรงกับรูปแบบ

git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch

บันทึกที่มีประโยชน์เกี่ยวกับตัวเลือก

คุณสามารถใช้*เป็นสัญลักษณ์แทนในรูปแบบรวม

สแลชไม่จำเป็นต้องหลบหนี

นอกจากนี้คุณสามารถใช้ - ยกเว้นและนำไปใช้กับทุกสิ่งยกเว้นไฟล์ที่ตรงกับรูปแบบหรือย้อนกลับโปรแกรมแก้ไขด้วย -R

ตัวเลือก -p1 เป็นโฮลด์จากคำสั่ง * unix patch และความจริงที่ว่าเนื้อหาของไฟล์แพตช์เป็นการเตรียมชื่อไฟล์แต่ละชื่อด้วยa/หรือb/(หรือมากกว่านั้นขึ้นอยู่กับวิธีสร้างไฟล์แพทช์) ซึ่งคุณต้องดึงเพื่อให้สามารถเข้าใจได้ ไฟล์จริงไปยังพา ธ ไปยังไฟล์ที่แพตช์จำเป็นต้องใช้

ตรวจสอบหน้า man สำหรับ git-Apply สำหรับตัวเลือกเพิ่มเติม

ขั้นตอนที่สาม: ไม่มีขั้นตอนที่สาม

เห็นได้ชัดว่าคุณต้องการที่จะยอมรับการเปลี่ยนแปลงของคุณ แต่ใครจะบอกว่าคุณไม่มีการปรับแต่งที่เกี่ยวข้องอื่น ๆ ที่คุณต้องการทำก่อนที่จะทำการกระทำของคุณ


1
สิ่งนี้มีประโยชน์มากเมื่อ current_branch มีการเปลี่ยนแปลง "เพิ่มเติม" จำนวนมากซึ่งต้องได้รับการเก็บรักษาไว้ มีความแตกต่างเพียงการเปลี่ยนแปลงที่นำโดย branch_b เมื่อ: git diff HEAD ... branch_b (ใช่ - สามช่วงเวลาทำให้เวทมนต์)
ซาดมาลิก

@masukomi ในขั้นตอนที่ 2 คุณไม่ควรเพิ่มไฟล์แก้ไขที่สร้างในขั้นตอนที่ 1 เป็นอาร์กิวเมนต์หรือไม่
Spiralis

สำหรับฉันการเปลี่ยนแปลงทั้งหมดจะถูกปฏิเสธ มีความคิดอะไรไหม
LinusGeffarth

ตอนแรกคิดว่า @LinusGeffarth เป็นไปได้ไหมว่าบางทีคุณอาจได้สาขากลับมาตอนที่ทำแพทช์? จะติดตามด้านนอกของ SO เพื่อดูว่าเราจะเข้าใจได้ไหม
masukomi

24

นี่คือวิธีที่คุณจะได้รับประวัติเพื่อติดตามไฟล์เพียงสองสามไฟล์จากสาขาอื่นด้วยความยุ่งยากขั้นต่ำแม้ว่าการผสาน "แบบง่าย" จะทำให้เกิดการเปลี่ยนแปลงมากกว่าที่คุณไม่ต้องการ

ขั้นแรกคุณจะใช้ขั้นตอนที่ผิดปกติในการประกาศล่วงหน้าว่าสิ่งที่คุณกำลังจะคอมมิทคือการผสานโดยไม่ต้องคอมไพล์ทำอะไรกับไฟล์ในไดเรกทอรีการทำงานของคุณเลย:

git merge --no-ff --no-commit -s ours branchname1

. . . โดยที่ "branchname" คือสิ่งที่คุณอ้างว่าได้รับการรวมเข้าด้วยกัน ถ้าคุณต้องทำทันทีมันจะไม่เปลี่ยนแปลง แต่มันจะยังแสดงบรรพบุรุษจากสาขาอื่น คุณสามารถเพิ่มสาขา / แท็ก / ฯลฯ เพิ่มเติมได้ ไปยังบรรทัดคำสั่งหากคุณต้องการเช่นกัน ถึงจุดนี้แม้ว่าจะไม่มีการเปลี่ยนแปลงใด ๆ ที่จะส่งผลให้ได้รับไฟล์จากการแก้ไขอื่น ๆ ต่อไป

git checkout branchname1 -- file1 file2 etc

หากคุณรวมสาขามากกว่าหนึ่งสาขาให้ทำซ้ำตามต้องการ

git checkout branchname2 -- file3 file4 etc

ตอนนี้ไฟล์จากสาขาอื่นอยู่ในดัชนีพร้อมที่จะคอมมิทพร้อมประวัติ

git commit

และคุณจะมีคำอธิบายมากมายที่ต้องทำในข้อความยืนยัน

โปรดทราบว่าในกรณีที่ยังไม่ชัดเจนว่าสิ่งนี้เกิดขึ้น มันไม่ได้อยู่ในจิตวิญญาณของสิ่งที่ "สาขา" สำหรับและเชอร์รี่เลือกเป็นวิธีที่ซื่อสัตย์มากขึ้นในการทำสิ่งที่คุณจะทำที่นี่ หากคุณต้องการที่จะทำอีก "รวม" สำหรับไฟล์อื่น ๆ ในสาขาเดียวกันกับที่คุณไม่ได้นำมาใช้ครั้งล่าสุดมันจะหยุดคุณด้วยข้อความ "ทันสมัยแล้ว" มันเป็นอาการของการไม่แตกกิ่งเมื่อเราควรมีในสาขา "จาก" ควรมีมากกว่าหนึ่งกิ่งที่แตกต่างกัน


3
คำสั่งแรกของคุณ ( git merge --no-ff --no-commit -s outs branchname1) คือสิ่งที่ฉันกำลังมองหา! ขอบคุณ!
RobM

1
ด้วยสาขาที่หลากหลายจำเป็นต้องมีประวัติต้องผสานไฟล์เดียวและต้องเปลี่ยนเนื้อหาของไฟล์ก่อนที่จะทำการพุชนี่เป็นทางเลือกที่เหมาะสม ตัวอย่างเช่น dev => master แต่คุณต้องการเปลี่ยนข้อกำหนดของโฮสต์หรือสิ่งที่คล้ายกันก่อนที่จะพุชไปยัง master
timss

15

ฉันรู้ว่าฉันมาสายนิดหน่อย แต่นี่เป็นขั้นตอนการทำงานของฉันในการรวมไฟล์ที่เลือก

#make a new branch ( this will be temporary)
git checkout -b newbranch
# grab the changes 
git merge --no-commit  featurebranch
# unstage those changes
git reset HEAD
(you can now see the files from the merge are unstaged)
# now you can chose which files are to be merged.
git add -p
# remember to "git add" any new files you wish to keep
git commit

ฉันใช้รูปแบบเล็กน้อยกับสิ่งนี้ แทนที่จะผสมผสานฉันเลือกเชอร์รี่ มันทำงานได้ ข้อเสียเพียงอย่างเดียวของวิธีนี้คือคุณสูญเสียการอ้างอิงแฮชการส่งต้นฉบับ
แมตต์ฟลอเรนซ์

15

วิธีที่ง่ายที่สุดคือการตั้งค่า repo ของคุณให้เป็นสาขาที่คุณต้องการรวมกับเรียกใช้แล้ว

git checkout [branch with file] [path to file you would like to merge]

ถ้าคุณวิ่ง

git status

คุณจะเห็นไฟล์ที่จัดฉากแล้ว ...

จากนั้นเรียกใช้

git commit -m "Merge changes on '[branch]' to [file]"

ง่าย


3
นี่เป็นคำตอบที่ดีที่สุดที่ฉันพบ โปรดดูjasonrudolph.com/blog/2009/02/25/ … ชัดเจนกระชับและมันก็ใช้ได้!
superuseroi

1
ที่จะแทนที่เนื้อหาไฟล์ทั้งหมดจากสาขาต้นทางแทนที่จะรวมเข้าด้วยกัน
Amare

ฉันเพิ่งจะตอบแบบนี้ฉันคิดว่าฉันคิดค้นสิ่งใหม่ ๆ ที่ยังไม่ได้รับคำตอบ! แต่นี่เป็นวิธีที่ง่ายที่สุดที่จะทำ นี่ควรจะอยู่ด้านบน!
Irfandy Jip

15

ฉันพบโพสต์นี้เพื่อให้มีคำตอบที่ง่ายที่สุด เพียงทำ:

$ #git checkout <branch from which you want files> <file paths>

ตัวอย่าง:

$ #pulling .gitignore file from branchB into current branch
$ git checkout branchB .gitignore

ดูโพสต์สำหรับข้อมูลเพิ่มเติม


3
สิ่งนี้ไม่ได้ผสานจริงๆมันเขียนทับไฟล์ในสาขาปัจจุบัน
Igor Ralic

1
@igrali นั่นเป็นความคิดเห็นที่มีประโยชน์ แต่เมื่อเทียบกับความยากของวิธี "เหมาะสม" ในการทำเช่นนี้นี่เป็นวิธีแก้ปัญหาที่ดี เพียงแค่ต้องระวังให้มาก
owensmartin

12

มันแปลกที่คอมไพล์ยังไม่มีเครื่องมือที่สะดวก "ออกจากกล่อง" ฉันใช้มันอย่างหนักเมื่ออัปเดตสาขาเวอร์ชันเก่าบางแห่ง (ซึ่งยังมีผู้ใช้ซอฟต์แวร์จำนวนมาก) โดยเพียงแก้ไขบั๊กจากสาขาเวอร์ชันปัจจุบัน ในกรณีนี้บ่อยครั้งที่ต้องการรับโค้ดบางบรรทัดจากไฟล์ใน trunk อย่างรวดเร็วโดยไม่สนใจการเปลี่ยนแปลงอื่น ๆ มากมาย (ซึ่งไม่ควรจะเป็นเวอร์ชั่นเก่า) ... และแน่นอนว่าการผสานสามทางแบบโต้ตอบเป็นสิ่งจำเป็นในกรณีgit checkout --patch <branch> <file path>นี้ไม่สามารถใช้งานได้สำหรับวัตถุประสงค์การผสานแบบเลือกนี้

คุณสามารถทำได้อย่างง่ายดาย:

เพียงเพิ่มบรรทัดนี้ไปยัง[alias]ส่วนในไฟล์ทั่วโลก.gitconfigหรือในท้องถิ่นของคุณ.git/config:

[alias]
    mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; /C/BCompare3/BCompare.exe $2.theirs $2 $2.base $2; rm -f $2.theirs; rm -f $2.base;' -"

มันบอกเป็นนัยว่าคุณใช้นอกเหนือจากการเปรียบเทียบ เพียงเปลี่ยนซอฟต์แวร์ที่คุณต้องการหากจำเป็น หรือคุณสามารถเปลี่ยนเป็นการผสานรวมแบบสามทางโดยอัตโนมัติหากคุณไม่ต้องการการผสานการเลือกแบบโต้ตอบ:

[alias]
    mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; git merge-file $2 $2.base $2.theirs; rm -f $2.theirs; rm -f $2.base;' -"

จากนั้นใช้ดังนี้:

git mergetool-file <source branch> <file path>

สิ่งนี้จะทำให้คุณได้รับโอกาสในการผสานทรีทางเลือกเฉพาะของไฟล์ใด ๆ ในสาขาอื่น


10

มันไม่ใช่สิ่งที่คุณกำลังมองหา แต่มันมีประโยชน์สำหรับฉัน:

git checkout -p <branch> -- <paths> ...

มันเป็นการผสมผสานของคำตอบบางอย่าง


2
นี่เป็นประโยชน์อย่างยิ่งและสามารถเพิ่มเข้าไปในคำตอบที่ดีที่สุดสำหรับฉันคือคำตอบของ @ alvinabad เมื่อทำ: git checkout HEAD file1เพื่อเก็บเวอร์ชันปัจจุบันและยกเลิกการรวมไฟล์file1หนึ่งสามารถใช้-pตัวเลือกเพื่อเลือกส่วนของไฟล์ที่จะผสาน ขอบคุณสำหรับเคล็ดลับ!
Simon C.

นี่คือคำตอบที่ฉันชอบ เรียบง่ายตรงประเด็นและผลงาน
Jesse Reza Khorasanee

8

ฉันจะทำ

git diff commit1..commit2 filepattern | git- ใช้ - ดัชนี && git กระทำ

วิธีนี้คุณสามารถ จำกัด ช่วงของการคอมมิตสำหรับรูปแบบไฟล์จากสาขา

ถูกขโมยจาก: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html


ในบางสถานการณ์สิ่งนี้อาจมีประโยชน์มาก อย่างไรก็ตามหากการเปลี่ยนแปลงอยู่ในสาขาที่แตกต่างกันคุณสามารถชำระเงินได้จากส่วนปลายของสาขาดังเช่นในคำตอบของ Bart J ด้านบน
cdunn2001

Bart Js คือใคร
Black

8

ฉันมีปัญหาเดียวกันตามที่คุณกล่าวไว้ข้างต้น แต่ฉันพบบล็อกคอมไพล์นี้ชัดเจนขึ้นในการอธิบายคำตอบ

คำสั่งจากลิงค์ด้านบน:

#You are in the branch you want to merge to
git checkout <branch_you_want_to_merge_from> <file_paths...>

คุณทดสอบสิ่งนี้หรือไม่? ฉันแน่ใจว่าไฟล์จะถูกแทนที่จาก <branch_you_want_to_merge_from> แทนที่จะถูกรวมเข้าด้วยกัน
Amare

7

ฉันชอบคำตอบ 'git-interactive-merge' ด้านบน แต่ก็มีได้ง่ายกว่า ให้ git ทำสิ่งนี้ให้คุณโดยใช้ rebase ชุดโต้ตอบและลงบน:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o master

ดังนั้นกรณีคือคุณต้องการ C1 และ C2 จากสาขา 'คุณสมบัติ' (จุดสาขา 'A') แต่ตอนนี้ไม่เหลือเลย

# git branch temp feature
# git checkout master
# git rebase -i --onto HEAD A temp

สิ่งที่ดังกล่าวข้างต้นส่งคุณเข้าสู่เครื่องมือแก้ไขเชิงโต้ตอบซึ่งคุณเลือกบรรทัด 'เลือก' สำหรับ C1 และ C2 (ดังที่กล่าวมา) บันทึกและออกแล้วจากนั้นจะดำเนินการรีบูตและมอบสาขา 'temp' และสาขา HEAD ที่ master + C1 + C2:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o-master--C1---C2 [HEAD, temp]

จากนั้นคุณสามารถอัปเดต master เป็น HEAD และลบสาขา temp และคุณทำได้ดี:

# git branch -f master HEAD
# git branch -d temp

7

เกี่ยวกับgit reset --soft branchอะไร ฉันประหลาดใจที่ยังไม่มีใครพูดถึง

สำหรับฉันมันเป็นวิธีที่ง่ายที่สุดในการเลือกการเปลี่ยนแปลงจากสาขาอื่นเนื่องจากคำสั่งนี้วางไว้ในแผนผังการทำงานของฉันการเปลี่ยนแปลงต่าง ๆ ทั้งหมดและฉันสามารถเลือกหรือเปลี่ยนกลับที่ฉันต้องการได้อย่างง่ายดาย ด้วยวิธีนี้ฉันสามารถควบคุมไฟล์ที่กำหนดไว้ได้อย่างสมบูรณ์


6

ฉันรู้ว่าคำถามนี้เก่าและมีคำตอบอื่น ๆ อีกมากมาย แต่ฉันเขียนสคริปต์ของตัวเองชื่อ 'pmerge' เพื่อรวมไดเรกทอรีบางส่วน มันเป็นงานที่อยู่ระหว่างดำเนินการและฉันยังคงเรียนรู้ทั้ง git และ bash scripting

คำสั่งนี้ใช้git merge --no-commitแล้วยกเลิกการใช้การเปลี่ยนแปลงที่ไม่ตรงกับเส้นทางที่ให้ไว้

การใช้: git pmerge branch path
ตัวอย่าง:git merge develop src/

ฉันไม่ได้ทำการทดสอบอย่างกว้างขวาง ไดเรกทอรีการทำงานควรเป็นอิสระจากการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดและไฟล์ที่ไม่ได้ติดตาม

#!/bin/bash

E_BADARGS=65

if [ $# -ne 2 ]
then
    echo "Usage: `basename $0` branch path"
    exit $E_BADARGS
fi

git merge $1 --no-commit
IFS=$'\n'
# list of changes due to merge | replace nulls w newlines | strip lines to just filenames | ensure lines are unique
for f in $(git status --porcelain -z -uno | tr '\000' '\n' | sed -e 's/^[[:graph:]][[:space:]]\{1,\}//' | uniq); do
    [[ $f == $2* ]] && continue
    if git reset $f >/dev/null 2>&1; then
        # reset failed... file was previously unversioned
        echo Deleting $f
        rm $f
    else
        echo Reverting $f
        git checkout -- $f >/dev/null 2>&1
    fi
done
unset IFS

4

คุณสามารถใช้read-treeเพื่ออ่านหรือรวมทรีรีโมตที่กำหนดลงในดัชนีปัจจุบันตัวอย่างเช่น:

git remote add foo git@example.com/foo.git
git fetch foo
git read-tree --prefix=my-folder/ -u foo/master:trunk/their-folder

หากต้องการผสานให้ใช้-mแทน

ดูเพิ่มเติม: ฉันจะรวมไดเรกทอรีย่อยในคอมไพล์ได้อย่างไร


3

วิธีการง่ายๆสำหรับการรวม / คัดสรรโดยเลือกไฟล์:

git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes


3

หากคุณไม่มีไฟล์ที่เปลี่ยนแปลงมากเกินไปสิ่งนี้จะทำให้คุณไม่มีข้อผูกมัดใด ๆ เพิ่มเติม

1. ทำซ้ำสาขาชั่วคราว
$ git checkout -b temp_branch

2. รีเซ็ตเป็นค่าคอมมิชชันที่ต้องการล่าสุด
$ git reset --hard HEAD~nซึ่งnเป็นจำนวนการคอมมิทที่คุณต้องย้อนกลับ

3. ชำระเงินแต่ละไฟล์จากสาขาดั้งเดิม
$ git checkout origin/original_branch filename.ext

ตอนนี้คุณสามารถคอมมิทและบังคับให้กด (เพื่อเขียนทับรีโมต) ถ้าจำเป็น


3

ถ้าคุณจะต้องผสานไดเรกทอรีและโดยเฉพาะอย่างยิ่งการลาทุกอย่างอื่นเหมือนเดิมและยังรักษาประวัติ, คุณอาจจะลองนี้ ... สร้างใหม่target-branchออกจากmasterก่อนที่จะทดลอง

ขั้นตอนด้านล่างถือว่าคุณมีสองสาขาtarget-branchและsource-branchและไดเรกทอรีที่คุณต้องการผสานอยู่ในdir-to-merge source-branchนอกจากนี้สมมติว่าคุณมีไดเรกทอรีอื่น ๆ เช่นdir-to-retainในเป้าหมายที่คุณไม่ต้องการเปลี่ยนและเก็บประวัติ dir-to-mergeนอกจากนี้ยังถือว่ามีความขัดแย้งในการผสาน

git checkout target-branch
git merge --no-ff --no-commit -X theirs source-branch
# the option "-X theirs", will pick theirs when there is a conflict. 
# the options "--no--ff --no-commit" prevent a commit after a merge, and give you an opportunity to fix other directories you want to retain, before you commit this merge.

# the above, would have messed up the other directories that you want to retain.
# so you need to reset them for every directory that you want to retain.
git reset HEAD dir-to-retain
# verify everything and commit.

2

เมื่อมีการเปลี่ยนแปลงเพียงไม่กี่ไฟล์ระหว่างการกระทำปัจจุบันของสองสาขาฉันรวมการเปลี่ยนแปลงด้วยตนเองโดยผ่านไฟล์ต่างๆ

git difftoll <branch-1>..<branch-2>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.