Git的操作经常忘记, 这里记录下常用的操作。Git中文手册、图解Git和常用 Git 命令清单是很好的资料。
可以参考beego的项目管理:
其它资料:
有一些项目使用了自己的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
更详细的说明见: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。
如果自己的代码托管工具是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
把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 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中子模块相关信息删除。
从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 :远程分支
git push origin TagName //推送指定tag
git push origin --tags //推送全部tag
git tag -d TagName //删除本地tag
git push origin :TagName //删除远程tag
https://help.github.com/articles/remove-sensitive-data/
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,一定要小心。