Git 求救指南
不增添 Commit 前提下修改内容
哒哒,git commit --amend
指令
>> git log
commit b7a2d1fb4b00ac3207ff7251ebdc92a181853322 (HEAD -> master)
Author: PuQing <me@puqing.work>
Date: Mon Jul 31 16:18:57 2023 +0800
add
你已经有了一个 commit 记录,之后修改了内容:
>> git status
On branch master
Changes not staged for commit:
(use "git add <file>…" to update what will be committed)
(use "git restore <file>…" to discard changes in working directory)
modified: a.md
no changes added to commit (use "git add" and/or "git commit -a")
这个时候先将添加内容加入暂存区
>> git add .
之后通过 git commit --amend
提交,弹出:
add
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Mon Jul 31 16:18:57 2023 +0800
#
# On branch master
#
# Initial commit
#
# Changes to be committed:
# new file: a.md
这时修改可能的 commit 记录就好。然后 VIM 退出就好。
如果你已经将该 commit 记录提交至远端,则将会出现冲突。可以使用 git push -f
强制推送 (三思而后行强制推送,操作不当可能导致记录丢失)。
这是个啥 ?
>> git pull
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
在第一次创建仓库,或者开发时很可能会遇到这个问题。
这里需要解释其中的几个名词:
Fast-forward
…--G--H <-- main
\
K--L <-- origin/main
假设你现在 main 分支开发,这时该分支追踪的上游分支提交了内容 (可能是 fork 的远程仓库更新,可能是在其他地方更新了记录),这时你想更新本地分支,与上游保持一致,这时便可以使用 Fast-forward
更新本地提交。其命令是 git merge --ff-only
…--G--H--K--L <-- main && origin/main
可是想象一下这种情况
…--G--H--F <-- main
\
K--L <-- origin/main
你在 main
分支中提交了记录 F,这时与上游不在是同一 base
,所以无法直接 merge,所以需要下面的方式。
Merge
I--J <-- main
/
…--G--H
\
K--L <-- origin/main
merge 操作会产生新的提交
I--J
/ \
…--G--H M <-- main (HEAD)
\ /
K--L <-- origin/main
其中的 M 便是一个 merge
提交。
Rebase
或许你觉得上面再产生一个 commit 记录不够优雅,可以使用 rebase 操作。看这个名字就是变基。
I--J <-- main
/
…--G--H
\
K--L <-- origin/main
同样的有这样的记录。
在 rebase 后
I--J [abandoned]
/
…--G--H--K--L <-- origin/main
\
I'-J' main
它会把 base 重新指向为 merge 分支的开头,并产生两个原来提交记录的拷贝。
所以 rebase 会更加干净一点。
另外可以使用 Interactive Rebase
可控的 rebase.使用指令 git rebase -i origin/main
即可打开窗口。
合并多个 Commit
上面我们提到了在不添加 commit 的记录下修改一个 commit,这个是如果你有多个 commit 如何合并成一个。
>> git log
commit 9c2a820fd60b114a91028792c3c2393d88c4c8da (HEAD -> master)
Author: PuQing <me@puqing.work>
Date: Mon Jul 31 20:31:29 2023 +0800
add
commit 5bea38d6493949135d96e0e8ab5545ff245cc1d8
Author: PuQing <me@puqing.work>
Date: Mon Jul 31 20:31:15 2023 +0800
add
commit 5b048ef5016347e1c2c9c59ed12868866f930d01
Author: PuQing <me@puqing.work>
Date: Mon Jul 31 16:18:57 2023 +0800
add
commit 31b5627acb83d0a5c262d01aa9cb1a650c9e8514 (origin/main)
Author: PuQing <liangjiaming@isrc.iscas.ac.cn>
Date: Mon Jul 31 08:36:40 2023 +0000
Initial commit
可以看到我们有很多次提交,下面我们通过 rebase 进行合并。
>> git rebase -i origin/main
pick 5b048ef add
pick 5bea38d add
pick 9c2a820 add
# Rebase 31b5627.c2a820 onto 31b5627 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# create a merge commit using the original merge commit's
# message (or the oneline, if no original merge commit was
# specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
# to this position in the new commits. The <ref> is
# updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
如果该界面编辑出现问题(比如 backspace 不能用之类的),请将默认编辑器换成 vim
git config --global core.editor vim
治疗好了我的高血压
这是 rebase 后的
>> git log
commit 24b56eaa875848cebf2d60f06f0c4ae484da4747 (HEAD -> master)
Author: PuQing <me@puqing.work>
Date: Mon Jul 31 16:18:57 2023 +0800
add
add
add
add
commit 31b5627acb83d0a5c262d01aa9cb1a650c9e8514 (origin/main)
Author: PuQing <liangjiaming@isrc.iscas.ac.cn>
Date: Mon Jul 31 08:36:40 2023 +0000
Initial commit