HOME

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?

เหตุผลหลักมีสองอย่าง:

  1. ลองทำงานหลายแนวทางในโปรเจกต์เดียวกัน โดยไม่เอางานที่กำลังทำไปปะปนกับ branch หลัก เช่น feature/add-yellow-color
  2. ให้หลายคนทำงานพร้อมกัน แล้วค่อยรวมงานที่ตรวจสอบแล้วกลับเข้ามาใน 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 ชี้ไปที่ commit orange
  • HEAD กำลังชี้ไปที่ branch main
  • ตอนนี้เราจึงกำลังทำงานบน main

ถ้า branch เป็นป้ายชื่อที่วางอยู่บน commit เราก็ขยับป้ายชื่อนั้นไปข้างหน้าได้เมื่อทำ commit ใหม่ โดยไม่ต้องก๊อปปี้ไฟล์ทั้งหมด

ลูกศรสองแบบที่ห้ามสับสน

เวลาอ่านไดอะแกรมของ Git ให้แยกลูกศรสองแบบนี้ออกจากกัน:

สิ่งที่ชี้ความหมายขยับได้ไหม?
Branch pointermain หรือ feature ชี้ไปยัง commit ล่าสุดของสายตัวเองขยับตาม commit ใหม่
Parent linkcommit ลูกชี้กลับไปยัง 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 branchlist 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 จะทำงานหลัก ๆ สามอย่าง:

  1. เปลี่ยน HEAD ให้ชี้ไปยัง branch ใหม่
  2. เตรียม staging area ให้ตรงกับ snapshot ของ commit ที่ branch ใหม่ชี้ไป
  3. นำเนื้อหาจาก 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 ให้เช็กสองเรื่อง:

  1. เพิ่มบรรทัดตามตัวอย่างแล้วหรือยัง
  2. กดเซฟใน 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 เลื่อนไปชี้ commit yellow
  • HEAD ยังชี้ feature
  • main ยังชี้ไปที่ commit orange
  • yellow มี 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

ทุก 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:

  1. รัน git branch และ git status แล้วดูว่า * อยู่หน้า branch ไหน และ HEAD อยู่ที่ branch ไหน
  2. รัน git log --oneline --decorate แล้วระบุว่า main ชี้ไปที่ commit ไหน และ feature ชี้ไปที่ commit ไหน
  3. ใช้ git switch main แล้วเปิด rainbowcolors.txt เพื่อตรวจว่าบรรทัด Yellow is the third color of the rainbow. ไม่อยู่ใน snapshot ของ main จากนั้นใช้ git switch feature แล้วตรวจว่าบรรทัดนั้นกลับมา
  4. สร้าง branch ใหม่ชื่อ practice จาก feature ด้วย git branch practice แล้วตรวจด้วย git branch ว่า branch ถูกสร้างขึ้นจริง แต่ยังไม่ได้สลับไปที่ branch นั้น
  5. สลับไป practice ด้วย git switch practice เพิ่มบรรทัด Green is the fourth color of the rainbow. แล้วเซฟไฟล์
  6. รัน git status --short และอธิบายว่า M rainbowcolors.txt ต่างจาก ?? rainbowcolors.txt ที่เห็นในตอนที่ 2 และ 3 อย่างไร
  7. ทำ git add rainbowcolors.txt และ git commit -m "green" จากนั้นใช้ git log --oneline --decorate ยืนยันว่า practice เลื่อนไป commit ใหม่ แต่ feature ยังอยู่ที่ yellow
  8. รัน git cat-file -p HEAD และหา parent ให้เจอ จากนั้นอธิบายด้วยคำของตัวเองว่า parent link ต่างจาก branch pointer อย่างไร

ตรวจตัวเองให้ครบ:

  • main ยังไม่เห็นสี yellow และ green
  • feature เห็นสี yellow แต่ยังไม่มีสี green
  • practice เห็นทั้ง yellow และ green
  • commit green เกิดบน practice ไม่ใช่ main
  • หลัง commit แล้ว git status บอกว่า working tree clean

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 อื่นก็ทำงานด้วยกติกาเดียวกัน

สรุป

  1. Branch คือสายการพัฒนาที่แยกออกมา ช่วยให้เราทำงานหลายแนวทางหรือทำงานร่วมกับหลายคนได้
  2. ในทางเทคนิค branch คือ movable pointer ที่ชี้ไปยัง commit หนึ่ง ไม่ใช่สำเนาโปรเจกต์ทั้งก้อน
  3. git branch ใช้ list branch เมื่อไม่ใส่ชื่อ และใช้สร้าง branch เมื่อใส่ชื่อใหม่
  4. git branch <name> สร้าง branch แต่ไม่สลับเราไป branch นั้น
  5. git switch <name> เปลี่ยน HEAD ให้ไปชี้ branch ที่เลือก และอาจเปลี่ยนไฟล์ใน working directory ตาม commit ใหม่
  6. HEAD เป็น pointer ที่บอกว่าเรากำลังอยู่บน branch ไหน ไม่ใช่ branch อีกตัวหนึ่ง
  7. tracked file ที่ยังไม่ถูกแก้คือ unmodified ส่วนไฟล์ที่แก้และเซฟแล้วแต่ยังไม่ commit คือ modified
  8. เมื่อ commit บน branch ที่ HEAD ชี้อยู่ branch นั้นจะเลื่อนไปยัง commit ใหม่ ส่วน branch อื่นยังอยู่ที่เดิม
  9. commit ใหม่มี parent link ย้อนกลับไปยัง commit ก่อนหน้า แต่ parent link ไม่ได้เลื่อนตาม branch pointer
  10. 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 branch
  • git switch — คำสั่งสลับไปทำงานบน branch ที่ระบุ
  • git log --decorate — แสดงประวัติ commit พร้อมชื่อ branch และ HEAD ที่ชี้อยู่
  • Detached HEAD state — ภาวะที่ HEAD ชี้ commit โดยไม่มี branch ชี้อยู่
  • git cat-file -p — คำสั่งอ่านข้อมูลภายใน Git object เช่น parent ของ commit

SEARCH