จากที่เคยแนะนำการใช้ Git GUI ในบทความตอน [Dev] ใช้ Git เพื่อชีวิต (Source Code) ที่ดีกว่า – การใช้งาน Git GUI เบื้องต้น ไปแล้ว คราวนี้มาต่อกันด้วยเรื่องของการใช้งานกับ Git Server เช่น GitHub, Bitbucket หรือ Git Server จ้าวอื่น ๆ กันหน่อย
สำหรับใครที่ยังไม่ Account สำหรับ Git Server อย่าลืมไปสมัครใช้งานก่อนนะครับ ถ้าไม่รู้จะใช้งานของจ้าวไหน ลองอ่าน Blog ของ NuuNeoI ตอน Software Developer ทั้งหลาย จงใช้ git เพื่อชีวิตที่ยั่งยืน ดูก่อนก็ได้ครับ เค้าแนะนำอยู่ 3 ตัว คือ GitHub, Bitbucket และ GitLab โดยผมจะสรุปสั้น ๆ ให้ ดังนี้
- ชอบแจก Code สู่สาธารณะ (ฟรี Public) เลือก GitHub
- ชอบความเป็นส่วนตั๊วส่วนตัว (ฟรี Private) เลือก Bitbucket
- ไม่ไว้ใจใคร (ทำ Git Server เอง) เลือก GitLab
ส่วนความสามารถของแต่ละจ้าว ลองไปเล่น ๆ ดูก่อนก็ได้คับ ชอบตัวไหน เลือกตัวนั้น สำหรับการใช้งานเบื้องต้น ก็แทบจะเหมือนกันหมด
สำหรับบทความตอนนี้ ขอเลือก GitHub มาแนะนำน่ะครับ…
List of contents
Git Remote Repository
ก่อนหน้านี้ เราได้รู้จักคำว่า Local Repository กันไปแล้ว คราวนี้มาทำความรู้จักกับ Remote Repository กันบ้าง…
Remote Repository ก็คือ Repository ที่เราฝากไว้กับ Git Server นั่นแหล่ะ มาเริ่มสร้าง Remote Repository บน GitHub กันก่อน
ทำการ Login เข้าสู่ GitHub แล้วคลิกที่เครื่องหมาย + ที่เมนูด้านบน เลือก New repository

แล้วตั้งชื่อ Repository (1) เลือกการเข้าถึง Repository ว่าเป็น Public หรือ Private (2)
ส่วนจุดที่ (3) จะเป็นส่วนของการสร้างไฟล์เริ่มต้น เช่น README, .gitignore, License ตรงนี้ยังไม่ต้องเลือกก่อน (สามารถเพิ่มทีหลังได้) เพื่อจะได้ไม่เกิด Initial Commit เนื่องจากเราจะสร้าง Repository เปล่า ๆ กันก่อน
กรณีที่เริ่มต้นที่ Remote Repo ก่อน ยังไม่มีการสร้าง Local Repo ใด ๆ จะเลือกไฟล์เหล่านี้ไว้ก็ได้นะ แต่จะต้อง Clone Remote Repo ลงไปที่ Local Repo
กดปุ่ม Create repository (4) ก็จะสร้าง Remote Repository แล้ว

เท่านี้ก็จะได้ Remote Repository แล้วครับ ซึ่ง GitHub จะแนะนำทางเลือกให้ 4 ทางเลือก คือ
- Quick setup — if you’ve done this kind of thing before (1) – สำหรับการใช้งานเริ่มต้น จะมีเลือกการเชื่อมต่อผ่าน HTTPS หรือ SSH (จะพูดถึงในหัวข้อต่อไป)
- …or create a new repository on the command line (2) – ชุดคำสั่งตัวอย่างสำหรับการสร้าง Local Repository แล้วเพิ่ม Remote Repository นี้ ผ่านทาง command line (ใช้ Git Bash)
- …or push an existing repository from the command line (3) – ชุดคำสั่งตัวอย่างสำหรับการเพิ่ม Remote Repository นี้ กับ Local Repository ที่มีอยู่แล้ว ผ่านทาง command line (ใช้ Git Bash)
- …or import code from another repository (4) – สำหรับการ Import code จาก Repository อื่น ๆ โดยสามารถ Import จาก Subversion, Mercurial, or TFS project ซึ่งเป็น Version Control เจ้าอื่น ๆ ได้ด้วย

Git URL
การใช้งาน Remote Repository นั้น ส่วนใหญ่จะมี URL ให้เลือก 2 แบบ คือ HTTPS และ SSH
สำหรับ GitHub สามารถคลิกเลือกที่ HTTPS ก็จะได้ URL มา (1) และสามารถกดปุ่ม Copy to clipboard (2) เพื่อ Copy URL ได้เลย

สำหรับ SSH ก็เช่นเดียวกัน

ถ้าสามารถใช้งาน HTTPS ได้ ก็คือจะสามารถเชื่อมต่อผ่าน https protocol ได้เลย
สำหรับ Network ไหนที่ต้องใช้งานผ่าน Proxy สามารถดูวิธีกำหนดค่า Proxy ได้จากบทความตอน [How to] วิธีการตั้งค่า Git บน Windows ให้ใช้งานผ่าน Proxy
แต่ถ้าจะใช้งานผ่าน SSH นั้น จำเป็นจะต้องสร้าง SSH Key ของ PC ที่เราจะใช้งานกับ Git Server ขึ้นมาก่อน โดยการเปิด Git GUI ขึ้นมา แล้วคลิกไปที่เมนู Help > Show SSH Key

กรณียังไม่เคยสร้าง SSH Key ก็จะขึ้นว่า No keys found. ดังรูปด้านล่าง เราสามารถสร้างได้โดยการกดปุ่ม Generate Key

Git GUI ก็จะมี Dialog ให้เรากำหนด Passphrase และยืนยันอีกรอบ

เมื่อสร้าง SSH Key เรียบร้อยแล้ว ระบบจะสร้างไฟล์ id_rsa สำหรับ SSH Private Key และ id_rsa.pub สำหรับ SSH Public Key ไว้ที่ %userprofile%\.ssh
ถ้าอยากสร้าง Key ใหม่ ก็มาลบ 2 ไฟล์นี้ทิ้ง ก็แค่นั้นเอง
สำหรับ Git GUI จะแสดงเฉพาะส่วนของ SSH Public Key ดังรูป สามารถกด Copy To Clipboard ไปใช้งานได้เลย

กลับไปที่ GitHub ไปที่เมนู Settings (1) > SSH Keys (2) แล้วคลิกปุ่ม Add SSH key (3) ระบุชื่อของ Key และ Key (4) แล้วกดปุ่ม Add key (5) ทาง GitHub จะให้เราใส่ Password ของ Account เราเพื่อยืนยัน เป็นอันเสร็จพิธี

เมื่อเพิ่ม Key แล้ว ที่เมนู SSH Keys จะแสดงรายชื่อ Key ที่เราได้เพิ่มไว้ ดังรูป

Add Git Remote
เมื่อได้ URL มาแล้ว ไม่ว่าจะเป็นแบบ HTTPS หรือ SSH ก็ตาม ก็จะต้องนำไปเพิ่มให้กับ Local Repository เพื่อที่จะได้ไว้เชื่อมโยงกับ Remote Repository โดยไปที่เมนู Remote บน Git GUI เลือก Add…

จะพบกับ Add Remote dialog ให้เราเพิ่ม Git Server ลงไป โดยในส่วนของ Remote Details (1) ในช่อง Name จะใส่ชื่อที่เป็นตัวแทนของ Git Server โดยปกตินิยมตั้งชื่อว่า origin ส่วนของ Location จะใส่ URL ของ Remote Repository ที่ได้สร้างไว้บน Git Server รูปด้านล่างเป็นตัวอย่างการใส่ URL แบบ HTTPS และ SSH ตามลำดับ
ในส่วนของ Further Action (2) จะมีตัวเลือกดังนี้
- Fetch Immediately – ให้ทำการ Fetch ข้อมูล จาก Remote Repository มาทันที
- Initialize Remote Repository and Push – ให้เริ่มต้น Remote Repository และ Push เลย
- Do Nothing Else Now – ยังไม่ต้องทำอะไร


เมื่อกำหนด Git Server เรียบร้อย เมนู Remote ใน Git GUI จะมีเมนูเพิ่มขึ้นมา ดังรูปด้านล่าง

Git Push
Push คือการนำ Commit, Branch และ Tag จาก Local Repository ที่เราต้องการ ขึ้นไปไว้ที่ Remote Repository ก่อนอื่นผมขอใช้ Local Repository ตัวอย่าง ดังรูปด้านล่าง ซึ่งจะมี 7 Commits, 3 Branches และ 1 Tag

สำหรับการ Push นั้น ที่ Git GUI ให้ไปที่เมนู Remote > Push… ดังรูปด้านล่าง

จะพบกับ Push Dialog โดยในส่วนของ Source Branches (1) คือ Branch ที่เราต้องการ Push ขึ้น Remote Repository ในส่วนของ Destination Repository (2) คือ Git Server ที่เราได้เพิ่มไว้ก่อนหน้านี้ (ขอเลือกแบบ HTTPS ให้ดูก่อน) และ Transfer Options (3) จะเป็นตัวเลือกเพิ่มเติม โดยมีให้เลือกดังนี้
- Force overwrite existing branch (may discard changes) – จะทำการ Push Branch ที่เลือกไว้ ไปทับบน Remote Repository โดยไม่สนใจว่าบน Remote Repository จะแตกต่างจาก Local Repository อย่างไร
- Use thin pack (for slow network connections) – สำหรับกำหนดให้ทำการ Pack ข้อมูลให้เป็นขนาดเล็ก สำหรับ Network ที่ช้า
- Include tags – สำหรับการ Push Tag ขึ้นไปด้วย
เมื่อเลือก Option ตามต้องการแล้ว กดปุ่ม Push (4)

กรณีที่เลือก Push ไปที่ Git Server ที่กำหนดไว้แบบ HTTPS ระบบจะให้ยืนยัน Account ของเรา ด้วย Username และ Password ดังรูปด้านล่าง
แต่หากกำหนดไว้แบบ SSH จะต้องยืนยันด้วย Passphrase ของ SSH Key ที่สร้างไว้


เมื่อยืนยัน Account เรียบร้อย รอสักครู่ จะพบกับผลการทำงาน ดังรูปด้านล่าง ซึ่งจะแจ้งให้ทราบว่า ทำการ Push ไปที่ไหน และผลการทำงานเป็นอย่างไร รวมถึงทำการ Tracking Branch บน Local Repository กับ Remote Repository ให้ด้วย ก็คือการทำ Reference ไว้ว่า Branch ไหนบน Local Repository คือ Branch ไหนบน Remote Repository
การ Push ด้วย Git GUI จะทำการสร้าง Branch ที่ Remote Repository ชื่อเดียวกับ Local Repository เสมอ

ลองเปิด History ดู จะเห็น Branch ที่มีแถบสีส้มนำหน้า บอกให้รู้ว่า Branch บน Remote Repository อยู่ตรงไหน

ถ้าลองเปิดเว็บ GitHub ที่ Repository ที่สร้างไว้ จะเห็นว่ามีข้อมูลเข้ามาแล้ว จากรูปด้านล่าง จะเห็นว่า มี 7 Commits, 3 Branches และ 1 Tag ตามที่มีอยู่บน Local Repository นั่นเอง




Git Fetch
สำหรับการ Fetch นั้น คือการนำข้อมูลจาก Remote Repository มาอัพเดตยัง Local Repository โดยจะไม่แตะต้อง Branch ใด ๆ บน Local Repository บน Git GUI ให้ไปที่เมนู Remote > Fetch from > [Git Server] ดังรูปด้านล่าง (คราวนี้จะเลือกแบบ SSH ให้ดูบ้าง)

กรณีที่เป็น Private Repository จำเป็นจะต้องยืนยัน Account เช่นเดียวกับตอน Push แต่… บน GitHub ที่ผมสร้างไว้ เป็น Public Repository จึงทำการ Fetch ได้เลยโดยไม่ต้องยืนยัน
รูปด้านล่าง เป็นผลการ Fetch จะเห็นว่ามีการ Fetch ข้อมูลจาก Remote Repository มาแล้ว

ลองเปิดดู History จะเห็นว่าตำแหน่ง Branch บน Remote Repository ที่เพิ่มไว้แบบ SSH นั้น เพิ่มขึ้นมาแล้ว

คราวนี้ลอง Update ที่ Remote Repository ดูบ้าง เพื่อให้ Remote Repository ใหม่กว่า Local Repository โดยการเพิ่มไฟล์ใหม่และ Commit ที่ Branch dev…

ลบ Branch design…

จะเห็นว่า Branch dev มี Commit ที่เพิ่มมาใหม่ และ Branch design ได้ถูกลบออกไปแล้ว

ที่ Git GUI ลอง Fetch เฉพาะ Remote แบบ HTTPS ดู จะเห็นว่า Fetch มาเฉพาะ Branch dev เท่านั้น

และเมื่อตรวจสอบ History ดู จะเห็นว่า Commit ใหม่ และ Remote (HTTPS) Branch dev แสดงขึ้นมาแล้ว แต่ Local Branch dev ยังอยู่ที่เดิม…

สำหรับ Branch design ที่ลบทิ้งไปแล้วบน GitHub จากรูปบนจะเห็นว่ายังอยู่ เพราะการ Fetch ไม่ได้ทำการอัพเดต Branch ที่ลบบน Remote Repository ด้วย ถ้าอยากให้อัพเดต สามารถใช้ Git GUI เลือกไปที่เมนู Remote > Prune from > [Git Server] ดังรูปด้านล่าง



ตรวจสอบ History ดู จะเห็นว่า Remote Branch design ทั้งแบบ HTTPS และ SSH ถูกลบออกไปแล้ว ยังเหลือ Local Branch design ยังอยู่ ก็สามารถลบออกได้เลย แค่คลิกขวา…


ส่วน Remote (SSH) Branch dev ที่ยังคาอยู่ ก็แค่ Fetch ก็เรียบร้อยแล้ว

Git Pull
การ Pull คือการนำ Remote Repository มาอัพเดตยัง Local Repository คล้าย ๆ การ Fetch แต่จะทำการ Merge Remote Branch กับ Local Branch ด้วย ดังสมการต่อไปนี้
Pull = Fetch + Merge
ถ้าหาก Commit ทั้งหมดบน Local Repository อยู่บน Remote Repository ทั้งหมดอยู่แล้ว เราสามารถใช้สมการต่อไปนี้ได้เช่นกัน
Pull = Fetch + Reset
แต่การ Pull บน Git GUI ไม่มีเมนูนี้ให้ใช้งาน แต่ถ้าเราเข้าใจสมการข้างบน ก็ไม่มีอะไรยาก มาดูตัวอย่างกันเลยดีกว่า…
รูปด้านล่าง เป็น History ต่อจากหัวข้อ Fetch คราวที่แล้ว ซึ่งทำการ Fetch มาก่อนแล้ว จะเห็นว่า Remote Branch dev อยู่ที่ Commit ใหม่แล้ว ก็ทำการ Reset Local Branch dev ไปยัง Commit เดียวกันกับ Remote Branch dev ได้เลย โดยการเปลี่ยนไปยัง Branch dev ก่อน แล้วคลิกขวาที่ Commit ใหม่ เลือกเมนู Reset [Local Branch] branch to here ได้เลย

ก็จะมี Dialog ขึ้นมาให้ยืนยัน ว่าการ Reset นั้น จะเลือก Reset แบบไหน ซึ่งจะมีตัวเลือกดังนี้
- Soft – จะเป็นการย้ายตำแหน่ง Branch โดยไม่แตะต้องไฟล์ที่อยู่ใน Unstaged Changes และ Staged Changes เลย
- Mixed – จะเป็นการย้ายตำแหน่ง Branch โดยไม่แตะต้องไฟล์ที่อยู่ใน Unstaged Changes เท่านั้น
- Hard – จะเป็นการย้ายตำแหน่ง Branch โดยไฟล์ที่อยู่ใน Unstaged Changes และ Staged Changes จะหายไปทั้งหมด
เนื่องจากตอนนี้ Local Repository ไม่มีไฟล์ค้างอยู่ใน Unstaged Changes และ Staged Changes จะ Reset แบบไหน ก็จะให้ผลเท่ากัน

เมื่อ Reset เรียบร้อย Branch dev ทั้ง Local Repository และ Remote Repository ก็อยู่ที่ Commit เดียวกันแล้ว

คราวนี้มาลองเพิ่ม Commit ใหม่บน Branch dev ทั้ง Local Repository และ Remote Repository ดูบ้าง แล้วก็ Fetch จาก Remote ลงมาให้เรียบร้อย

จะเห็นได้ว่า Branch dev ทั้ง Local Repository และ Remote Repository เป็นคนละ Commit กัน หากจะ Reset Local Branch dev ไปยังตำแหน่ง Commit ของ Remote Branch dev ก็จะไม่ถูกต้องนัก หากต้องการเก็บการเปลี่ยนแปลงใน Commit ล่าสุดจาก Local Branch dev อยู่ กรณีนี้จึงจำเป็นต้องทำการ Merge Branch อย่างที่พูดถึงในสมการ Pull ที่ว่า Pull = Fetch + Merge นั่นเอง

การ Merge Remote Branch ไปยัง Local Branch ทำได้โดยใช้ Git GUI เลือกที่เมนู Merge > Local Merge… (อย่าลืมเปลี่ยนไปยัง Local Branch ปลายทางก่อนนะ)

บน Merge dialog เลือกไปที่ Tracking Branch จะแสดงรายชื่อ Remote Branch ทั้งหมดมาให้เลือก แล้วกดปุ่ม Merge

ผลการ Merge จะเห็นว่า Git GUI ทำการ Merge Remote Branch dev ไปยัง Local Branch dev เรียบร้อยแล้ว

เนื่องจากเป็นการ Merge แบบ 3 way จึงเกิดเป็น Commit ใหม่ ทำให้มี Commit บน Local Branch ที่ใหม่กว่า

ถ้าอยากอัพเดต Remote Branch ตาม Local Branch ก็แค่ Push ขึ้นไปก็เสร็จละ
สำหรับ Remote Repository ที่ทำมาทั้งหมด ถึงตรงนี้ ดูได้จาก GitHub ที่ https://github.com/first087/Test-Remote-Repository
Git Clone
การ Clone นั้น คือการทำ Remote Repository ที่มีอยู่แล้ว ลงมาใช้งานยัง Local Repository สำหรับ Git GUI นั้น ณ ปัจจุบัน ยังไม่สามารถ Clone จาก Git Server ได้ จำเป็นที่จะต้องเขียนคำสั่งผ่าน Command เอาเองด้วย Git Bash โดยคลิกขวาที่ Folder ที่ต้องการ

แล้วทำการพิมพ์คำสั่ง ดังนี้
1 |
git clone [url] |
โดย URL จะเป็นแบบ HTTPS หรือ SSH ก็ได้

จะเห็นว่าการ Clone นั้น จะทำการดึง Commit, เพิ่ม Remote Branch และ Tag ทั้งหมด ลงมาให้ พร้อมทั้งสร้าง Local Branch master ไว้ที่เดียวกับ Remote Branch master
ถ้าอยากได้ Branch อื่น ๆ ก็สร้างเอาที่ Commit ที่ต้องการได้เลย

ถึงจุดนี้ ก็เทียบเท่ากับการ Add Remote + Fetch + Pull แล้วล่ะ
Git Fork
ว่าจะไม่พูดถึงการ Fork (เพราะมันไม่ได้ทำบน Git GUI) ก็เหมือนจะขาดจุดเด่นของระบบ Git Server ไป เนื่องจากการ Fork ช่วยให้ Developer สามารถทำงานเป็นทีมได้อย่างมีประสิทธิภาพ ก็เลยพูดถึงสักหน่อยแล้วกัน
Fork คือการนำ Repository ของคนอื่น มาเป็นของเรา (ปล้นกันเห็น ๆ) โดยจะเหมือนยกทั้ง Repository มาเลย และจะมี Reference ไปยังเจ้าของ Repository ที่เรา Fork มา แต่จะกันอย่างอิสระ
สำหรับ GitHub นั้น ก็แค่กดปุ่ม Fork ที่ Repository ที่ต้องการ

ก็จะกลายเป็น Repository ของเราแล้ว ซึ่งจะแสดงที่มาของ Repository ของเราด้วย ว่า Fork มาจากไหน

ในเมื่อกลายเป็น Repository ของเราแล้ว จะ Clone ลงมาทำอะไร ก็เรื่องของเราละ แต่ถ้าเจ้าของเค้ามี Commit ใหม่ ก็จะอยู่ใน Repository ของเรา เราก็ไม่ได้มาด้วยเช่นกัน
แล้วจะทำงานร่วมกันยังไง!?
ถึงตรงนี้แล้ว หากเรามีการ Commit อะไรใหม่ ๆ ขึ้นไป แล้วอยากให้เจ้าของ Repository นำไปรวมด้วย ทำได้โดยการสร้าง Pull Request แล้วเจ้าของ Repository จะเห็น และสามารถตัดสินใจได้ว่า จะนำ Commit ใหม่ของเรา เข้าไป Merge รวมกับ Repository ของเรารึเปล่า
ก็จะออกมาเป็น ประมาณนี้…

ข้างบน คือ Repository ที่ผม Fork มาจาก Akexorcist มาเพิ่ม Feature, แก้ Bug และ Refactor ให้ สามารถดู Repository นี้ได้ที่ https://github.com/first087/Android-RoundCornerProgressBar
คงทิ้งเรื่อง Fork ให้ทราบกันแต่เพียงเท่านี้ หากมีโอกาสเหมาะ ๆ จะเขียน Blog เรื่องนี้ให้รับชมกันนะคร๊าบบบบบบ