Git 的一些使用技巧
Git 是一个非常强大的版本控制工具,是程序员必须要掌握的技能。
这里记录常用的命令技巧和碰到的一些问题。
首先应该了解 Git 里面的几个概念。
- Workspace:工作区
- Index/Stage:暂存区(使用
git add
命令将工作区的改动添加到暂存区) - Repository:本地仓库(使用
git commit
命令将暂存区的改动提交到本地仓库) - HEAD:指向本地仓库的当前版本,上一个版本就是
HEAD^
,上上一个版本就是HEAD^^
,往上 10 个版本,可以 写成HEAD~10
。 - Remote:远程仓库
克隆仓库
|
将 shipengqi.github.io.git
克隆到 target dir
指定的文件夹(默认是远程仓库的名字),并切换到指定
分支 branch
(默认是 master 分支)。
未暂存的内容
把未暂存的内容添加到暂存区
|
把未暂存的内容移动到一个新分支
|
把未暂存的内容移动到另一个已存在的分支
|
放弃未暂存的修改
|
暂存的内容
把暂存的内容添加到上一次的提交
|
取消暂存的内容
添加到暂存区的文件,但是还没有提交,如果想要撤销暂存的文件,可以使用 git reset HEAD <file1> <file2>...
的方式取消暂存。
|
这样 file2
文件又回到了之前已修改未暂存的状态。
编辑提交
修改提交信息
|
如果已经 push 了这次提交, 那么可以修改这次提交(commit)然后强推(force push), 但是不推荐。
编辑指定 commit 的提交信息
编辑指定 commit 的提交信息,可以先使用 rebase
来修改某一次的提交信息
如果当前在 main
分支:
git rebase -i main^^
# 使用 commit 生成的哈希值来定位
git rebase -i aa588cd
git rebase -i aa588cd72b95ab35ec6e15637fb1e110281b2200
main^^
表示当前 main
指向的 commit 之前倒数第 2 个 commit。main~2
也是一样的意思。^
和 ~{count}
都是表示把 commit 往回偏移。
执行上面的命令之后,会进入如下的编辑界面:
pick aa588cd display error
pick e10dddf regex draft
# Rebase aa588cd..e10dddf onto aa588cd (2 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# 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.
#
# Note that empty commits are commented out
找到想要修改的 commit,将 pick
改为 edit
,然后 wq
保存退出,接着再运行:
git commit --amend -m 'changed commit mesasge'
修改提交里的用户名和邮箱
|
改完信息后,还需要 git rebase --continue
,将基准从当前倒数第二位置移到最新一次提交。git log
去检查下状态。
commit 添加签名
git commit -m "xx" -s
如果你配置了 username 和 email,参数 -s
会自动在 commit 的信息中添加签名,如下:
commit d52618492b788425b7c86d25c5e37eb67fd8fba6
Author: shipengqi <xxx@gmail.com>
Date: Mon May 2 18:36:11 2022 +0800
regex draft
Signed-off-by: shipengqi <xxx@gmail.com>
从一个提交(commit)里移除一个文件
从一个提交(commit)里移除一个文件:
|
当你有一个开放的补丁(open patch),你往上面提交了一个不必要的文件,需要强推(force push)去更新这个远程补丁。
撤销某一次提交
修改已经提交到了当前分支,但是还没有 push 到远程仓库
|
已经 push 到远程仓库的提交
已经 push 到远程仓库的提交,使用 git revert
,回滚到指定的历史版本,再 git push
更新远程仓库。
|
对于已经 push 到远程仓库的提交,也可以使用 reset,然后执行 git push -f
强制推到远程仓库中去,但是可能导致冲突。
如果只是回退到上一个 commit,建议使用 revert,如果要回退到多个版本之前,还是要使用 reset。
revert 与 reset 的区别
- reset 是在正常的 commit 历史中,删除了指定的 commit,这时 HEAD 是向后移动了,而 revert 是在正常的 commit 历史中再 commit 一 次,HEAD 是一直向前的。
- 对于已经把代码已经 push 到远程仓库,reset 删除指定 commit 以后,
push
可能导致一大堆冲突.但是 revert 不会。 - revert 是撤销指定的某个 commit 版本,但是指定 commit 之后的版本,还会保留下来。reset 是将 HEAD 移动到了指定的 commit, 指定 commit 之后的版本都会被丢弃。
如果想恢复到之前某个提交的版本,且那个版本之后提交的版本都不要了,就用 reset。 如果想撤销之前的某一版本,但是又想保留该目标版本后面的版本,就用 revert。
revert Merge Commit
执行 git revert commitId
可能会报错:
|
这是因为指定的 commit 是一次 merge,需要 -m
参数指定要 revert 的这个 merge commit 中的哪一个。
比如:git revert HEAD~1 -m 1
会 revert 第一个 commit。
你也可以在 git log
找到你要 revert 的那个 commit。
意外的做了一次硬重置(hard reset),如何找回内容
当你用 git reset --hard HEAD^
回退到上个版本时,再想恢复,就必须找到要恢复版本的 commit id。可以通过 git reflog
找到
那次 commit。
选择你想要回到的提交(commit)的 commit id,再重置一次:
|
提交错分支怎么办
还没有提交代码
比如忘了创建分支,并且 master 的代码可能还不是最新的,但是已经直接在 master 分支上进行了修改。这种情况下可以先把代码暂存起来,然后把 master 分 支更新到最新,再创建并切换到新的分支,然后把暂存的代码恢复回来。
|
然后就可以直接 commit 了。
已经提交
代码提交了,还没有 push,这个时候可以先把它撤回来
|
这样就把上一次的提交恢复为未提交的状态了,如果确定当前所在的 master 分支代码已经是最新的,就可以直接 checkout 到新的分支,来进行提交。否则,就就参考第一种情况。
查看 commit 历史
|
回退前,用 git log
可以查看提交历史,以便确定要回退到哪个版本。
回退后,用 git reflog
查看命令历史,以便确定要回到未来的哪个版本。
查看某次提交
|
Stash
stash
和 add
的区别:
git stash
的作用是把工作区(必须是工作区中已经被 git 追踪到的文件)和暂存区中的内容暂时存到一个栈上。而且这个堆是和分支不
相关的。切换分支后,依然可以看到并使用。
git add
命令将修改添加到暂存区。
暂存工作目录下的所有改动
|
暂存所有改动,包括 untracked 的文件(新建的文件)
|
暂存指定文件
|
暂存时记录消息
|
使用某个指定暂存
|
n
是 stash 在栈中的位置,最上层的 stash 会是 0
。
使用最后一个 stash 的状态,并删除这个 stash
|
删除所有的 stash
|
仅从 stash 中拿出某个文件的修改
|
比较差异
|
分支
|
需要提交到一个新分支,但错误的提交到了 master
在 master 下创建一个新分支,不切换到新分支,仍在 master 下:
|
把 master 分支重置到前一个提交:
|
checkout 到刚才新建的分支继续工作:
|
从错误的分支拉取了内容,或把内容拉取到了错误的分支
使用 git reflog
找到在这次 pull 之前 HEAD 的指向。
|
重置分支到你所需的提交:
|
恢复误删除的分支
有些时候可能删除了还没有推到远程的分支,如何恢复?例,创建一个分支,并做一次提交:
|
现在我们切回到主(master)分支,‘不小心的’删除 my-branch
分支
|
开始恢复删除的分支,先使用 reflog
命令, 它存储了仓库(repo)里面所有动作的历史。
|
可以看到一个删除分支的提交 hash(commit hash),开始恢复:
|
标签
|
恢复已删除标签
首先, 需要找到无法访问的标签(unreachable tag):
|
得到这个标签(tag)的 hash,然后:
|
这时标签(tag)应该已经恢复了。
远程仓库
|
同步远程仓库到自己 fork 的仓库
如果一个项目多人维护,每个人都 fork 了主仓库,并修改,提交 PR,那么如果在你提交自己的修改之前,主仓库 merge 了别人的 PR,
你 fork 的仓库的 commit 就会落后于主仓库,例如会有类似 This branch is 12 commit behind ITOM-Shared-Services:master.
的提示。这个时候
直接提交你的代码,创建 PR,如果 merge 你的 PR,可能就会有冲突,怎么解决?
- 切换在你本地的仓库
- 添加 remote
|
上面的命令中 itom
是给这个 remote 命名,git@github.houston.softwaregrp.net:ITOM-Shared-Services/keel-service.git
是 remote 的地址。
- 验证
git remote -v
- 在每次提交前执行
git pull itom master
,可以把主仓库的最新 commits 拉去到本地。 - 提交代码
Rebase 和 Merge
rebase 和 merge 有什么区别
rebase
rebase 会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。 例如,你从 master 拉了个 feature 分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西合并到 master 了,这个时 候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的话,就会把你当前的几个 commit,放到那个 人 commit 的后面。
merge
merge 会把公共分支和你当前的 commit 合并在一起,形成一个新的 commit 提交。
撤销 rebase/merge
如果 merge 或 rebase 了一个错误的分支, 或者完成不了一个进行中的 rebase/merge。 Git 在进行危险操作的时候会把原始的 HEAD 保
存在一个叫 ORIG_HEAD
的变量里, 所以要把分支恢复到 rebase/merge 前的状态是很容易的。
|
合并冲突时如何撤销 merge
如果已经执行了 git merge
命令,但是发生了冲突,可以使用下面的命令撤销:
git merge --abort
配置
配置 http 和 socks 代理
|
配置常用的命令别名
|
如:
|
可以使用 git st
代替 git status
。
或者修改配置文件,Linux 下, Git 的配置文件储存在 ~/.gitconfig
。在 [alias]
部分添加快捷别名,如下:
|
配置 git log 格式
原生的 git log
不太好用,一样可以配置:
|
然后git lg
就成了下面的样子:
生成压缩包
|