Alomerry Wu @ alomerry.com

git 手册

Jul 7, 2020 · 13min · 3.1k · · updated at 4 years ago

配置

用户信息

首先要配置个人用户名称和电子邮件地址。每次 git 提交时会引用这两条信息。

以下是全局配置,也可以在对应的项目中输入 git config -e 来配置单个项目的 name 和 email

git config --global user.name "xxx xxx"
git config --global user.email "xxx@xxx.xxx"
git config --global core.editor vim
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_rsa.pub

SSH 公钥

使用 ssh-keygen 来创建公钥和密钥,它会要求你确认保存公钥的位置,然后会让你重复一个密码两次,如果不想在使用公钥时输入密码,可以留空。

ssh-keygen
cat ~/.ssh/id_rsa.pub

ssh-keygen -t rsa -C "any comment can be here"

  • -t = The type of the key to generate 密钥的类型
  • -C = comment to identify the key 用于识别这个密钥的注释

SSH 秘钥签名提交

  • git config gpg.format ssh
  • git config user.signingkey /PATH/TO/.SSH/KEY.PUB

基础

操作

查看提交历史

在项目中运行 git log 可以查看项目的更新,可以使用参数:

  • -n 仅显示最近 n 次的提交
  • -p 展开显示每次提交的内容差异
  • start 仅显示简要的增改行数同级
  • -pretty 使用其他格式显示历史提交信息,有如下可选项:
    • oneline 在一行显示
    • format 按制定样式显示
  • shortstat 只显示 --stat 中最后的行数修改添加移除统计
  • --since 限制输出长度,如 2.weeks
  • --author 显示指定作者的提交
  • --grep 可以搜索提交中的关键字
  • --committer 仅显示指定提交者相关的提交

在提交完成后发现有一些文件未添加,或者是发起 MR 后需要重新修改代码合并提交,可以使用 git commit --amend 命令,删除不必要的冗余 commit。

取消对文件的修改

有时发现对某个文件的修改是没必要的,可以将文件会退到之前的某个指定版本,使用 git checkout <branchId / commitId> <fileName> ,该命令会使文件被之前的版本覆写。

文件

移除文件

使用命令 git rm 将某个文件移除版本管理,如果删除前文件已修改则需要使用参数 -f 进行强制删除。

如果希望从Git仓库移除但是保留在工作目录中,可以使用 git rm --cashed xxx

移动文件

使用命令 git mv file_from file_to。该命令实际上是 Git 运行了如下三条命令:

mv file_from file_to
git rm file_from
git add file_to

取消已经暂存的文件

使用命令 git reset HEAD [file] 来将文件从暂存区域中取消。

仓库

从远程仓库抓取数据

使用 git fetch [remote-name] 命令会从远程仓库中拉取本地仓库中还没有的数据。

推送数据到远程仓库

使用 git push origin master 命令将本地仓库中的数据推送到远程仓库,如果有人在你推送数据前已经推送了更新,那你的推送操作会被驳回,需要先更新数据到本地仓库合并后才能再次推送。

工具

高级合并

hooks

客户端钩子

  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • post-applypatch
  • pre-rebase
  • post-rewrite
  • pre-push

git hook 默认位置是 .git/hooks,可以通过 git config 'core.hooksPath' 来指定自定义位置。

pre-push
#!/bin/sh

PROJECT_PATH=$(cd `dirname ${0}`; cd ../; pwd)
COMMAND="${PROJECT_PATH}/blog/.vuepress/ossPusher --configPath ${PROJECT_PATH}/blog/.vuepress/core.toml"
${COMMAND}
exit 0

服务端钩子

  • pre-receive
  • update
  • post-receive

案例

添加额外的 remote

  • git remote add gitlab <remote-git-url>

rebase 后撤销

  • 执行 git reflog 查看操作日志
  • 执行 git reset --hard [commit id]

强制同步远程分支

git fetch --all
git reset --hard origin/develop
git pull

撤销 commit

git reset --soft HEAD^

git reset --soft HEAD@{1}

本地推送多个远程仓库

  • 使用 git remote add 命令

    git remote add origin <url 1>
    git remote add alomerry <url 2>
    
    git push origin
    git push alomerry
  • 使用 git remote set-url add 命令

    git remote set-url --add origin <url>
    git push origin

    git remote set-url --add origin 就是在当前 git 项目的 config 文件中增加一行记录。

    使用 git config -e 查看:

    [remote "origin"]
            url = git@github.com:Alomerry/Note.git
            fetch = +refs/heads/*:refs/remotes/origin/*
            url = git@gitee.com:alomerry/Note.git
    [branch "develop"]
            remote = origin
            merge = refs/heads/develop

    使用 git remote -v 查看当前仓库的远程分支信息:

    git remote -v
    origin  git@github.com:Alomerry/Note.git (fetch)
    origin  git@github.com:Alomerry/Note.git (push)
    origin  git@gitee.com:alomerry/Note.git (push)

    使用 git push 可以看到:

    git push
    Enumerating objects: 7, done.
    Counting objects: 100% (7/7), done.
    Delta compression using up to 6 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (4/4), 945 bytes | 945.00 KiB/s, done.
    Total 4 (delta 1), reused 0 (delta 0)
    remote: Resolving deltas: 100% (1/1), completed with 1 local object.
    To github.com:Alomerry/Note.git
       896e0ca..dd63a8b  develop -> develop
    Enumerating objects: 7, done.
    Counting objects: 100% (7/7), done.
    Delta compression using up to 6 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (4/4), 945 bytes | 945.00 KiB/s, done.
    Total 4 (delta 1), reused 0 (delta 0)
    remote: Powered by GITEE.COM [GNK-5.0]
    To gitee.com:alomerry/Note.git
       896e0ca..dd63a8b  develop -> develop

合并 dev 并处理冲突

git checkout developgit pull origin develop

git checkout <branch>

这些命令会把你的 branch 分支里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到 .git/rebase 目录中),然后把 branch 分支更新 为最新的 origin 分支,最后把保存的这些补丁应用到 branch 分支上。

git rebase develop

branch 分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令,这些被丢弃的提交就会删除。(git gc)

解决冲突

在 rebase 的过程中,也许会出现冲突(conflict)。在这种情况,Git 会停止 rebase 并会让你去解决冲突;在解决完冲突后,用 git-add 命令去更新这些内容的索引,然后你无需执行 git commit,只要执行:

git rebase --continue

这样 git 会继续应用余下的补丁

git push -f

删除本地/远程分支后恢复

找到远程提交的 commit 哈希值后 git checkout -b [hash code],然后 git checkout -b [new branch] 后重新 push origin

clone 指定分支的指定 commit 版本

git clone [git-url] -b [branch-name]

git reset --hard [commit-number]

cherry-pick 指定 commit 部分文件

MR revert 后重建 MR 的修改

git log 查看提交 mr 的 commit 的 hash 值

commit 90bd4af583c9d5c2876dd3fdc3eba97e4713a452 (HEAD -> develop)
Author: Alomerry Wu <xxx@xxx.com>
Date:   Tue Feb 2 13:30:14 2021 +0800

    core: update grpc

commit 4becc71f2e504c0960e77df4d01c846117ce4c94
Author: Alomerry Wu <xxx@xxx.com>
Date:   Tue Feb 2 13:30:00 2021 +0800

    vendor: update grpc

commit 67a320491052a781e8c7f53a094a20f4fc3ade34
Merge: f2dd7dd23 b15b73788
Author: xxx <xxx@xxx.com>
Date:   Thu Feb 4 17:26:12 2021 +0800

    Merge branch 'feat-xxx' into 'develop'

    xxx: xxx

    See merge request xxx!7402

commit b15b73788feec28c8906dd0d61dc737b77b6017e

此时 4becc71f2e504c0960e77df4d01c846117ce4c9490bd4af583c9d5c2876dd3fdc3eba97e4713a452 是想要提交新 MR 的 commit

git checkout 67a320491052a781e8c7f53a094a20f4fc3ade34
git checkout -b feat-grpc
git cherry-pick 4becc71f2e504c0960e77df4d01c846117ce4c94 90bd4af583c9d5c2876dd3fdc3eba97e4713a452
git push --set-up stream orgin feat-grpc

合并 commit

git rebase -i HEAD~2

修改过去的 Commit

git log 如下:

commit <commit_id_a> (HEAD -> trans, origin/trans)
Date:   Tue Nov 13 23:57:05 2018 +0800

    message a

commit <commit_id_b>
Date:   Sat Nov 10 23:22:19 2018 +0800

    message b

commit <commit_id_c>
Date:   Sat Nov 10 17:41:55 2018 +0800

    message c

需要回到第一个 commit commit_id_c 对文件进行修改:

  • 将当前分支无关的工作状态进行暂存 git stash
  • 将 HEAD 移动到需要修改的 commit 上 git rebase commit_id_c^ --interactive
  • 找到需要修改的 commit ,将首行的 pick 改成 edit 后保存
  • 修改文件内容
  • 将改动文件添加到暂存 git add
  • 追加改动到提交 git commit --amend
  • 移动 HEAD 回到最新的 commit
  • 恢复之前的工作状态 git stash pop

作用

最现实的用处是如果你不小心把密码等敏感信息上传了,需要删掉,但后面又已经有新的 commit 信息你又不希望丢掉的时候,这个方法就派上用场了。

缺点

被修改分支后的所有 commit 都会被重新提交一遍,此时 master 分支 merge 这个分支的话会出现 commit 重复的问题。所以也只能在没有其他分支的情况下在主分支干这事。

submodule

https://www.xiexianbin.cn/git/command/git-submodule/index.html?to_index=1

合并两个不同的仓库

  • 拉取 A 库的代码,切换到 master 分支

    git clone https://github.com/project/A.gitgit checkout master

  • 添加需要合并的 B 仓库

    git remote add B http://github.com/project/B.git

  • 拉取 B 仓库代码

    git fetch B

  • 切换到 B 的 develop 分支上

    git checkout -b develop B/develop

  • 切换到 master 分支并合并

    git checkout mastergit merge develop --allow-unrelated-histories

  • 处理冲突,推送到远程

清理 git 仓库中废弃的大文件

  • 查找大文件[^remove-git-big-object-1]

      blog git:(master) git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -5
    f628e3087f5e32c2c84f2f7d534e744df31511e1 blob   348670 347901 444010
    3e2109358e393b52d0583c28cae8d3b36a4d3c41 blob   503391 146406 59027
    21e3ba4aad85cc3ae2cb7e666196b008cac0fbae blob   752709 150644 288525
    2832523cb6c5daa0dffac74e4388a11e20af9f64 blob   1415831 297634 10476233
    0a160bb8b890e3347121f4c6113e7292f4a279df blob   22888095 9603172 791911
    
      blog git:(master) git rev-list --objects --all | grep f628e3087f5e32c2c84f2f7d534e744df31511e1
    286e7fead83c53e1fa0f422776a8fcd06cf1f73d blog/posts/2020-07-06-todo~redis.md
    d7cf01cd434650c6505de73427a249b357cb6bea blog/posts/2022-04-27-todo~docker.md
    0252758734fe77a418eff2f0220cb8f7b6e6793e blog/posts/2022-02-14-code-style.md
    35535d0eb686254faeaab66565ef644e0cfc871b blog/posts/2020-07-06-html.md
    4fae8d57e9528c276f874de3b4a3c73504e41098 blog/LICENSE
    1e17f83f8e2b09eadb9bc66c18f36d68da8d0e11 blog/posts/2019-09-09-pat.md
    b2fbff53666b91b5b9f7df962bf2f3e54c7a0c10 blog/posts/2022-02-14-todo-book~gopl.md
    a0f78d64d79b3437023ade363819e4e0895b5e08 blog/posts/2022-06-23-jenkins-[note].md
    ff26e09e47c110fb39f0c1e09df08afa2be59a8f blog/posts/2022-06-23-todo~jenkins.md
    5cb8597ebade3476b5299d26680349eb81051f8b blog/posts/2019-07-25-pat.md
    21476c91f308f89a8ef7d0d5468303b2ea26bef4 blog/posts/2021-05-22-todo~mongodb.md
    a2279c7e98571ae5440a7c747777457056fd2e0d blog/posts/2021-06-23-todo~grpc.md
    ebb80851f93ca00d9f6ed3542c7f887076e97975 blog/posts/2020-08-10-golang-note.md
    30e8a08f69f28637949a67a1f7c465e62bbbcbc1 blog/posts/2019-07-02-digest.md
    47adee0986d85158d839eab966e203444c77fbfb pnpm-lock.yaml
  • 将文件从分支移除关联

      blog git:(master) git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch blog/.vuepress/public/img/*' --prune-empty --tag-name-filter cat -- --all
    WARNING: git-filter-branch has a glut of gotchas generating mangled history
    rewrites.  Hit Ctrl-C before proceeding to abort, then use an
    alternative filtering tool such as 'git filter-repo'
    (https://github.com/newren/git-filter-repo/) instead.  See the
    filter-branch manual page for more details; to squelch this warning,
    set FILTER_BRANCH_SQUELCH_WARNING=1.
    Proceeding with filter-branch...
    
    Rewrite 9bc72355596374a8a4d889056112b2a2bf6b78d3 (1/45) (0 seconds passed, remaining 0 predicted)    rm 'blog/.vuepress/public/img/.DS_Store'
    Rewrite 26f44f8526864b440f00fcfcb3a904acf2ab8481 (2/45) (0 seconds passed, remaining 0 predicted)    rm 'blog/.vuepress/public/img/.DS_Store'
    rm 'blog/.vuepress/public/img/home-bg/2.jpg'
    Rewrite c9125a07343776286a12c22e5b880b8f78ffe5ad (11/45) (1 seconds passed, remaining 3 predicted)    rm 'blog/.vuepress/public/img/about-avatar.png'
    Rewrite c14ff84ab1cf0c69cf8efa2ee6ef16bc1b9e801e (11/45) (1 seconds passed, remaining 3 predicted)    rm 'blog/.vuepress/public/img/about-avatar.png'
    rm 'blog/.vuepress/public/img/avatar.png'
  • 清理缓存,执行 gc 回收垃圾[^remove-git-big-object-2]

      blog git:(master) git reflog expire --expire=now --all && git gc --prune=now --aggressive
    Enumerating objects: 995, done.
    Counting objects: 100% (995/995), done.
    Delta compression using up to 8 threads
    Compressing objects: 100% (927/927), done.
    Writing objects: 100% (995/995), done.
    Total 995 (delta 463), reused 436 (delta 0), pack-reused 0
  • 推送到远程仓库 git push origin --force --all --no-thin

删除历史文件或敏感信息

Git 仓库中每一个修改都会保存记录,所以如果仅仅是删除敏感信息,然后 commit,那么那个敏感信息至少会在两个历史 commit 里面出现,也就是出现和删除的两次 commit,可以使用以下命令搜索:

git log -S 'sensitive string' -p --all

重写历史 commit

例如将代码中的 alomerry 全部替换成 **\*\*\*\***

git filter-branch -f --tree-filter 'find . -type f ! -path "./.git*" -exec sed -i "s/alomerry/********/g" {} \;' HEAD --all

无论使用 rebase 还是 filter-branch[^git-filter-branch],都会在本地 reflog 里面留下一下信息可以回溯到修改之前的状态,但是 reflog 是可以清空的,而且不会随着 push 传输到远程仓库的,可以放心使用。

清空 reflog

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now

上传代码

git push --force --all

删除文件

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *.go' --prune-empty --tag-name-filter cat -- --all
  • --prune-empty 表示如果修改后的提交如果为空则扔掉不要

Some kinds of filters will generate empty commits that leave the tree untouched. This switch allows git-filter-branch to ignore such commits …

git ssh 代理

git 代理

设置 git config --global http.https://github.com.proxy socks5://127.0.0.1:1086

设置完成后,~/.gitconfig 文件中会增加以下条目:

[http "https://github.com"]
    proxy = socks5://127.0.0.1:1086

ssh 代理

修改 ~/.ssh/config 文件

Host github.com
    User git
    ProxyCommand nc -v -x 127.0.0.1:1086 %h %p

Reference

 
 comment..
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.0.1
Theme by antfu
2018 - Present © Alomerry Wu