Git 版本管理、Github

摘要:IDEA 集成开发环境、Linux 开发工具、Git 版本控制、项目管理/构建工具等。


目录

[TOC]

Git 代码管理/版本控制

认识Git

版本控制的主要功能有备份、回滚、分支管理。

TortoiseSVN 与 Git 区别
  1. SVN:是集中式的版本控制系统,中央服务器,简单; CVS、Subversion等
    1. 保存一组基本文件和每个文件随时间逐步累积的差异。
    2. 增量多的话,得到最终文件耗时长。
    3. 缺点是必须联网才能工作;
    4. 易发生单点故障;严重依赖中央服务器,安全性低。
  2. Git:是分布式的版本控制系统;
    1. 用直接记录快照的方式,而非差异比较。对当前的全部文件制作一个快照并保存其索引。 跟踪并管理的是修改,而非文件。
    2. 为了高效,不再重新存储没有修改的文件,只保留一个链接指向之前存储的文件。
    3. 每个客户端都有代码仓库的完整镜像,不用联网
    4. 多个镜像安全性高。实际应用时也有一台充当“中央服务器”的电脑,但仅是用来方便“交换”大家的修改,没有也可以。
    5. 强大的分支管理。
    6. 开源。
Git的三个区域

三种状态:

  1. 已修改(modified):表示已修改了文件,但还没添加到暂存区。
    1. 手动把文件恢复到上一个版本的状态;
    2. git checkout -- readme.txt 撤销readme.txt文件在工作区的全部修改
  2. 已暂存(staged):表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
    • git reset HEAD readme.txt 可撤销暂存区的修改,重新放回工作区。
  3. 已提交(committed):数据已安全的保存在本地仓库中。
    1. 未把本地版本库推送到远程版本库:
    2. 已把错误修改提交推送到远程版本库:

三个工作区域/工作流:

  1. 工作目录(Working Directory):持有实际文件;用git add把文件修改(快照)添加到暂存区;
  2. 暂存区(Index / Staging Area):暂存文件修改,等待commit;用git commit提交更改到仓库,实际上就是一次性提交暂存区的所有修改(快照)到当前分支。与SVN的区别。
  3. Git 仓库(.git directory、Repository):永久记录文件或目录状态,存储着内容修改的历史提交记录。分布式开发 + 集中式管理。
    1. 远程仓库、origin 原始仓库、源仓库: 配有专用的服务器,为了多人共享而建立的数据库。汇总参与该项目的各个开发者的代码;存放趋于稳定和可发布的代码。只有项目管理者能对其进行较高权限的操作。
    2. 本地仓库:为了方便用户个人使用,在自己的机器上配置的数据库。

git-repo

基本的 Git 工作流程如下:

img

Git 参考
  1. 图解Git
  2. git - 简明指南
  3. 廖雪峰–史上最浅显易懂的Git教程
  4. 使用git和github管理自己的项目—基础操作学习
  5. Git Cheat Sheet
  6. Git 学习 可视化提交树
  7. Git入门指南使用资料汇总及文章推荐

Git 命令

Git 常用命令思维导图

img

HEAD 是一个对当前检出记录的符号引用,指向正在其基础上进行工作的提交记录。

实际上,通常情况下HEAD指向分支名,分支名指向当前分支上最近一次提交记录。

分离 HEAD 就是让其指向某个具体的提交记录而不是分支名。

1
2
3
#在命令执行前的状态如下所示:HEAD -> main -> C1
git checkout C1
#变成了:HEAD -> C1

相对引用:用 ^~<n> 将HEAD向上移动 1 个、n个提交记录,可代替

1
2
3
git checkout <commit id>
git checkout main^
git checkout HEAD~1 #HEAD~1:历史版本库最新提交的第一父提交

Repository 仓库

  • git clone <server url> [directory name]:克隆远程仓库到本地目录,默认为./。<server url>https://github.com/Snailclimb/test.gitusername@host:/path/to/repository.git。Git支持多种协议,默认的git://使用ssh,https速度慢,每次推送都必须输入口令,但某些公司内部只开放http端口。

  • git fetch

  • git init:在当前目录中初始化仓库,创建一个名为 .git 的子目录(Git用来跟踪管理版本库的)。

  • git pull:拉取远程仓库;获取(fetch)并合并(merge)远程改动,覆盖本地工作目录。Git会自动合并已有的变更点;但如果远程数据库和本地数据库的同一个地方都发生了修改,无法自动判断要选用哪一个修改,就会发生冲突,需要手动修正冲突。

    • --progress

      1
        pull —progress origin: Fast-forward
      
  • git push origin [branch name]:将分支在本地仓库的提交历史推送/共享到远程仓库,二者保持同步。push前应先合并(pull),否则push将被拒绝。

    • --force
    • -u:把本地的master分支内容推送到远程新的master分支,并关联起来;
  • git remote

    • -v:查看远程库信息
    • add origin <server>:关联本地仓库和远程仓库,并指定远程仓库别名,origin是默认习惯命名,如https://github.com/Snailclimb/test.git>,可用origin指代远程仓库地址
    • rename origin ori
    • rm origin:删除远程库,解除了本地和远程的绑定关系,并不是物理上删除了远程库。
1
2
3
# 丢弃在本地的所有改动与提交:从服务器获取最新的版本历史,并将本地主分支指向它
git fetch origin
git reset --hard origin/master

work on the current change

  • git add <filename>:添加文件到暂存区;修改文件来手动合并冲突后,标记为合并成功
    • git add -i:交互式添加文件到暂存区
  • describe:显示离当前提交最近的标签。
  • git mv README.md README:对文件重命名,相当于mv README.md READMEgit rm README.mdgit add README 三条命令的集合
  • git restore:把文件从缓存区撤销,回到未被追踪的状态。
  • rm test.txt:删除文件后,工作区和版本库不一致。先手动删除文件,然后使用git rm <file>git add<file>效果是一样的。
    • git status 显示哪些文件被删除了。
    • 从版本库中删除该文件:git rm <filename> ,从暂存区域移除,然后提交;
    • 错误删除后恢复:git checkout -- test.txt,用版本库中的最新版本,替换工作区的。

state

  • git diff [<source commit id>] <target commit id> [--] [<path>…]:显示提交间的差异
    • <source commit id>:默认为工作目录,可为branch名等;
      • --cached表示Index时,显示暂存区与HEAD的差异
    • <target commit id>:默认为暂存区,指定版本库(默认为HEAD)

img

  • git grep
  • git log --<option> :列出所有提交
    • -p --patch:按 补丁 的格式 显示每次提交引入的差异
    • --stat:显示每次提交的文件修改统计信息。
      • --shortstat:只显示 –stat 中最后的行数修改添加移除统计。
    • --name-status:显示新增、修改、删除的文件清单。
      • --name-only:仅在提交信息后显示已修改的文件清单。
    • --pretty:使用其他格式显示历史提交信息,可选 oneline、short、full、fuller 和 format。
    • --abbrev-commit:短字符 commit-id,仅显示 SHA-1 校验和所有 40 个字符中的前几个字符。
      • --oneline:–pretty=oneline –abbrev-commit 合用的简写,压缩后的每一条提交记录只占一行的输出。
    • --graph:在日志旁以 ASCII 图形显示分支与合并历史。
    • --relative-date:使用较短的相对时间而不是完整格式显示日期(如“2 weeks ago”)。常用选项:
      • -<n> :只显示最近的n条提交。
      • —since—after:指定时间后的提交,可取2.weeks、2008-01-15
      • —until—before:指定时间前的提交。
      • —author:作者匹配指定字符串。
      • —committer:提交者匹配指定字符串。
      • —grep:搜索提交说明中的关键字。
      • -S:添加或删除内容匹配指定字符串的提交。

      • [—] <path>:指定某些文件或目录的路径。
      • —no-merges :隐藏合并提交
  • git show:用于显示各种类型的对象。
  • git stash:可把当前工作现场“储藏”起来,等以后恢复现场后继续工作。查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心的创建分支来修复bug了。
  • git status:查看当前文件状态

基本操作

branch
  • git branch <branch name>:默认创建分支,基于这个提交及它所有的父提交进行新工作;分支是用来将特性开发绝缘开来的。
  • git branch:查看所有分支,,当前分支前面会标一个*号。
    • -d <branch name>:删除分支;即删除分支指针。
    • -f main HEAD~3:让分支指向另一个提交,将分支强制移动到指定位置;将 main 分支强制指向 HEAD 的第 3 级父提交。
cherry-pick
  • git cherry-pick:”复制”一个提交节点并在当前分支做一次完全一样的新提交。

img

commit
  • git commit :给暂存区生成快照,并提交。每完成一个功能就提交一次,不要累计代码。

    1. 提交时,用暂存区的文件创建一个新提交,并把此时的节点(HEAD)设为父节点,把当前分支(顺移)指向新的提交节点。

      img

    2. 若当前分支stable是某次提交的祖父节点,提交后生成了1800bstable分支就不再是main分支的祖父节点。此时,merge是必须的。

      img

    3. HEAD处于分离状态(不依附于任一分支)时,commit不会更新任何已命名的分支。可认为是在更新一个匿名分支。一旦切换到别的分支(如main),那么这个提交节点再也不会被引用到,会被丢弃掉。想保存这个状态,可用命令git checkout -b <name>来创建一个新分支。

      • 如图:

        img img

      • -m "备注"

      • -a/add:跳过暂存区直接提交代码到仓库;自动把所有已跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤。

      • --amend:更改一次提交,用与当前提交相同的父节点进行一次新提交,旧的提交会被取消。添加漏掉的文件或修改提交信息,尝试重新提交.

      img

checkout
  • git checkout <branch name>:切换分支,即HEAD标识会移动到指定分支,暂存区域和工作目录中的内容会和HEAD对应的提交节点一致。新提交节点(a47c3)中的所有文件都会被复制(到暂存区域和工作目录中);只存在于老的提交节点(ed489)中的文件会被删除;不属于上述两者的文件会被忽略,不受影响。
    • -b <new branch> <source branch> :在source 分支(默认为当前分支)上创建分支,并切换过去。
    • git checkout <>:如果既没指定文件名,也没指定分支名,而是一个标签、远程分支、SHA-1值或是像main~3类似的东西,就得到一个匿名分支,称作detached HEAD(被分离的HEAD标识)。这样可方便地在历史版本间互相切换。

img

img

  • git checkout [HEAD] -- <filename>
    • 当给定某个文件名(或打开-p选项)时,用于将指定历史提交节点(如果没有指定,默认为暂存区域)中的文件,拷贝到工作目录,并加到暂存区域中。用来丢弃本地修改。
    • 文件自修改后还没放到暂存区,用当前历史提交节点覆盖工作目录;回到最近一次git commit到版本库后的状态;
    • 已添加到暂存区后,又作了修改,用暂存区覆盖工作目录;回到最近一次git add添加到暂存区后的状态。
    • 注意当前分支不会发生变化。已添加到暂存区的改动及新文件都不会受影响。

img

merge
  • git merge <branch name>:把不同分支合并起来。合并前,索引必须和当前提交相同,否则可能会有冲突。每次 merge 前先 pull 远程分支。

    • git status 检查冲突的文件;

      • 手动解决冲突后,再add、commit。
    • 如果另一个分支是当前提交的祖父节点,那么什么也不做。

    • git merge main如果当前提交是另一个分支的祖父节点,就导致fast-forward合并。指向只是简单的移动,并生成一个新的提交。

    • git merge other否则就是一次真正的合并。默认把当前提交(ed489 )和另一提交(33104)及他们的共同祖父节点(b325c)进行一次三方合并。结果先保存当前目录和索引,然后和父节点(33104)一起做一次新提交。

      img

      img

    • --no-ff参数:表示不执行快进式(fast-forward、plain)合并,不在当前分支留有指定分支的演进过程。

      • 用普通模式合并,合并后的历史有分支,能看出来曾经做过合并。而fast forward 快进模式,直接把master指向dev的当前提交,所以合并速度非常快;但看不出来曾经做过合并,删除分支后,会丢掉分支信息。
      • 将feature分支(一组提交实现的整个功能)打包作为develop分支的一个commit节点合并进来。
      • 常用于对feature分支实现的整个功能进行回退、简化日志信息。

    img

rebase
  • git rebase main:合并分支。在当前分支(topic)上重演另一个分支(main)的历史,提交历史是线性的。 本质上是线性化的自动的cherry-pick。注意旧提交(169a6、2c33a)没有被引用,将被回收。

    • 如图:

      img

    • --onto:限制回滚范围。在main分支上重演当前分支从169a6以来的最近几个提交,即2c33a

    img

reflog
  • git reflog:查看命令历史,操作类型、commit id、注释。
reset
  • git reset --<mode> [<commit id>, 默认HEAD, origin/master] [file]:作用于索引,分支指向不变;撤销暂存区的修改,重新放回工作区,用指定提交(默认为HEAD)覆盖暂存区。“改写历史”,原来指向的提交记录就跟从来没有提交过一样。 对远程分支无效。?省略文件名表示回退所有。

    • -- filename:撤销最后一次git add files;相当于checkout file;更新索引。
    • --soft :作用于仓库,回退到指定版本commit前的状态?。如果还要提交,直接commit即可。索引和工作目录都不变。
    • --mixed:默认方式。
    • --hard: 作用于索引和工作目录。
    1
    2
    3
    4
    5
      #查找commit id
      git reflog
        
      #恢复到因reset回退的commit
      git reset --hard <commit id>
    

img

revert
  • git revert:新提交记录引入更改用来撤销某个提交。回退状态。
switch
  • git switch <branch name>:切换分支
    • -c dev:创建并切换到新的dev分支
tag
  • git tag <tag name> <commit id>:在指定提交上创建标签

    • -d:删除标签
    1
    2
    3
    4
    5
    6
      #一次性推送全部尚未推送到远程的本地标签
      git push origin —tags
        
      #标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除,然后从远程删除
      git tag -d v0.9
      git push origin :refs/tags/v0.9
    

其它 config等

  • gitk:内建的图形化 git
  • git config color.ui true:彩色的 git 输出
  • git config format.pretty oneline:显示历史记录时,每个提交的信息只显示一行
  • git config
    • --global参数,表示这台机器上所有的Git仓库都会用此配置;
    • --global user.email "you@example.com":配置邮件;
    • --global user.name "Your Name" 配置用户名,否则后面的commit、push到远程库都会失败。
  • git config
    • --global alias.br branch:配置别名
    • --global alias.ci commit
    • --global alias.co checkout
    • --global alias.st status

Git 分支管理策略

  1. 介绍一个成功的 Git 分支模型
  2. 使用 git 和 github 管理自己的项目—分支管理策略实战

策略:

  • origin/master 主分支: 用于正式发布、线上生产环境。用于存放经过完全测试、代码reivew,已经完全稳定、任何时刻用户可用的代码,应随时保持代码的清洁。分支版本的设立、master版本的merge,统一由管理员操作。发布后需打上 tag。

    • develop 开发分支:用于本地日常开发环境,用于开发者存放基本稳定代码、生成代码的最新隔夜版本(nightly)。

      • feature/topic 功能分支: 通常为即将发布或未来发布版开发新的功能。合并到develop。分支版本的merge,一般先在本地仓库的feature分支merge到本地仓库的develop分支,然后将develop分支push到服务器上。

        • 删除分支:develop分支测试完毕,合入master主分支后。
        • 不删除:开发周期长,与develop分支处于并行关系,自身有特定功能的feature分支。
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
          >>> git checkout develop
          # 回到develop分支
                    
          >>> git merge --no-ff feature-discuss
          # 把做好的功能合并到develop中
                    
          >>> git branch -d feature-discuss
          # 删除功能性分支
                    
          >>> git push origin develop
          # 把develop提交到自己的远程仓库中
        
      • feature/weixin_recharge 临时功能分支:按照功能点(而不是需求)命名, 用于开发新功能,预发布成功后删除。

      • release-1.2 预发布分支:用于线上测试环境,待发布版本的提测及细小修改、修复 bug,严禁增加大的新features。实际开发中用的较少。

        • 创建时机:develop分支达到了发布的理想状态后,至少所有此次要发布的features已合并到develop分支。从develop创建。创建后,所有未来准备发布的features可合并到develop分支。
        • 必须合并到 master:需打 tag,以便将来引用这个版本。
        • 必须合并到 develop:临时分支用完删除。
    • fixbug-0.1、hotfix/#1 、issue-101 临时修补分支:通过平台生成的问题编号来命名 ,生产环境紧急bug修复。可以基于master分支,必须合并回develop和master分支。与发布分支很相似。临时分支用完删除。

      1. 在 master 分支上拉一个 hotfix 分支 hotfix/0.0.1;
      2. 修复后 merge 回 master 分支;
      3. 再 merge 回 develop 分支;
      4. 删除该分支;
      5. 应始终保证 master 和 develop 上都修复了该bug。

img

开发功能分支 feature/search-recommend为例,工程师需要做以下步骤:

  1. 建立 develop 的分支 feature/search-recommend;
  2. 在该分支上进行开发,完成后进行本地提交;
  3. 切换到 develop 分支,pull拉取远程仓库最新版本;
  4. 此时本地 develop 分支是最新版本,然后 merge 分支 feature/search-recommend;
    • 如果此时有冲突,清除后commit;
  5. 把本地合并后的分支 develop push 到远程 develop;
  6. 在 develop 分支环境下进行测试;
  7. 一切ok,删除该功能分支;
  8. 切到 master 分支,pull 然后 merge develop,收工。

git flow

搭建本地环境

本地安装 Node.js

直接下载安装,一路下一步,建议安装在非系统盘。

一般安装包会默认勾选Add to PATH选项,可以不再单独配置系统环境变量。

1
2
3
# 在 cmd 控制台查看环境变量配置是否成功
node -v
npm -v
安装 Git

听说有墙下载慢,可以试试迅雷或者梯子代理

直接安装,可以右键 -> Git Bash Here 查看 Git 命令行

1
2
# 在 cmd 控制台查看环境变量配置是否成功
git --version
设置 SSH 连接到 GitHub

用于本地和 GitHub 通信

  1. 设置用户名、邮箱:注意用户名不是昵称。
1
2
git config --global user.name "your_name"
git config --global user.email "your_email@example.com"
  1. 生成 SSH 秘钥
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建秘钥
ssh-keygen -t rsa -C "your_email@example.com"

# 三次回车
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/you/.ssh/id_rsa): [Press enter]
Enter passphrase (empty for no passphrase): [Type a passphrase]
Enter same passphrase again: [Type passphrase again]

# 创建成功
Your identification has been saved in /c/Users/you/.ssh/id_rsa.
Your public key has been saved in /c/Users/you/.ssh/id_rsa.pub.
The key fingerprint is:
01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com
  1. 复制 SSH key 秘钥
1
2
#clip < ~/.ssh/id_rsa.pub
C:\Users\Cooper\.ssh\id_rsa.pub
  1. 在 GitHub 头像->Settings->SSH and GPG keys->New SSH key 中添加 SSH key 密钥。这是本地主机和 GitHub 相互识别的标志
  2. 测试
1
2
3
4
# 在 Git Bash 中测试
ssh -T git@github.com
# 表示链接成功
Hi your_name! You've successfully authenticated, but GitHub does not provide shell access.

Github Desktop 报错 443: Timed out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# Github Desktop 报错
# github desktop fatal: unable to access Failed to connect to github.com port 443: Timed out

# 设置 ssh 连接 github
# C:\Users\Cooper\.ssh\config 中添加:
Host github.com
 Hostname ssh.github.com
 Port 443
 User git

# C:\Users\Cooper\.ssh\.gitconfig
[user]
	name = {name}
	email = {username@mail.com}
[color]
	ui = true
[core]
	autocrlf = false
[filter "lfs"]
	clean = git-lfs clean -- %f
	smudge = git-lfs smudge -- %f
	process = git-lfs filter-process
	required = true
[http]
	sslverify = true
	sslBackend = openssl
[credential]
	helper = wincred
[https]
	sslverify = true
[commit]
	gpgsign = false

#  C:\Users\Cooper\.ssh\known_hosts,github 2023年重新设置了秘钥,
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=

# 重新生成 SSH 秘钥,并添加到 github

# 生成 GPG

# 改用 ssh 连接 github
git remote set-url origin git@github.com:FaceShawn/Job2021.git

Github Desktop 客户端

  1. Github 的 SSH 配置
  2. GitHub for Windows 客户端的使用教程

使用迅雷下载 https://desktop.github.com/ 会快点

项目初始化

项目最好存储在纯英文路径下

创建项目

一般在某一文件夹,如使用 IDE 创建项目文件夹后,将此项目文件夹创建为 Git 项目。

添加本地项目

此时项目中应有 /.git 文件夹,表示这是一个 git 项目,操作是将其添加入本地仓库。

从 Github 克隆项目

fork 指将别人的项目拷贝到自己的账户中。

clone 指将在 Github 网站上的项目克隆到本地计算机的仓库中,默认是自己的项目,可通过 URL 克隆其他用户的项目。

克隆时本地文件夹可重命名。

remove 项目

默认只是将项目移出本地仓库,勾选后才删除项目到回收站。

更改本地项目存储位置

将本地项目移动到其它路径下

  1. 通过设置 Options-clone 里面的路径,v1.6.5 中没有发现这个功能
  2. 直接将项目文件夹移动到目标位置,打开 Github Desktop 项目时会提示重新定位(locate)。或手动将项目重新添加到本地仓库即可
通过 GitHub Desktop 版本回退
  1. 在本地仓库 commit to master 未 push 到远程仓库

    undo

  2. 已 push 到远程仓库

    History->右键->Reserve this commit commit to master push

错误处理

使用git时出现:warning: LF will be replaced by CRLF

提交失败
0%