git: 版本管理工具使用手册

Tags: manual 

目录

说明

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

使用方式参考 beego

git project

其它资料:

Git 全局配置

设置代理

有一些项目使用了自己的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 config core.quotepath false

配置编辑器

git config --global core.editor vim

设置提交用户名

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,一定要小心。

远端协作流程

GitHub 项目的基本过程

更详细的说明见: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  

注意:

1. 切换到其它的分支之前一定要先 commit ,否则其它分支中的内容会受影响
2. 可以将多个 commit 合并为一个 commit,见“合并 commit ”一节
3. 将本次的 commit 合并到上一次 commit,使用 “--amend” 

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

git push origin local_branch:remote_branch  

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

git fetch origin

第六步,master 有更新后,将 master 上的改动同步到开发分支(rebase 方式):

git rebase master dev-branch

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

git rebase master --continue

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

git rebase -onto master  anotherbranch  currunbranch

rebase 之后,分支的 commitID 会变化,需要用 force 提交:

git push --force

第七步:同分支的的开发人员,在各自本地 rebase 当前分支:

git rebase

这一步是为了解决 rebase 后 commit ID 发生变化的问题

第八步,所有人代码合并后,将开发分支改动合并到 master:

git checkout master
git merge dev-branch

将开发分支合并到 master,推荐在 github/gitlab 中发起 pull request

第九步,根据需要在 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 

拉取远端分支

查看远程分支列表:

git branch -r 

拉取远端分支:

git branch -b 本地分支名 -t 远端分支名

-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

master/dev/feature 分支间的 rebase 操作

所有分支在 merge 到其它分支前,都基于目标分支进行一个 rebase。这种方式都缺点是,如果本地分支的提交次数很多,rebase 时要多次处理冲突。一种规避方式是把此次改动的所有 commit 合并成一个 commit。

master 创建提交:

mkdir git_test_rebase && cd git_test_rebase
git init
echo "master 0 " > file_master
git add . && git commit -m "master 0"

基于 master 创建 dev 分支:

git branch dev && git checkout dev
echo "dev 0 " > file_dev
git add . && git commit -m "dev 0"

基于 dev 创建 feature 分支:

git checkout dev
git branch feature && git checkout feature
echo "feature 0" > file_feature
git add . && git commit -m "feature 0"

master 发生了一次提交:

git checkout master
echo "master 1 " >> file_master
git add . && git commit -m "master 1"

接下来,dev 分支 rebase master,然后 feature 分支 rebase dev。

dev 分支 rebase master 前:

git checkout dev
git log 
----

commit 4791abc47b686ef09a8047e8ae3645674eb0d682 (HEAD -> dev)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:13 2021 +0800

    dev 0

    Change-Id: I4ca78716aba990fd3f59621897c06e717d163097

commit d63e40c3a68a8e176cc218da016ce0914bb9448b
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:26:59 2021 +0800

    master 0

    Change-Id: I2583c7f15ff324a75dc92b85c2a11f107340f125

dev 分支 rebase master 后:

git checkout dev
git rebase master
git log
----

commit 745fa8803901dfb8cff5732b6cb65dd48bb0c28d (HEAD -> dev)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:13 2021 +0800

    dev 0

    Change-Id: I4ca78716aba990fd3f59621897c06e717d163097

commit ff1f0e1a98b0538b274f963db83cff993634e111 (master)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:31 2021 +0800

    master 1

    Change-Id: I08ebc7eaaf0d40f553067766959118f511b38f2b

commit d63e40c3a68a8e176cc218da016ce0914bb9448b
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:26:59 2021 +0800

    master 0

    Change-Id: I2583c7f15ff324a75dc92b85c2a11f107340f125

feature 分支 rebase dev 前:

git checkout feature
git log 
----

commit b2254336717ba211368fb07559d45d11f52666d4 (HEAD -> feature)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:20 2021 +0800

    feature 0

    Change-Id: Ifcf9d77321d0c028f3bbee0f57704b115168eb20

commit 4791abc47b686ef09a8047e8ae3645674eb0d682
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:13 2021 +0800

    dev 0

    Change-Id: I4ca78716aba990fd3f59621897c06e717d163097

commit d63e40c3a68a8e176cc218da016ce0914bb9448b
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:26:59 2021 +0800

    master 0

    Change-Id: I2583c7f15ff324a75dc92b85c2a11f107340f125

feature 分支 rebase dev 后:

git checkout feature
git rebase dev
git log
----

commit 47dab5e6b5c97189862ad4e73990025bdfdcce1b (HEAD -> feature)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:20 2021 +0800

    feature 0

    Change-Id: Ifcf9d77321d0c028f3bbee0f57704b115168eb20

commit 745fa8803901dfb8cff5732b6cb65dd48bb0c28d (dev)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:13 2021 +0800

    dev 0

    Change-Id: I4ca78716aba990fd3f59621897c06e717d163097

commit ff1f0e1a98b0538b274f963db83cff993634e111 (master)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:27:31 2021 +0800

    master 1

    Change-Id: I08ebc7eaaf0d40f553067766959118f511b38f2b

commit d63e40c3a68a8e176cc218da016ce0914bb9448b
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:26:59 2021 +0800

    master 0

    Change-Id: I2583c7f15ff324a75dc92b85c2a11f107340f125

之后 dev merge feature 分支,mastr merge dev 分支:

git checkout dev && git merge feature
git checkout master && git merge dev

master/dev 分支间的 merge 操作

这种方式会在 master 的日志中出现 “merge master to dev” 的记录,看起来会比较奇怪。

master 创建提交:

mkdir git_test_merge && cd git_test_merge
git init
echo "master 0 " > file_master
git add . && git commit -m "master 0"

基于 master 创建 dev 分支:

git branch dev && git checkout dev
echo "dev 0 " > file_dev
git add . && git commit -m "dev 0"

master 发生了一次提交:

git checkout master
echo "master 1 " >> file_master
git add . && git commit -m "master 1"

dev 分支 merge master 前:

git checkout dev
git log
----

commit 0b3a1f9045abd32566faa682294bb9312074ece8 (HEAD -> dev)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:39:23 2021 +0800

    dev 0

    Change-Id: I45195e1136ff4fa47841470f30868eb213a09f5a

commit d3e7922668ed53fbf21b5288d714e52222a6c012
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:39:12 2021 +0800

    master 0

    Change-Id: Ifce8f87a662df1bae33c299a0b0ed6f906834f35

dev 分支 merge master 后:

git checkout dev
git merge master
git log
----

commit 12581ef3ff9ea8fe6df1f0ca4020723c97baff0b (HEAD -> dev)
Merge: 0b3a1f9 330d0fc
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:41:46 2021 +0800

    Merge branch 'master' into dev

    Change-Id: Ibe2b3eb8d188ec40e8a4ae22304ed8524c92c0fd

commit 330d0fcfd1969b18ba96d9ddd3f3ae2cfea87ed5 (master)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:40:04 2021 +0800

    master 1

    Change-Id: Id6645766cb4ad0a232f7ace89dd56510ffc10469

commit 0b3a1f9045abd32566faa682294bb9312074ece8
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:39:23 2021 +0800

    dev 0

    Change-Id: I45195e1136ff4fa47841470f30868eb213a09f5a

commit d3e7922668ed53fbf21b5288d714e52222a6c012
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:39:12 2021 +0800

    master 0

    Change-Id: Ifce8f87a662df1bae33c299a0b0ed6f906834f35

dev 分支 merge master 之后,发生提交:

git checkout dev
echo "dev 1 " >> file_dev
git add . && git commit -m "dev 1"

master 分支 merge dev:

git checkout master
git merge dev
git log
----

commit 81231ce9b5012e468bb2bd4e341129044f48bee5 (HEAD -> master, dev)
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:46:05 2021 +0800

    dev 1

    Change-Id: Ibafe4e1a99c509d2889204cf77da282ead3c7efe

commit 12581ef3ff9ea8fe6df1f0ca4020723c97baff0b
Merge: 0b3a1f9 330d0fc
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:41:46 2021 +0800

    Merge branch 'master' into dev

    Change-Id: Ibe2b3eb8d188ec40e8a4ae22304ed8524c92c0fd

commit 330d0fcfd1969b18ba96d9ddd3f3ae2cfea87ed5
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:40:04 2021 +0800

    master 1

    Change-Id: Id6645766cb4ad0a232f7ace89dd56510ffc10469

commit 0b3a1f9045abd32566faa682294bb9312074ece8
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:39:23 2021 +0800

    dev 0

    Change-Id: I45195e1136ff4fa47841470f30868eb213a09f5a

commit d3e7922668ed53fbf21b5288d714e52222a6c012
Author: lijiaocn <[email protected]>
Date:   Sun Mar 28 17:39:12 2021 +0800

    master 0

    Change-Id: Ifce8f87a662df1bae33c299a0b0ed6f906834f35

rebase 后 commit ID 变化时的处理

两个人同时在一个分支上工作,A 执行 rebase 后,进行 force commit,更改了 commit id,这时候 B 在同一个分支下执行 git rebase,可以解决 commit 被 A 改写的问题。 How can multiple developers work on the same branch using git rebase?

B 的操作:

git fetch origin/BranchWithA
git rebase                                   //在BranchWithA分支中执行
git rebase --fork-point origin/BranchWithA   //如果指定特定分支,必须使用 --fork-point

把一个分支中特定的 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

commit 代码对比

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

 git diff  commit1  commit2

分支改动临时保存

切换到其它分支时,如果当前分支有修改,需要先提交当前的修改。如果不想提交,用 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

本地 add 取消

git reset HEAD benchmarks.rb

本地 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

本地 rebase 撤销

How to undo a mistaken git rebase (LIFE SAVER)

$ git reflog testBranch
73d836b testBranch@{0}: rebase finished: refs/heads/testBranch onto e806e41f1fe22624e6546abd65c332c934214891
129e6d3 testBranch@{1}: commit: some sort of commit message

$ git reset — hard 129e6d3 # or testBranch@{1}

本地 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 取代。

永久删除文件

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''

设置分支跟踪的远端仓库

为本地分支设置远端仓库,新建一个名为 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

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

更改本地的远端仓库

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子 命令更改远端仓库的 url:

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

增加本地的远端仓库

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协作开发

本地删除远端仓库

git remote remove 删除远端仓库:

git remote remove upstream

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中子模块相关信息删除。

文件永久删除2

从所有提交记录中删除文件:Purging a file from your repository’s history

brew install bfg

Git 操作细节

git rebase 过程

假设要将分支 feature 基于 dev 进行 rebase:

1. 找到 feature 和 dev 最新的一个共同 commit
2. 将 feature 中共同 commit 之后的 commit,依次回放到最新的 dev 上,如果有冲突则修改

参考

  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 命令清单
  11. How can multiple developers work on the same branch using git rebase?
  12. How to undo a mistaken git rebase (LIFE SAVER)
  13. https://rtyley.github.io/bfg-repo-cleaner/
  14. Purging a file from your repository’s history
  15. git-flow-and-its-problems

推荐阅读

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

友情链接:  系统软件  程序语言  运营经验  水库文集  网络课程  微信网文  发现知识星球