ฉันมักจะส่งรายการข้อผูกพันเพื่อตรวจสอบ หากฉันมีข้อผูกพันต่อไปนี้:
HEADCommit3Commit2Commit1
... git commit --amendฉันรู้ว่าฉันสามารถปรับเปลี่ยนหัวกระทำด้วย แต่ฉันจะแก้ไขCommit1ได้อย่างไรว่ามันไม่ได้HEADกระทำ
ฉันมักจะส่งรายการข้อผูกพันเพื่อตรวจสอบ หากฉันมีข้อผูกพันต่อไปนี้:
HEADCommit3 Commit2 Commit1... git commit --amendฉันรู้ว่าฉันสามารถปรับเปลี่ยนหัวกระทำด้วย แต่ฉันจะแก้ไขCommit1ได้อย่างไรว่ามันไม่ได้HEADกระทำ
คำตอบ:
คุณสามารถใช้rebase คอมไพล์ ตัวอย่างเช่นหากคุณต้องการแก้ไขคอมมิชชันbbc643cdให้รัน
$ git rebase --interactive 'bbc643cd^'
โปรดทราบลูกศร^ในตอนท้ายของคำสั่งเพราะคุณจะต้องจริง rebase กลับไปกระทำก่อนที่คนที่คุณต้องการแก้ไข
ในตัวแก้ไขเริ่มต้นปรับเปลี่ยนpickเป็นeditในบรรทัดที่กล่าวถึง 'bbc643cd'
บันทึกไฟล์และออก: git จะตีความและดำเนินการคำสั่งในไฟล์โดยอัตโนมัติ bbc643cdคุณจะพบว่าตัวเองอยู่ในสถานการณ์ก่อนหน้านี้ในที่คุณเพิ่งได้สร้างกระทำ
ณ จุดนี้bbc643cdเป็นความมุ่งมั่นครั้งสุดท้ายของคุณและคุณสามารถแก้ไขได้อย่างง่ายดาย : ทำการเปลี่ยนแปลงแล้วส่งคำสั่งด้วย:
$ git commit --all --amend --no-edit
หลังจากนั้นให้พิมพ์:
$ git rebase --continue
เพื่อกลับไปที่ HEAD ก่อนหน้านี้กระทำ
คำเตือน : โปรดทราบว่าสิ่งนี้จะเปลี่ยน SHA-1 ของการกระทำเช่นเดียวกับเด็กทุกคน - ในคำอื่น ๆ นี้จะเขียนประวัติจากจุดนั้นไปข้างหน้า คุณสามารถทำลาย repos การทำเช่นนี้ถ้าคุณกดใช้คำสั่งgit push --force
rewordดำเนินการgit rebase -iแทนedit(จะเปิดตัวแก้ไขโดยอัตโนมัติและดำเนินการต่อด้วยขั้นตอนการ rebase ที่เหลือซึ่งจะเป็นการยกเลิกการใช้งานgit commit --ammendและgit rebase --continueเมื่อคุณจำเป็นต้องเปลี่ยนข้อความการกระทำไม่ใช่เนื้อหา )
git stashก่อนgit rebaseและgit stash popหลังหากคุณมีการเปลี่ยนแปลงที่ค้างอยู่
git commit --all --amend --no-editที่นี่ ทั้งหมดที่ฉันต้องทำหลังจากที่git rebase -i ...เป็นไปได้ตามปกติแล้วgit commit --amend git rebase --continue
git rebase -i @~9 # Show the last 9 commits in a text editor
ค้นหาการกระทำที่คุณต้องการเปลี่ยนpickเป็นe( edit) และบันทึกและปิดไฟล์ Git จะย้อนกลับไปสู่การกระทำนั้น ๆ ซึ่งจะช่วยให้คุณ:
git commit --amendเพื่อทำการเปลี่ยนแปลงหรือgit reset @~เพื่อละทิ้งการคอมมิทครั้งล่าสุด แต่ไม่ใช่การเปลี่ยนแปลงไฟล์ (เช่นพาคุณไปยังจุดที่คุณอยู่เมื่อคุณแก้ไขไฟล์ แต่ยังไม่ได้คอมมิท)หลังมีประโยชน์สำหรับการทำสิ่งที่ซับซ้อนมากขึ้นเช่นการแบ่งออกเป็นหลายคอมมิชชัน
จากนั้นเรียกใช้git rebase --continueแล้ว Git จะเล่นซ้ำการเปลี่ยนแปลงที่ตามมาที่ด้านบนของการคอมมิทที่คุณแก้ไข คุณอาจถูกขอให้แก้ไขข้อขัดแย้งในการผสาน
หมายเหตุ: @เป็นการจดชวเลขHEADและ~เป็นการกระทำก่อนส่งมอบที่ระบุ
อ่านเพิ่มเติมเกี่ยวกับประวัติการเขียนใหม่ในเอกสาร Git
ProTip ™: อย่ากลัวที่จะทดสอบด้วยคำสั่ง "อันตราย" ที่เขียนประวัติใหม่ * - Git จะไม่ลบการกระทำของคุณเป็นเวลา 90 วันโดยค่าเริ่มต้น คุณสามารถค้นหาได้ใน reflog:
$ git reset @~3 # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started
* ระวังตัวเลือกเช่น--hardและ--force- พวกเขาสามารถทิ้งข้อมูล
* นอกจากนี้อย่าเขียนประวัติในสาขาใด ๆ ที่คุณร่วมมือ
ในหลาย ๆ ระบบgit rebase -iจะเปิด Vim เป็นค่าเริ่มต้น เป็นกลุ่มไม่ทำงานชอบมากที่สุดการแก้ไขข้อความที่ทันสมัยเพื่อให้ดูที่วิธีการ rebase ใช้เป็นกลุ่ม git config --global core.editor your-favorite-text-editorถ้าคุณต้องการใช้โปรแกรมแก้ไขที่แตกต่างกันเปลี่ยนมันด้วย
@เป็นชวเลขHEADได้ ขอขอบคุณที่โพสต์สิ่งนี้
git reset @~git rebase ...สิ่งที่ผมอยากจะทำหลังจากเลือกกระทำกับ คุณคือฮีโร่ของฉัน)
การรีบูตด้วยอินเทอร์แอคทีฟ--autosquashเป็นสิ่งที่ฉันใช้บ่อยเมื่อต้องแก้ไขก่อนหน้านี้ให้ลึกลงไปในประวัติศาสตร์ มันช่วยเร่งกระบวนการที่คำตอบของ ZelluX แสดงให้เห็นและเป็นประโยชน์อย่างยิ่งเมื่อคุณมีมากกว่าหนึ่งข้อตกลงที่คุณต้องแก้ไข
จากเอกสาร:
--autosquashเมื่อข้อความบันทึกการคอมมิชชันเริ่มต้นด้วย "squash! …" (หรือ "fixup! …") และมีการคอมมิชชันที่ชื่อขึ้นต้นด้วย…เดียวกันให้แก้ไขรายการสิ่งที่ต้องทำของ rebase -i โดยอัตโนมัติ ทำเครื่องหมายสำหรับการบีบมาทันทีหลังจากการคอมมิทที่จะแก้ไข
สมมติว่าคุณมีประวัติที่มีลักษณะเช่นนี้:
$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1
และคุณมีการเปลี่ยนแปลงที่คุณต้องการแก้ไข Commit2 จากนั้นส่งการเปลี่ยนแปลงของคุณโดยใช้
$ git commit -m "fixup! Commit2"
หรือคุณสามารถใช้ commit-sha แทนข้อความคอมมิชชันดังนั้น"fixup! e8adec4หรือแม้แต่คำนำหน้าของข้อความคอมมิชชัน
จากนั้นเริ่มต้นการปฏิเสธแบบโต้ตอบกับการกระทำก่อนหน้านี้
$ git rebase e8adec4^ -i --autosquash
เครื่องมือแก้ไขของคุณจะเปิดขึ้นพร้อมกับคำสั่งที่สั่งไว้อย่างถูกต้องแล้ว
pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3
สิ่งที่คุณต้องทำคือบันทึกและออก
git commit --fixup=@~ git commit -m "fixup! Commit2"สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อข้อความยืนยันของคุณยาวขึ้นและอาจเป็นเรื่องยากที่จะพิมพ์ข้อความทั้งหมด
วิ่ง:
$ git rebase --interactive commit_hash^
แต่ละอัน^บ่งบอกว่าคุณต้องการแก้ไขกี่ครั้งหากมีเพียงหนึ่งรายการ (แฮชการกระทำที่คุณระบุ) จากนั้นคุณเพียงเพิ่ม^แล้วคุณก็เพิ่มอีกหนึ่ง
ใช้เป็นกลุ่มคุณเปลี่ยนคำpickไปrewordสำหรับการกระทำที่คุณต้องการเปลี่ยนแปลงการบันทึกและเลิก ( :wq) จากนั้นคอมไพล์จะแจ้งให้คุณทราบถึงการกระทำแต่ละครั้งที่คุณทำเครื่องหมายว่าเป็นคำพูดเพื่อให้คุณสามารถเปลี่ยนข้อความการส่งข้อความได้
แต่ละข้อความส่งมอบคุณต้องบันทึกและออกจาก ( :wq) เพื่อไปที่ข้อความส่งข้อความถัดไป
หากคุณต้องการออกโดยไม่ใช้การเปลี่ยนแปลงให้กด :q!
แก้ไข : เพื่อนำทางvimคุณใช้jเพื่อขึ้น, kลง, hไปทางซ้ายและlไปทางขวา (ทั้งหมดนี้อยู่ในNORMALโหมดกดESCเพื่อไปที่NORMALโหมด) หากต้องการแก้ไขข้อความให้กดiเพื่อให้คุณเข้าสู่INSERTโหมดที่คุณแทรกข้อความ กดESCเพื่อกลับไปที่NORMALโหมด :)
UPDATE : นี่คือลิงค์ที่ยอดเยี่ยมจากรายชื่อ GitHub วิธีการยกเลิก (เกือบ) ทุกอย่างด้วย git
git push --force?
git push --forceคือการเขียนทับรีโมตที่คอมมิตด้วยการคอมมิทท้องถิ่นของคุณ นั่นไม่ใช่กรณีของหัวข้อนี้ :)
git rebase --ontoหากมีเหตุผลบางอย่างที่คุณไม่ชอบบรรณาธิการโต้ตอบคุณสามารถใช้
Commit1สมมติว่าคุณต้องการที่จะแก้ไข ก่อนอื่นสาขาจากก่อน Commit1 :
git checkout -b amending [commit before Commit1]
ประการที่สองคว้าCommit1ด้วยcherry-pick:
git cherry-pick Commit1
ตอนนี้แก้ไขการเปลี่ยนแปลงของคุณสร้างCommit1':
git add ...
git commit --amend -m "new message for Commit1"
และในที่สุดหลังจากที่ได้ทำการเปลี่ยนแปลงอื่น ๆ แล้วให้ทำการโยกย้ายส่วนที่เหลือของคุณไปจนถึงmasterการกระทำใหม่:
git rebase --onto amending Commit1 master
อ่าน: "rebase สู่สาขาamendingทั้งหมดกระทำระหว่างCommit1(ไม่รวม) และmaster(รวม)" นั่นคือ Commit2 และ Commit3 ตัด Commit1 เก่าออกทั้งหมด คุณสามารถเลือกพวกเชอร์รี่ได้ แต่วิธีนี้ง่ายกว่า
อย่าลืมล้างสาขาของคุณ!
git branch -d amending
git checkout -b amending Commit1~1เพื่อรับการกระทำก่อนหน้า
git checkout -b amending Commit1หรือไม่
ขึ้นอยู่กับเอกสาร
การแก้ไขข้อความของข้อความที่เก่ากว่าหรือหลายข้อความที่ส่งมอบ
git rebase -i HEAD~3
ด้านบนแสดงรายการ 3 การกระทำล่าสุดในสาขาปัจจุบันเปลี่ยน 3 เป็นอย่างอื่นถ้าคุณต้องการมากขึ้น รายการจะมีลักษณะคล้ายกับต่อไปนี้:
pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.
แทนที่pickด้วยrewordก่อนที่จะส่งข้อความยอมรับที่คุณต้องการเปลี่ยน สมมติว่าคุณเปลี่ยนคอมมิชชันที่สองในรายการไฟล์ของคุณจะมีลักษณะดังนี้:
pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.
บันทึกและปิดไฟล์ commit list ซึ่งจะปรากฎตัวแก้ไขใหม่ให้คุณเปลี่ยนข้อความคอมมิชชันเปลี่ยนข้อความ commit และบันทึก
Finaly Force-push the commits ที่แก้ไขแล้ว
git push --force
ฉันแค่คิดว่าฉันจะแบ่งปันนามแฝงที่ฉันใช้สำหรับสิ่งนี้ มันขึ้นอยู่กับการปฏิเสธแบบโต้ตอบไม่โต้ตอบ ในการเพิ่มไปยังคอมไพล์ของคุณให้เรียกใช้คำสั่งนี้ (คำอธิบายด้านล่าง):
git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'
ประโยชน์ที่ใหญ่ที่สุดของคำสั่งนี้เป็นความจริงที่ว่ามันไม่มีเสียงเรียกเข้า
(1)ระบุว่าไม่มีความขัดแย้งระหว่างการรีบูตแน่นอน
git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111
ชื่อamend-toดูเหมือนว่าเหมาะสม IMHO เปรียบเทียบการไหลด้วย--amend:
git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>
git config --global alias.<NAME> '!<COMMAND>'- สร้างนามแฝง git ทั่วโลกที่มีชื่อว่า<NAME>จะดำเนินการคำสั่งที่ไม่ใช่ git<COMMAND>f() { <BODY> }; f - ฟังก์ชันทุบตี "ไม่ระบุชื่อ"SHA=`git rev-parse "$1"`; - แปลงอาร์กิวเมนต์เป็น git revision และกำหนดผลลัพธ์ให้กับตัวแปร SHAgit commit --fixup "$SHA"- fixup SHAกระทำสำหรับ ดูgit-commitเอกสารGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^" ส่วนหนึ่งได้รับการคุ้มครองโดยคำตอบอื่น ๆ--autosquashคือสิ่งที่ใช้ร่วมกับgit commit --fixupดูgit-rebaseเอกสารสำหรับข้อมูลเพิ่มเติมGIT_SEQUENCE_EDITOR=trueเป็นสิ่งที่ทำให้สิ่งทั้งหมดไม่ใช่แบบโต้ตอบ แฮ็คนี้ฉันได้เรียนรู้จากโพสต์บล็อกนี้amend-toจัดการไฟล์ที่ไม่มีการจัดการ: git config --global alias.amend-to '!f() { SHA=git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
ฉันพบว่าตัวเองแก้ไขการกระทำที่ผ่านมาบ่อยครั้งมากพอที่ฉันจะเขียนสคริปต์ให้มัน
นี่คือขั้นตอนการทำงาน:
git commit-edit <commit-hash>
สิ่งนี้จะทำให้คุณอยู่ในความมุ่งมั่นที่คุณต้องการแก้ไข
แก้ไขและแสดงความมุ่งมั่นตามที่คุณต้องการในตอนแรก
(คุณอาจต้องการใช้git stash saveเพื่อเก็บไฟล์ที่คุณไม่ได้ทำไว้)
ทำซ้ำการกระทำด้วย--amendเช่น:
git commit --amend
ทำ rebase ให้สมบูรณ์:
git rebase --continue
เพื่อให้การทำงานด้านบนวางสคริปต์ด้านล่างนี้ลงในไฟล์ที่สามารถเรียกทำงานได้ซึ่งมีชื่อgit-commit-editอยู่ใน$PATH:
#!/bin/bash
set -euo pipefail
script_name=${0##*/}
warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }
[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"
# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
message=$(git log -1 --format='%h %s' "$commit")
if [[ $OSTYPE =~ ^darwin ]]; then
sed_inplace=(sed -Ei "")
else
sed_inplace=(sed -Ei)
fi
export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)" # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty # Commit an empty commit so that that cache diffs are un-reversed
echo
echo "Editing commit: $message" >&2
echo
มาถึงวิธีนี้ (และมันก็อาจจะเหมือนกับการใช้ rebase เชิงโต้ตอบ) แต่สำหรับฉันมันค่อนข้างตรงไปตรงมา
หมายเหตุ: ฉันนำเสนอวิธีการนี้เพื่อให้เห็นภาพของสิ่งที่คุณสามารถทำได้มากกว่าทางเลือกในชีวิตประจำวัน เนื่องจากมันมีหลายขั้นตอน (และอาจเป็นไปได้บางประการ)
สมมติว่าคุณต้องการเปลี่ยนการมอบหมาย0และคุณเปิดอยู่feature-branch
some-commit---0---1---2---(feature-branch)HEAD
Checkout quick-branchเพื่อกระทำนี้และสร้าง นอกจากนี้คุณยังสามารถโคลนสาขาคุณลักษณะของคุณเป็นจุดกู้คืน (ก่อนที่จะเริ่ม)
?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch
ตอนนี้คุณจะมีสิ่งนี้:
0(quick-branch)HEAD---1---2---(feature-branch)
การเปลี่ยนแปลงในเวทีเก็บทุกอย่างไว้ที่อื่น
git add ./example.txt
git stash
ยอมรับการเปลี่ยนแปลงและเช็คเอาต์กลับเป็น feature-branch
git commit --amend
git checkout feature-branch
ตอนนี้คุณจะมีสิ่งนี้:
some-commit---0---1---2---(feature-branch)HEAD
\
---0'(quick-branch)
Rebase feature-branchสู่quick-branch(แก้ไขข้อขัดแย้งระหว่างทาง) quick-branchสมัครซ่อนและลบ
git rebase quick-branch
git stash pop
git branch -D quick-branch
และคุณท้ายด้วย:
some-commit---0'---1'---2'---HEAD(feature-branch)
Git จะไม่ซ้ำกัน (แม้ว่าฉันจะไม่สามารถพูดได้จริง ๆ ว่าขอบเขตใด) 0 ที่กระทำเมื่อทำการรีบูต
หมายเหตุ: แฮชการคอมมิชชันทั้งหมดมีการเปลี่ยนแปลงเริ่มจากคอมมิชชันที่เราตั้งใจจะเปลี่ยนแปลง
หากต้องการรับคำสั่งที่ไม่โต้ตอบให้วางสคริปต์พร้อมเนื้อหานี้ใน PATH ของคุณ:
#!/bin/sh
#
# git-fixup
# Use staged changes to modify a specified commit
set -e
cmt=$(git rev-parse $1)
git commit --fixup="$cmt"
GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"
ใช้มันโดยการแสดงละครการเปลี่ยนแปลงของคุณ (กับgit add) git fixup <commit-to-modify>และเรียกใช้แล้ว แน่นอนว่ามันจะยังคงมีการโต้ตอบหากคุณได้รับความขัดแย้ง
git stash+ rebaseระบบอัตโนมัติ
สำหรับเมื่อฉันต้องการแก้ไขเก่ากระทำหลายครั้งสำหรับความคิดเห็น Gerrit ฉันได้ทำ:
git-amend-old() (
# Stash, apply to past commit, and rebase the current branch on to of the result.
current_branch="$(git rev-parse --abbrev-ref HEAD)"
apply_to="$1"
git stash
git checkout "$apply_to"
git stash apply
git add -u
git commit --amend --no-edit
new_sha="$(git log --format="%H" -n 1)"
git checkout "$current_branch"
git rebase --onto "$new_sha" "$apply_to"
)
GitHub ต้นน้ำ
การใช้งาน:
git addมีอยู่แล้วใน repogit-amend-old $old_shaฉันชอบสิ่งนี้มากกว่า--autosquashเพราะมันไม่ได้แก้ไขปัญหาที่ไม่เกี่ยวข้องอื่น ๆ
git amendเพื่อใช้การเปลี่ยนแปลงกับคอมมิทเฉพาะกับการใช้การซ่อนปัจจุบันฉลาดมาก!
ฉันแก้ไขสิ่งนี้
1) โดยการสร้างคอมมิทใหม่ด้วยการเปลี่ยนแปลงที่ฉันต้องการ ..
r8gs4r commit 0
2) ฉันรู้ว่าการกระทำใดที่ฉันต้องรวมเข้าด้วย ซึ่งกระทำ 3
ดังนั้นgit rebase -i HEAD~4# 4 หมายถึงการกระทำ 4 ครั้งล่าสุด (ที่นี่การส่งมอบ 3 อยู่ในอันดับที่ 4)
3) ในการตอบโต้ rebase ล่าสุดกระทำจะอยู่ที่ด้านล่าง มันจะดูเหมือนกัน
pick q6ade6 commit 3
pick vr43de commit 2
pick ac123d commit 1
pick r8gs4r commit 0
4) ที่นี่เราจำเป็นต้องจัดเรียงคอมมิชชันใหม่ถ้าคุณต้องการรวมเข้าด้วยกัน มันควรจะเป็นเช่น
parent
|_child
pick q6ade6 commit 3
f r8gs4r commit 0
pick vr43de commit 2
pick ac123d commit 1
หลังจากจัดเรียงใหม่คุณจะต้องแทนที่ p pickด้วยf( fixupจะผสานโดยไม่ต้องส่งข้อความ) หรือs( สควอชผสานกับข้อความคอมมิชชันสามารถเปลี่ยนแปลงได้ในเวลาทำงาน)
แล้วบันทึกต้นไม้ของคุณ
ตอนนี้ผสานทำกับกระทำที่มีอยู่
หมายเหตุ: เป็นวิธีที่ไม่ดีกว่าเว้นแต่คุณจะดูแลด้วยตัวเอง หากคุณมีขนาดใหญ่ทีมมันไม่ใช่วิธีที่ยอมรับได้ในการเขียนแผนผัง git จะสิ้นสุดลงในความขัดแย้งที่คุณรู้ว่าเคยชินอื่น ๆ ถ้าคุณต้องการรักษาต้นไม้ให้สะอาดด้วยความมุ่งมั่นที่น้อยลงสามารถลองสิ่งนี้และหากเป็นทีมขนาดเล็กมิฉะนั้นจะไม่ดีกว่า .....
ตัวเลือกที่ดีที่สุดคือการใช้คำสั่ง "rebase Interactive"
git rebaseคำสั่งที่มีประสิทธิภาพอย่างไม่น่าเชื่อ มันช่วยให้คุณสามารถแก้ไข การส่งข้อความรวมคอมมิทสั่งซื้อใหม่ ...ทุกครั้งที่คุณปฏิเสธการส่งมอบ SHA ใหม่จะถูกสร้างขึ้นสำหรับการส่งมอบแต่ละรายการโดยไม่คำนึงถึงเนื้อหาที่จะมีการเปลี่ยนแปลงหรือไม่! คุณควรระวังเวลาที่จะใช้คำสั่งนี้เพราะอาจมีผลกระทบรุนแรงโดยเฉพาะถ้าคุณทำงานร่วมกับนักพัฒนาอื่น ๆ พวกเขาอาจเริ่มทำงานกับความมุ่งมั่นของคุณในขณะที่คุณกำลังรีบูตบางอย่าง หลังจากที่คุณบังคับให้ส่งการคอมมิทพวกเขาจะไม่ซิงค์และคุณอาจพบภายหลังในสถานการณ์ที่ยุ่งเหยิง ดังนั้นระวัง!
ขอแนะนำให้สร้าง
backupสาขาก่อนที่จะทำการรีบูตดังนั้นเมื่อใดก็ตามที่คุณพบสิ่งที่อยู่นอกเหนือการควบคุมคุณสามารถกลับไปสู่สถานะก่อนหน้า
git rebase -i <base>
-iยืนสำหรับ"การโต้ตอบ" โปรดทราบว่าคุณสามารถดำเนินการ rebase ในโหมดที่ไม่โต้ตอบ อดีต:
#interactivly rebase the n commits from the current position, n is a given number(2,3 ...etc)
git rebase -i HEAD~n
HEADระบุที่ตั้งปัจจุบันของคุณ (สามารถเป็นชื่อสาขาหรือการมอบหมาย SHA) ~nหมายถึง "n beforeéดังนั้นHEAD~nจะมีรายการของ 'n' กระทำก่อนที่หนึ่งที่คุณมีอยู่ในขณะนี้
git rebase มีคำสั่งที่แตกต่างกันเช่น:
pหรือpickเพื่อให้การกระทำเหมือนเดิมrหรือreword: เพื่อเก็บเนื้อหาของการกระทำ แต่แก้ไขข้อความการส่งsหรือsquash: เพื่อรวมการเปลี่ยนแปลงของคอมมิทนี้เข้ากับคอมมิชชันก่อนหน้า (คอมมิตข้างบนในรายการ)... ฯลฯ
หมายเหตุ: จะเป็นการดีกว่าถ้าให้ Git ทำงานร่วมกับเครื่องมือแก้ไขรหัสของคุณเพื่อทำให้สิ่งต่าง ๆ ง่ายขึ้น git config --global core.editor "code --wait"อย่างเช่นถ้าคุณใช้รหัสภาพคุณสามารถเพิ่มเช่นนี้ หรือคุณสามารถค้นหาวิธีเชื่อมโยงที่คุณต้องการในโปรแกรมแก้ไขรหัสด้วย GIT ใน Google
git rebaseฉันต้องการเปลี่ยน 2 คำตอบสุดท้ายที่ฉันทำดังนั้นฉันจึงดำเนินการดังนี้:
#This to show all the commits on one line
$git log --oneline
4f3d0c8 (HEAD -> documentation) docs: Add project description and included files"
4d95e08 docs: Add created date and project title"
eaf7978 (origin/master , origin/HEAD, master) Inital commit
46a5819 Create README.md
ตอนนี้ฉันใช้git rebaseเพื่อเปลี่ยนข้อความที่ส่งล่าสุด 2 ข้อความ:
$git rebase -i HEAD~2
มันเปิดตัวแก้ไขรหัสและแสดงสิ่งนี้:
pick 4d95e08 docs: Add created date and project title
pick 4f3d0c8 docs: Add project description and included files
# Rebase eaf7978..4f3d0c8 onto eaf7978 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
...
เนื่องจากฉันต้องการเปลี่ยนข้อความการส่งมอบสำหรับ 2 การกระทำ ดังนั้นผมจะพิมพ์rหรือในสถานที่ของreword pickจากนั้นบันทึกไฟล์และปิดแท็บ โปรดทราบว่าrebaseจะดำเนินการในกระบวนการหลายขั้นตอนดังนั้นขั้นตอนต่อไปคือการปรับปรุงข้อความ โปรดทราบว่าคอมมิชชันจะแสดงตามลำดับเวลาย้อนกลับดังนั้นการคอมมิทล่าสุดจะแสดงในคอมมิชชันแรกและคอมมิชชันแรกในบรรทัดแรกและอื่น ๆ
อัปเดตข้อความ: อัปเดตข้อความแรก:
docs: Add created date and project title to the documentation "README.md"
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
...
บันทึกและปิดแก้ไขข้อความที่สอง
docs: Add project description and included files to the documentation "README.md"
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
...
บันทึกและปิด
คุณจะได้รับข้อความเช่นนี้ในตอนท้ายของการรีบูต: Successfully rebased and updated refs/heads/documentationซึ่งหมายความว่าคุณจะประสบความสำเร็จ คุณสามารถแสดงการเปลี่ยนแปลง:
5dff827 (HEAD -> documentation) docs: Add project description and included files to the documentation "README.md"
4585c68 docs: Add created date and project title to the documentation "README.md"
eaf7978 (origin/master, origin/HEAD, master) Inital commit
46a5819 Create README.md
ฉันหวังว่าจะช่วยผู้ใช้ใหม่ :)
สำหรับฉันมันคือการลบข้อมูลประจำตัวบางส่วนจาก repo ฉันพยายามลดระดับใหม่และพบกับความขัดแย้งที่ดูเหมือนไม่เกี่ยวข้องระหว่างทางเมื่อพยายามลดระดับ - ยุติ ไม่ต้องพยายามรีบูตตัวเองใช้เครื่องมือที่เรียกว่า BFG (ชงติดตั้ง bfg) บน mac
หากคุณยังไม่ได้ส่งการผูกมัดคุณสามารถกลับไปใช้การคอมมิชชันก่อนหน้าได้ git reset HEAD^[1,2,3,4...]
ตัวอย่างเช่น
git commit <file1> -m "Updated files 1 and 2"
git commit <file3> -m "Updated file 3"
โอ๊ะลืมเพิ่ม file2 ไปที่การส่งครั้งแรก ...
git reset HEAD^1 // because I only need to go back 1 commit
git add <file2>
สิ่งนี้จะเพิ่ม file2 ในการส่งครั้งแรก
วิธีนี้อาจฟังดูงี่เง่ามาก แต่สามารถช่วยคุณได้ในเงื่อนไขบางประการ
เพื่อนของฉันเพิ่งพบเจอไฟล์บางไฟล์ขนาดใหญ่โดยไม่ตั้งใจ ( ไฟล์ที่สร้างอัตโนมัติสี่ไฟล์ระหว่าง 3GB ถึง 5GB แต่ละรายการ) จากนั้นทำโค้ดเพิ่มเติมให้พร้อมก่อนที่จะตระหนักถึงปัญหาที่git pushไม่ได้ทำงานอีกต่อไป!
ไฟล์ถูกแสดงรายการไว้.gitignoreแต่หลังจากเปลี่ยนชื่อโฟลเดอร์คอนเทนเนอร์แล้วไฟล์จะถูกเปิดเผยและถูกคอมมิท! และตอนนี้ก็มีอีกไม่กี่กระทำของรหัสที่ด้านบนของที่ แต่pushทำงานได้ตลอดไป (พยายามอัปโหลด GB ของข้อมูล) และในที่สุดก็จะล้มเหลวเนื่องจากข้อ จำกัด ขนาดไฟล์ Github ของ
ปัญหาของการรีบูตเดอร์อินเทอร์แอคทีฟหรือสิ่งที่คล้ายกันคือพวกเขาจะจัดการกับไฟล์ขนาดใหญ่เหล่านี้และจะใช้เวลาตลอดไปในการทำทุกอย่าง อย่างไรก็ตามหลังจากใช้เวลาเกือบหนึ่งชั่วโมงใน CLI เราไม่แน่ใจว่าไฟล์ (และเดลต้า) ถูกลบออกจากประวัติจริงหรือไม่รวมอยู่ในคอมมิชชันปัจจุบัน แรงผลักก็ไม่ได้ผลเช่นกันและเพื่อนของฉันก็ติดอยู่จริงๆ
ดังนั้นวิธีแก้ปัญหาที่ฉันพบคือ:
~/Project-oldเปลี่ยนชื่อโฟลเดอร์คอมไพล์ปัจจุบัน~/Project) cp -rไฟล์จากโฟลเดอร์ ~/Project-old~/Projectmvและรวมอยู่ใน.gitignoreอย่างเหมาะสม .gitโฟลเดอร์ในการโคลนล่าสุด~/Projectเก่าที่นั่นคือสิ่งที่บันทึกของประวัติศาสตร์ที่มีปัญหาอาศัยอยู่!push'edปัญหาที่ใหญ่ที่สุดในการแก้ปัญหานี้คือมันเกี่ยวกับการคัดลอกไฟล์บางไฟล์ด้วยตนเองและยังรวมการคอมมิทล่าสุดทั้งหมดไว้ในไฟล์เดียว
ประโยชน์ที่สำคัญคือมันชัดเจนมากในทุกขั้นตอนใช้งานได้ดีสำหรับไฟล์ขนาดใหญ่ (รวมถึงไฟล์ที่ละเอียดอ่อน)และไม่ทิ้งร่องรอยใด ๆ ในประวัติศาสตร์ไว้เบื้องหลัง!