➜ git-exercise git:(229cf94) git add . ➜ git-exercise git:(229cf94) ✗ git commit --amend [detached HEAD 8fec5f4] rebase i 22 修改了一下,并直接使用add . 1 file changed, 2 insertions(+) ➜ git-exercise git:(8fec5f4)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
➜ git-exercise git:(8fec5f4) git rebase --continue Auto-merging sami1.txt CONFLICT (content): Merge conflict in sami1.txt error: could not apply 45d3a51... rebase i 333 Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 45d3a51... rebase i 333 # 解决文件冲突 ➜ git-exercise git:(8fec5f4) ✗ git add sami1.txt ➜ git-exercise git:(8fec5f4) ✗ git rebase --continue [detached HEAD d480273] rebase i 333 1 file changed, 2 insertions(+) Successfully rebased and updated refs/heads/sami.
交互式rebase
交互式 rebase,它可以在 rebase 开始之前指定一些额外操作。交互式 rebase 最常用的场景是修改写错的 commit,但也可以用作其他用途。它的大致用法:
使用方式是 git rebase -i 目标commit;
在编辑界面中指定需要操作的 commits 以及操作类型;
操作完成之后用 git rebase --continue 来继续 rebase 过程。
如果不是最新的 commit 写错,就不能用 commit --amend 来修复了,而是要用 rebase。不过需要给 rebase 也加一个参数:-i。
rebase -i 是 rebase --interactive 的缩写形式,意为「交互式 rebase」。
所谓「交互式 rebase」,就是在 rebase 的操作执行之前,你可以指定要 rebase 的 commit 链中的每一个 commit 是否需要进一步修改。那么你就可以利用这个特点,进行一次「原地 rebase」。
用法
1 2 3 4 5 6
git rebase -i HEAD^^ # 定位到HEAD之前2个的commit上 # 把当前 commit ( HEAD 所指向的 commit) rebase 到 HEAD 之前 2 个的 commit 上 #把要修改的commit 前面的pick 改成edit 然后使用之前那一套 git add 处理要修改的文件 git commit --amend git rebase --continue
git reset --hard HEAD^ ➜ git-exercise git:(main) git reset --hard HEAD^ HEAD is now at 5ce1e26 rebase分支提交
丢弃非最新提交
不是最新的提交,就不能用 reset --hard 来撤销了。这种情况的撤销,就要用之前介绍过的一个指令:交互式 rebase ——rebase -i。
「撤销过往的提交」。方法有两种:
用 git rebase -i 在编辑界面中删除想撤销的 commits
用 git rebase --onto 在 rebase 命令中直接剔除想撤销的 commits
方法有两种,理念是一样的:在 rebase 的过程中去掉想撤销的 commit,让他它消失在历史中。
演示示例丢弃rebase 1
把第一条删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14
➜ git-exercise git:(sami) git rebase -i sami~3 Auto-merging sami1.txt CONFLICT (content): Merge conflict in sami1.txt error: could not apply 8fec5f4... rebase i 22 修改了一下,并直接使用add . Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 8fec5f4... rebase i 22 修改了一下,并直接使用add . ➜ git-exercise git:(4b3689d) ✗ git add . ➜ git-exercise git:(4b3689d) ✗ git rebase --continue [detached HEAD f15d6cf] rebase i 22 修改了一下,并直接使用add . 1 file changed, 3 insertions(+) Successfully rebased and updated refs/heads/sami.
从sami最新rebase到之前3个commits,HEAD到了4b3689,产生冲突。
1 2 3 4 5 6 7
Sami de branch xiugai <<<<<<< HEAD ======= Rebase交互式修改不是最新的commits 1 Rebase交互式修改不是最新的commits 22 修改倒数第二个22222 >>>>>>> 8fec5f4 (rebase i 22 修改了一下,并直接使用add .)
➜ git-exercise git:(main) git revert HEAD~1 CONFLICT (modify/delete): revert.txt deleted in parent of 534e060 (test-revert) and modified in HEAD. Version HEAD of revert.txt left in tree. error: could not revert 534e060... test-revert hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and commit the result with 'git commit' ➜ git-exercise git:(main) ✗ git revert HEAD error: Reverting is not possible because you have unmerged files. hint: Fix them up in the work tree, and then use 'git add/rm <file>' hint: as appropriate to mark resolution and make a commit. fatal: revert failed ➜ git-exercise git:(main) ✗ git status On branch main Your branch is ahead of 'origin/main' by 6 commits. (use "git push" to publish your local commits)
You are currently reverting commit 534e060. (fix conflicts and run "git revert --continue") (use "git revert --skip" to skip this patch) (use "git revert --abort" to cancel the revert operation)
Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add/rm <file>..." as appropriate to mark resolution) deleted by them: revert.txt
no changes added to commit (use "git add" and/or "git commit -a") ➜ git-exercise git:(main) ✗ git add . ➜ git-exercise git:(main) git status On branch main Your branch is ahead of 'origin/main' by 6 commits. (use "git push" to publish your local commits)
You are currently reverting commit 534e060. (all conflicts fixed: run "git revert --continue") (use "git revert --skip" to skip this patch) (use "git revert --abort" to cancel the revert operation)
nothing to commit, working tree clean ➜ git-exercise git:(main) git revert --continue On branch main Your branch is ahead of 'origin/main' by 6 commits. (use "git push" to publish your local commits)
You are currently reverting commit 534e060. (all conflicts fixed: run "git revert --continue") (use "git revert --skip" to skip this patch) (use "git revert --abort" to cancel the revert operation)
nothing to commit, working tree clean ➜ git-exercise git:(main) git revert --abort ➜ git-exercise git:(main) git revert HEAD [main 6db3b2e] Revert "test-revert-1" 1 file changed, 1 deletion(-)
reset 的本质——不止可以撤销提交
reset 指令的本质:重置 HEAD 以及它所指向的 branch 的位置。同时,介绍了 reset 的三种参数:
--hard:重置位置的同时,清空工作目录的所有改动;
--soft:重置位置的同时,保留工作目录和暂存区的内容,并把重置 HEAD 的位置所导致的新的文件差异放进暂存区。
--mixed(默认):重置位置的同时,保留工作目录的内容,并清空暂存区。
reset --hard 不仅可以撤销提交,还可以用来把 HEAD 和 branch 移动到其他的任何地方。
reset 指令可以重置 HEAD 和 branch 的位置,不过在重置它们的同时,对工作目录可以选择不同的操作,而对工作目录的操作的不同,就是通过 reset 后面跟的参数来确定的。
reset–hard
reset --hard 会在重置 HEAD 和 branch 的同时,重置工作目录里的内容。当你在 reset 后面加了 --hard 参数时,你的工作目录里的内容会被完全重置为和 HEAD 的新位置相同的内容。换句话说,就是你的未提交的修改会被全部擦掉。
你的 HEAD 和当前 branch 切到上一条 commit 的同时,你工作目录里的新改动也一起全都消失了,不管它们是否被放进暂存区
reset–soft
reset --soft 会在重置 HEAD 和 branch 时,保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。--hard 会清空工作目录的改动,而 --soft 则会保留工作目录的内容,并把因为保留工作目录内容所带来的新的文件差异放进暂存区。还没有放入暂存区的文件仍然存在,实际上所有的工作目录文件都在。
➜ git-exercise git:(main) git add gitstash.txt ➜ git-exercise git:(main) ✗ git status On branch main Your branch is ahead of 'origin/main' by 7 commits. (use "git push" to publish your local commits)
Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: gitstash.txt
Untracked files: (use "git add <file>..." to include in what will be committed) gitstas1.txt
➜ git-exercise git:(main) ✗ git stash Saved working directory and index state WIP on main: 6db3b2e Revert "test-revert-1" ➜ git-exercise git:(main) ✗ git checkout sami Switched to branch 'sami' ➜ git-exercise git:(sami) ✗ git status On branch sami Untracked files: (use "git add <file>..." to include in what will be committed) gitstas1.txt
nothing added to commit but untracked files present (use "git add" to track) ➜ git-exercise git:(sami) ✗ git checkout main Switched to branch 'main' Your branch is ahead of 'origin/main' by 7 commits. (use "git push" to publish your local commits) ➜ git-exercise git:(main) ✗ git status On branch main Your branch is ahead of 'origin/main' by 7 commits. (use "git push" to publish your local commits)
Untracked files: (use "git add <file>..." to include in what will be committed) gitstas1.txt
nothing added to commit but untracked files present (use "git add" to track) ➜ git-exercise git:(main) ✗ git stash pop On branch main Your branch is ahead of 'origin/main' by 7 commits. (use "git push" to publish your local commits)
Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: gitstash.txt
Untracked files: (use "git add <file>..." to include in what will be committed) gitstas1.txt
git stash -u #include 没有被 track 的文件 git checkout other # after operate git checkout old git stash pop #查看list git stash list ------------------- git stash //把本地的改动暂存起来 git stash save "message" 执行存储时,添加备注,方便查找。 git stash pop // 应用最近一次暂存的修改,并删除暂存的记录 git stash apply // 应用某个存储,但不会把存储从存储列表中删除,默认使用第一个存储,即 stash@{0},如果要使用其他个,git stash apply stash@{$num} 。 git stash list // 查看 stash 有哪些存储 git stash clear // 删除所有缓存的 stash
找回已经删除的branch
reflog 是 “reference log” 的缩写,使用它可以查看 Git 仓库中的引用的移动记录。如果不指定引用,它会显示 HEAD 的移动记录。假如你误删了 branch1 这个 branch,那么你可以查看一下 HEAD 的移动历史:
git fetch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
➜ git-exercise-b git:(main) git fetch ➜ git-exercise-b git:(main) git fetch origin main From github.com:cutegentle/git-exercise * branch main -> FETCH_HEAD ➜ git-exercise-b git:(main) git pull Updating 942f1d3..877ca87 Fast-forward branch-a-1.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 branch-a-1.txt ➜ git-exercise-b git:(main) git status On branch main Your branch is up to date with 'origin/main'.
You are in'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 08c7221 sami分支第一次提交 ➜ git-exercise-b git:(08c7221) git add . ➜ git-exercise-b git:(08c7221) ✗ git commit -m "回退08c7进行一些更改" [detached HEAD 0cd559b] 回退08c7进行一些更改 1 file changed, 1 insertion(+) ➜ git-exercise-b git:(0cd559b) git log ➜ git-exercise-b git:(0cd559b) git checkout sami Warning: you are leaving 1 commit behind, not connected to any of your branches:
0cd559b 回退08c7进行一些更改
If you want to keep it by creating a new branch, this may be a good time to do so with: