6 คะแนน โดย GN⁺ 2024-05-27 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • PDF ที่รวบรวมงานที่มักติดขัดบ่อยใน Git ให้ค้นหาได้รวดเร็วตามหมวด การเขียนคอมมิต, การย้ายบรานช์, การเปรียบเทียบการเปลี่ยนแปลง, การซิงก์กับรีโมต และคำสั่งยกเลิกการเปลี่ยนแปลง
  • เวิร์กโฟลว์บนเครื่องจะเน้น git status, git add, git commit, git diff เพื่อตรวจสอบ สถานะก่อนและหลัง staging แล้วสร้างคอมมิต
  • งานเกี่ยวกับบรานช์ใช้ git switch, git checkout, git branch, git merge, git rebase, git cherry-pick เพื่อจัดการ การสร้าง·การย้าย·การ merge·การ rebase
  • การสำรวจประวัติและการกู้คืนมี git log, git blame, git show, git reflog, git reset, git restore รวมถึงสามารถใช้บรานช์·แท็ก·HEAD·บรานช์รีโมตเป็นตัวอ้างอิงคอมมิตได้
  • งานกับรีโมต repository ครอบคลุมขั้นตอนการรับและส่งการเปลี่ยนแปลงด้วย git remote add, git fetch, git pull, git push, git push --force-with-lease, git push --tags

เริ่มต้น repository และตรวจสอบสถานะปัจจุบัน

  • เริ่ม repository ใหม่:
    • git init
  • clone repository ที่มีอยู่:
    • git clone $URL
  • ตรวจสอบตำแหน่งและสถานะปัจจุบัน:
    • git status

เตรียมและสร้างคอมมิต

  • เพิ่มไฟล์ที่ยังไม่ถูกติดตาม:
    • git add $FILE
  • เพิ่มไฟล์ที่ยังไม่ถูกติดตามทั้งหมดและการเปลี่ยนแปลงที่ยังไม่ได้ stage:
    • git add .
  • เลือก stage เฉพาะบางส่วนของการเปลี่ยนแปลงในไฟล์:
    • git add -p
  • ลบหรือย้ายไฟล์:
    • git rm $FILE
    • git mv $OLD $NEW
  • นำไฟล์ออกจากการติดตามของ Git โดยไม่ลบไฟล์:
    • git rm --cached $FILE
  • ยกเลิก staging ทั้งหมด:
    • git reset HEAD
  • สร้างคอมมิต:
    • git commit
    • เปิด text editor เพื่อเขียนข้อความ
  • คอมมิตโดยระบุข้อความทันที:
    • git commit -m 'message'
  • คอมมิตพร้อมข้อความโดยรวมถึงการเปลี่ยนแปลงที่ยังไม่ได้ stage ด้วย:
    • git commit -am 'message'

การย้ายและจัดการบรานช์

  • สลับบรานช์:
    • git checkout $NAME
    • git switch $NAME
  • สร้างบรานช์:
    • git checkout -b $NAME
    • git switch -c $NAME
  • ดูรายการบรานช์:
    • git branch
  • เรียงบรานช์ตามคอมมิตล่าสุด:
    • git branch --sort=-committerdate
  • ลบบรานช์:
    • git branch -d $NAME
  • บังคับลบบรานช์:
    • git branch -D $NAME

สำรวจประวัติและติดตามโค้ด

  • ดูประวัติของบรานช์:
    • git log main
  • ดูความสัมพันธ์ของสองบรานช์เป็นกราฟ:
    • git log --graph a b
  • ดู log แบบหนึ่งบรรทัด:
    • git log --oneline
  • ตรวจสอบว่าใครเป็นคนแก้แต่ละบรรทัดของไฟล์ล่าสุด:
    • git blame $FILENAME
  • ดูคอมมิตทั้งหมดที่แก้ไขไฟล์:
    • git log $FILENAME
  • ค้นหาคอมมิตที่เพิ่มหรือลบข้อความเฉพาะ:
    • git log -S banana

เปรียบเทียบการเปลี่ยนแปลง

  • ดูความแตกต่างระหว่างคอมมิตกับคอมมิตแม่:
    • git show $COMMIT_ID
  • ดูความแตกต่างระหว่าง merge commit กับคอมมิตแม่ที่ถูก merge เข้ามา:
    • git show --remerge-diff $COMMIT_ID
  • ดูสรุป diff:
    • git diff $COMMIT_ID --stat
    • git show $COMMIT_ID --stat
  • เปรียบเทียบสองคอมมิต:
    • git diff $COMMIT_ID $COMMIT_ID
  • เปรียบเทียบเฉพาะไฟล์กับคอมมิต:
    • git diff $COMMIT_ID $FILENAME
  • เปรียบเทียบการเปลี่ยนแปลงที่ stage แล้วและยังไม่ได้ stage ทั้งหมด:
    • git diff HEAD
  • เปรียบเทียบเฉพาะการเปลี่ยนแปลงที่ stage แล้ว:
    • git diff --staged
  • เปรียบเทียบเฉพาะการเปลี่ยนแปลงที่ยังไม่ได้ stage:
    • git diff

ไฟล์ตั้งค่าและตัวเลือก

  • ไฟล์ตั้งค่า Git แบบ local:
    • .git/config
  • ไฟล์ตั้งค่า Git แบบ global:
    • ~/.gitconfig
  • รายการไฟล์ที่ต้อง ignore:
    • .gitignore
  • กำหนดตัวเลือกการตั้งค่า:
    • git config user.name 'Julia'
  • กำหนดตัวเลือกแบบ global:
    • git config --global ...
  • เพิ่ม alias:
    • git config alias.st status
  • ตรวจสอบตัวเลือกการตั้งค่าที่เป็นไปได้:
    • man git-config

แก้ไขประวัติและกู้คืนไฟล์

  • ย้อนคอมมิตล่าสุด โดยคง working directory ไว้เหมือนเดิม:
    • git reset HEAD^
  • ย้อน rebase ที่ล้มเหลว:
    • git reflog BRANCHNAME
    • git reset --hard $COMMIT_ID
  • รวม 5 คอมมิตล่าสุดให้เป็นคอมมิตเดียว:
    • git rebase -i HEAD^^^^^^
    • เปลี่ยน pick ของคอมมิตที่จะรวมเป็น fixup
  • นำเวอร์ชันของไฟล์จากบรานช์หรือคอมมิตอื่นมาใช้:
    • git checkout $COMMIT_ID $FILE
    • git restore $FILE --source $COMMIT_ID
  • เปลี่ยนข้อความคอมมิตหรือเพิ่มไฟล์ที่ลืมใส่:
    • git commit --amend

รวมบรานช์

  • fast-forward merge เพื่ออัปเดตบรานช์ปัจจุบันด้วยบรานช์อื่น:
    • git switch main
    • git merge banana
  • คัดลอกหนึ่งคอมมิตไปยังบรานช์อื่น:
    • git cherry-pick $COMMIT_ID
  • รวมบรานช์ที่แยกจากกันด้วย rebase:
    • git switch banana
    • git rebase main
  • รวมบรานช์ที่แยกจากกันด้วย merge:
    • git switch main
    • git merge banana
    • git commit
  • รวมบรานช์ที่แยกจากกันด้วย squash merge:
    • git switch main
    • git merge --squash banana
    • git commit

รีโมต repository และการซิงก์

  • เพิ่มรีโมต repository:
    • git remote add $NAME $URL
  • push บรานช์ main ไปยังรีโมต origin:
    • git push origin main
  • อัปโหลดบรานช์ที่ push ครั้งแรกไปยัง origin และตั้งค่าบรานช์ติดตาม:
    • git push -u origin $NAME
  • push บรานช์ปัจจุบันไปยังบรานช์ติดตามบนรีโมต:
    • git push
  • force push:
    • git push --force-with-lease
  • push แท็ก:
    • git push --tags
  • ดึงการเปลี่ยนแปลงมาโดยไม่เปลี่ยนบรานช์ local:
    • git fetch origin main
  • fetch ทุกบรานช์:
    • git fetch --all
  • rebase เข้ากับบรานช์ปัจจุบันหลัง fetch:
    • git pull --rebase
  • merge เข้ากับบรานช์ปัจจุบันหลัง fetch:
    • git pull origin main
    • git pull

วิธีอ้างอิงคอมมิต

  • ในตำแหน่ง $COMMIT_ID สามารถใช้ตัวอ้างอิงได้หลายแบบ:
    • บรานช์: main
    • แท็ก: v0.1
    • คอมมิต ID: 3e887ab
    • บรานช์รีโมต: origin/main
    • คอมมิตปัจจุบัน: HEAD
    • คอมมิตก่อนหน้า 3 คอมมิต: HEAD^^^
    • คอมมิตก่อนหน้า 3 คอมมิต: HEAD~3

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

  • ลบทั้งการเปลี่ยนแปลงที่ stage แล้วและยังไม่ได้ stage ของไฟล์หนึ่งไฟล์:
    • git checkout HEAD $FILE
  • ลบการเปลี่ยนแปลงที่ยังไม่ได้ stage ของไฟล์หนึ่งไฟล์:
    • git checkout $FILE
  • ลบการเปลี่ยนแปลงทั้งหมดทั้งที่ stage แล้วและยังไม่ได้ stage:
    • git reset --hard
  • stash การเปลี่ยนแปลงที่ stage แล้วและยังไม่ได้ stage:
    • git stash
  • ลบไฟล์ที่ยังไม่ถูกติดตาม:
    • git clean

1 ความคิดเห็น

 
GN⁺ 2024-05-27
ความคิดเห็นจาก Hacker News
  • มีคำสั่งที่เหมือนอัญมณีซ่อนอยู่หลายคำสั่ง: git diff --staged จะแสดงความแตกต่างระหว่างคอมมิตล่าสุดกับสิ่งที่สเตจไว้ตอนนี้ จึงเหมาะมากสำหรับตรวจว่ามีเฉพาะสิ่งที่ตั้งใจไว้หรือไม่เมื่อต้องสเตจไฟล์หรือ hunk แบบละเอียด
    git log <file> จะแสดงเฉพาะคอมมิตที่ไฟล์นั้นถูกเปลี่ยนแปลง ทำให้ไม่ต้องไล่ดู git log ทั้งหมดมากนัก และมีประโยชน์เป็นพิเศษกับไฟล์ที่ไม่ค่อยเปลี่ยนบ่อย
    เวลาใช้ git add --patch ถ้าอยากเลือกให้ละเอียดกว่า hunk ที่ Git แบ่งไว้ ลองใช้ ตัวเลือก e ได้ มีคำแนะนำวิธีรวม/ตัดแต่ละบรรทัดให้ดู จึงไม่จำเป็นต้องท่องจำ

    • เพิ่งรู้ว่า git diff --staged เป็น alias ของ git diff --cached ใช้ cached มาหลายปีแล้ว แต่ staged เข้าใจง่ายกว่ามากจริง ๆ แค่ว่าไม่รู้จะลบ muscle memory นี้ได้ไหม
    • ถ้าสร้าง alias สำหรับคำสั่งแบบนี้ไว้เยอะ ๆ ก็ช่วยประหยัดเวลาได้ไม่น้อย และลดอุปสรรคในการจัดระเบียบงานให้ดีขึ้นด้วย
      ถ้าสนใจก็ดูหรือเสนอ alias เพิ่มได้: https://gitlab.com/Falimonda/gitrc
    • ถ้าตั้งค่า git config --global commit.verbose true Git จะใส่ diff ที่สเตจไว้ ลงในส่วนคอมเมนต์ของ editor สำหรับข้อความคอมมิตโดยอัตโนมัติ
  • คำสั่งหนึ่งที่ชอบแต่ไม่มีอยู่ในรายการคือ git log -LstartLine,endLine:fileName
    มันเหมือน git blame แบบขยาย โดยแสดงว่าบรรทัดที่ระบุเปลี่ยนไปอย่างไรตามเวลา และใครเป็นคนเปลี่ยน แม้หมายเลขบรรทัดจะเปลี่ยนหรือไฟล์ถูกย้ายก็ยังติดตามได้
    ช่วยตอบคำถามอย่าง “ใครทำแบบนี้ เมื่อไร และทำไม?” หรือ “มันเป็นแบบนี้มาตั้งแต่เมื่อไร?”

  • นึกถึงคำพูดของ Phil Karlton ที่ว่า “ในวิทยาการคอมพิวเตอร์มีเรื่องยากอยู่แค่สองอย่าง: การทำให้แคชหมดอายุ และการตั้งชื่อ”
    มองจากมุมนั้น ชื่อคำสั่ง Git ว่า blame ก็รู้สึกค่อนข้างแปลก และไม่ได้มีแค่ฉันที่คิดแบบนั้น
    What does 'git blame' do? https://stackoverflow.com/questions/31203001/what-does-git-blame-do
    Blame someone else for your bad code https://news.ycombinator.com/item?id=27963868
    Git blame should be called git credit https://dev.to/damcosset/git-blame-should-be-called-git-credit-27h5
    Does Git Blame sound too negative? https://www.reddit.com/r/ProgrammerHumor/comments/r5lzyo/does_git_blame_sound_too_negative_just_look_up/

    • ถ้าคิดถึงชื่อเครื่องมือว่า git แล้ว blame ก็ดูเป็น ชื่อที่เข้ากับแบรนด์ อยู่
    • เห็นด้วย ฉันเปลี่ยน blame เป็น who ใน การตั้งค่า แล้ว จริง ๆ เป็นผู้ใช้ Vim สายแข็งเลยใช้แค่ w
  • ชอบวิธีที่ตัวเองเรียน Git ตอนแรกเริ่มจาก Sourcetree ซึ่งเป็น Git GUI ของบุคคลที่สาม ใช้งานและทำความเข้าใจง่ายมาก
    จากนั้นย้ายไป git gui แต่ขั้นนี้ข้ามได้ ต่อมารู้สึกว่าการเปิด UI น่ารำคาญ เลยเรียนคำสั่งบนเทอร์มินัล
    แนะนำสำหรับมือใหม่ Git แต่ก็เป็นแค่ประสบการณ์ n=1 ของฉันเท่านั้น

    • สิ่งที่รู้เกี่ยวกับ Git มีแค่ประมาณ clone, pull, commit, push และจนถึงตอนนี้ก็พอแล้ว Git อาจเรียบง่ายได้ขนาดนั้น แน่นอนว่าถ้าจำเป็นก็เรียนวิธีใช้ที่ซับซ้อนกว่านี้ได้
    • ไม่อยากกลับไปใช้คำสั่งเทอร์มินัลแล้ว เพราะ repository และ workflow ของ Git เข้าใจได้ดีกว่ามากเมื่อมองเป็นภาพ ดังนั้น Git แทบจะเป็น เครื่องมือที่เรียกร้องให้ใช้งานผ่าน GUI
      พอเริ่มใช้ Magit ก็เริ่มเข้าใจ Git ขึ้นมา
    • ฉันย้ายจาก Sourcetree ไปใช้ Fork คล้ายกันมาก แต่ประสิทธิภาพดีกว่ามากและ UI ลื่นกว่า ถ้า Sourcetree ไม่ได้ดีขึ้นในช่วงไม่กี่ปีมานี้นะ
    • เส้นทางคล้ายกัน แต่ฉันใช้ GitKraken กับ Sublime Merge และยังเก็บ Sublime Merge ไว้เพราะมันทำให้งานซับซ้อนเป็นเรื่องง่าย
      Sublime Merge มีแต่เรื่องให้ชม
  • สงสัยว่า Git ซับซ้อนเกินจำเป็นด้วย เหตุผลทางประวัติศาสตร์ หรือเปล่า
    พอดูชีตสรุปนี้แล้วก็ยิ่งรู้สึกถึงความซับซ้อนนั้นมากขึ้น

    • ใช่แล้ว เพราะ Git เป็นเครื่องมือที่ Linus Torvalds สร้างขึ้นเพื่อให้การ พัฒนาเคอร์เนล Linux เป็นไปได้และก้าวหน้าขึ้น
      การที่มันถูกใช้แพร่หลายขนาดนี้อาจเป็น “อุบัติเหตุที่น่ายินดี” หรืออาจเป็นโชคร้ายก็ได้ GitHub มีความดีความชอบมากในการทำให้ Git เป็นที่นิยมด้วย “โฮสติ้ง Git ฟรี” แต่ผมไม่คิดว่า Git เป็นระบบควบคุมเวอร์ชันที่เหมาะสมที่สุดสำหรับหลาย ๆ โปรเจกต์
      เพราะมันถูกสร้างมาเพื่อ Linus และ Linux คำศัพท์และเวิร์กโฟลว์ของมันจึงบางครั้งให้ความรู้สึกกลับทางกับระบบควบคุมเวอร์ชันทั่วไปอื่น ๆ แม้แต่ชื่อ Pull Request ก็เป็นเพราะในการพัฒนา Linux นั้น Linus หรือเมนเทนเนอร์จะดึงการเปลี่ยนแปลงเข้ามาในทรีของเคอร์เนล ในระบบอื่นมักเรียกว่า Merge Request ซึ่งดูมีเหตุผลกว่ามาก เพราะไม่ว่าการเปลี่ยนแปลงจะมาจากที่ไหน ก็คือการ merge เข้าสู่ทรี
      Git แทบจะเป็น ระบบควบคุมเวอร์ชันแบบกระจายศูนย์ โอเพนซอร์สเพียงตัวเดียวที่จัดการโค้ดเบสขนาดใหญ่มากได้อย่างรวดเร็ว จึงเกิดแรงเฉื่อยในการใช้งานในองค์กรขนาดใหญ่ด้วย
      สำหรับโปรเจกต์ส่วนตัว ผมชอบและใช้ Mercurial มากกว่าเยอะ แต่ถ้าลองใช้ Hg กับโค้ดเบสใหญ่ ๆ อย่าง Android AOSP จะเห็นว่ามันหน่วงอย่างหนัก Mercurial มีส่วนติดต่อผู้ใช้และระบบคำสั่งที่ดีกว่า และยังมีฟีเจอร์เปิดเว็บเซิร์ฟเวอร์ขึ้นมาทันทีเพื่อดูทรีของการเปลี่ยนแปลงได้ด้วย แต่เพราะเขียนด้วย Python ประสิทธิภาพและความสามารถในการขยายสเกลจึงไม่ใช่อุดมคติ
    • ส่วนหนึ่งของความซับซ้อนมาจากช่วงเวอร์ชันแรก ๆ ที่ต้นทุนในการเพิ่มคำสั่งย่อยใหม่ค่อนข้างสูง ผลคือฟีเจอร์ต่าง ๆ ถูกยัดเพิ่มเข้าไปในคำสั่งย่อยเดิมอย่าง git checkout เรื่อย ๆ ทำให้ ประสบการณ์ผู้ใช้ สับสนยิ่งขึ้น
      ใน Git รุ่นใหม่ ๆ ต้นทุนในการเพิ่มคำสั่งย่อยลดลงแล้ว และเริ่มเพิ่มคำสั่งที่เฉพาะเจาะจงมากขึ้นอย่าง git switch
    • สำหรับเวิร์กโฟลว์ส่วนใหญ่ ผมคิดว่าแค่รู้คำสั่ง Git ไม่กี่คำสั่งอย่าง log, add, commit, pull, push ก็พอแล้ว และยังมีเครื่องมือ GUI ด้วย
      พูดตรง ๆ ในงานทั่วไปผมไม่คิดว่า Git ซับซ้อนขนาดนั้น เพียงแต่มันมี ฟีเจอร์ทรงพลัง จำนวนมากให้ใช้เมื่อต้องการเท่านั้น
    • Git ไม่ได้ซับซ้อนเกินจำเป็น เวิร์กโฟลว์ที่ Git ถูกสร้างมาเพื่อรองรับต่างหากที่ซับซ้อนผิดปกติ และผู้ใช้เป้าหมายอย่างนักพัฒนาเคอร์เนลก็มีความเป็นเทคนิคสูงมาก ความซับซ้อนจึงไม่ใช่ปัญหาใหญ่
      นักพัฒนาเคอร์เนลต้องสื่อสารกันแบบกระจายศูนย์ และต้องทำงานต่อยอดจากงานของกันและกัน ในโปรเจกต์ที่มีคนเขียนโค้ด 15,000 คน จะทำงานกันอย่างไร? Git ถูกสร้างขึ้นมาเพื่อจุดประสงค์นั้น
      มันซับซ้อนเท่าที่จำเป็นเพื่อรองรับเวิร์กโฟลว์ที่ออกแบบมาให้รองรับ การสร้างเครื่องมือที่ง่ายกว่านั้นทำได้ง่าย แต่จะไม่สามารถรองรับเวิร์กโฟลว์ซับซ้อนอย่างการพัฒนาเคอร์เนล Linux ได้ ดังนั้นมันไม่ได้ซับซ้อนเกินจำเป็น แต่ก็จริงที่ว่าสำหรับการใช้งานง่าย ๆ มันซับซ้อนกว่าที่จำเป็น
      ถ้าต้องการฟรอนต์เอนด์ที่ซับซ้อนน้อยกว่า ก็มีเครื่องมือมากมายที่ช่วยให้ใช้งาน Git ได้ง่ายขึ้น ถ้าไม่ใช่นักพัฒนาซอฟต์แวร์เต็มเวลา ผมไม่แนะนำให้ใช้ Git โดยตรง แต่ถ้าเป็นนักพัฒนาเต็มเวลา ก็คุ้มที่จะใช้เวลาทำความเข้าใจแนวคิดภายใน และเมื่อเข้าใจแล้ว Git ก็ค่อนข้างสง่างามเมื่อเทียบกับสิ่งที่มันทำ
      ผมคงไม่ใช้การรู้ Git มาแบ่งว่าใครมีคุณสมบัติเป็นนักพัฒนาซอฟต์แวร์หรือไม่ แต่ถ้าการพยายามทำความเข้าใจด้วยตัวเองว่าระบบพื้นฐานแบบนี้ทำงานอย่างไรไม่ได้ให้โดพามีนกับคุณเลย สาขานี้อาจไม่ใช่รสนิยมของคุณก็ได้ ซึ่งก็ไม่เป็นไร ทุกคนมีสิ่งที่เหมาะและไม่เหมาะกับตัวเอง
      สำหรับการเรียนรู้การเคลื่อนที่ใน Git ขอแนะนำ https://learngitbranching.js.org แน่นอนว่า https://xkcd.com/1597/ ก็ใช้ได้เช่นกัน
    • เพราะการออกแบบ UI ที่ดีเป็นทักษะแยกต่างหากและต้องใช้ความพยายามเพิ่ม โดยส่วนใหญ่จึงมักถูกละเลยไปเฉย ๆ
  • ไม่เคยรู้จัก git add -p มาก่อน แต่มันมีประโยชน์จริง ๆ
    -p, --patch ช่วยให้เลือก patch hunk ระหว่าง index กับ working tree แบบโต้ตอบ แล้วเพิ่มเข้า index ได้ เปิดโอกาสให้ตรวจสอบ diff ก่อนเพิ่มการแก้ไขเข้า index

    • ถ้าเป็นไปได้ ผมจะเลือก hunk ของงานปัจจุบันด้วยตัวเองแล้วประกอบเป็น commit ที่สอดคล้องกัน วิธีนี้ช่วยให้ผมจัดระเบียบสิ่งที่ทำไปใหม่ในหัวได้ และเมื่อต้องอธิบายให้ใครฟัง ก็สามารถอธิบายตามลำดับ commit ได้
  • สิ่งที่อยากเพิ่มตรงนี้คือคอมโบ git commit --fixup $COMMIT_ID กับ git rebase -i upstream/master --autosquash
    มันกลายเป็นองค์ประกอบจำเป็นในเวิร์กโฟลว์ช่วงหลัง ๆ ของผมแล้ว ตัวอย่างของ Julia ใช้ HEAD^^^^^ เพื่อ rebase commit 5 รายการก่อนหน้า แต่จนถึงไม่นานมานี้ผมใช้ HEAD~5 อยู่ แล้วตอนนี้เพิ่งรู้ว่าสามารถ rebase commit ทั้งหมดจนถึง upstream HEAD ได้เลย

    • git commit --fixup $COMMIT_ID นี่ต้องเอามาใช้ทันทีเลย ปกติผมมักสร้าง commit สำหรับแก้เล็ก ๆ อย่าง “oops GET users/me” แล้วค่อยย้ายไป fixup เองในการ rebase แบบโต้ตอบครั้งถัดไป แต่วิธีนี้ดีกว่ามาก
    • เพิ่งเรียนรู้เรื่องนี้ไม่นานมานี้ และมันดีมากเวลาทำงานกับ แพตช์แบบสแต็ก ใน Gerrit
  • “รวม 5 commit ล่าสุดให้เป็นหนึ่งเดียว: git rebase -i HEAD^^^^^^” ผมว่าน่าจะเป็น git rebase -i HEAD~5 มากกว่า
    โดยมีเงื่อนไขว่าต้องการ rebase เฉพาะ history แบบเส้นตรงเท่านั้น
    https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git

  • การตระหนักครั้งใหญ่ที่สุดคือช่วงที่เข้าใจว่า commit ทั้งหมด ยังคงอยู่ข้างใน แท็กและ branch เป็นเพียงตัวชี้ไปยัง commit เท่านั้น และ commit ที่ branch เคยชี้ไปก่อนหน้านี้ก็ไม่ได้หายไปไหน
    คำสั่งจำนวนมาก หรืออาจพูดได้ว่าเกือบทั้งหมด เป็นแบบไม่ทำลายข้อมูล จึงสามารถอ้างอิงสถานะเดิมของ branch ได้ง่าย
    เคยเห็น git reflog มาก่อน แต่ส่วนใหญ่ใช้แค่เพื่อจำว่า “branch ที่เคยทำงานอยู่ก่อนหน้านี้ชื่ออะไรนะ?”
    เลยเกิดความกลัวแบบพอสมควรต่อการทำงานบางอย่างที่อาจพาเข้าไปอยู่กลางการแก้ conflict ที่ไม่ต้องการ เพราะปกติ conflict มักเกิดจากการอ้างอิง commit หรือ branch ผิด
    ความกลัวนั้นยังไม่ได้หายไปทั้งหมด แต่ อย่างน้อยก็รู้สึกสบายใจขึ้นมากในการกู้คืนงานเก่าระหว่างงานอย่าง rebase

    • Jujutsu ทำให้ความกลัวแบบนั้นหายไปหมด
      ถ้าไม่แน่ใจว่าหลังทำงานบางอย่างแล้วจะเกิด conflict ไหม ก็แค่ลองทำแล้วดูผล ถ้าเกิด conflict ก็แก้ไข ย้อนกลับงานที่ทำให้เกิด conflict หรือสร้าง commit ใหม่ไว้ที่อื่น แล้วปล่อย conflict ไว้จัดการทีหลัง
      ถ้ารู้อยู่แล้วว่าจะเกิด conflict ก็ clone branch ที่เกี่ยวข้องแล้วลองปรับให้เข้ากันล่วงหน้า หรือรันงานที่ทำให้เกิด conflict แล้วลองทำขั้นตอนการแก้ไขดู ถ้าการแก้เริ่มยุ่งเหยิง ก็ย้อนกลับเฉพาะบางส่วนที่แก้ไปแล้วลองต่อไป หรือพักไว้ชั่วคราวแล้วไปทำอย่างอื่น หรือทิ้งทั้ง tree ไปเลยก็ได้
  • พูดตรง ๆ คือควรวาง Git ลงแล้วไปดู JJ
    https://martinvonz.github.io/jj/v0.17.1/
    แม้แต่ Linus ก็น่าจะคิดว่า UI ของ Git แย่มาก JJ มี workflow ที่ยอดเยี่ยม

    • ผมไม่ค่อยเห็นด้วยกับจุดที่ไม่มี index อาจมี workflow บางแบบที่ทำให้เรียบง่ายขึ้นก็จริง แต่ไม่ว่าจะดีหรือร้าย ผมคุ้นกับ index ของ Git มากเกินไป จนดูเหมือนว่าวิธีทำงานคงจะเปลี่ยนไปค่อนข้างมาก
      อย่างไรก็ตาม นอกจากลองจับเล่นนิดหน่อยแล้ว ยังไม่ได้ใช้จริงจังในงานจริง จึงยังฟันธงไม่ได้