Gitub

克隆github仓库:执行 git clone命令后我们会默认处于 master 分支下,同时系统会自动将 origin 设置成该远程仓库的标识符。

将本地仓库推送至github:在github中新建一个仓库。创建时请不要勾选 Initialize this repository with a README 选项(如果勾选,则远程将建立一个分支,与本地仓库冲突)。

git push -u origin master:-u参数可以在推送的同时,将 origin 仓库的 master 分支设置为本地仓库当前分支的 upstream(上游)。添加了这个参数,将来运行 git pull命令从远程仓库获取内容时,本地仓库的这个分支就可以直接从 origin 的 master 分支获取内容,省去了另外添加参数的麻烦。

git checkout -b feature-D origin/feature-D:获取远程的 feature-D 分支。此命令会将远程设为上游,直接 git push即可。

git pull——获取最新的远程仓库分支

团队合作 Pull Request

Pull Request 是自己修改源代 码后,请求对方仓库采纳该修改时采取的一种行为。

虽然可以代码完成后再发送 Pull Request,但在实际开发过程中,这样做很可能导致一个功能在完成后才收到设计或实现方面的指正,从而使代码需要大幅更改或重新实现。 在 GitHub 上,我们可以尽早创建 Pull Request,从审查中获得反馈, 让大家在设计与实现方面思路一致,借此逐渐提高代码质量。这个方法在团队开发大型项目时尤其有效,已将 GitHub 运用到实际开发中的团队请务必试一试。

即便某个功能尚在开发之中,只要在 Pull Request 中附带一段简单代码让大家有个大体印象,就能获取不少反馈。 如果在 Pull Request 中再加入直观易懂的 Tasklist,就能很清楚反映出哪些功能已经实现,将来要做哪些工作。这不但能加快审查者的工作效率,还能作为自己的备忘录使用。

向发送过 Pull Request 的分支添加提交时,该提交会自动添加至已发送的 Pull Request 中。 这一方法要求尽早发送 Pull Request,越早效果越明显。另外还有一件事要记住,就是千万不要在 Pull Request 中添加无关的修改。处理与主题无关的作业请另外创建分支,不然会让原本清晰的讨论变得一团糟。

前期准备

  1. fork创建自己的仓库
  2. 克隆到本地。’git clone git@…..’。
  3. 创建新分支,在新分支中作业。发送pull request时,一般都是发送特性分支,这样,pull request就有了更明确的特性(主题)。让对方了解自己修改代码的意图,有助于提高代码审查效率。
  4. 创建远程分支。

Fork 工作流

当前 Git 的主流开发模式都会使用特性分支。各位请养成创建特性分支后再修改代码的好习惯。在 GitHub 上发送 Pull Request 时,一般都是发送特性分支。这样一来,Pull Request 就拥有了更明确的特性(主题)。让对方了解自己修改代码的意图,有助于提高代码审查的效率。

在无法给不特定的多数人赋予提交权限的公开软件开发中,Fork流程能够防止仓库收到计划之外的提交。 然而在公司企业的开发中,开发者每天都要见面,要经常互相发送 Pull Request,这种流程就显得有些繁琐了。

GitHub Flow——以部署为中心的开发模式

由 20 人左右的团队使用这个流程来共同开发一个项目,基本不会出现什么大问题。

整个开发流程大致如下。

  1. 令 master 分支时常保持可以部署的状态
  2. 进行新的作业时要从 master 分支创建新分支,新分支名称要具有描述性
  3. 在第二步新建的本地仓库分支中进行提交
  4. 在 GitHub 端仓库创建同名分支,定期 push
  5. 需要帮助或反馈时创建 Pull Request,以 Pull Request 进行交流
  6. 让其他开发者进行审查,确认作业完成后与 master 分支合并
  7. 与 master 分支合并后立刻部署

要点:

  • master分支时常保持可以部署的状态,保证代码无Bug
  • 创建新分支前先pull,在最新代码上修改
  • 新分支名要具有描述性,其他开发者可以清除了解该分支正在进行什么工作。
  • 一个功能分成几个小 pull request:防止过大代码量难以阅读
  • 一个pull request多次commit:让每个差别有更清晰的定义
  • 修改代码时要注意不要进行与该分支内容无关的修改
  • 定期push,让其他人能够看到自己的代码,创建交流的机会。以尽早创建 Pull Request 让其他开发者进行审查,一边 听取反馈一边编写代码,没必要等到与 master 分支合并时再进行。

Git Flow——以发布为中心的开发模式

  1. 从开发版的分支(develop)创建工作分支(feature branches),进 行功能的实现或修正
  2. 工作分支(feature branches)的修改结束后,与开发版的分支 (develop)进行合并
  3. 重复上述❶和❷,不断实现功能直至可以发布
  4. 创建用于发布的分支(release branches),处理发布的各项工作
  5. 发布工作完成后与 master 分支合并,打上版本标签(Tag)进行发布
  6. 如果发布的软件出现 BUG,以打了标签的版本为基础进行修正 (hotfixes)

推荐工具git-flow来辅助开发。

由于在实际开发现场需要多人分工合作,这一开发流程往往会变得很复杂。建议各位把开发流程图放大并张贴在墙壁上,这样能够有效帮助团队成员理解流程内容。

GIT

初始设置

  • 设置使用 Git 时的姓名和邮箱地址。
1
2
3
名字请用英文输入。命令会应用到“~/.gitconfig”中,也可以直接编辑这个文件。
$ git config --global user.name "Firstname Lastname"
$ git config --global user.email "your_email@example.com"

这里设置的姓名和邮箱地址会用在 Git 的提交日志中。由于在 GitHub 上公开仓库时,这里的姓名和邮箱地址也会随着提交日志一同被公开,所以请不要使用不便公开的隐私信息。

设置SSH Key
$ ssh-keygen -t rsa -C "your_email@example.com"

id_rsa 文件是私有密钥,id_rsa.pub 是公开密钥。

在 GitHub 中添加公开密钥,今后就可以用私有密钥进行认证了。

设置后,通过命令 ssh -T git@github.com来测试与github的连接

文件管理

1
2
git clone git@github.com:......gitz
git push //推送至远程仓库

git init:在当前文件夹下创建仓库,会生成.git文件,其中记录了该仓库有关数据
git status :查看仓库状态,包括未跟踪的文件,修改但未提交的文件。

git add filename——将文件加入暂存区

  • git add -A:添加当前目录中的所有文件
  • git add .:添加当前目录中所有文件更改
  • git add -p:选择要添加的更改(可以Y或N完成所有的更改)

git commit -m "comment" —-提交。如果没有参数-m,就会启动编辑器。将提交信息留空并直接关闭编辑器,会中止提止。:

在编辑器中记录提交信息的格式为

第一行:用一行文字简述提交的更改内容
第二行:空行
第三行以后:记述更改的原因和详细内容。

  • git commit -am等于执行 git add命令 再执行 git commit命令

git log:查看谁在什么时候进行了提交或合并,以及操作前后的差别。如果嫌输出信息太多,可以试试加上 --pretty=oneline参数,git log --pretty=short

git diff :查看工作树和暂存区的差别。

git diff HEAD:查看工作树和最新提交的差别。好习惯:在执行 git commit命令之前先执行 git diff HEAD命令,查看本次提交与上次提交之间有什么差别,等 确认完毕后再进行提交。这里的 HEAD 是指向当前分支中最新一次提交 的指针。

忽略文件:

如果将其他的git仓库添加到暂存区中,会出现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint:
hint: git submodule add <url> vue-element-admin
hint:
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint:
hint: git rm --cached vue-element-admin
hint:
hint: See "git help submodule" for more information.

可将该git仓库路径添加到.gitignore文件中。一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为 .gitignore的文件,列出要忽略的文件的模式。

1
2
3
$ cat .gitignore
*.[oa]
*~

第一行告诉 Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有名字以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存
副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就为你的新仓库设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。
文件 .gitignore 的格式规范如下:
• 所有空行或者以 # 开头的行都会被 Git 忽略。
• 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
• 匹配模式可以以(/)开头防止递归。
• 匹配模式可以以(/)结尾指定目录。
• 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c); 问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(**)表示匹配任意中间目录,比如 a/**/z 可以匹配 a/z 、 a/b/z 或 a/b/c/z 等。

1
2
3
4
5
6
7
8
9
10
11
12
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf

GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在https://github.com/github/gitignore 找到它。

在最简单的情况下,一个仓库可能只根目录下有一个 .gitignore 文件,它递归地应用到整个仓库中。 然而,子目录下也可以有额外的 .gitignore 文件。子目录中的 .gitignore文件中的规则只作用于它所在的目录中。 (Linux 内核的源码库拥有 206 个 .gitignore 文
件。)
多个 .gitignore 文件的具体细节超出了本书的范围,更多详情见 man gitignore 。

分支管理

查看分支:git branch。显示的结果中, *号标记的是前所在的位置。 -a 参数可以同时显示本地和远程仓库的信息。可用 git log --graph以图表形式查看分支。

创建分支:git branch A。会在当前所提交的对象上创建一个新指针,这样,当前对象有两个指针(比如master和A)指向它,git通过特殊指针Head来辨别目前在哪一个分支上(可以将Head想象为当前所在分支的别名)。

切换分支:git checkout A或者 git switch A

切换至上一个分支:git checkout -

在切换分支之前,留意工作目录和暂存区中还未被提交的修改,它可能会和即将迁出的分支产生冲突从而阻止git切换到该分支。最好的方法是在迁出前保持一个干净的状态。见”贮藏与清理“一节。现在,我们假设你已经把你的修改全部提交了。

创建+切换分支:git checkout -b A或者 git switch -c <name>

删除分支:git branch -d <name>

合并分支A到当前分支:git merge A。–no-ff参数启动编辑器,用于录入合并提交的信息。

在A上所做的工作并没有包含在其他分支如B中。如果B想要拉取A所作的修改,可以使用git merge master来和master分支合并,或者也可以等到B分支完成后,再将其合并到master分支。

Rebase rebase操作可以把本地未push的分叉提交历史整理成直线; 现在假设我们在本地上提交了两次。用`(HEAD -> master)`和`(origin/master)`标识出当前分支的HEAD和远程origin的位置分别是`582d922 add author`和`d1be385 init hello`
1
2
3
4
$ git log --graph --pretty=oneline --abbrev-commit
* 582d922 (HEAD -> master) add author
* 8875536 add comment
* d1be385 (origin/master) init hello

然后我们尝试推送本地分支,如果失败,说明有人先于我们推送了远程分支。按照经验,先pull一下(pull会自动merge),最后结果是提交历史分叉了。

1
2
3
4
5
6
7
8
$ git log --graph --pretty=oneline --abbrev-commit
* e0ea545 (HEAD -> master) Merge branch 'master' of github.com:michaelliao/learngit
|\
| * f005ed4 (origin/master) set exit=1
* | 582d922 add author
* | 8875536 add comment
|/
* d1be385 init hello

Rebase命令可以让提交历史变成一条干净的直线(https://www.liaoxuefeng.com/wiki/896043488029600/1216289527823648 )。Git的文档特别强调需要注意的使用情形和原则: 只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作。 因为rebase会改变提交历史记录,这会影响到别人使用这一远程仓库。

版本回退

  1. 查看提交历史,用 git log命令看历史。回退,用 git reset --hard HEAD^命令:用 HEAD表示当前版本,上一个版本就是 HEAD^,上上一个版本就是 HEAD^^,当然往上100个版本写100个 ^比较容易数不过来,所以写成 HEAD~100
  2. git log 命令只能查看以当前状态为终点的历史日志。使用 git reflog命令可查看当前仓库的操作日志。在日志中找出 回溯历史之前的哈希值,通过 git reset –hard命令恢复到回溯历 史前的状态。历史之间穿梭:git reset –-hard (commit id)。版本号没必要写全,前几位就可以了,Git会自动去找。

穿梭前,用 git log可以查看提交历史,要重返未来,用 git reflog查看命令历史

git rebase -i HEAD~2——将这个修改包含到前一个提交之中,压缩成一 个历史记录。

撤销修改

git commit -amend: 重新提交,将替换上一次的提交。不会让“啊,忘了添加一个文件”或者“小补修,修正笔误”这样的提交信息弄乱你的仓库历史。

取消暂存的文件和撤销对文件的修改

使用git status 命令来查看当前的状态,它提示了可用命令

1
2
3
4
5
$ git status
On branch master
Changes to be committed: //暂存的文件:
(use "git restore --staged <file>..." to unstage)
deleted: pom.xml

针对“Changes to be committed”,可以使用”git restore –staged <file>…” 来取消暂存:

1
2
3
4
5
6
7
8
9
$ git restore --staged *
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: pom.xml

no changes added to commit (use "git add" and/or "git commit -a")

命令 “git restore <file>…” 会将文件还原成最近提交时的样子 ,丢弃工作区所有修改。该命令不会删除还未tracked的新建文件。

git clean : Remove untracked files from the working tree。

usage : git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [–] <paths>.

如果你仍然想保留对那个文件做出的修改,但是现在仍然需要撤消,我们将会在 Git 分支 介绍保存进度与分支,这通常是更好的做法。
记住,在 Git 中任何 已提交 的东西几乎总是可以恢复的。 甚至那些被删除的分支中的提交或使用 –amend 选项覆盖的提交也可以恢复 (阅读 数据恢复 了解数据恢复)。 然而,任何你未提交的东西丢失后很可能再也找不到了。

git: undo all working dir changes including new files | stackoverflow

参考:

  1. 廖雪峰-git教程
  2. GitHub入门与实践
  3. A successful Git branching model » nvie.com