Git Pull Force - วิธีเขียนทับการเปลี่ยนแปลงในเครื่องด้วย Git

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

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

เวิร์กโฟลว์ทั่วไป

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

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

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

การเปลี่ยนแปลงในท้องถิ่น

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

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

คุณเคยประหารชีวิตgit pullเพียงเพื่อดูความหวั่นไหวerror: Your local changes to the following files would be overwritten by merge:หรือไม่? ไม่ช้าก็เร็วทุกคนเจอปัญหานั้น

สิ่งที่น่าสับสนกว่านี้คือคุณไม่ต้องการรวมอะไรเลยเพียงแค่ดึงใช่ไหม? จริงๆแล้วการดึงนั้นซับซ้อนกว่าที่คุณคิดไว้เล็กน้อย

Git Pull ทำงานอย่างไร?

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

git fetch git merge origin/$CURRENT_BRANCH

origin/$CURRENT_BRANCHส่วนหนึ่งหมายความว่า:

  • Git จะรวมการเปลี่ยนแปลงจากที่เก็บระยะไกลที่ชื่อorigin(อันที่คุณโคลนมา)
  • ที่ถูกเพิ่มลงในไฟล์ $CURRENT_BRANCH
  • ที่ยังไม่มีอยู่ในสาขาเช็คเอาต์ในพื้นที่ของคุณ

เนื่องจาก Git จะทำการผสานเฉพาะเมื่อไม่มีการเปลี่ยนแปลงที่ไม่ได้ผูกมัดทุกครั้งที่คุณเรียกใช้git pullการเปลี่ยนแปลงที่ไม่ได้กำหนดอาจทำให้คุณมีปัญหาได้ โชคดีที่มีวิธีแก้ปัญหาในชิ้นเดียว!

เราเป็นครอบครัว

แนวทางต่างๆ

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

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

แต่ละแนวทางต้องการโซลูชันที่แตกต่างกัน

คุณไม่สนใจเกี่ยวกับการเปลี่ยนแปลงในท้องถิ่น

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

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

git fetch git reset --hard HEAD git merge origin/$CURRENT_BRANCH

หากคุณไม่ต้องการที่จะพิมพ์ชื่อสาขาทุกครั้งที่คุณเรียกใช้คำสั่งนี้ Git @{u}มีทางลัดที่ดีที่ชี้ไปยังสาขาต้นน้ำ: สาขาต้นน้ำคือสาขาในที่เก็บระยะไกลที่คุณพุชและดึงข้อมูลจาก

นี่คือลักษณะของคำสั่งข้างต้นเมื่อใช้ทางลัด:

git fetch git reset --hard HEAD git merge '@{u}'

เรากำลังอ้างถึงทางลัดในตัวอย่างเพื่อป้องกันไม่ให้เชลล์ตีความ

คุณให้ความสำคัญกับการเปลี่ยนแปลงในท้องถิ่นเป็นอย่างมาก

เมื่อการเปลี่ยนแปลงที่ไม่ได้ผูกมัดของคุณมีความสำคัญต่อคุณมีสองตัวเลือก คุณสามารถผูกมัดพวกเขาแล้วแสดงgit pullหรือคุณสามารถซ่อนไว้ก็ได้

การซ่อนหมายถึงการนำการเปลี่ยนแปลงออกไปสักครู่เพื่อนำกลับมาในภายหลัง เพื่อให้แม่นยำยิ่งขึ้นgit stashให้สร้างคอมมิตที่มองไม่เห็นในสาขาปัจจุบันของคุณ แต่ Git ยังเข้าถึงได้

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

เวิร์กโฟลว์อาจมีลักษณะดังนี้:

git fetch git stash git merge '@{u}' git stash pop

By default, the changes from the stash will become staged. If you want to unstage them, use the command git restore --staged (if using Git newer than 2.25.0).

You Just Want to Download the Remote Changes

The last scenario is a little different from the previous ones. Let's say that you are in the middle of a very messy refactoring. Neither losing the changes nor stashing them is an option. Yet, you still want to have the remote changes available to run git diff against them.

As you have probably figured out, downloading the remote changes does not require git pull at all! git fetch is just enough.

One thing to note is that by default, git fetch will only bring you changes from the current branch. To get all the changes from all the branches, use git fetch --all. And if you'd like to clean up some of the branches that no longer exist in the remote repository, git fetch --all --prune will do the cleaning up!

Some Automation

Have you heard of Git Config? It's a file where Git stores all of the user-configured settings. It resides in your home directory: either as ~/.gitconfig or ~/.config/git/config. You can edit it to add some custom aliases that will be understood as Git commands.

For example, to have a shortcut equivalent to git diff --cached (that shows the difference between the current branch and the staged files), you'd add the following section:

[alias] dc = diff --cached

After that, you can run git dc whenever you wish to review the changes. Going this way, we can set up a few aliases related to the previous use cases.

[alias] pull_force = !"git fetch --all; git reset --hard HEAD; git merge @{u}" pf = pull_force pull_stash = !"git fetch --all; git stash; git merge @{u}; git stash pop"

This way, running git pull_force will overwrite the local changes, while git pull_stash will preserve them.

The Other Git Pull Force

Curious minds may have already discovered that there is such a thing as git pull --force. However, this is a very different beast to what's presented in this article.

It may sound like something that would help us overwrite local changes. Instead, it lets us fetch the changes from one remote branch to a different local branch. git pull --force only modifies the behavior of the fetching part. It is therefore equivalent to git fetch --force.

Like git push, git fetch allows us to specify which local and remote branch do we want to operate on. git fetch origin/feature-1:my-feature will mean that the changes in the feature-1 branch from the remote repository will end up visible on the local branch my-feature. When such an operation modifies the existing history, it is not permitted by Git without an explicit --force parameter.

Just like git push --force allows overwriting remote branches, git fetch --force (or git pull --force) allows overwriting local branches. It is always used with source and destination branches mentioned as parameters. An alternative approach to overwriting local changes using git --pull force could be git pull --force "@{u}:HEAD".

Conclusion

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

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