Git Basic
初始化git
在一个空目录下,初始化git
在目录中放一些文件,然后添加到本地git中
检查git状态
要提交到远程仓库,那么必须先commit一下
如果git commit message写错了,可以用 --amend 修改:
提交到远程仓库,如果没有配置远程地址,则会报错,解决办法请参考下面的步骤
如果不小心git add了,要删除add的文件,可以执行
使用 git stash 将未完成的工作进行暂存
使用 git cherry-pick 来选择将某个commit merge到当前分支。比如在 dev 分支下,有两个 test1 和 test2分支,然后在test1分支下做了一些修改,已经提交上去,但没有merge到dev分支。这会想要在test2分支下,也应用这个变更。那么可以先用 git log看一下test1提交的commit id,然后cherry-pick选择commit到test2分支
Git rebase 压缩commit
使用 git rebase -i 命令,可以将多个 commit,压缩成1个commit。比如此时git log里,看到有历史3个commit,想要压缩成一个,那么可以用 git rebase -i HEAD~3 或者 git rebase-i HEAD~~~ 的方式,进行选择。之后会进入交互式界面,在交互式界面,编辑这个commit文件,将其他两个前面的pick改成s,表示squash,然后074c959 和 d38c6aa 就会被压缩到 5f7f01e 里了。如果想要从历史中,删除这两个commit,那么可以将s改成drop。之后保存退出就可以了
使用 fixup 和 autosquash 自动压缩commit
虽然使用 git rebase -i 可以将多个commit压缩成一个,或者在压缩的时候,选择drop commit,但是需要手动操作,且commit message里默认是有其他commit的message,此时我们可以用 git fixup 结合 autosquash帮我们实现.
具体操作方法是:在本地先提交一个commit,然后记下commitid,此时后续的其他变动,git add 之后,都可以使用 git commit --fixup COMMITID 的方式进行提交,然后git log里,我们能看到commit message都是 !fixup开头。
接下来使用 git rebase -i --autosquash 来帮我们自动合并commit,不需要做任何额外操作,我们能看到,默认其他的commit就是fixup的,而不是squash,然后保存,git log就看到只有一个commit了。
.git 文件夹太大压缩
如果经常对仓库里的文件操作,尤其是对一些大文件,图片之类的操作,那么 .git 文件夹有可能会非常大,比如10多G,甚至更大,可以使用 git gc 命令对其进行压缩
也可以使用下面的命令(在2007年linus提供的补丁之后,git gc和repack已经没区别了,可以看Linus的说明)
Git rebase 进行merge
如果在 master分支下,直接执行 git merge test,则会将 test分支的commit 方到master分支,同时会产生一个新的merge的commit 但是如果在 test分支下,先执行 git fetch origin master,然后 git rebase origin/master (或者执行 git pull origin master --rebase),则表示将本地的test分支的commit 历史,更新成跟master完全一样的commit历史
解决冲突
在git pull origin master --rebase更新本地代码,遇到冲突的时候,git rebase --skip可以让本地代码和远程保持一致,但本地的更改将在分支上丢失.
如果想保留本地,则执行 git checkout --ours . 之后执行git add. 最后执行 git rebase --continue 就可以了
配置github的key
在github上创建一个repo,然后在账户设置,SSH and GPG keys里面,添加 ssh pub key 产生ssh public key方法,添加~/.ssh/id_rsa.pub文件内容
之后可以测试一下
添加remote origin:
然后进行push
默认情况下,git credential是对所有仓库都生效的,如果有多个git账号,想访问不同的git repo的时候,使用不同的git credential,那么可以启用 useHttpPath,但需要注意的是,一旦启用了,任何新仓库,都会请求credential.
将远程git同步到本地
git 管理多个github repo
在本地创建另外一个folder,在github上创建好repo
Git 多分支管理
Git 中文显示
默认情况下,git 是无法显示中文的,而是显示八进制的字符。可以通过下面的修改,使git中文可正常显示
Git 高级使用方法
使用 git add -p 对同一个文件分段进行上传管理。比如一个文件中,有多处修改,我们在这次执行commit的时候,指向提交部分的修改,不想提交这个文件中的所有修改,就可以使用 git add -p 的方式来将文件添加进去。需要注意的是:如果本次想加入到git中的修改和不想加入的修改是分开在2个不同地方的,那么输入 git add -p FILENAME 后,然后输入 s 就能进行split,之后可以选择需要添加的区块。但如果想添加的地方和不想添加的地方是在一个地方,那么就没有 s 子命令,需要输入 e 手动进行编辑 示例:
git 日志与回滚
git reset 的时候,如果是 --soft,那么撤销的其他commit的变更,都会放到 暂存区,通过git status能看到。如果git reset --hard,则不会保留到暂存区。同时 git reset --soft HEAD~2 这种方式,可以直接回退2个commit
重新提交
正如在 "git 日志与回滚" 片段里提到的,我们可以用 git reset --soft 的方式,对已经提交的commit 进行撤销,撤销之后,在git status里能看到在staged中,处于git add 的状态,此时可以用 git restore --staged . 的方式对git add 进行撤销,然后重新add要提交进去的文件,再进行git commit。
这种方式在对于将 a b c 三个文件都提交到仓库里,但此时后悔了,只想提交a文件,b和c不想提交,此时就可以用git reset --soft COMMIT_ID 或 git reset origin/master 或 git reset HEAD~1 的方式,回退到指定commit,并且保留现有更改,然后再重新git add进行提交
撤消回退
在 "git 日志与回滚"中,我们提到可以用 git reset --hard HEAD1 直接丢弃某一个commit,这个和 git rebase -i HEAD1 之后,选中commit 进行drop有什么区别呢?
答案是:git reset --hard 的操作是直接丢弃commit,虽然在 git reflog 里能看到,但git reflog是保留在本地的,会自动清理的,不是很安全,如果使用这种方法,git reflog看到commit hash之后,要使用 git checkout或者 git cherry-pick 的方式添加这个commit,也不是很方便。如果使用 git rebase -i 的方式对commit进行操作,那么操作之前的HEAD信息,会保留到 ORIG_HEAD 这个分支下,这是一个特殊的分支,git branch 是看不到的,但如果git rebase -i之后后悔了,可以用 git reset --hard ORIG_HEAD的方式,轻松的撤销 git rebase 的结果,回退到 rebase之前的状态
查看某一个文件历史
通过 git blame 可以看文件中所有行的历史,但只能看这一行最后一次是谁修改的。如果想要看一个文件的历史改动,可以用git log。此时能看到文件改动的所有历史
然后使用 git blame可以看某一个commit的时候这个文件内容
删除git历史中的一个文件
现在不推荐使用 filter-branch,建议使用 filter-repo。不过 filter-repo需要单独安装
如果想要从git 历史中,使用本地的某个文件,对其进行替换
其中 -- --all 指的是,对所有分支都进行修改,如果直接写 HEAD的话,则只对当前分支进行修改
github pr merge 的三种方式
merged pull request:
这种方式是直接将源分支的一个或多个commit,移动到目的分支,同时再创建一个merge commit
squash merge:
这种方式是将源分支的一个或多个commit,压缩成一个新的commit放到目的分支。注意此事因为目的分支并没有源分支的commit,所以如果源分支下次提交的时候,没有rebase 当前目的分支,那么会将之前变更在pr里继续带上。尤其是如果更改的文件和目的分支不一样,又没有rebase,就会提示冲突
rebase merge:
这种方式是将源分支的一个或多个commit,创建一个或多个commit,放到目的分支
pre-commit
如果我们本地仓库根目录里有 .pre-commit-config.yaml文件,那么在仓库根路径下执行 pre-commit install 命令,则会自动根据这个yaml文件,生成hooks脚本,放在 .git/hooks/ 文件夹下。但此时需要我们针对每一个仓库目录,在本地都执行这个 pre-commit install 命令。当然我们可以在 ~/.gitconfig 文件里,指定 templatedir 目录,然后将 hooks文件放到这个目录里,这样以后只要 git clone 一个仓库,就会自动将 templatedir 路径下的hooks文件拷贝过来了.
如果想要在 git 提交或合并PR前对代码进行一些检查,我们可以借助于 pre-commit 这个工具来做。首先需要安装一下 pre-commit 这个工具,然后在git项目的根目录,需要存在一个 .pre-commit-config.yaml 文件,将 pre-commit 的一些hook可以在这里定义,然后通过 github action pipeline,对pr 进行检查。
如果想要在本地提交到本地仓库之前,就通过pre-commit进行一些检查,而不依赖仓库的 .pre-commit-config.yaml 文件。此时我们可以通过修改 ~/.gitconfig 里init的templatedir,这样以后 git clone或者git init的时候,会将这个 templatedir 目录下的文件,都拷贝到 项目.git/ 路径下,示例配置
此时我们在 ~/.git-template/文件夹下,创建一个 hooks 文件夹,在里面创建 pre-commit 文件,执行 chmod +x pre-commit 将其设置为可执行文件。之后运行git clone的时候,就会将 hooks文件夹都拷贝到 项目的.git/路径下,而在本地执行 git commit 的时候,就会执行 pre-commit 这个脚本。
当然我们也可以设置 pre-push, post-update 等脚本,我们可以执行 pre-commit install 命令 ,就会在 ~/.git/hooks/ 文件夹下,产生一些 .sample 结尾的示例文件,可以参考这个文件。
如果想要在本地也执行 pre-commit,可以将这个脚本放到 /home/USERNAME/.git-template/hooks/pre-commit 文件里
Git Tag
git tag 一般比较常见的有:轻标签(lightweight tag)和注释标签(annotated tag)。如果使用 git cat-file -t TAG_NAME 观察,轻标签是一个commit,注释标签是一个tag。用git show TAG_NAME对比,轻标签只能看到commitid,注释标签能看到很多信息。
创建轻标签
创建注释标签
如果想列出一个commit上的tag,可以用 git describe 命令,如果不加 --tags,有可能列出来的是轻标签,而非最新的标签。
git repo搭建
完整 clone git 仓库
如果想要完整clone git 仓库,然后迁移到另外一个仓库里,那么我们再 clone的时候,要加上 --bare 参数
示例:将远程仓库完全clone到本地,并还原成一个可以操作的仓库
示例:将远程仓库clone到本地后,再push到远端另外一个仓库
Git Config
默认情况下,git 仓库将会用 ~/.gitconfig 配置文件里的配置,如果有多个不同的仓库,想要让部分仓库使用另外的邮箱和用户名,那么可以将这些仓库放在一个特定路径下,然后通过 includeIf 来包含这个路径,然后在这个路径下的repo,都会用另外一个配置文件。想要检查当前repo的git配置,可以直接在仓库路径下输入 git config user.email 或者 git config user.name (需要注意的是,git配置里尽量避免使用 ~,可能导致配置不生效)
如果有多个git 配置文件,那么可以用下面的命令来查看
Git 也有一个全局配置
Git Debug
在执行git 任何命令的时候,如果想要显示更详细的日志,可以在前面加上 GIT_TRCE=1 来显示
最后更新于