0%

Mosh的Git课程笔记(5)--Collaboration

Mosh的课程网址

Workflows

👉 Centralized: a single repository
👉 Distributed:every developer has a repository √

Centralized Workflow

平时与中央服务器交互,万一中央服务器瘫痪,各repository之间可以交互。

5_01

5_02

中央服务器放在哪?

👉 private server

👉 cloud, 如 GitHub,GitLab

具体场景:

  1. John 和 Amy 都将 repository 拷贝到本地

5_03

  1. John commit了一些内容,想 share 给 Amy,就从本地 repository 拷贝到中央 repository

5_04

  1. Amy 将这些 commit 从中央 repository pull 到本地

5_05

  1. 如果和 Amy 自己的 commit 有 conflict,Amy 解决之后 push 到中央 repository

5_06

Integration-Manager

多用于Open-source project。通常有 maintainer 管理 project repository,其他的 contributors 不能直接 commit 到 project repository。

  1. Fork project repository 到自己的 repository,然后拷贝到本地

5_07

  1. Contributor 将自己的 commit push 到 repository

5_08

  1. Contributor 向 maintainer 发出 pull request,希望在 project repository commit 自己的贡献

5_09

  1. Maintainer 同意的话就从 contributor 的 repository pull 到自己的本地目录

5_10

  1. Maintainer review 过这些 commit 觉得没问题,就可以 push 到 project repository 了。

5_11

Cloning a Repository

拷贝远程仓库到本地,仓库目前只有一个commit:

1
2
3
4
5
6
7
8
9
10
11
$ git clone https://github.com/PurpleMStone/Mars.git MarsProject
Cloning into 'MarsProject'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

$ cd MarsProject/

(master)$ git log --oneline --all --graph
* 7216ded (HEAD -> master, origin/master, origin/HEAD) Initial commit

origin 指代的是远程仓库:

1
2
3
(master)$ git remote -v
origin https://github.com/PurpleMStone/Mars.git (fetch)
origin https://github.com/PurpleMStone/Mars.git (push)

Fetching

5_12

1
2
(master)$ git log --oneline --all --graph
* 7216ded (HEAD -> master, origin/master, origin/HEAD) Initial commit

在 remote repository 进行修改(update README.md,增加了第二行):

1
2
# Mars
A new line of code

用 git fetch 获取到本地,此时 origin/master 前进了,但是本地 master 还没动:

5_13

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(master)$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 645 bytes | 1024 bytes/s, done.
From https://github.com/PurpleMStone/Mars
7216ded..e27337b master -> origin/master

(master)$ git log --oneline --all --graph
* e27337b (origin/master, origin/HEAD) Update README.md
* 7216ded (HEAD -> master) Initial commit

(master)$ git branch -vv
* master 7216ded [origin/master: behind 1] Initial commit

由于没有diverse branch, 直接让本地 master fast-forward merge origin/master 就行了:

5_14

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(master)$ git merge origin/master
Updating 7216ded..e27337b
Fast-forward
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

(master)$ git log --oneline --all --graph
* e27337b (HEAD -> master, origin/master, origin/HEAD) Update README.md
* 7216ded Initial commit

(master)$ git branch -vv
* master e27337b [origin/master] Update README.md

(master)$ cat README.md
# Mars
A new line of code

而如果有 diverse branch,可能 merge 的时候会有 conflict,解决了再 merge 就行了。

Pulling

1
pull = fetch + merge

比如在本地有个commit B, 在 remote repository 有个 commit C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(master)$ echo hello > file1.txt

(master)$ git add .
warning: LF will be replaced by CRLF in file1.txt.
The file will have its original line endings in your working directory

(master)$ git commit -m "Add file1.txt"
[master ce83c2f] Add file1.txt
1 file changed, 1 insertion(+)
create mode 100644 file1.txt

(master)$ git log --oneline --all --graph
* ce83c2f (HEAD -> master) Add file1.txt
* e27337b (origin/master, origin/HEAD) Update README.md
* 7216ded Initial commit

在 remote repository 将 README.md update 了两次(commit C )。

现在可以用 git pull 获取 commit C 并进行 3-way merge:

5_15

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(master)$ git pull
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), 1.28 KiB | 1024 bytes/s, done.
From https://github.com/PurpleMStone/Mars
e27337b..4085604 master -> origin/master
Merge made by the 'recursive' strategy.
README.md | 2 ++
1 file changed, 2 insertions(+)

(master)$ git log --oneline --all --graph
* b6e7d23 (HEAD -> master) Merge branch 'master' of https://github.com/PurpleMStone/Mars
|\
| * 4085604 (origin/master, origin/HEAD) Update README.md
| * 3e40ffc Update README.md
* | ce83c2f Add file1.txt
|/
* e27337b Update README.md
* 7216ded Initial commit

也可以用 git pull —rebase 将 B rebase,然后就是 linear history 了:

5_18

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(master)$ git log --oneline --all --graph
* ce83c2f (HEAD -> master) Add file1.txt
| * 4085604 (origin/master, origin/HEAD) Update README.md
| * 3e40ffc Update README.md
|/
* e27337b Update README.md
* 7216ded Initial commit

(master)$ git pull --rebase
Successfully rebased and updated refs/heads/master.

(master)$ git log --oneline --all --graph
* ec68ae1 (HEAD -> master) Add file1.txt
* 4085604 (origin/master, origin/HEAD) Update README.md
* 3e40ffc Update README.md
* e27337b Update README.md
* 7216ded Initial commit

Pushing

将本地的 commit push 到 remote repository,然后 remote repository 的 master 会 move forward,然后 origin/master 会 move forward.

1
(master)$ git push

有些情况,push 会被拒绝:

如想将C push 到 remote,但是此时别人push了个D到remote,Git为了防止你overwrite别人的work,就不让push:

5_19

5_17

如果用

1
$ git push -f

remote就会丢掉D,然后让C push到remote, remote 的 master 指向C。(别用,谨慎)

好的做法是:用 git pull 在本地存下 D,然后用 3-way merge 或 rebase 的方法结合 local master 和 D,有冲突就解决冲突,然后再 git push 到 remote repository。这样,local 和remote 就一致了。

5_20

Storing Credentials

windows 在 https://github.com/Microsoft/Git-Credential-Manager-for-Windows 下载

不用每次 push 都登录一次。

Sharing Tags

给最近的一次 commit 加tag,并且share 到 github 上去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(master)$ git tag v1.0

(master)$ git log --oneline --all --graph
* 125409a (HEAD -> master, tag: v1.0, origin/master, origin/HEAD) add file2.txt
* ec68ae1 Add file1.txt
* 4085604 Update README.md
* 3e40ffc Update README.md
* e27337b Update README.md
* 7216ded Initial commit

(master)$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/PurpleMStone/Mars.git
* [new tag] v1.0 -> v1.0

更新 github 的页面会发现多了一个 tag。

删除tag:

1
2
3
$ git push origin --delete v1.0
To https://github.com/PurpleMStone/Mars.git
- [deleted] v1.0

更新 github 的页面会发现这个 tag被删了。但是在本地目录,tag还在:

1
2
3
4
5
6
7
8
9
10
$ git log --oneline --all --graph
* 125409a (HEAD -> master, tag: v1.0, origin/master, origin/HEAD) add file2.txt
* ec68ae1 Add file1.txt
* 4085604 Update README.md
* 3e40ffc Update README.md
* e27337b Update README.md
* 7216ded Initial commit

$ git tag -d v1.0
Deleted tag 'v1.0' (was 125409a)

Releases

在 github 上release, 会给当前 commit 版本打一个 tag。

加上Release Notes。

如果还不是stable的版本,勾上“Pre-release”。

5_21

Sharing branches

增加分支

在本地创建了一个新分支,git push 的报错信息意思是这个branch 没有 link to origin 的 branch:

1
2
3
4
5
6
7
8
(master)$ git switch -C feature/change-password
Switched to a new branch 'feature/change-password'

(feature/change-password)$ git push
fatal: The current branch feature/change-password has no upstream branch.
To push the current branch and set the remote as upstream, use

git push --set-upstream origin feature/change-password

-vv 查看当前的本地分支与远程分支的关联关系

-r 查看tracked branch (远程分支):

1
2
3
4
5
6
7
(feature/change-password)$ git branch -vv
* feature/change-password 125409a add file2.txt
master 125409a [origin/master] add file2.txt

(feature/change-password)$ git branch -r
origin/HEAD -> origin/master
origin/master

将新分支push上去(-u中的u是upstream的意思):

1
2
3
4
5
6
7
8
9
(feature/change-password)$ git push -u origin feature/change-password
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'feature/change-password' on GitHub by visiting:
remote: https://github.com/PurpleMStone/Mars/pull/new/feature/change-password
remote:
To https://github.com/PurpleMStone/Mars.git
* [new branch] feature/change-password -> feature/change-password
Branch 'feature/change-password' set up to track remote branch 'feature/change-password' from 'origin'.

再查看一下:

本地分支和远程分支关联起来了,github上也能看到新增的分支

1
2
3
4
5
6
7
8
(feature/change-password)$ git branch -vv
* feature/change-password 125409a [origin/feature/change-password] add file2.txt
master 125409a [origin/master] add file2.txt

(feature/change-password)$ git branch -r
origin/HEAD -> origin/master
origin/feature/change-password
origin/master

删除分支

删除远程分支:

1
2
3
4
5
6
7
(feature/change-password)$ git push -d origin feature/change-password
To https://github.com/PurpleMStone/Mars.git
- [deleted] feature/change-password

(feature/change-password)$ git branch -r
origin/HEAD -> origin/master
origin/master

但是本地分支还在,要切换回master分支删掉:

1
2
3
4
5
6
7
8
9
10
11
12
13
(feature/change-password)$ git branch -vv
* feature/change-password 125409a [origin/feature/change-password: gone] add file2.txt
master 125409a [origin/master] add file2.txt

(feature/change-password)$ git switch master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

(master)$ git branch -d feature/change-password
Deleted branch feature/change-password (was 125409a).

(master)$ git branch
* master

Collaboration Workflow

1
2
本Demo展示了两个contributor是如何通过GitHub来协作的
协作者:👉 我 👉 Amy

1. 我来创建新分支

在GitHub上创建一个新分支feature/change-password,然后在本地目录下:

1
2
3
4
5
6
7
8
9
10
11
12
(master)$ git fetch
From https://github.com/PurpleMStone/Mars
* [new branch] feature/change-passwork -> origin/feature/change-passwork
* [new tag] v1.0 -> v1.0

(master)$ git branch
* master

(master)$ git branch -r
origin/HEAD -> origin/master
origin/feature/change-passwork
origin/master

我们只得到一个remote tacked branch origin/feature/change-passwork,而本地没有一个branch是feature/change-passwork。

创建一个feature/change-passwork分支,相当于一个指针指向remote branch origin/feature/change-passwork:

1
2
3
(master)$ git switch -C feature/change-passwork origin/feature/change-passwork
Switched to a new branch 'feature/change-passwork'
Branch 'feature/change-passwork' set up to track remote branch 'feature/change-passwork' from 'origin'.

2. 另一个contributor

现在比如说有另一个协作者Amy,将这个库clone下来:

1
2
3
4
5
6
7
8
9
10
Amy$ git clone https://github.com/PurpleMStone/Mars.git
Cloning into 'Mars'...
remote: Enumerating objects: 17, done.
remote: Counting objects: 100% (17/17), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 17 (delta 1), reused 4 (delta 0), pack-reused 0
Receiving objects: 100% (17/17), done.
Resolving deltas: 100% (1/1), done.

Amy$ cd Mars

查看本地分支,依然只有一个master,所以也要创建一个feature/change-passwork分支,相当于一个指针指向remote branch origin/feature/change-passwork:

1
2
3
4
5
6
7
Amy/Mars (master)$ git branch
* master

Amy/Mars (master)$
git switch -C feature/change-passwork origin/feature/change-passwork
Switched to a new branch 'feature/change-passwork'
Branch 'feature/change-passwork' set up to track remote branch 'feature/change-passwork' from 'origin'.

在这个分支下进行修改并commit,然后push到github,可以在 github 的该分支下看到这个修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Amy/Mars (feature/change-passwork)$ echo password > file1.txt

Amy/Mars (feature/change-passwork)
$ git commit -am "Update file1"
[feature/change-passwork 244f7a7] Update file1
1 file changed, 1 insertion(+), 1 deletion(-)

Amy/Mars (feature/change-passwork)$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 306 bytes | 306.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/PurpleMStone/Mars.git
125409a..244f7a7 feature/change-passwork -> feature/change-passwork

3. 我来Merge

这时本人将GitHub的变化pull到本地,并且发现HEAD指向feature/change-passwork分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(feature/change-passwork)$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 286 bytes | 0 bytes/s, done.
From https://github.com/PurpleMStone/Mars
125409a..244f7a7 feature/change-passwork -> origin/feature/change-passwork
Updating 125409a..244f7a7
Fast-forward
file1.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

(feature/change-passwork)$ git log --oneline --all --graph
* 244f7a7 (HEAD -> feature/change-passwork, origin/feature/change-passwork) Update file1
* 125409a (tag: v1.0, origin/master, origin/HEAD, master) add file2.txt
* ec68ae1 Add file1.txt
* 4085604 Update README.md
* 3e40ffc Update README.md
* e27337b Update README.md
* 7216ded Initial commit

现在希望将分支merge到master,可以发现是一个Fast-forward merge,并且查看log,两个分支在本地确实是merge了,但是origin的远程master分支还是原样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(feature/change-passwork)$ git switch master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

(master)$ git merge feature/change-passwork
Updating 125409a..244f7a7
Fast-forward
file1.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

(master)$ git log --oneline --all --graph
* 244f7a7 (HEAD -> master, origin/feature/change-passwork, feature/change-passwork) Update file1
* 125409a (tag: v1.0, origin/master, origin/HEAD) add file2.txt
* ec68ae1 Add file1.txt
* 4085604 Update README.md
* 3e40ffc Update README.md
* e27337b Update README.md
* 7216ded Initial commit

这就需要用 git push 提交merge更改。再次查看log,远程分支也merge了。并且github上也可看到merge结果(feature/change-passwork的commit merge到master上了)。

1
2
3
4
5
6
7
8
9
10
11
12
13
(master)$ git push
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/PurpleMStone/Mars.git
125409a..244f7a7 master -> master

(master)$ git log --oneline --all --graph
* 244f7a7 (HEAD -> master, origin/master, origin/feature/change-passwork, origin/HEAD, feature/change-passwork) Update file1
* 125409a (tag: v1.0) add file2.txt
* ec68ae1 Add file1.txt
* 4085604 Update README.md
* 3e40ffc Update README.md
* e27337b Update README.md
* 7216ded Initial commit

4. 我来删除分支

既然 merge 了,分支留着也没用了,咱就把这分支删了吧,先删 remote branch,再删 local branch:

1
2
3
4
5
6
7
8
9
10
(master)$ git push -d origin feature/change-passwork
To https://github.com/PurpleMStone/Mars.git
- [deleted] feature/change-passwork

(master)$ git branch
feature/change-passwork
* master

(master)$ git branch -d feature/change-passwork
Deleted branch feature/change-passwork (was 244f7a7).

看看是不是真的删了:

1
2
3
4
5
6
(master)$ git branch
* master

(master)$ git branch -r
origin/HEAD -> origin/master
origin/master

NICE.

5. 另一个contributor的同步

git pull 获取GitHub变化:

1
2
3
4
5
6
7
Amy/Mars (master)$ git pull
From https://github.com/PurpleMStone/Mars
125409a..244f7a7 master -> origin/master
Updating 125409a..244f7a7
Fast-forward
file1.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

本地还有这个branch,删掉:

1
2
3
4
5
6
Amy/Mars (master)$ git branch
feature/change-passwork
* master

Amy/Mars (master)$ git branch -d feature/change-passwork
Deleted branch feature/change-passwork (was 244f7a7).

会发现origin还有这个branch:

1
2
3
4
Amy/Mars (master)$ git branch -r
origin/HEAD -> origin/master
origin/feature/change-passwork
origin/master

可以这样移除(可以刷新本地仓库与远程仓库,保持这些改动的同步):

1
2
3
4
5
6
7
8
Amy/Mars (master)$ git remote prune origin
Pruning origin
URL: https://github.com/PurpleMStone/Mars.git
* [pruned] origin/feature/change-passwork

Amy/Mars (master)$ git branch -r
origin/HEAD -> origin/master
origin/master