Git使用手册

目录

摘要

Git的操作经常忘记, 这里记录下常用的操作。Git中文手册图解Git常用 Git 命令清单是很好的资料。

可以参考beego的项目管理:

git project

其它资料:

设置代理

有一些项目使用了自己的git服务器,因为“墙”的存在,从国内访问这些git服务的时候,需要通过能够翻墙的代理。

可以设置为全局的:

git config --global http.proxy 127.0.0.1:49710
git config --global https.proxy 127.0.0.1:49710
git config --global http.sslverify false 

git的全局配置文件是~/.gitconfig:

[http]
    proxy = 127.0.0.1:49710
    sslverify = false
[https]
    proxy = 127.0.0.1:49710

不需要代理的时候,可以用#号注释掉。

将repo获取到以后,可以在repo里设置local config,只在当前repo中使用代理:

git config --local http.proxy 127.0.0.1:49710
git config --local https.proxy 127.0.0.1:49710
git config --local http.sslverify false 

跨repo协作开发

更详细的说明见:git 跨 repo 操作

第一步,在github上fork目标项目。

第二步,将fork到自己账户中项目代码clone到本地。

第三步,在本地添加上游代码的索引,这里命名为upstream:

git remote add upstream  https://github.com/kubernetes/kubernetes

第四步,在本地开始开发工作,本地的开发过程参考下一节“在本地分支中开发”。

第五步,获取上游代码的更新,注意upstream是上游代码的索引:

git remote update upstream

第六步,将本地分支设置为基于最新的上游代码:

git rebase upstream/master  (将当前所在分支的设置为基于upstream/master)
git rebase upstream/branchX  branchL  (将本地branchL分支的修改设置为基于upstream/branchX) 

第七步,将本地的修改提交到自己的repo中。

第八步,在github上发起pull request。

跨托管平台协作:将github项目导入gitlab

如果自己的代码托管工具是gitlab,要参与github上的项目开发,需要将github上的项目导入到gitlab。

较新版本的gitlab支持导入,直接填入github项目地址即可:如何把已存在的git项目转移到Gitlab项目?

如果gitlab版本不支持导入,可以用修改远程仓库地址的方式。

第一步,clone github上的项目:

git clone https://github.com/lijiaocn/containers.git
cd containers

第二步,修改远端仓库origin的名字,修改为upstream(上游代码的意思):

// 重命名前:
$ git remote
origin

// 重命名操作:
$ git remote rename origin upstream

// 重命名后:
$ git remote
upstream

第三步,在gitlab上创建一个git项目,名称根据需要设置,假设gitlab上创建的git项目地址如下:

http://gitlab.local/lijiao/containers.git

第四步,重新添加一个名为origin的远端仓库,指向gitlab中的项目:

// 添加新的origin
$ git remote add origin http://gitlab.local/lijiao/containers.git

// 添加后:
$ git remote -v
origin	http://gitlab.local/lijiao/containers.git (fetch)
origin	http://gitlab.local/lijiao/containers.git (push)
upstream	https://github.com/lijiaocn/containers.git (fetch)
upstream	https://github.com/lijiaocn/containers.git (push)

这时候在containers中进行操作,默认操作的是gitlab中的项目,先将代码推送到gitlab:

git push -u origin master

后续操作和上一节相同,例如:

// 获取上游代码的更新
git remote update upstream

// 将上游代码同步到当前项目
git rebase upstream/master            (将当前所在分支的设置为基于upstream/master)
git rebase upstream/branchX  branchL  (将本地branchL分支的修改设置为基于upstream/branchX) 

这样做能把github上代码不停的更新到当前使用的gitlab,但不能反过来提交pull request到github。

修改远程仓库的地址

可以用set-url直接修改远程仓库的地址:

git remote set-url origin  新的git地址   旧的的git地址

例如:

git remote set-url origin http://gitlab.local/infrastructure/kong-ingress-controller.git  http://gitlab.local/lijiao/kong-ingress-controller.git

查看 当前分支的跟踪的远程仓库

git branch -vv

在本地分支中开发

Merging vs Rebasing-zh(Merging vs Rebasing-en)中给出特别详细的说明。

第一步,获取master代码:

git checkout master

第二步,本地创建开发分支:

git checkout -b dev-branch

第三步,本地开发完成后,提交开发分支中的内容:

git add .

git status

git commit --verbose  

注意:切换到其它的分支之前一定要先commit,否则其它分支中的内容会受影响。

可以将多个commit合并为一个commit,见“合并commit”一节。

将本次的commit合并到上一次commit,可以使用“–amend”选项

第四步,如果其他人员也参与这个分支的开发,将本地分支推送到远端:

git push origin local_branch:remote_branch  

第五步,将远端的更新下载到本地:

git fetch origin

第六步,将本地开发分支的内容设置为基于最新的的master代码:

git rebase master dev-branch

这个过程会有多次冲突,必须一个一个地解决!然后继续rebase:

git rebase master --continue

如果开发分支是基于另一个分支的,也可以将其修改为基于master分支:

git rebase -onto master  anotherbranch  currunbranch

第七步,在master中合并已经做过rebase的开发分支,注意是merge!

git merge dev-branch

或者在github页面中发起pull request,请求将开发分支中的内容合并到master。

第八步,在master中完成commit、push、打tag:

git add .

git status

git commit

git push

标记tag:

git tag v0.0.X
git push origin v0.0.X

第九步,删除本地开发分支和远端的开发分支:

git branch -d dev-branch
git push origin :dev-branch 

把一个分支中指定的commit提交到另一个分支

把dev分支中的部分commit同步到lijiaocn分支,dev分支commit如下,只把8e73合并到lijiaocn分支:

commit 8e7e4df6a9d1fedcd69ded6e0ded475f9d8217a7 (HEAD -> dev)
Author: lijiaocn <[email protected]>
Date:   Fri Mar 22 16:42:17 2019 +0800

    fix: --update-state=false cause panic

    Signed-off-by: lijiaocn <[email protected]>

commit 020ae332c34905471ca6fdb22616f781c783ffc0 (origin/dev)
Author: lijiaocn <[email protected]>
Date:   Wed Mar 20 19:53:50 2019 +0800

    【文档】代码管理规范

commit 5fd0735bdd9abb1841a058e369858874d5152d4d (upstream/master, upstream/HEAD, origin/master, master, lijiaocn)
Author: Harry Bagdi <[email protected]>
Date:   Mon Mar 4 10:11:35 2019 -0800

    chore(deploy) do not pin the patch version for Kong
...

lijiaocn分支commit历史如下:

commit 5fd0735bdd9abb1841a058e369858874d5152d4d (HEAD -> lijiaocn, upstream/master, upstream/HEAD, origin/master, master)
Author: Harry Bagdi <[email protected]>
Date:   Mon Mar 4 10:11:35 2019 -0800

    chore(deploy) do not pin the patch version for Kong
...

只把dev分支中8e7e同步到lijiaocn分支,在lijiaocn分支中操作:

git checkout lijiaocn
git cherry-pick -x 8e7e

操作之后lijiaocn分支的commit历史变成:

commit e806e627d8df760b64c2cc3dbf0eef51b71dfc84 (HEAD -> lijiaocn)
Author: lijiaocn <[email protected]>
Date:   Fri Mar 22 16:42:17 2019 +0800

    fix: --update-state=false cause panic

    Signed-off-by: lijiaocn <[email protected]>
    (cherry picked from commit 8e7e4df6a9d1fedcd69ded6e0ded475f9d8217a7)

commit 5fd0735bdd9abb1841a058e369858874d5152d4d (upstream/master, upstream/HEAD, origin/master, master)
Author: Harry Bagdi <[email protected]>
Date:   Mon Mar 4 10:11:35 2019 -0800

也可以指定commit区间,例如:

git cherry-pick -x e806e627..09859d72   # 左开右闭,不包含第一个commit
git cherry-pick -x e806e627^..09859d72  # 闭区间,包含第一个commit

临时保存修改

切换到其它分支时,如果当前分支有修改,需要先提交当前的修改,如果不想提交,可以用 git stash 暂存:

$ git stash
Saved working directory and index state WIP on nginx-0.25.0-fp: e904814e0 【发布】0.25.1-fp-1

然后就可以切换到其它分支,从其它分支回来后,用下面的命令恢复到原状态:

git stash pop

推送本地分支到远端

创建一个发布分支:

git branch release-v1.8.0

将发布分支推送到远端:

git push origin release-v1.8.0:release-v1.8.0

在项目的github主页上,点击release,进行发布,注意在分支上进行release。

如果要删除release,只需要在本地和远端删除对应的tag即可。Git: 删除tag

远端仓库的地址设置

remote命令用来设置跟踪的远程仓库地址,默认有一个名为origin的远程跟踪,用git remote -v可以看到当前所有的远程跟踪,例如:

$ git remote -v
origin	https://github.com/introclass/kubernetes-yamls.git (fetch)
origin	https://github.com/introclass/kubernetes-yamls.git (push)

remote set-url子命令更改远程跟踪的地址:

git remote set-url origin https://github.com/lijiaocn/kube-lb.git

增加远程跟踪

remote add命令添加一个新的远程跟踪,例如下面添加了一个名为upstream的远程跟踪:

➜  kubernetes-yamls git:(master) ✗ git remote add upstream https://github.com/lijiaocn/kubernetes-yamls.git
➜  kubernetes-yamls git:(master) ✗ git remote -v
origin	https://github.com/introclass/kubernetes-yamls.git (fetch)
origin	https://github.com/introclass/kubernetes-yamls.git (push)
upstream	https://github.com/lijiaocn/kubernetes-yamls.git (fetch)
upstream	https://github.com/lijiaocn/kubernetes-yamls.git (push)zo

添加了新的远程跟踪之后,要正常工作,需要先用fetch命令将新的远程跟踪的代码拉取:

➜  kubernetes-yamls git:(another_repo) ✗  git fetch upstream
From https://github.com/lijiaocn/kubernetes-yamls
 * [new branch]      master     -> upstream/master

创建多个远程跟踪的好处是:可以将一个远程仓库中的更新同步到本地,然后提交到另一个远程仓库中,见github协作开发

另外要注意的是,远程跟踪只存在于本地,不能提交到远程仓库中。

删除远程跟踪

remote remove删除远程跟踪:

git remote remove upstream

为不同分支设置不同的远程跟踪

可以为本地不同的分支设置不同的跟踪地址,下面新建一个名为another_repo的分支:

$ git branch another_repo
$ git checkout another_repo

git branch -vv查看分支的远程跟踪,[]中是分支的远程跟踪:

$ git branch -vv
* another_repo 92ecfec add NodePort                  # another_repo分支当前没有远程跟踪
  master       92ecfec [origin/master] add NodePort

为another_repo设置远程跟踪,跟踪upstream中的master分支:

$ git branch -u upstream/master another_repo
➜  kubernetes-yamls git:(another_repo) ✗  git branch -u upstream/master another_repo
Branch 'another_repo' set up to track remote branch 'master' from 'upstream'.

这时候可以看到another_repo分支有了跟踪的分支:

$ git branch -vv
* another_repo 92ecfec [upstream/master] add NodePort
  master       92ecfec [origin/master] add NodePort

注意即使分支跟踪的是另一个远程仓库中的分支,也可以被推送到远程仓库中:

git push origin another_repo:another_repo

但是如果这时你从远程仓库中取出another_repo的分支,会发现它跟踪的不是upstream中的分支,而是origin中的分支:

$ git branch -vv
* another_repo 92ecfec [origin/another_repo] add NodePort
  master       92ecfec [origin/master] add NodePort

因此最好不要把跟踪另一个远程仓库的分支推送到远程仓库中,除非你确定就是要这样操作。

子模块,git项目嵌套

通过子模块,可以在一个git项目中包含另一个git项目。

添加子模块:

git submodule add https://github.com/chaconinc/DbConnector [目标路径] 

之后用git status查看,可以发现多出了一个.gitmodules文件,这个文件中记录了子模块信息。。

克隆包含自模块的项目时,子模块会是一个空的目录,需要用下面的两个命令获取子模块的内容。

git submodule init
git submodule update

或者在clone时使用--recursive参数。

更新子模块,可以进入到子模块中更新:

git fetch
git merge

或者使用命令更新所有子模块,默认更新master分支:

git submodule update --remote

如果要跟踪其它分支,在.gitmodules中配置:

git config -f .gitmodules submodule.DbConnector.branch stable

查看子模块的提交日志:

git log -p --submodule

如果要在子模块中进行修改并提交,在子模块中进行修改后,用下面的命令合并子模块的上游代码:

git submodule update --remote --merge    //merge
git submodule update --remote --rebase   //rebase
git submodule update --remote            //获取子模块更新,不做merge

在推送主项目中的变更时,可以用下面的命令:

git push --recurse-submodules=check      //如果子模块没有推送,push失败
git push --recurse-submodules=on-demand  //自动推送子模块,如果子模块推送失败,push失败

在所有的子模块中执行命令:

git submodule foreach 'git stash'

删除子模块时,将子模块目录删除后,在.gitmodules和.git/config中子模块相关信息删除。

常用git操作

合并commit

从log中找到一个在要合并的分支之前的commit(ffe)

在rebase中设置要合并的commit

git rebase -i ffe

编辑界面如下(将7143, 2a7c合并到ffe39):

 pick ffe398c d1

 s 2a7ccaa d2+d3

 s 714ef1b d4 amend

越靠前的commit越老, 将一个commit前面的pick修改为s, 表示这个commit将和它前面的commit合并为一个commit

保存、推出编辑后,如果存在合并的commit,会立即弹出问本次合并填写注释的编辑窗口,编写新的注释后推出即可

退出注释编辑窗口后,ffe,2a7,714消失, 被一个新的commit取代。

回退

git reset:

git reset --soft:   只将HEAD移动到指定的commit, 不会改动index文件和工作目录

git reset --mixed 或者 git reset:   index文件回退到指定的commit, 不改动工作目录

git reset --hard:  index文件和工作目录都回退到指定的commit

git rm之后,还没有提交:

git reset HEAD <删除的文件或目录>
git checkout <删除的文件或目录>

删除commit:

git reset --hard <commit_id>
git push origin HEAD --force

查看/拉取远程分支

查看:

git branch -r 

拉取远程分支:

git checkout -b 本地分支名 -t 远程分支名

推送分支

git push origin 本地分支:远程分支

删除远程分支

git push origin :远程分支

推送tag

git push origin TagName   //推送指定tag
git push origin --tags    //推送全部tag

删除tag

git tag -d TagName        //删除本地tag
git push origin :TagName  //删除远程tag

永久删除

https://help.github.com/articles/remove-sensitive-data/

http://zpz.name/2287/

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch path/to/your/file' HEAD
git push origin master --force
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now''

配置编辑器

git config --global core.editor vim

代码对比

展示commit2相对于commit1发生的改动:

 git diff  commit1  commit2

常见问题解决

取消已经暂存的文件

git reset HEAD benchmarks.rb

中文名乱码

解决中文文件名显示乱码:

git config core.quotepath false

修改提交记录中的用户名

How can I change the author name / email of a commit?

先配置用户名:

$ git config --global user.name "John Doe"
$ git config --global user.email "[email protected]"

$ git config --local user.name "John Doe"
$ git config --local user.email "[email protected]"

设置下一次提交中的用户名:

git commit --author="John Doe <[email protected]>"

覆盖上一次提交中的用户名:

git commit --amend --author="John Doe <[email protected]>"

如果要同时修改多个记录中的用户名:

git rebase -i -p 0ad14fa5      // 最近一个不需要修改的commit的id

在弹出的编辑页面中将要修改的commit前面的pick修改为edit,然后重复下面的过程,直到rebase结束:

git commit --amend
git commit --amend --author="John Doe <[email protected]>" --no-edit
git rebase --continue

还可以使用git filter

$ git filter-branch --env-filter '
WRONG_EMAIL="[email protected]"
NEW_NAME="New Name Value"
NEW_EMAIL="[email protected]"

if [ "$GIT_COMMITTER_EMAIL" = "$WRONG_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$NEW_NAME"
    export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$WRONG_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$NEW_NAME"
    export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

上述操作会生成新的commit,如果已经push到远程仓库了,可能需要使用force push,一定要小心。

参考

  1. undo git rm
  2. Merging vs Rebasing-zh
  3. Merging vs Rebasing-en
  4. Git: 在分支中开发
  5. Git: 删除tag
  6. beego git branch
  7. Git 工具 - 子模块
  8. Git中文手册
  9. 图解Git
  10. 常用 Git 命令清单

作者微信

推荐阅读

Copyright @2011-2019 All rights reserved. 转载请添加原文连接,合作请加微信lijiaocn或者发送邮件: [email protected],备注网站合作

友情链接:  李佶澳的博客  小鸟笔记  软件手册  编程手册  运营手册  爱马影视  网络课程  奇技淫巧  课程文档  精选文章  发现知识星球  百度搜索 谷歌搜索