LEARNING GIT
ตอนที่ 4: Branches
On this page
ตอนที่แล้วเราเก็บสี red และ orange ลงใน commit history ของ rainbow แล้ว ตอนนี้ main จึงมีประวัติการทำงานให้ย้อนดูได้เรียบร้อย
แต่ถ้าเราอยากลองเพิ่ม feature ใหม่โดยไม่เสี่ยงทำให้ main มีงานที่ยังไม่เรียบร้อยล่ะ? เราก็สร้าง branch ใหม่แยกออกมาก่อน นั่นคือการใช้ branch
สิ่งที่จะได้ตอนจบบทนี้:
- อธิบายได้ว่า branch คือ movable pointer ที่ชี้ไปยัง commit และใช้แยกสายการพัฒนาออกจาก
mainเพื่อทำงานต่อโดยไม่กระทบสายหลัก - ใช้
git branchเพื่อ list และสร้าง local branch - ใช้
git switchสลับ branch และตรวจสอบว่าอยู่ branch ไหน - แยกความหมายของ
HEAD,refs/heads/และ branch pointer ออกจากกัน - แยกได้ว่า tracked file อยู่ในสถานะ unmodified หรือ modified
- สร้าง commit บน
featureโดยให้mainค้างอยู่ที่ commit เดิม - อ่าน parent link ของ commit และดูว่า history สองสายเริ่มแยกจากกันอย่างไร
flowchart LR A["main ชี้ orange"] -->|"git branch feature"| B["main และ feature ชี้ orange"] B -->|"git switch feature"| C["HEAD -> feature"] C -->|"commit yellow"| D["feature ชี้ yellow
main ยังชี้ orange"]
วิธีทำตามบทนี้
บทนี้ต่อจากตอนที่ 3 โดยสมมติว่าใน rainbow มี commit อย่างน้อยสองตัวแล้ว และ working tree อยู่ในสถานะ clean หลังจากทำ commit orange
เข้าไปใน repository ก่อน:
cd ~/rainbow
pwd
git status
git log --oneline --decorate
ผลลัพธ์ควรมีหน้าตาประมาณนี้:
On branch main
nothing to commit, working tree clean
7acb333 (HEAD -> main) orange
abc1234 red
hash บนเครื่องของเราจะไม่เหมือนตัวอย่าง ไม่เป็นไร ขอให้เห็นว่า HEAD -> main อยู่ที่ commit ล่าสุด และ working tree อยู่ในสถานะ clean ก็พอ
ถ้าตอนนี้ยังมีไฟล์ modified หรือมีการแก้ไขที่ staged ค้างอยู่ ให้ตรวจ git status ก่อนสลับ branch แล้ว commit หรือ stash งานที่ค้างไว้ก่อน หากจำเป็น Git อาจไม่อนุญาตให้สลับ branch ถ้าการสลับนั้นเสี่ยงทำให้ไฟล์ถูกทับหรือเกิด conflict
เครื่องหมาย $ ที่เห็นในตัวอย่างเป็นเพียง command prompt ไม่ต้องพิมพ์ตามไปด้วย
Step 1: Branch มีไว้ทำไม?
Branch คือ pointer ที่ชี้ไปยัง commit ซึ่งเป็น snapshot ของโค้ด ณ จุดหนึ่ง เราจึงใช้ branch สร้างสายการพัฒนาแยกออกมา ทำงานต่อและบันทึก commit ของตัวเองได้โดยไม่กระทบ branch หลัก
ทำไมต้องใช้ branch?
เหตุผลหลักมีสองอย่าง:
- ลองทำงานหลายแนวทางในโปรเจกต์เดียวกัน โดยไม่เอางานที่กำลังทำไปปะปนกับ branch หลัก เช่น
feature/add-yellow-color - ให้หลายคนทำงานพร้อมกัน แล้วค่อยรวมงานที่ตรวจสอบแล้วกลับเข้ามาใน branch หลัก หรือ
main
ใน workflow ที่เจอกันบ่อย เราจะมี branch หลักชื่อ main แล้วแตก topic branch หรือ feature branch ออกมาทำงานเฉพาะเรื่อง เช่น:
feature/add-yellow-colorสำหรับเพิ่มสีเหลืองfix/incorrect-totalสำหรับแก้ bug คำนวณยอดรวมผิดdocs/update-readmeสำหรับปรับเอกสาร
พองานใน branch ย่อยเสร็จและผ่านการ review แล้ว ค่อยรวมกลับเข้า main ด้วยการทำ merge หรือ rebase ซึ่งเราจะลงรายละเอียดในตอนถัด ๆ ไป
ใช้อย่างไร?
workflow พื้นฐานของบทนี้มีหน้าตาแบบนี้:
อยู่บน main
↓ git branch feature
สร้าง feature แต่ยังอยู่บน main
↓ git switch feature
ย้ายไปทำงานบน feature
↓ git add และ git commit
feature เดินหน้า แต่ main อยู่ที่เดิม
จุดที่ต้องจำให้แม่นคือ git branch <name> สร้าง branch แต่ ไม่ได้สลับเราไป branch นั้นให้อัตโนมัติ
Branch ไม่ใช่การก๊อปปี้ไฟล์ทั้งโปรเจกต์ แต่เป็นการสร้างป้ายชื่อกำกับไว้ที่ commit ล่าสุดเพื่อสร้างสายการพัฒนาใหม่
Step 2: Branch ใน Git เป็นแค่ pointer
คำว่า branch อาจทำให้คิดว่า Git ต้องสร้างไฟล์โปรเจกต์ชุดใหม่ทั้งก้อน แต่เบื้องหลัง Git ทำงานง่ายกว่านั้นมาก
ในทางเทคนิค branch คือ movable pointer หรือ pointer ที่เลื่อนไปชี้ commit ใหม่ได้
ลองดูข้อมูล branch ที่มีอยู่ตอนนี้:
git log --oneline --decorate
ตัวอย่าง output:
7acb333 (HEAD -> main) orange
abc1234 red
ข้อความ (HEAD -> main) บอกว่า:
mainชี้ไปที่ commitorangeHEADกำลังชี้ไปที่ branchmain- ตอนนี้เราจึงกำลังทำงานบน
main
ถ้า branch เป็นป้ายชื่อที่วางอยู่บน commit เราก็ขยับป้ายชื่อนั้นไปข้างหน้าได้เมื่อทำ commit ใหม่ โดยไม่ต้องก๊อปปี้ไฟล์ทั้งหมด
ลูกศรสองแบบที่ห้ามสับสน
เวลาอ่านไดอะแกรมของ Git ให้แยกลูกศรสองแบบนี้ออกจากกัน:
| สิ่งที่ชี้ | ความหมาย | ขยับได้ไหม? |
|---|---|---|
| Branch pointer | main หรือ feature ชี้ไปยัง commit ล่าสุดของสายตัวเอง | ขยับตาม commit ใหม่ |
| Parent link | commit ลูกชี้กลับไปยัง commit แม่ก่อนหน้า | ไม่ขยับ เพราะเป็นประวัติที่บันทึกไปแล้ว |
ในไดอะแกรมของบทนี้ ลูกศรจากชื่อ branch ไปยัง commit คือ branch pointer ส่วนความสัมพันธ์จาก commit ใหม่ย้อนกลับไปยัง commit เก่าคือ parent link
feature ───────► yellow commit
│
│ parent link
▼
main ───────► orange commit
│
│ parent link
▼
red commit
feature และ main จึงชี้คนละ commit ได้ แต่ commit yellow ยังรู้ว่า orange เป็น parent ของตัวเองอยู่เสมอ
ส่อง commit ที่ branch ชี้อยู่
ใช้คำสั่งนี้เพื่อถาม Git ตรง ๆ ว่า branch แต่ละตัวชี้ไปที่ hash ไหน:
git rev-parse main
git rev-parse HEAD
ก่อนสร้าง feature ทั้งสองบรรทัดควรคืนค่า hash เดียวกัน เพราะตอนนี้ HEAD อยู่บน main และ main ชี้ไปยัง commit ล่าสุดตัวเดียวกัน
7acb333f08e12020efb5c6b563b285040c9dba93
7acb333f08e12020efb5c6b563b285040c9dba93
hash ในตัวอย่างเป็นเพียงตัวอย่าง จุดสำคัญคือผลลัพธ์สองบรรทัดเท่ากัน
main กับ master ต่างกันไหม?
ในทางเทคนิค main ไม่ได้มีพลังพิเศษอะไร มันเป็นเพียงชื่อ branch ที่ชุมชนนิยมใช้เป็น default branch มากขึ้น ส่วน master คือชื่อ default branch แบบเก่า
เราตั้งชื่อ branch แรกเป็นอะไรก็ได้ เช่น git init -b main ที่ใช้มาตั้งแต่ตอนที่ 2 เป็นการเลือกชื่อ main ให้ชัดเจนและสอดคล้องกับ convention ปัจจุบัน
Step 3: สร้าง branch ใหม่ด้วย git branch
ตอนนี้เรายังอยู่บน main และมี commit orange เป็นจุดล่าสุด มาสร้าง branch สำหรับลองเพิ่มสี yellow กัน
เริ่มจาก list branch ที่มีอยู่:
git branch
ควรเห็น:
* main
เครื่องหมาย * คือสัญลักษณ์ที่บอกว่าเรากำลังอยู่บน branch ไหน
สร้าง branch ชื่อ feature:
git branch feature
จากนั้น list อีกครั้ง:
git branch
ผลลัพธ์ควรเป็น:
feature
* main
เราสร้าง feature สำเร็จแล้ว แต่ยังอยู่บน main เหมือนเดิม นี่เป็นจุดที่คนเพิ่งเริ่มใช้ Git พลาดกันบ่อยมาก
รัน git log จะเห็นว่า branch ทั้งสองชี้ไปที่ commit เดียวกัน:
git log --oneline --decorate
7acb333 (HEAD -> main, feature) orange
abc1234 red
ข้อความ (HEAD -> main, feature) หมายถึง HEAD อยู่บน main และทั้ง main กับ feature ต่างก็ชี้ไปที่ orange
สรุปคำสั่งใน Step นี้
| คำสั่ง | ทำอะไร | หลังรันคำสั่งเราอยู่ที่ไหน? |
|---|---|---|
git branch | list local branch | อยู่ที่เดิม |
git branch feature | สร้าง branch ชื่อ feature | ยังอยู่ที่เดิม คือ main |
git branch <name> | สร้าง branch ตามชื่อที่กำหนด | ไม่สลับ branch |
ชื่อ branch ห้ามมีช่องว่าง ถ้าเป็นโปรเจกต์จริงควรตั้งชื่อให้บอกเรื่องที่กำลังทำ ไม่ใช้ชื่อกว้าง ๆ จนเปิดมาอีกทีแล้วจำไม่ได้ว่า branch นี้มีไว้ทำอะไร
Step 4: สลับ branch ด้วย git switch
เราสร้าง feature แล้ว ถึงเวลาย้ายไปทำงานบน branch นี้:
git switch feature
Git ควรตอบกลับว่า:
Switched to branch 'feature'
ตรวจว่าเราย้ายสำเร็จหรือยัง:
git branch
git status
git log --oneline --decorate
ผลลัพธ์สำคัญควรเป็นแบบนี้:
main
* feature
On branch feature
nothing to commit, working tree clean
7acb333 (HEAD -> feature, main) orange
abc1234 red
ตอนนี้ HEAD เปลี่ยนจาก main มาชี้ feature แล้ว แต่ commit ที่เรากำลังดูยังเป็น orange เพราะ main และ feature ยังชี้ commit เดียวกันอยู่
HEAD คืออะไร?
ในสถานะปกติ HEAD เป็น pointer ที่บอกว่า ตอนนี้เราอยู่บน branch ไหน การเขียนด้วยตัวพิมพ์ใหญ่เป็น convention ของ Git ไม่ใช่ acronym ที่ต้องแปลเป็นคำย่อ
ถ้าอยากดูด้วยคำสั่ง:
git symbolic-ref --short HEAD
ควรได้:
feature
หรือเปิดไฟล์ .git/HEAD ดูก็ได้:
cat .git/HEAD
ผลลัพธ์:
ref: refs/heads/feature
อ่านได้ว่า HEAD อ้างอิงไปยังไฟล์ของ branch feature ในโฟลเดอร์ refs/heads/
อย่าสับสนสองคำนี้:
HEAD— pointer พิเศษที่บอกว่าเราอยู่ branch ไหนrefs/heads/— โฟลเดอร์ที่เก็บข้อมูลของ local branch แต่ละตัว
git switch ทำอะไรบ้าง?
การสลับ branch ไม่ได้มีแค่เปลี่ยนข้อความใน prompt แต่ Git จะทำงานหลัก ๆ สามอย่าง:
- เปลี่ยน
HEADให้ชี้ไปยัง branch ใหม่ - เตรียม staging area ให้ตรงกับ snapshot ของ commit ที่ branch ใหม่ชี้ไป
- นำเนื้อหาจาก staging area มาแสดงใน working directory
ในตัวอย่างนี้ branch ทั้งสองชี้ไปยัง commit เดียวกัน จึงเห็นผลชัดเจนเฉพาะข้อแรก ถ้า branch ทั้งสองชี้ไปยังคนละ commit ไฟล์ใน working directory ก็อาจเปลี่ยนตามไปด้วย
สำหรับ Git รุ่นเก่ากว่า 2.23 ที่ยังไม่มี git switch ใช้คำสั่งนี้แทนได้:
git checkout feature
git checkout ทำได้มากกว่าการสลับ branch ส่วน git switch ถูกออกแบบมาให้สื่อความหมายเรื่องการสลับ branch ได้ตรงกว่า จึงเหมาะกับการเรียนและลดโอกาสสั่งผิดงาน
Step 5: ทำงานแยกบน feature
ตอนนี้เราอยู่บน feature แล้ว ลองเพิ่มสี yellow โดยไม่เปลี่ยน commit ล่าสุดของ main
เปิด rainbowcolors.txt ด้วย text editor แล้วเพิ่มบรรทัดนี้ต่อท้าย จากนั้น เซฟไฟล์:
Yellow is the third color of the rainbow.
กลับมาที่ terminal แล้วตรวจสถานะ:
git status --short
ผลลัพธ์ควรเป็น:
M rainbowcolors.txt
รูปแบบ M หมายความว่าไฟล์ที่ Git ติดตามอยู่ถูกแก้ไขใน working directory แต่การแก้ไขยังไม่ได้เข้า staging area
ถ้าไม่เห็น M ให้เช็กสองเรื่อง:
- เพิ่มบรรทัดตามตัวอย่างแล้วหรือยัง
- กดเซฟใน text editor แล้วหรือยัง
Git จะเห็นการแก้ไขเมื่อไฟล์ถูกบันทึกลงดิสก์แล้ว ถ้าแก้ข้อความค้างอยู่ใน editor แต่ยังไม่เซฟ Git ก็ยังมองไฟล์นั้นเป็น unmodified
ไฟล์ tracked มีสองสถานะที่ควรรู้
หลังจากไฟล์ถูกบันทึกไว้ใน commit แล้ว Git จะติดตามไฟล์นั้นต่อไป ใน working directory เราจะเจอสถานะสำคัญสองแบบ:
| สถานะ | ความหมาย | แสดงใน git status ไหม? |
|---|---|---|
| Unmodified | ยังไม่แก้ตั้งแต่ commit ล่าสุด | ไม่แสดงเป็นรายการไฟล์ |
| Modified | แก้และเซฟแล้ว แต่ยังไม่ commit | แสดงเป็นรายการไฟล์ |
นี่เป็นเหตุผลที่เมื่อ repository อยู่ในสถานะ clean เราเห็นแค่:
nothing to commit, working tree clean
git status ไม่ได้พิมพ์รายชื่อไฟล์ทุกไฟล์ในโปรเจกต์ แต่เน้นรายงานไฟล์ที่มีการเปลี่ยนแปลงหรือยังไม่ถูกติดตาม
Stage และ commit บน feature
เริ่มจากดู diff ของ working directory ก่อน:
git diff
ถ้าเห็นเฉพาะบรรทัดที่ตั้งใจเพิ่ม ให้ stage แล้วตรวจ staging area:
git add rainbowcolors.txt
git status
ก่อน commit git status ควรมีข้อความประมาณนี้:
Changes to be committed:
modified: rainbowcolors.txt
ถ้า git status ถูกต้อง ค่อยสร้าง commit:
git commit -m "yellow"
output จะมีหน้าตาประมาณนี้:
[feature fc8139c] yellow
1 file changed, 1 insertion(+)
hash fc8139c เป็นเพียงตัวอย่าง แต่ละเครื่องอาจได้ค่าอื่น ชื่อ [feature ...] จะช่วยยืนยันว่า commit นี้เกิดบน feature
ตรวจ history หลัง commit:
git log --oneline --decorate
ควรเห็น:
fc8139c (HEAD -> feature) yellow
7acb333 (main) orange
abc1234 red
สิ่งที่เกิดขึ้นคือ:
featureเลื่อนไปชี้ commityellowHEADยังชี้featuremainยังชี้ไปที่ commitorangeyellowมี parent link ย้อนกลับไปorange
นี่คือเหตุผลที่ branch มีประโยชน์ เราเพิ่มงานบน feature ได้โดยยังไม่ทำให้สายหลักเดินตามไปด้วย
เมื่อทำ commit เฉพาะ branch ที่
HEADชี้อยู่เท่านั้นที่จะเลื่อนไปยัง commit ใหม่ ส่วนmainไม่ได้เลื่อนตามเพียงเพราะเราทำงานใน repository เดียวกัน
Step 6: ดูสองสายและเบื้องหลังของ pointer
หลังจากทำ commit yellow เราสามารถสลับไปดู main ได้ เพราะตอนนี้ working tree ควรอยู่ในสถานะ clean แล้ว:
git switch main
git status
git log --oneline --decorate
ผลลัพธ์:
Switched to branch 'main'
On branch main
nothing to commit, working tree clean
7acb333 (HEAD -> main) orange
abc1234 red
เมื่ออยู่บน main ถ้าเปิด rainbowcolors.txt จะยังไม่เห็นบรรทัด Yellow is the third color of the rainbow. เพราะ main ยังชี้ไปยัง snapshot ของ orange
สลับกลับไป feature:
git switch feature
git log --oneline --decorate
fc8139c (HEAD -> feature) yellow
7acb333 (main) orange
abc1234 red
ตอนนี้ถ้าเปิดไฟล์อีกครั้งจะเห็นบรรทัด Yellow กลับมา นี่ไม่ใช่ Git ลบงานแล้วค่อยเอากลับมาให้เรา แต่เป็นผลจากการที่แต่ละ branch ชี้ไปยัง snapshot คนละตัว
ตรวจ pointer ด้วยคำสั่ง Git
ใช้คำสั่งเหล่านี้เพื่อดู commit ที่แต่ละ branch ชี้อยู่:
git rev-parse main
git rev-parse feature
git symbolic-ref --short HEAD
คาดว่าจะได้ความสัมพันธ์ประมาณนี้:
<hash ของ orange>
<hash ของ yellow>
feature
ผลลัพธ์สองบรรทัดแรกต่างกัน เพราะ branch ทั้งสองแยกกันแล้ว ส่วนบรรทัดสุดท้ายยืนยันว่า HEAD อยู่บน feature
เปิดไฟล์ที่ Git ใช้เก็บ branch
ถ้าอยากเห็นภาพเบื้องหลังแบบตรง ๆ ให้ลองอ่านไฟล์เหล่านี้ โดย อ่านได้ แต่อย่าแก้ไขเอง:
cat .git/HEAD
cat .git/refs/heads/main
cat .git/refs/heads/feature
ผลลัพธ์จะมีลักษณะดังนี้:
ref: refs/heads/feature
7acb333f08e12020efb5c6b563b285040c9dba93
fc8139cbf8442cdbb5e469285abaac6de919ace6
ไฟล์ main และ feature แต่ละไฟล์เก็บ hash ของ commit ล่าสุดใน branch นั้น ส่วน .git/HEAD เก็บ reference ว่าตอนนี้เราอยู่บน branch ไหน
มองภาพง่าย ๆ ได้แบบนี้:
.git/HEAD -> refs/heads/feature
.git/refs/heads/main -> orange commit
.git/refs/heads/feature -> yellow commit
ตรวจ parent link ของ commit
ทุก commit ยกเว้น commit แรกสุดจะมี parent commit อย่างน้อยหนึ่งตัว เราดูข้อมูลของ commit ปัจจุบันได้ด้วยคำสั่งนี้:
git cat-file -p HEAD
output จะมีหน้าตาประมาณนี้:
tree 407fe6a858cd7f157405e013a088fdc1c61f0a40
parent 7acb333f08e12020efb5c6b563b285040c9dba93
author Your Name <you@example.com> 1780000000 +0700
committer Your Name <you@example.com> 1780000000 +0700
yellow
บรรทัด parent บอกว่า yellow ย้อนกลับไปหา orange ได้ ส่วน branch pointer เป็นป้ายที่ชี้ไปยัง commit ล่าสุดและขยับได้ในอนาคต
คำสั่ง git cat-file -p มีไว้ช่วยเรียนรู้โครงสร้างภายในมากกว่างานประจำวันที่เราใช้ git log เป็นหลัก
แบบฝึกหัด
ทำแบบฝึกหัดต่อไปนี้ใน rainbow โดยเริ่มจากสถานะที่มี main อยู่ที่ orange และ feature อยู่ที่ yellow:
- รัน
git branchและgit statusแล้วดูว่า*อยู่หน้า branch ไหน และHEADอยู่ที่ branch ไหน - รัน
git log --oneline --decorateแล้วระบุว่าmainชี้ไปที่ commit ไหน และfeatureชี้ไปที่ commit ไหน - ใช้
git switch mainแล้วเปิดrainbowcolors.txtเพื่อตรวจว่าบรรทัดYellow is the third color of the rainbow.ไม่อยู่ใน snapshot ของmainจากนั้นใช้git switch featureแล้วตรวจว่าบรรทัดนั้นกลับมา - สร้าง branch ใหม่ชื่อ
practiceจากfeatureด้วยgit branch practiceแล้วตรวจด้วยgit branchว่า branch ถูกสร้างขึ้นจริง แต่ยังไม่ได้สลับไปที่ branch นั้น - สลับไป
practiceด้วยgit switch practiceเพิ่มบรรทัดGreen is the fourth color of the rainbow.แล้วเซฟไฟล์ - รัน
git status --shortและอธิบายว่าM rainbowcolors.txtต่างจาก?? rainbowcolors.txtที่เห็นในตอนที่ 2 และ 3 อย่างไร - ทำ
git add rainbowcolors.txtและgit commit -m "green"จากนั้นใช้git log --oneline --decorateยืนยันว่าpracticeเลื่อนไป commit ใหม่ แต่featureยังอยู่ที่yellow - รัน
git cat-file -p HEADและหาparentให้เจอ จากนั้นอธิบายด้วยคำของตัวเองว่า parent link ต่างจาก branch pointer อย่างไร
ตรวจตัวเองให้ครบ:
mainยังไม่เห็นสีyellowและgreenfeatureเห็นสีyellowแต่ยังไม่มีสีgreenpracticeเห็นทั้งyellowและgreen- commit
greenเกิดบนpracticeไม่ใช่main - หลัง commit แล้ว
git statusบอกว่าworking treeclean
Common Pitfalls — ข้อผิดพลาดที่พบบ่อย
- คิดว่า
git branch featureจะย้ายไปfeatureให้เลย — คำสั่งนี้สร้าง branch อย่างเดียว ต้องใช้git switch featureต่อ - ลืมเช็ก branch ก่อน commit — รัน
git branchหรือgit statusก่อน commit เพื่อให้แน่ใจว่าอยู่สายที่ตั้งใจ - คิดว่า branch คือการก๊อปปี้ไฟล์ทั้งโปรเจกต์ — branch เป็น pointer ที่ชี้ไปยัง commit หนึ่ง การสร้าง branch จึงเบากว่าการก๊อปปี้โฟลเดอร์ทั้งก้อน
- สับสน
HEADกับrefs/heads/—HEADบอกว่าเราอยู่ branch ไหน ส่วนrefs/heads/เก็บ reference ของ local branch แต่ละตัว - แยก branch pointer กับ parent link ไม่ออก — branch pointer ขยับตาม commit ใหม่ แต่ parent link ของ commit ที่สร้างแล้วไม่ขยับ
- แก้ไฟล์แล้วไม่เซฟ — Git จะยังมองไฟล์เป็น unmodified จนกว่าการแก้จะถูกบันทึกลงดิสก์
- คิดว่า
git statusจะแสดงไฟล์ unmodified ทุกไฟล์ — คำสั่งนี้เน้นแสดงไฟล์ที่ modified, staged หรือ untracked - สลับ branch ทั้งที่มีงานค้าง แล้ว Git ปฏิเสธ — ให้ commit หรือ stash งานก่อน หากการสลับอาจทับการแก้ไขที่ยังไม่พร้อม
- แก้ไฟล์ใน
.gitเอง — เปิดอ่านเพื่อเรียนรู้ได้ แต่ใช้คำสั่ง Git จัดการ repository แทนการแก้ไฟล์ภายในโดยตรง - คิดว่า
mainพิเศษกว่า branch อื่นในเชิงกลไก —mainเป็นชื่อ convention ที่นิยมใช้ ชื่อ branch อื่นก็ทำงานด้วยกติกาเดียวกัน
สรุป
- Branch คือสายการพัฒนาที่แยกออกมา ช่วยให้เราทำงานหลายแนวทางหรือทำงานร่วมกับหลายคนได้
- ในทางเทคนิค branch คือ movable pointer ที่ชี้ไปยัง commit หนึ่ง ไม่ใช่สำเนาโปรเจกต์ทั้งก้อน
git branchใช้ list branch เมื่อไม่ใส่ชื่อ และใช้สร้าง branch เมื่อใส่ชื่อใหม่git branch <name>สร้าง branch แต่ไม่สลับเราไป branch นั้นgit switch <name>เปลี่ยนHEADให้ไปชี้ branch ที่เลือก และอาจเปลี่ยนไฟล์ใน working directory ตาม commit ใหม่HEADเป็น pointer ที่บอกว่าเรากำลังอยู่บน branch ไหน ไม่ใช่ branch อีกตัวหนึ่ง- tracked file ที่ยังไม่ถูกแก้คือ unmodified ส่วนไฟล์ที่แก้และเซฟแล้วแต่ยังไม่ commit คือ modified
- เมื่อ commit บน branch ที่
HEADชี้อยู่ branch นั้นจะเลื่อนไปยัง commit ใหม่ ส่วน branch อื่นยังอยู่ที่เดิม - commit ใหม่มี parent link ย้อนกลับไปยัง commit ก่อนหน้า แต่ parent link ไม่ได้เลื่อนตาม branch pointer
git log --oneline --decorate,git branchและgit statusเป็นสามคำสั่งที่ช่วยเช็กว่าเรากำลังทำงานบนสายไหน
ตอนนี้ rainbow มีสองสายแล้ว: main หยุดอยู่ที่ orange ส่วน feature เดินหน้าต่อไปถึง yellow เราจึงลองของใหม่ได้โดยไม่ต้องเอางานที่ยังไม่ผ่านไปปนกับสายหลัก
แค่นี้เราก็ใช้ branch แยกงานที่ยังไม่เสร็จออกจากสายหลักได้แล้ว
ตอนถัดไปเราจะพา
mainกับfeatureที่แยกกันแล้วกลับมารวมเป็นประวัติเดียวด้วยgit merge
Glossary
- Branch — สายการพัฒนาที่แยกออกจากสายหลักของโปรเจกต์
- Movable pointer — pointer ที่เลื่อนไปชี้ commit ใหม่ได้เมื่อมีการทำ commit
- Feature branch / topic branch — branch ย่อยสำหรับทำงานเฉพาะเรื่อง มักรวมกลับเข้าสายหลักเมื่อเสร็จ
HEAD— pointer ที่บอกว่าเราอยู่บน branch ไหนrefs/heads/— โฟลเดอร์ที่เก็บ reference ของ local branch แต่ละตัว- Branch pointer — reference ที่ชี้ไปยัง commit ล่าสุดของ branch และขยับตาม commit ใหม่
- Parent link — ความสัมพันธ์ที่ commit ใหม่ชี้กลับไปยัง commit ก่อนหน้า
- Unmodified file — tracked file ที่ยังไม่ถูกแก้ตั้งแต่ commit ล่าสุด
- Modified file — tracked file ที่ถูกแก้และเซฟแล้ว แต่ยังไม่ commit
git branch— คำสั่ง list หรือสร้าง local branchgit switch— คำสั่งสลับไปทำงานบน branch ที่ระบุgit log --decorate— แสดงประวัติ commit พร้อมชื่อ branch และHEADที่ชี้อยู่- Detached HEAD state — ภาวะที่
HEADชี้ commit โดยไม่มี branch ชี้อยู่ git cat-file -p— คำสั่งอ่านข้อมูลภายใน Git object เช่น parent ของ commit
Related
- ตอนที่ 1: Git and the Command Line — เตรียม command line, ติดตั้ง Git และสร้างโฟลเดอร์
rainbow - ตอนที่ 2: Local Repositories — เปลี่ยน
rainbowให้เป็น local repository และรู้จักพื้นที่ทำงานของ Git - ตอนที่ 3: Making a Commit — ใช้
git add,git commitและgit logสร้างประวัติที่บทนี้นำมาแตก branch - ตอนที่ 5: Merging — รวม
mainกับfeatureหลังจากสองสายพัฒนาแยกกันแล้ว