Fork me on GitHub

学习Git(二)基本操作

这是崔斯特的第三十七篇原创文章

继续补基础 (๑• . •๑)

Git 基础操作

1. 创建版本库

什么是版本库呢?版本库又名仓库,英文名 repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被 Git 管理起来,每个文件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

所以,创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录:

1
2
3
4
$ mkdir learngit
$ cd learngit
$ pwd
/Users/learngit

pwd命令用于显示当前目录。

如果你使用 Windows 系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文。

第二步,通过git init命令把这个目录变成 Git 可以管理的仓库:

1
2
$ git init
Initialized empty Git repository in /Users/learngit/.git/

瞬间 Git 就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository)

ls -ah命令就可以看见当前目录下多了一个.git的目录,这个目录是 Git 来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把 Git 仓库给破坏了。

一定要放到 learngit 目录下或子目录下

1
$ git status # 随时用git status 查看文件状态

一个文件放到 Git 仓库只需要两步。

  1. 用命令git add告诉 Git,把文件添加到仓库:
1
$ git add . # 把所有文件都添加到仓库

执行上面的命令,没有任何显示,这就对了,Unix 的哲学是“没有消息就是好消息”,说明添加成功。(因为没有添加任何文件,如果添加结果不同,可以使用 git status 随时查看 Git 状态)

  1. 用命令git commit告诉 Git,把文件提交到仓库:
1
2
3
4
$ git commit abc/aaa.py -m"chore:wrote a readme file"
[master (root-commit) cb926e7] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 aaa.py

commit 必须遵循commit规范

1
2
3
4
5
6
7
8
9
**git commit规范**
- feat:新功能(feature)
- fix:修补bug
- docs:文档(documentation)
- style: 格式(不影响代码运行的变动)
- refactor:重构(即不是新增功能,也不是修改bug的代码变动)
- test:增加测试
- chore:构建过程或辅助工具的变动

2. 新机器配置 Git

  1. 创建 SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到第2步。如果没有,打开 Shell(Windows 下打开 Git Bash),创建 SSH Key:
1
$ ssh-keygen -t rsa -C "你的github邮箱"

把邮件地址换成你自己的邮件地址,一路回车,使用默认值即可,无需设置密码。

如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有 id_rsa 和 id_rsa.pub 两个文件,这两个就是 SSH Key 的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。

  1. 登陆 GitHub,打开“Account settings”,“SSH Keys”页面:

然后,点“Add SSH Key”,填上任意 Title,在 Key 文本框里粘贴id_rsa.pub文件的内容:

img

点“Add Key”,你就应该看到已经添加的 Key

img

当然,GitHub 允许你添加多个 Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的 Key 都添加到 GitHub,就可以在每台电脑上往 GitHub 推送了。

3. 关联远程库

  1. 如果公司已创建该项目的远程库,本地还没有,clone 该项目地址: clone with ssh

    1
    $ git clone git@github.com:xxxx/xxx.git

SSH 警告

当你第一次使用 Git 的 clone 或者 push 命令连接 GitHub 时,会得到一个警告:

1
2
3
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?

这是因为 Git 使用 SSH 连接,而 SSH 连接在第一次验证 GitHub 服务器的 Key 时,需要你确认 GitHub 的 Key 的指纹信息是否真的来自 GitHub 的服务器,输入 yes 回车即可。

Git 会输出一个警告,告诉你已经把 GitHub 的 Key 添加到本机的一个信任列表里了:

1
Warning: Permanently added 'github.com' (RSA) to the list of known hosts.

这个警告只会出现一次,后面的操作就不会有任何警告了。

  1. 如果已经在本地创建了一个 Git 仓库后,公司也已在 GitHub 创建一个 Git 仓库,

    • 实现让这两个仓库进行远程同步
    1
    $ git remote add origin git@github.com:xxxx/xxxx.git
    • 下一步,就可以把本地库的所有内容推送到远程库上

      1
      $ git push -u origin master

      把本地库的内容推送到远程,用git push命令,实际上是把当前分支 master 推送到远程。

      由于远程库是空的,我们第一次推送 master 分支时,加上了-u参数,Git 不但会把本地的 master 分支内容推送的远程新的 master 分支,还会把本地的 master 分支和远程的 master 分支关联起来,在以后的推送或者拉取时就可以简化命令。

      推送成功后,可以立刻在 GitHub 页面中看到远程库的内容已经和本地一模一样

      从现在起,只要本地作了提交,就可以通过命令:

      $ git push origin master 把本地master分支的最新修改推送至GitHub

  2. 一般我们在develop分支开发

    1. 如果github上没有develop分支
    • 首先,我们在本地创建 develop 分支,然后切换到 develop 分支:

      1
      2
      $ git checkout -b develop
      Switched to a new branch 'develop'

      git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

      1
      2
      3
      $ git branch develop
      $ git checkout develop
      Switched to branch 'develop'

      然后,用git branch命令查看当前分支:

      1
      2
      3
      $ git branch
      * develop
      master

      git branch命令会列出所有分支,当前分支前面会标一个*

    • 发布develop分支

      发布dev分支指的是同步develop分支的代码到远程服务器

      1
      2
      git push origin develop:develop # 这样远程仓库也有一个develop分支了 或者
      git push origin develop # 这两种应该都可以
    1. 如果github已经有master分支和develop分支

      在本地

      git checkout -b develop 新建并切换到本地develop分支

      git pull origin develop 本地develop分支与远程develop分支相关联


Git 总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
git add . # 添加所有改动的文件到仓库
git commit 文件路径 -m'fix:修复xx bug'
# github上已经有master分支 和dev分支在本地
git checkout -b dev # 创建+切换分支dev
git pull origin dev # 本地分支与远程分支相关联dev
# github无dev分支,在本地新建分支并推送到远程
git checkout -b dev
git push origin dev:dev # 这样远程仓库中也就创建了一个dev分支
git branch # 查看本地有多少分支
git branch 分支名字 # 创建分支
git checkout dev # 切换到dev分支进行开发
git push # 提交到远程
git branch -d dev # 删除本地dev分支
git merge dev # 合并dev到当前分支(master)

git remote 深入研究

git-remote - Manage set of tracked repositories

1
2
3
4
5
6
7
8
9
10
11
12
13
git remote [-v | --verbose]
git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>] <name> <url>
git remote rename <old> <new>
git remote remove <name>
git remote set-head <name> (-a | --auto | -d | --delete | <branch>)
git remote set-branches [--add] <name> <branch>…​
git remote get-url [--push] [--all] <name>
git remote set-url [--push] <name> <newurl> [<oldurl>]
git remote set-url --add [--push] <name> <newurl>
git remote set-url --delete [--push] <name> <url>
git remote [-v | --verbose] show [-n] <name>…​
git remote prune [-n | --dry-run] <name>…​
git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)…​]

查看远程仓库

如果想查看你已经配置的远程仓库服务器,可以运行 git remote 命令。 它会列出你指定的每一个远程服务器的简写。 如果你已经克隆了自己的仓库,那么至少应该能看到 origin - 这是 Git 给你克隆的仓库服务器的默认名字:

1
2
3
4
5
6
7
8
9
10
$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin

你也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。

1
2
3
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)

如果你的远程仓库不止一个,该命令会将它们全部列出。 例如,与几个协作者合作的,拥有多个远程仓库的仓库看起来像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
$ cd grit
$ git remote -v
bakkdoor https://github.com/bakkdoor/grit (fetch)
bakkdoor https://github.com/bakkdoor/grit (push)
cho45 https://github.com/cho45/grit (fetch)
cho45 https://github.com/cho45/grit (push)
defunkt https://github.com/defunkt/grit (fetch)
defunkt https://github.com/defunkt/grit (push)
koke git://github.com/koke/grit.git (fetch)
koke git://github.com/koke/grit.git (push)
origin git@github.com:mojombo/grit.git (fetch)
origin git@github.com:mojombo/grit.git (push)

这样我们可以轻松拉取其中任何一个用户的贡献。 此外,我们大概还会有某些远程仓库的推送权限,虽然我们目前还不会在此介绍。

注意这些远程仓库使用了不同的协议;我们将会在 在服务器上搭建 Git 中了解关于它们的更多信息。

添加远程仓库

运行 git remote add <shortname> <url> 添加一个新的远程 Git 仓库,同时指定一个你可以轻松引用的简写:

1
2
3
4
5
6
7
8
$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)

现在你可以在命令行中使用字符串 pb 来代替整个 URL。 例如,如果你想拉取 Paul 的仓库中有但你没有的信息,可以运行 git fetch pb

1
2
3
4
5
6
7
8
$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
* [new branch] master -> pb/master
* [new branch] ticgit -> pb/ticgit

现在 Paulmaster 分支可以在本地通过 pb/master 访问到 - 你可以将它合并到自己的某个分支中,或者如果你想要查看它的话,可以检出一个指向该点的本地分支。

##从远程仓库中抓取与拉取
就如刚才所见,从远程仓库中获得数据,可以执行:

$ git fetch [remote-name]
这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。

如果你使用 clone 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 “origin” 为简写。 所以,git fetch origin 会抓取克隆(或上一次抓取)后新推送的所有工作。 必须注意 git fetch 命令会将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。

如果你有一个分支设置为跟踪一个远程分支,可以使用 git pull 命令来自动的抓取然后合并远程分支到当前分支。 这对你来说可能是一个更简单或更舒服的工作流程;默认情况下,git clone 命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支(或不管是什么名字的默认分支)。 运行 git pull 通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。

推送到远程仓库

当你想分享你的项目时,必须将其推送到上游。 这个命令很简单:git push [remote-name] [branch-name]。 当你想要将 master 分支推送到 origin 服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字),那么运行这个命令就可以将你所做的备份到服务器:

$ git push origin master
只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。 当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。

查看远程仓库

如果想要查看某一个远程仓库的更多信息,可以使用 git remote show [remote-name] 命令。 如果想以一个特定的缩写名运行这个命令,例如 origin,会得到像下面类似的信息:

1
2
3
4
5
6
7
8
9
10
11
12
$ git remote show origin
* remote origin
Fetch URL: https://github.com/schacon/ticgit
Push URL: https://github.com/schacon/ticgit
HEAD branch: master
Remote branches:
master tracked
dev-branch tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)

它同样会列出远程仓库的 URL 与跟踪分支的信息。 这些信息非常有用,它告诉你正处于 master 分支,并且如果运行 git pull,就会抓取所有的远程引用,然后将远程 master 分支合并到本地 master 分支。 它也会列出拉取到的所有远程引用。

这是一个经常遇到的简单例子。 如果你是 Git 的重度使用者,那么还可以通过 git remote show 看到更多的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ git remote show origin
* remote origin
URL: https://github.com/my-org/complex-project
Fetch URL: https://github.com/my-org/complex-project
Push URL: https://github.com/my-org/complex-project
HEAD branch: master
Remote branches:
master tracked
dev-branch tracked
markdown-strip tracked
issue-43 new (next fetch will store in remotes/origin)
issue-45 new (next fetch will store in remotes/origin)
refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove)
Local branches configured for 'git pull':
dev-branch merges with remote dev-branch
master merges with remote master
Local refs configured for 'git push':
dev-branch pushes to dev-branch (up to date)
markdown-strip pushes to markdown-strip (up to date)
master pushes to master (up to date)

这个命令列出了当你在特定的分支上执行 git push 会自动地推送到哪一个远程分支。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了,还有当你执行 git pull 时哪些分支会自动合并。

远程仓库的移除与重命名

如果想要重命名引用的名字可以运行 git remote rename 去修改一个远程仓库的简写名。 例如,想要将 pb 重命名为 paul,可以用 git remote rename 这样做:

1
2
3
4
$ git remote rename pb paul
$ git remote
origin
paul

值得注意的是这同样也会修改你的远程分支名字。 那些过去引用 pb/master 的现在会引用 paul/master

如果因为一些原因想要移除一个远程仓库 - 你已经从服务器上搬走了或不再想使用某一个特定的镜像了,又或者某一个贡献者不再贡献了 - 可以使用 git remote rm

1
2
3
$ git remote rm paul
$ git remote
origin

回顾:学习Git(一)起步