การสควอชกระทำในคอมไพล์หมายความว่าอย่างไร?


117

Squashing กระทำใน git หมายถึงอะไร ฉันจะทำสควอชใน Github ได้อย่างไร

ฉันเพิ่งเริ่มใช้ Git และขอให้กำหนดบั๊กสำหรับผู้มาใหม่ใน Coala-analyzer ฉันแก้ไขข้อบกพร่องแล้วและตอนนี้ฉันถูกขอให้บีบข้อตกลง ฉันต้องทำอย่างไร?


เฮ้ @Lakshman อย่าลังเลที่จะยอมรับคำตอบที่ได้รับการโหวตสูงสุด ตอบคำถามของคุณได้อย่างเหมาะสม
Mostafiz Rahman

คำตอบ:


181

คุณสามารถคิดว่า Git เป็นฐานข้อมูลขั้นสูงของสแน็ปช็อตของไดเร็กทอรีการทำงานของคุณ (ies)

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

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

ถ้าคุณเริ่มงานที่คอมมิตแท็กStartคุณต้องการสิ่งนี้

Git กระทำการ squashing

คุณอาจสังเกตเห็นว่าคอมมิตใหม่มีสีน้ำเงินเข้มขึ้นเล็กน้อย นี่คือเจตนา

ในการบีบ Git จะประสบความสำเร็จกับRebaseของรูปแบบพิเศษที่เรียกว่าอินเตอร์แอคที Rebase
การทำให้ง่ายขึ้นเมื่อคุณสร้างชุดของคอมมิตใหม่เป็นสาขาBคุณจะใช้การเปลี่ยนแปลงทั้งหมดที่แนะนำโดยคอมมิตเหล่านั้นเมื่อเสร็จสิ้นโดยเริ่มจากBแทนบรรพบุรุษเดิม

เบาะแสภาพ

ใส่คำอธิบายภาพที่นี่

สังเกตอีกครั้งถึงเฉดสีน้ำเงินที่แตกต่างกัน

rebase แบบโต้ตอบช่วยให้คุณเลือกได้ว่าควรจะปรับฐานคอมมิตอย่างไร หากคุณรันคำสั่งนี้:

 git rebase -i branch

คุณจะได้ไฟล์ที่แสดงรายการคอมมิตที่จะได้รับการ rebased

 pick ae3...
 pick ef6...
 pick 1e0...
 pick 341...

ฉันไม่ได้ตั้งชื่อคอมมิต แต่ทั้งสี่คนนี้มีจุดประสงค์เพื่อเป็นการคอมมิตตั้งแต่ต้นจนจบ

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

 pick ae3...
 squash ef6...
 squash 1e0...
 squash 341...

หากคุณปิดตัวแก้ไขและไม่พบข้อขัดแย้งในการผสานคุณจะได้รับประวัตินี้:

ใส่คำอธิบายภาพที่นี่

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

git rebase -i HEAD~4

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


หมายเหตุเกี่ยวกับการแก้ไขประวัติศาสตร์

ใน Git จะไม่มีการแก้ไขคอมมิต พวกเขาสามารถตัดแต่งทำให้ไม่สามารถเข้าถึงได้โคลน แต่ไม่เปลี่ยนแปลง
เมื่อคุณสร้างฐานใหม่คุณกำลังสร้างคอมมิตใหม่
คนเก่าไม่สามารถเข้าถึงได้อีกต่อไปโดยการอ้างอิงใด ๆ ดังนั้นจึงไม่ปรากฏในประวัติศาสตร์ แต่ยังคงอยู่ที่นั่น!

นี่คือสิ่งที่คุณได้รับจาก rebase:

ใส่คำอธิบายภาพที่นี่

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


Nice - จะเกิดอะไรขึ้นกับคอมเมนต์คอมเมนต์ดั้งเดิม - พวกเขารวมกันเป็นคอมเมนต์คอมมิตใหญ่ ๆ เดียวหรือว่าพวกเขาหลงทาง?
Paul R

จากman git rebase: ข้อความคอมมิตที่แนะนำสำหรับการคอมมิตแบบพับคือการต่อกันของข้อความคอมมิตของคอมมิตแรกและของข้อความที่มีคำสั่ง "สควอช"
Margaret Bloom

1
นี่เป็นคำอธิบายที่ดีที่สุดที่ฉันเคยเห็นเกี่ยวกับการลดราคาขอบคุณ
Kerry Jones

เกี่ยวกับการสควอชในภาพแรกของคุณ: คุณสามารถสร้างตัวอย่างที่ HEAD มีไดเร็กทอรีการทำงานที่แตกต่างกันก่อน (สีน้ำเงินอ่อน) และหลัง (สีน้ำเงินเข้ม) ได้หรือไม่? ในตัวอย่างทั้งหมดฉันลอง squashing ดูเหมือนว่ามันเพิ่งลบการกระทำสามอย่างระหว่าง START และ HEAD
actual_panda

@actual_panda ไม่แน่ใจว่าติดตาม HEAD คือการอ้างถึงการกระทำ ยอมรับเดลต้าร้านค้า dir ทำงานเป็นคุณสมบัติของที่เก็บโดยรวมขึ้นอยู่กับคอมมิตที่คุณเช็คเอาต์ โดยทั่วไปการอ้างอิงสองรายการ (เช่น HEAD และ START) จะให้ workdirs สองตัวที่แตกต่างกันเสมอเมื่อเช็คเอาต์ หากคุณ rebase squash ในสาขาเดียวกันเอฟเฟกต์ก็คือการ "หลวม" การกระทำของตัวกลาง แต่ในความเป็นจริงคอมไพล์สร้างใหม่ด้วยเดลต้าทั้งหมด git diffอาจช่วยให้คุณแสดงสิ่งที่เกิดขึ้น
Margaret Bloom

22

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

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

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

ใส่คำอธิบายภาพที่นี่

การกระทำ 4 ครั้งสุดท้ายจะมีความสุขมากขึ้นถ้าพวกเขารวมเข้าด้วยกันดังนั้นเรามาทำสิ่งนั้นผ่านการตอบกลับแบบโต้ตอบ

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, 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 ว่าฉันต้องการสร้างฐานใหม่โดยใช้การคอมมิตสี่ครั้งสุดท้ายจากที่ HEAD อยู่กับ HEAD ~ 4 ตอนนี้ Git ทำให้ฉันเป็นเครื่องมือแก้ไขที่มีข้อความด้านบนและมีคำอธิบายเล็กน้อยเกี่ยวกับสิ่งที่สามารถทำได้ คุณมีตัวเลือกมากมายให้คุณจากหน้าจอนี้ แต่ตอนนี้เรากำลังจะรวมทุกอย่างเข้าด้วยกัน ดังนั้นการเปลี่ยนสี่บรรทัดแรกของไฟล์เป็นสิ่งนี้จะทำเคล็ดลับ:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

โดยทั่วไปสิ่งนี้จะบอกให้ Git รวมการคอมมิตทั้งสี่เข้าไว้ในคอมมิตแรกในรายการ เมื่อเสร็จสิ้นและบันทึกโปรแกรมแก้ไขอื่นจะปรากฏขึ้นพร้อมสิ่งต่อไปนี้:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    # Explicit paths specified without -i nor -o; assuming --only paths...
    # Not currently on any branch.
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   new file:   LICENSE
    #   modified:   README.textile
    #   modified:   Rakefile
    #   modified:   bin/jekyll
    #

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

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
    Successfully rebased and updated refs/heads/master.

และหากเราดูประวัติศาสตร์อีกครั้ง… ใส่คำอธิบายภาพที่นี่

ดังนั้นสิ่งนี้จึงค่อนข้างไม่เจ็บปวด หากคุณพบความขัดแย้งระหว่างการสร้างฐานข้อมูลใหม่มักจะแก้ไขได้ง่ายและ Git จะนำคุณผ่านไปให้ได้มากที่สุด พื้นฐานของสิ่งนี้คือแก้ไขข้อขัดแย้งที่เป็นปัญหาgit addไฟล์จากนั้นgit rebase --continueจะดำเนินการต่อ แน่นอนว่าการทำgit rebase --abortจะทำให้คุณกลับไปสู่สถานะเดิมได้หากคุณต้องการ หากคุณสูญเสียคอมมิตใน rebase ด้วยเหตุผลบางประการคุณสามารถใช้ reflog เพื่อเรียกคืนได้

สามารถดูรายละเอียดได้ที่ลิงค์นี้


3
ขอบคุณ! ในกรณีที่ใคร ๆ ก็ไม่สบายใจกับ VIM เหมือนกับฉัน ... เมื่อคุณไปถึงจุดที่คุณป้อนการดำเนินการเพื่อแก้ไขกด 'i' เพื่อเข้าสู่โหมดแก้ไข เมื่อคุณแก้ไขเสร็จแล้วให้กด Escape แล้วพิมพ์ ": wq" และมันจะเคลื่อนไปข้างหน้า (Mac)
Farasi78

+1 สำหรับข้อควรระวังและบริบทว่าเมื่อใดควรทำเช่นนี้ จากประสบการณ์ส่วนตัวของฉันเป็นเรื่องดีถ้าคุณทำงานคนเดียวในสาขาคุณลักษณะและมีการกระทำที่ไม่สำคัญมากมายเช่น "readme ที่อัปเดต" "ทำในสิ่งที่ไม่มีใครสนใจ" และคุณพร้อมที่จะรวมสาขาเข้าด้วยกันอาจเป็น ก็แค่สควอชทั้งหมดนี้เป็นคอมมิตเดียว คงไม่มีใครอยากเปลี่ยนกลับไปใช้ "ทำบางสิ่งที่ไม่มีใครสนใจ" ของคุณและก่อให้เกิดมลพิษต่อประวัติการกระทำ
Adam Hughes

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