เริ่มต้นใช้งาน Git
Git คือ เครื่องมือที่เอาไว้บันทึกเวอร์ชันการเปลี่ยนแปลงของไฟล์ในโปรเจคเรา ทำให้เราสามารถที่จะย้อนกลับไปดูเวอร์ชันต่างๆ ของโปรเจคได้ทุกเมื่อ หรือจะดูว่าใครเป็นคนแก้ไขไฟล์นั้นๆ ก็ได้ ซึ่ง Git นั้นจัดว่าเป็น Version Control แบบ Decentralized/Distributed คือไม่ต้องมีเซิร์ฟเวอร์เก็บโค้ดไว้ตรงกลาง ซึ่งจะต่างกับพวก Subversion หรือ CVS ที่ต้องมีเซิร์ฟเวอร์เก็บโค้ดรวมไว้ตรงกลาง (Centralized) และที่สำคัญ Git นั้นทำงานได้เร็วมากกว่าด้วย
ในบทความนี้จะพูดถึงบ้าง
Git basic workflow และ core features
วิธีการกู้คืนไฟล์ และการบันทึกหลายๆ เวอร์ชันในโปรเจค
การใช้ Git ทำงานร่วมกับคนอื่น (Collaborate) ผ่าน Remote Repository (GitHub)
เตรียมความพร้อมก่อนใช้งาน
การติดตั้ง Git
Windows ดาวน์โหลดตัวติดตั้งได้จาก https://git-scm.com/downloads
Mac OS X Yosemite or later ติดตั่งผ่าน Terminal ให้พิมพ์
$ git version
Linux ติดตั่งผ่าน Terminal ให้พิมพ์
$ sudo apt-get install git
Git Configurations
ก่อนจะเริ่มใช้งาน Git ได้นั้น จำเป็นต้องตั้งค่าการใช้งานเบื้องต้นก่อน ในบทความนี้จะใช้โปรแกรม Git Bash ที่ติดตั้งมาพร้อม Git for Windows
ตั้งชื่อผู้ใช้งาน “user.name”
ตั้งอีเมลของผู้ใช้งาน “user.email”
ตรวจสอบว่าที่ตั้งค่าถูกต้องหรือไม่
กำหนด Default Text Editor ให้กับ Git
จะใช้ Text Editor ตัวไหนก็ได้แล้วแต่ความถนัด แต่ในบทความจะเลือกใช้ Notepad++
กำหนด Path ที่ติดตั้ง Notepad++ ใน System Environment
กำหนดให้ Notepad++ เป็น Default Text Editor
ทดสอบ
สมัครใช้งาน GitHub
ไปที่ https://github.com/ และทำการ Sign up ให้เรียบร้อย
เชื่อมต่อ Github ด้วย SSH
ตรวจสอบว่ามี SSH keys แล้วหรือไม่ ผ่านโปรแกรม Git Bash
2. ถ้ายังไม่มี ให้สร้างใหม่โดยใช้ GitHub email โปรแกรมจะถามชื่อไฟล์ และรหัสผ่าน ถ้าไม่ต้องการเปลี่ยนแปลงก็กด Enter ไปได้เลย
3. เพิ่ม SSH keys ที่สร้างมาเข้าใน ssh-agent
4. เพิ่ม SSH keys ในบัญชี GitHub ของเรา โดยให้คัดลอก SSH key ก่อน
เริ่มได้สักที
1. Basic Git Workflow
ใน Git project จะประกอบด้วย 3 ส่วน
Working Directory: เป็นที่เก็บไฟล์ที่เราทำงานทุกอย่าง ทั้งสร้างใหม่ แก้ไข และลบทิ้ง
Staging Area: คือ ที่รวบรวมรายการที่แก้ไขไปทั้งหมดจาก working directory ที่จะนำเข้า repository
Repository: เป็นที่จัดเก็บไฟล์ที่มีการเปลี่ยนแปลงอย่างถาวร แยกเป็นเวอร์ชัน
ดังนั้น Git workflow จะประกอบด้วยการแก้ไขไฟล์ใน working directory แล้วนำไฟล์เหล่านั้นเข้า staging area สุดท้ายบันทึกการแก้ไขเข้า Git repository ด้วยคำสั่ง commit
ซึ่งมีวิธีการใช้งาน ดังนี้
เริ่มจากสร้าง working directory ชื่อ git-demo และสร้างไฟล์ greeting.txt ไว้ข้างใน
สร้าง Git repository (.git/)ด้วยคำสั่ง
init
ตรวจสอบสถานะไฟล์ในโปรเจค git-demo จะพบข้อความเตือนสีแดงใต้
untracked files
ซึ่งหมายความว่า Git มองเห็นว่ามีไฟล์อยู่ แต่ไฟล์นี้ยังไม่ได้เริ่ม tracking การเปลี่ยนแปลงของไฟล์นี้เลย
Git Life Cycle Staged : คือสถานะที่ไฟล์พร้อมจะ commit unstaged : คือไฟล์ที่ถูกแก้ไขแต่ว่ายังไม่ได้เตรียม commit untracked : คือไฟล์ที่ยังไม่ถูก track โดย Git (ส่วนมากจะเป็นไฟล์ที่เพิ่งสร้างใหม่) deleted : ไฟล์ที่ถูกลบไปแล้ว
วิธีการเริ่มต้น tracking ไฟล์ greeting.txt นั้น คือต้องเพิ่มไฟล์นี้ลงไฟใน staging area ก่อน โดยใช้คำสั่ง
git add filename1 filename2 filename3
แต่ถ้าต้องการเพิ่มทุกไฟล์ที่มีการแก้ไข/เปลี่ยนแปลงที่อยู่ใน working directory ใช้git add .
เมื่อลองตรวจสอบสถานะใหม่อีกครั้ง greeting.txt จะเปลี่ยนเป็นสีเขียวแล้ว พร้อมที่จะ commit
เราสามารถบอก Git ได้ว่าไม่ต้องการให้ Git เก็บไฟล์ไหนบ้าง โดยสร้างไฟล์ชื่อ
.gitignore
ไว้ที่ไดเรกทอรี Git project ภายในก็กำหนดค่าเป็นชื่อไฟล์ หรือชื่อไดเรกทอรีก็ไร หรือจะกำหนดเป็น*.log
คือไม่ต้องเก็บไฟล์ .log ทั้งหมด เป็นต้น
คราวนี้ให้แก้ไขไฟล์ greeting.txt โดยเพิ่มข้อความบรรทัดใหม่ว่า “git: Hey, Good to see you.” และเมื่อบันทึกเสร็จให้ลองใช้คำสั่ง
git diff filename
เพื่อดูความแตกต่างของไฟล์ระหว่าง working directory กับ staging area เสร็จแล้วให้เอาไฟล์นี้เอา staging area ด้วย
คำอธิบาย - “me: Hello Git” คือ ข้อความเดิมที่อยู่ใน staging area แสดงด้วยตัวอักษรสีขาว - ในส่วนที่มีการแก้ไขเพิ่มเข้ามาจะขึ้นต้นด้วย
+
ตัวอักษรสีเขียว - การออกจาก diff mode ให้กดq
ขั้นตอนสุดท้ายของ Git workflow คือการ ‘commit’ ไฟล์ที่อยู่ใน staging area เข้าไปเก็บใน Git repository แบบถาวร ด้วยคำสั่ง
git commit -m "commit message"
โดย commit message นั้นจะต้องอยู่ใน quotation marks, ข้อความต้องเป็น present tense และควรจะไม่เกิน 50 ตัวอักษร
ถ้าจะดูประวัติการ ‘commit’ ใน repository ทำได้โดยใช้คำสั่ง
git log
Output ที่ได้ มีดังนี้ - เลขการ ‘commit’ ออกมา 40 ตัวอักษร เรียกว่า SHA ตัวอักษรสีเหลือง แต่เวลาอ้างอิงใช้แค่ 7 ตัวอักษรแรก - ชื่อคน ‘commit’ - วันที่ และเวลาที่ ‘commit’ - commit message
เนื่องจากรูปแบบการแสดงผลปกติของ
git log
นั้นดูยากไปหน่อยถ้ามีประวัติการ ‘commit’ หลายๆ ครั้ง ส่วนตัวชอบใช้วิธีให้แสดงประวัติแต่ละครั้งในบรรทัดเดียว ตามนี้
ถ้าความขี้เกียจพิมพ์คำสั่งยาวๆ เราสามารถใช้ Git alias สร้างคำสั่งของเราขึ้นมาเองได้ โดยจะเอาการแสดง log ข้างบน มาสร้างเป็นคำสั่ง
git hist
ลองทดสอบคำสั่งใหม่ดู
สรุปคำสั่ง
git init
ไว้สร้าง Git repositorygit status
ตรวจสอบสถานะไฟล์ของ working directory และ staging areagit add
เพิ่มไฟล์ the working directory เข้าสู่ staging areagit diff
แสดงความแตกต่างของไฟล์ระหว่าง working directory กับ staging areagit commit
เก็บประวัติการแก้ไขแบบถาวรจาก staging area ไว้ใน repositorygit log
แสดงรายการที่ commit มาทั้งหมด
2. การกู้คืนไฟล์
บางครั้งในการทำงาน เช่น การแก้ซอร์สโค้ด เราอาจจะแก้ซอร์สโค้ดนั้นจนไม่สามารถรันได้อีก และจำไม่ได้ว่าเราแก้ไขอะไรไปแล้วบ้าง ซึ่ง Git นั้นมีฟีเจอร์ง่ายๆ ในการกู้คืนไฟล์ เพื่อแก้ไขความผิดพลาดที่เกิดขึ้นใน Git project ของเรา
สมมุติว่าเผลอลบข้อความในไฟล์ greeting.txt ออกทั้งหมด และบันทึกทับไปแล้ว
ลองพิมพ์คำสั่ง
git show HEAD
ซึ่งจะแสดงข้อมูลทุกอย่างจากคำสั่งgit log
จากHEAD
commit และต่อท้ายด้วยสิ่งที่แก้ไขเพิ่มเข้ามาจากการ ‘commit’ ครั้งนั้น
HEAD
: คือ pointer ที่เก็บทุกๆ commit ของเรา โดยปกติแล้วHEAD
จะชี้ไปที่commit
ล่าสุด reference ของHEAD
จะอยู่ในรูปแบบ SHA
ถ้าเราต้องการย้อนกลับแก้ไขไฟล์ greeting.txt กลับไปยังการ
HEAD
: commit ล่าสุด ให้ใช้คำสั่งgit checkout HEAD filename
ก็จะได้ไฟล์กลับมาเหมือนเดิม
แต่ถ้าเราเผลอไปใช้
git add
จะทำให้ไฟล์ถูกเปลี่ยนสถานะเป็น staged คือพร้อมที่จะ commit แต่เราไม่ต้องการ commit ไฟล์นั้นก่อน ดังนั้นต้องทำให้ไฟล์นั้นกลับมาเป็นสถานะ unstaged เสียก่อน โดยใช้คำสั่งgit reset HEAD filename
แต่ไฟล์ไม่ได้ย้อนกลับการแก้ไขให้เหมือนการcheckout
นะ
กรณีที่เราต้องการย้อนกลับไปยัง commit ใดๆ ใช้คำสั่ง
git reset SHA
(SHA ใช้แค่ 7 ตัวอักษรแรก) ซึ่งเมื่อย้อนกลับไปแล้วHEAD
จะถูกย้ายกลับไปยัง commit นั้นๆ ด้วย ดูได้จากรูปข้างล่าง และตรง commit สีเทานั้น ก็จะหายไปจาก Git project ด้วย
สรุปคำสั่ง
git checkout HEAD filename
: ยกเลิกการแก้ไขใน working directorygit reset HEAD filename
: ยกเลิกสถานะกลับเป็น Unstages ใน staging areagit reset SHA
: ยกเลิกการแก้ไขกลับไปยัง commit ก่อนหน้าตามที่เลือก
3. Branching and Merging
วิธีการดูว่าตอนนี้เรามี branch อะไรบ้าง และจะมี
*
(asterisk) อยู่หน้าชื่อ branch ที่กำลังทำงานอยู่ ทำได้โดย
สร้าง branch ใหม่ ชื่อ goodbye โดยใช้คำสั่ง
git branch new_branch_name
สลับไปใช้งาน branch ใหม่ โดย
git checkout branch_name
เราสามารถสั่ง
git checkout -b branch_name
เพื่อสร้าง branch ใหม่ พร้อมเปลี่ยนไปใช้งานได้เลย
ทดสอบสร้างไฟล์ใหม่ และ commit ดู
ลองดูจาก log เทียบกันระหว่าง 2 branch ดู จะพบว่า goodbye.txt จะมีอยู่แต่ใน branch ชื่อ goodbye เท่านั้น ส่วนใน master ไม่มีอะไรเปลี่ยนแปลง
แต่ถ้าต้องการรวม branch goodbye เข้าไปใน master ให้สลับกลับมาอยู่ master ก่อน จากนั้นใช้คำสั่ง
git merge branch_name
เมื่อลองดูจากลอง commit 9afb852 ของ branch goodbye จะถูกรวมเข้ากับ master เรียบร้อยแล้ว
แต่ถ้ามีการแก้ไขไฟล์จาก master และได้ทำการ commit ไปก่อนที่จะทำการ merge และใน goodbye branch ก็มีการแก้ไขไฟล์เดียวกันด้วย เมื่อสั่ง merge Git จะไม่ทราบว่าเราจะเอาเวอร์ชันไหนกันแน่ สิ่งนี้เรียกว่า Merge Conflict
เมื่อลองเปิดไฟล์ดูข้างใน
notepad++ goodbye.txt
จะข้อความแปลกๆ แบบนี้
คือ Git จะไม่รู้ว่าเราต้องการเก็บข้อมูลชุดไหนไว้กันแน่ โดยจะมี Git’s special markings บอกเอาไว้ว่าข้อความของ master
branch จะอยู่ระหว่าง <<<<<<< HEAD
กับ =======
ส่วนของ goodbye
branch อยู่ระหว่าง =======
กับ >>>>>>
ซึ่งเราต้องแก้ไขเองว่าจะเอาข้อความไหน และต้องลบ Git’s special markings ออกด้วย
เมื่อแก้ไข conflict เสร็จแล้วก็สั่ง add เข้า staging area และ commit เก็บไว้
สุดท้ายเมื่อเรา merge branch ที่เราแยกออกไปเสร็จแล้ว หรือไม่ต้องการ branch นั้นๆ แล้ว ก็สามารถลบทิ้งได้ โดยใช้คำสั่ง
git branch -d branch_name
สรุปคำสั่ง
git branch
: ใช้แสดงรายชื่อ branch ทั้งหมดgit branch branch_name
: สร้าง branch ใหม่git checkout branch_name
: สลับไปใช้งาน branch ที่ระบุgit merge branch_name
: ใช้รวมไฟล์จาก branch ที่ระบุ มายัง branch ปัจจุบันgit branch -d branch_name
: ลบ branch ที่ระบุ
4. Git Remote Repository
จากที่ศึกษาวิธีการใช้ Git มาจากข้างต้นนั้นจะเป็นการใช้งานแบบ single user บน local repository ที่อยู่บนเครื่องใครเครื่องมัน แต่ Git นั้นจัดเป็น collaboration tool ตัวนึงที่ทำให้เราทำงานร่วมกับผู้อื่นในโปรเจคได้ง่ายขึ้น โดยผ่าน remote repository เช่น GitHub หรือ Bitbucket ซึ่งจะเป็นตัวกลางในการทำ pulling หรือ pushing งานในโปรเจคที่ทำร่วมกัน
ตัวอย่างสร้าง remote repository อยู่บน GitHub ชื่อ github-demo
ล็อกอินเข้า GitHub เลือกเครื่องหมาย + ข้างๆ รูปโปรไฟล์ แล้วเลือกเมนู New repository
ตั้งชื่อ Repository name และเลือก “ Initialize this repository with a README” เพื่อสร้างไฟล์ README.md กดปุ่ม Create repository
เมื่อได้ remote repository มาแล้ว ก็ให้ ‘clone’ มาไว้ที่เครื่องของเรา โดยใช้คำสั่ง git clone remote_location clone_name
ซึ่ง remote_location คือที่อยู่ของ remote repository และ clone_name คือชื่อไดเรกทอรีที่จะให้บันทึก แต่ถ้าไม่ระบุ Git จะสร้างไดเรกทอรีชื่อเดียวกับชื่อของ repository ให้อัตโนมัติ
สิ่งที่ Git ทำอยู่เบื้องหลังเมื่อเรา clone โปรเจคมา คือ Git จะสร้าง remote address ขึ้นมาชื่อ origin เพื่อความสะดวกในการอ้างอิงถึง remote repository โดยใช้เพียงแค่ชื่อ ถ้าต้องการจะดูว่าใน Git project ของเรามีรายการ remotes อะไรบ้าง ใช้คำสั่ง git remote -v
จากในไดเรกทอรีของ Git project
fetch คือ remote address ที่จะให้ไปดึงจากฝั่ง remote มายังฝั่ง local push คือ remote address ที่จะให้เอาจากฝั่ง local ไปรวมที่ฝั่ง remote ที่ไหน
หลังจากที่เรา clone โปรเจคมานานแล้ว และไม่ทราบว่าทางฝั่ง remote นั้นมีการเปลี่ยนแปลงอะไรเกิดขึ้นแล้วบ้าง เราสามารถตรวจสอบได้โดยใช้คำสั่ง git fetch
แก้ไขไฟล์ README.md ที่ GitHub โดยเพิ่มข้อความในบรรทัดใหม่ว่า “This line from remote repository.”
ดึงข้อมูลจากฝั่ง remote ว่ามีการเปลี่ยนแปลงอะไรเกิดขึ้นบ้าง
ตรวจสอบด้วย
git status
จะได้ข้อความดังนี้
หมายความว่าบน local ( branch master)นั้นตามหลังบน remote ( branch origin/master) อยู่ 1 commit ซึ่งเราสามารถรวมโค้ดจาก remote มายัง local ได้ด้วยวิธีเดียวกันกับการรวมโค้ดจาก branch อื่น โดยใช้คำสั่ง
git merge
โดยระบุชื่อ branch เป็น “origin/master”
git pull
คือการรวมโค้ดจาก remote มายัง local เลยโดยไม่สนใจว่าระหว่าง remote กับ local ต่างกันอย่างไรบ้าง ซึ่งจริงแล้วgit pull
คือการทำgit merge
แล้วต่อด้วยgit pull
ให้แบบอัตโนมัติ
ต่อมาเมื่อเรามีการแก้ไขจากฝั่ง local และต้องการจะส่งไปเก็บไว้ที่ฝั่ง remote ด้วย ทำได้โดยใช้คำสั่ง git push remote_alias_name branch_name
เช่น git push -u origin master
-u
: เอาไว้จำ parameter origin master ครั้งต่อๆ ไปก็พิมพ์แค่git push
origin
: คือ ชื่อ alias ของ remote (github)master
: คือ ชื่อ branch ที่เราต้องการ push ขึ้นไป
เมื่อลองไปดูจาก GitHub จะเห็นว่าไฟล์ README.md จะถูกอัพเดทแล้ว
สรุปคำสั่ง
git clone
: สร้าง local repository จาก remote repositorygit remote -v
: แสดงรายการ remote address ทั้งหมดgit fetch
: ดึงข้อมูลทั้งหมดจากฝั่ง remote มายัง localgit merge origin/master
: สั่งรวมไฟล์จากorigin/master
มายัง local branchgit pull
: สั่งรวมไฟล์จาก ฝั่ง remote มายัง local (git fetch
+git merge
)git push origin <branch_name>
: ส่งข้อมูลจาก local branch ไปรวมกับorigin
remote.
5. Stashing
คือการบันทึกโปรเจคของเรา และซ่อนเอาไว้ เมื่อจะใช้ก็สั่ง restore กลับมาได้ตลอดเวลา เช่น กรณีที่เรากำลังแก้ไขไฟล์อยู่ และจำเป็นต้องสั่ง commit
โปรเจคนี้ แต่ไฟล์นี้ยังแก้ไขไม่เสร็จเลยไม่ต้องการ commit
ในครั้งนี้ด้วย ก็ใช้ stash
เพื่อซ่อนไฟล์นี้เอาไว้ก่อน เมื่อได้ commit
เสร็จแล้ว ก็สั่ง restore ไฟล์ที่ซ้อนไว้กลับมา แก้ไขจนเสร็จ แล้วค่อย commit
ใหม่
git stash
: สั่งซ้อนไฟล์git stash list
: แสดงรายการที่ซ้อนไว้ โดยรายการล่าสุดจะอยู่ที่stash@{0}
git stash pop
: สั่ง restore รายการล่าสุดกลับมา
6. Tagging
ก่อนที่จะทำการ release ระบบออกไปนั้น แนะนำให้ทำการสร้าง tag หรือ ป้ายชื่อ เพื่อบอกให้รู้ว่าเรากำลังทำอะไร อยู่ตรงไหน
git tag tag_name SHA
: สร้าง tag ขึ้นมาใน commit ที่ระบุ ถ้าไม่ระบุจะเป็นHEAD
commitgit tag --list
: แสดงรายการชื่อ tag ทั้งหมดgit tag -d tag_name
: สั่งลบจากชื่อ tag ที่ระบุgit show tag_name
: แสดงรายละเอียด commit จากชื่อ tag ที่ระบุgit tag -a tag_name -m "message"
: สร้าง tag แบบระบุข้อความบอกว่า tag นี้คืออะไร ซึ่งเมื่อใส่git show tag_name
จะแสดงข้อความจาก-m
ขึ้นมาให้ด้วย
7. Remove
git rm filename
: สั่งลบไฟล์ และสั่งให้ Git ทำการuntracked
ไฟล์ด้วยgit rm --cached filename
: สั่งลบไฟล์ออกจาก Git repository เฉยๆ ไม่ได้ลบไฟล์จริงใน working directory ออกด้วย
สรุป
บทความนี้จะพูดถึงการใช้งาน Git ผ่าน Command Line เพื่อต้องการให้เกิดความใจว่า Git นั้นทำงานอย่างไร แต่ละขั้นตอนใช้คำสั่งอะไรบ้าง เมื่อเปลี่ยนไปใช้ Git แบบ GUI เช่น SourceTree หรือ GitHub Desktop จะได้จะรู้ว่าการทำงานของมันมีที่มาที่ไปอย่างไร แต่สุดท้ายเราจะเลือกใช้งานแบบ Command Line หรือ GUI ก็แล้วความถนัดของเราครับ
Reference : https://medium.com
Last updated