ฉันจะรวมการเปลี่ยนแปลงที่ไม่ผูกมัดในท้องถิ่นเข้ากับสาขา Git อื่นได้อย่างไร


621

ฉันจะทำสิ่งต่อไปนี้ใน Git ได้อย่างไร

สาขาปัจจุบันของฉันคือ branch1 และฉันได้ทำการเปลี่ยนแปลงในท้องถิ่น อย่างไรก็ตามตอนนี้ฉันรู้ว่าจริง ๆ แล้วฉันตั้งใจจะนำการเปลี่ยนแปลงเหล่านี้ไปใช้กับ branch2 มีวิธีที่จะใช้ / รวมการเปลี่ยนแปลงเหล่านี้เพื่อให้พวกเขากลายเป็นการเปลี่ยนแปลงในท้องถิ่นใน branch2 โดยไม่ต้องกระทำใน branch1?


2
มี Git Tutorial ที่ดีที่นี่ใน SO มันเป็นศูนย์กลางสำหรับคำถามคอมไพล์ทั้งหมดในสแต็คล้น
Decio Lira

คำตอบ:


898

เนื่องจากไฟล์ของคุณยังไม่ได้ทำbranch1:

git stash
git checkout branch2
git stash pop

หรือ

git stash
git checkout branch2
git stash list       # to check the various stash made in different branch
git stash apply x    # to select the right one

ตามที่แสดงความคิดเห็นโดยbenjohn (ดูgit stashหน้าคน ):

หากต้องการซ่อนไฟล์ที่ยังไม่ได้ติดตาม (เพิ่มใหม่) ในปัจจุบันให้เพิ่มอาร์กิวเมนต์-uเพื่อ:

git stash -u

2
ยินดี. ตัวอย่างของการใช้งานที่ซ่อนที่unethicalblogger.com/posts/2008/11/...
VonC

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

1
สิ่งนี้ใช้ได้สำหรับฉัน อย่างไรก็ตามฉันต้องสร้างสาขาในท้องถิ่นเพื่อให้ 'stash pop' ทำงาน ชำระเงินstackoverflow.com/questions/1783405/git-checkout-remote-branchหากมีสิ่งที่คล้ายกันเกิดขึ้นกับคุณ
mimoralea

21
ยังไม่ได้ติดตามซ่อนอยู่ในปัจจุบัน (เพิ่มใหม่) ไฟล์เพิ่มอาร์กิวเมนต์เพื่อ:-u git stash -u
Benjohn

2
@Benjohn จุดดี ฉันได้รวมความคิดเห็นของคุณไว้ในคำตอบเพื่อให้มองเห็นได้ชัดเจนขึ้น
VonC

84

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

git checkout branch2

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

git checkout -m branch2

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

git reset

3
ฉันคิดว่าที่เก็บข้อมูล "เรียบง่าย" เพื่อทำความเข้าใจ แต่วิธีการของคุณดีกว่าที่จะคำนึงถึงไดเรกทอรีการทำงานในสาขาที่แตกต่างกัน +1
VonC

6
เช็คเอาต์แบบดั้งเดิมธรรมดาดูเหมือนจะเหมาะสมกับปัญหาในมือ การชำระเงินมีน้ำหนักเบาเพียงอัปเดตไฟล์ที่จำเป็นต้องเปลี่ยน บางทีมันอาจจะง่ายกว่าที่จะเข้าใจวิธีการสะสมหรืออาจเป็นได้ว่ามันไม่ชัดเจนเพียงพอว่าการชำระเงินนั้น 'ปลอดภัย' ในกรณีการใช้งานนี้
CB Bailey

หากcheckout -mไม่ปลอดภัยในบางสถานการณ์ (อาจทำให้เกิดความขัดแย้งในการรวม) การซ่อนจะให้ประโยชน์ใด ๆ (เช่นคุณสามารถยกเลิกการป็อปอัพสต็อก) ได้หรือไม่
Craig McQueen

1
@craigMcQueen คุณไม่สามารถยกเลิกการสะสมที่โผล่ออกมา แต่ที่เก็บจะบ่นเกี่ยวกับความขัดแย้งเมื่อคุณป๊อปมัน คุณสามารถแก้ไขข้อขัดแย้งและจากนั้นส่งมอบ แต่ที่เก็บดั้งเดิมยังอยู่ในสแต็กในกรณีนี้! :)
Shaun F

ในกรณีที่มีข้อขัดแย้งในการรวมไฟล์จะไม่ทำการสำรองข้อมูล.origหรือไม่?
jocull

13

ทางเลือกที่สั้นกว่าสำหรับวิธีการสะสมที่กล่าวถึงก่อนหน้านี้คือ:

ย้ายการเปลี่ยนแปลงไปยังที่เก็บชั่วคราว

  1. git stash

สร้างและสลับไปยังสาขาใหม่จากนั้นซ่อนที่เก็บไว้ในขั้นตอนเดียว

  1. git stash branch new_branch_name

จากนั้นเพียงaddและcommitการเปลี่ยนแปลงในสาขาใหม่นี้


10

คำเตือน:ไม่ใช่สำหรับมือใหม่คอมไพล์

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

นอกจากนี้ยังมีประโยชน์ - ถ้าคุณพบเจอสถานการณ์เช่นนี้ - ให้มีไดเรกทอรีทำงานอยู่ข้างๆไดเรกทอรีปัจจุบันของคุณที่มีmasterสาขาที่เช็คเอาท์อยู่เสมอ

ดังนั้นฉันจะบรรลุสิ่งนี้ได้อย่างไร:

  1. git commit การเปลี่ยนแปลงทันทีพร้อมข้อความยืนยันที่ดี
  2. git reset HEAD~1 เพื่อยกเลิกการกระทำจากสาขาปัจจุบัน
  3. (ไม่บังคับ) ยังคงทำงานต่อไป

บางครั้งในภายหลัง (แบบอะซิงโครนัส) หรือทันทีในหน้าต่างเทอร์มินัลอื่น:

  1. cd my-project-master ซึ่งเป็นอีกหนึ่ง WD ที่แชร์กัน .git
  2. git reflog เพื่อหาข้อผิดพลาดที่ฉันเพิ่งทำ
  3. git cherry-pick SHA1 ของการกระทำ

ทางเลือก (ยังไม่ตรงกัน) คุณสามารถรีบูต (หรือรวม) สาขาฟีเจอร์ของคุณเพื่อรับการแก้ไขข้อบกพร่องโดยปกติแล้วเมื่อคุณกำลังจะส่ง PR และทำความสะอาดสาขาฟีเจอร์ของคุณและ WD แล้ว:

  1. cd my-project ซึ่งเป็น WD หลักที่ฉันใช้งานอยู่
  2. git rebase master เพื่อรับข้อผิดพลาด

วิธีที่ฉันสามารถให้การทำงานในลักษณะการทำงานอย่างต่อเนื่องและไม่ต้องกังวลเกี่ยวกับgit stashไอเอ็นจีอะไรหรือมีการทำความสะอาด WD ของฉันก่อนgit checkout(แล้วต้องเช็ค Backout คุณลักษณะสาขาอีกครั้ง.) และยังคงมีการแก้ไขข้อบกพร่องทั้งหมดของฉันไปmasterแทน ซ่อนอยู่ในสาขาคุณลักษณะของฉัน

IMO git stashและgit checkoutเป็น PIA ที่แท้จริงเมื่อคุณอยู่ระหว่างการทำงานกับคุณสมบัติที่ยอดเยี่ยม


ทางเลือกที่น่าสนใจและถูกต้องสำหรับคำตอบของฉัน +1
VonC

คุณมาจาก Mercurial หรือไม่? การmy-project-masterแบ่งปันแบบเดียวกัน.gitทำให้ดูเหมือนกับเป็นเช่นนั้น ทำไมไม่git checkout -b bugfixABC; git commit -a; git reset HEAD^ --hardหลังจากนั้น (ถ่ายทอดสด) ในขณะที่master, git cherry-pick <SHA1 of the commit(s) in bugfixABC? (หรือแม้กระทั่งเพื่อหลีกเลี่ยงการค้นหา SHA1 git rebase --onto master feature bugfixABCจากที่ใดก็ตามที่คุณอยู่สาขาซึ่งหมายความว่าคุณสามารถทำเช่นนั้นได้โดยตรงหลังจากgit resetข้างต้นในขณะที่ในfeature)
Gauthier

อย่างไรก็ตาม OP ดูเหมือนว่าพวกเขายังไม่พร้อมที่จะยอมรับการเปลี่ยนแปลงในกรณีcheckout -mนั้นดีกว่า
Gauthier

2

ถ้ามันเกี่ยวกับการเปลี่ยนแปลงที่เกิดขึ้นคุณควรจะดู git-rebase แต่ตามที่ได้กล่าวไว้ในข้อคิดเห็นโดย VonC เมื่อคุณพูดถึงการเปลี่ยนแปลงในท้องถิ่น git-stash จะเป็นวิธีที่ดีในการทำเช่นนี้


ฉันไม่เข้าใจวิธีแก้ปัญหานี้: จะเขียนประวัติของ branch2 จาก branch1 อีกครั้ง ... ทำไมจึงได้รับการเปลี่ยนแปลงที่ถูกกำหนดทั้งหมดจาก branch1 ใน branch2 เมื่อเราต้องการรับเฉพาะการเปลี่ยนแปลงที่ไม่ได้กระทำของ branch1 ใน branch2? ...
VonC

@VonC: เห็นด้วยในกรณีนี้ rebase จะได้รับการเปลี่ยนแปลงที่มุ่งมั่นทั้งหมดตั้งแต่การรวมครั้งล่าสุดระหว่างสาขาเข้ากับ Branch1 ฉันไม่ได้รับพารามิเตอร์ "ไม่มุ่งมั่น" ของคำถามนี้ในตอนแรก rebase ไม่ใช่คำตอบที่ดี
claf

@claferri: ไม่กี่ ... ฉันเริ่มมีอาการปวดหัว;) ฉันจะลดระดับคำตอบของคุณ แต่เนื่องจากฉันตีพิมพ์ตัวเองจึงมี "ความขัดแย้งทางผลประโยชน์ที่ชัดเจน" ด้วยโพสต์ที่อัปเดตของคุณฉันไม่จำเป็นต้องลงคะแนนเลยตอนนี้ ขอบคุณ :)
VonC

@VonC: ครั้งต่อไปอย่าลังเลที่จะลงคะแนนตราบใดที่คำตอบของฉันเป็นที่ไม่ถูกต้องเช่นนี้หนึ่ง;)
claf

1

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

วิธีการผูกมัดกับสาขาอื่นในคอมไพล์

คุณมีการเปลี่ยนแปลงใน uncommited my_branchที่คุณต้องการที่จะกระทำการโดยไม่กระทำการเปลี่ยนแปลงทั้งหมดจากmastermy_branch

ตัวอย่าง

git merge master
git stash -u
git checkout master
git stash apply
git reset
git add example.js
git commit
git checkout .
git clean -f -d
git checkout my_branch
git merge master
git stash pop

คำอธิบาย

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

-uตัวเลือก (aka --include-untracked) ในgit stash -uป้องกันคุณจากการสูญเสียไฟล์ที่ไม่ได้ติดตามเมื่อคุณทำต่อมาภายในgit clean -f -dmaster

หลังจากgit checkout masterเป็นสิ่งสำคัญที่คุณไม่ทำgit stash popเพราะคุณจะต้องสะสมนี้ในภายหลัง หากคุณปรากฏที่เก็บที่สร้างขึ้นmy_branchแล้วทำgit stashในmasterคุณจะทำให้เกิดความขัดแย้งผสานโดยไม่จำเป็นเมื่อคุณใช้ที่เก็บในmy_branchภายหลัง

git resetgit stash applyทุกอย่างที่เกิดจากการ unstages ตัวอย่างเช่นไฟล์ที่ได้รับการแก้ไขในที่เก็บ แต่ไม่มีอยู่ในการmasterจัดฉากว่าเป็น "ลบโดยเรา" ความขัดแย้ง

git checkout . และ git clean -f -dทิ้งทุกสิ่งที่ไม่ได้ทำ: การเปลี่ยนแปลงทั้งหมดในไฟล์ที่ถูกติดตามและไฟล์และไดเรกทอรีที่ไม่ได้ติดตาม พวกเขาจะถูกบันทึกไว้แล้วในการสะสมและหากปล่อยทิ้งไว้ในที่จะทำให้เกิดความขัดแย้งในการผสานความจำเป็นเมื่อมีการสลับกลับไปmastermy_branch

สุดท้ายgit stash popจะเป็นไปตามต้นฉบับmy_branchและจะไม่ทำให้เกิดความขัดแย้งผสาน อย่างไรก็ตามหากที่เก็บข้อมูลของคุณมีไฟล์ที่ไม่ได้ติดตามซึ่งคุณได้กำหนดไว้ว่าจะใช้งานหลัก git จะบ่นว่า "ไม่สามารถเรียกคืนไฟล์ที่ไม่ได้ติดตามจากที่เก็บถาวร" ได้ ในการแก้ปัญหาความขัดแย้งนี้ลบไฟล์เหล่านั้นจากต้นไม้ที่ทำงานของคุณแล้วgit stash pop, และgit add .git reset


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

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

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

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