ฉันมักจะส่งรายการข้อผูกพันเพื่อตรวจสอบ หากฉันมีข้อผูกพันต่อไปนี้:
HEAD
Commit3
Commit2
Commit1
... git commit --amend
ฉันรู้ว่าฉันสามารถปรับเปลี่ยนหัวกระทำด้วย แต่ฉันจะแก้ไขCommit1
ได้อย่างไรว่ามันไม่ได้HEAD
กระทำ
ฉันมักจะส่งรายการข้อผูกพันเพื่อตรวจสอบ หากฉันมีข้อผูกพันต่อไปนี้:
HEAD
Commit3
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 และกำหนดผลลัพธ์ให้กับตัวแปร SHA
git 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
~/Project
mv
และรวมอยู่ใน.gitignore
อย่างเหมาะสม .git
โฟลเดอร์ในการโคลนล่าสุด~/Project
เก่าที่นั่นคือสิ่งที่บันทึกของประวัติศาสตร์ที่มีปัญหาอาศัยอยู่!push
'edปัญหาที่ใหญ่ที่สุดในการแก้ปัญหานี้คือมันเกี่ยวกับการคัดลอกไฟล์บางไฟล์ด้วยตนเองและยังรวมการคอมมิทล่าสุดทั้งหมดไว้ในไฟล์เดียว
ประโยชน์ที่สำคัญคือมันชัดเจนมากในทุกขั้นตอนใช้งานได้ดีสำหรับไฟล์ขนาดใหญ่ (รวมถึงไฟล์ที่ละเอียดอ่อน)และไม่ทิ้งร่องรอยใด ๆ ในประวัติศาสตร์ไว้เบื้องหลัง!