Git学习


Git

1.历史

同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代.

Linux 内核开源项目有着为数众多的参与者. 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间), 到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统BitKeeper来管理和维护代码.

到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用BitKeeper 的权力.这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统.他们对新的系统制订了若干目标:

  • 速度
  • 简单的设计
  • 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
  • 完全分布式
  • 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)

自诞生于 2005 年以来,Git日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标.它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统.

2.基本概念

1.Git是什么

对比其他的版本工具,会发现Git根本上的不同.

  • VCS\Subversion\Perforce等,会将它们存储的信息看作是一组基本文件和每个文件随时间逐步累积的差异(delte-based)

10124

  • Git最大的不同是,他会把数据看作是小型文件系统的一系列快照,每当提交更新或保存项目状态时,它基本上就会对当时的全部文件创建一个快照并保存这个快照的索引.为了效率.如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件.

综合以上,Git 更像是一个小型的文件系统.

2.Git 中文件状态

Git中,文件可能会处于以下其中一种状态.

  • Committed(已提交):数据已经安全地保存在本地数据库中
  • Modified(已修改):修改了文件,但还没保存到数据库中
  • Staged(已暂存):对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中

3.Git文件逻辑流程

一个文件,只能经过以下的流程状态

10122

4.Git文件逻辑状态

10123

Untrucked :未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.

Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件.

Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改.

**Staged**:暂存状态,执行git commit则将修改同步到库中,这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified

3.安装Git

  • ubuntu
$ sudo apt install git
  • windows

https://git-scm.com/下载对应的版本安装

4.Git命令

Git_com

注意:此图片使用xmind生成.如果图片不清晰,请下载原始文件:https://gitee.com/ningwenyan/font

如果需要xmind破解版软件,可直接在公众号回复xmind.

1.获取帮助git help

$ git help
用法:git [--version] [--help] [-C <path>] [-c <键名>=<>]
           [--exec-path[=<路径>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<路径>] [--work-tree=<路径>] [--namespace=<名称>]
           <命令> [<参数>]

这些是各种场合常见的 Git 命令:

开始一个工作区(参见:git help tutorial)
   clone      克隆一个仓库到一个新目录
   init       创建一个空的 Git 仓库或重新初始化一个已存在的仓库

在当前变更上工作(参见:git help everyday)
   add        添加文件内容至索引
   mv         移动或重命名一个文件、目录或符号链接
   reset      重置当前 HEAD 到指定状态
   rm         从工作区和索引中删除文件

检查历史和状态(参见:git help revisions)
   bisect     通过二分查找定位引入 bug 的提交
   grep       输出和模式匹配的行
   log        显示提交日志
   show       显示各种类型的对象
   status     显示工作区状态

扩展、标记和调校您的历史记录
   branch     列出、创建或删除分支
   checkout   切换分支或恢复工作区文件
   commit     记录变更到仓库
   diff       显示提交之间、提交和工作区之间等的差异
   merge      合并两个或更多开发历史
   rebase     在另一个分支上重新应用提交
   tag        创建、列出、删除或校验一个 GPG 签名的标签对象

协同(参见:git help workflows)
   fetch      从另外一个仓库下载对象和引用
   pull       获取并整合另外的仓库或一个本地分支
   push       更新远程引用和相关的对象

命令 'git help -a''git help -g' 显示可用的子命令和一些概念帮助。
查看 'git help <命令>''git help <概念>' 以获取给定子命令或概念的
帮助。

2.配置命令git config

在初始化仓库之前,最需要做的是配置用户名和电子邮件,这两条配置非常重要,每次Git提交时都会引用这两条信息,用于说明是谁提交了更新.

$ git config -help
usage: git config [<options>]

Config file location
 --global              use global config file  #全局变量
 --system              use system config file  # 登陆系统的账户
 --local               use repository config file   # 局部本地设置,针对当前的项目中的独立设置,优先级高于global
 --worktree            use per-worktree config file
 -f, --file <file>     use given config file
 --blob <blob-id>      read config from given blob object

其中有3个选项可供选择.

  • --global:全局变量,
  • --system:只针对当前登录到系统的用户
  • --local:局部本地设置,针对当前的项目中的独立设置,优先级高于global
git config --global user.name "用户名" # 设置用户名
git config --global user.email "用户邮箱"   #设置邮箱
git config --global user.name   # 查看用户名是否配置成功
git config --global user.email   # 查看邮箱是否配置

# 其他查看配置相关
git config --global --list  # 查看全局设置相关参数列表
git config --local --list # 查看本地设置相关参数列表
git config --system --list # 查看系统配置参数列表
git config --list  # 查看所有Git的配置(全局+本地+系统)

3.初始化仓库git init

进入要初始化的文件目录,然后创建Git仓库

$ git init

例如:

cd temp
❯ mkdir git_learn
❯ cd git_learn
❯ git init
已初始化空的 Git 仓库于 /home/kning/temp/git_learn/.git/

4.添加文件到暂存区git add

$ git add -help
usage: git add [<options>] [--] <pathspec>...
-n, --dry-run         dry run
-v, --verbose         be verbose

-i, --interactive     interactive picking
-p, --patch[=<patch-mode>]
                    select hunks interactively
-e, --edit            edit current diff and apply
-f, --force           allow adding otherwise ignored files
-u, --update          update tracked files
--renormalize         renormalize EOL of tracked files (implies -u)
-N, --intent-to-add   record only the fact that the path will be added later
-A, --all             add changes from all tracked and untracked files
--ignore-removal      ignore paths removed in the working tree (same as --no-all)
--refresh             don't add, only refresh the index
--ignore-errors       just skip files which cannot be added because of errors
--ignore-missing      check if - even missing - files are ignored in dry run
--chmod (+|-)x        override the executable bit of the listed files

常用的有

git add 文件名  # 添加单个文件
git add -u     # update被tracked 文件
git add -A     # 添加所有
git add .     #  添加当前工作区中所有文件

5.提交本地仓库git commit

提交修改

git commit -m "description"   # 提交本地仓库,并添加描述

6.查看working tree状态

# git status 官方解释是 show the working tree ,应该是能查看一个文件所有的逻辑状态信息
git  status
git status -s  # 结果以简短的形式输出

7.查看差异变化git diff

# git-diff - Show changes between commits, commit and working tree, etc
# 显示提交,提交和working tree 之间的所有的更改
git diff # 工作区与缓存区的差异
git diff 分支名 #工作区与某分支的差异,远程分支这样写:remotes/origin/分支名
git diff HEAD  # 工作区与HEAD指针指向的内容差异
git diff 提交id 文件路径 # 工作区某文件当前版本与历史版本的差异
git diff --stage # 工作区文件与上次提交的差异(1.6 版本前用 --cached)
git diff 版本TAG # 查看从某个版本后都改动内容
git diff 分支A 分支B # 比较从分支A和分支B的差异(也支持比较两个TAG)
git diff 分支A...分支B # 比较两分支在分开后各自的改动
# 另外:如果只想统计哪些文件被改动,多少行被改动,可以添加 --stat 参数

8.查看历史记录git log

git log # 查看所有commit记录(SHA-A校验和,作者名称,邮箱,提交时间,提交说明)
git log -p -次数 # 查看最近多少次的提交记录
git log --stat # 简略显示每次提交的内容更改
git log --name-only # 仅显示已修改的文件清单
git log --name-status # 显示新增,修改,删除的文件清单
git log --oneline # 让提交记录以精简的一行输出
git log –graph –all --online # 图形展示分支的合并历史
git log --author=作者  # 查询作者的提交记录(和grep同时使用要加一个--all--match参数)
git log --grep=过滤信息 # 列出提交信息中包含过滤信息的提交记录
git log -S查询内容 # 和--grep类似,S和查询内容间没有空格
git log fileName # 查看某文件的修改记录

9..gitignore

tracked的文件添加到缓存区后,Git就会开始跟踪这个文件.对于一些比如:自动生成的文件,日志,临时编译文件等,就 没必要进行跟踪了,这个时候可以编写.gitignore文件,在里面 把不需要跟踪的文件或文件夹都写上,git就不会对这些文件进行跟踪.
另外.gitignore文件与.git文件夹在同级目录下.

已我上面刚创建的目录为例:

  1. 创建.gitigore
$ cd git_learn
$ touch .gitignore
$ vim .gitignore
...
# 忽视c结尾文件
*.c
  1. 提交版本控制,注意.gitignore是可以版本控制的.
$ git add .
$ git commit -m 'add ignore file'
  1. 尝试添加一个.c文件.检验的方法就是创建完毕后,执行git status,工作区是clean的,干净的.
$ touch text.c
$ git status
位于分支 master
无文件要提交,干净的工作区

如果不想自己写,可以直接到:https://github.com/github/gitignore 复制粘贴.

示例:

# 忽略所有以 .c结尾的文件
*.c
# 但是 stream.c 会被git追踪
!stream.c
# 只忽略当前文件夹下的TODO文件, 不包括其他文件夹下的TODO例如: subdir/TODO
/TODO
# 忽略所有在build文件夹下的文件
build/
# 忽略 doc/notes.txt, 但不包括多层下.txt例如: doc/server/arch.txt
doc/*.txt
# 忽略所有在doc目录下的.pdf文件
doc/**/*.pdf

注意:配置.gitignore只对那些没有添加到版本控制系统的文件生效(未Tracked的文件)

比如:有A,B两个文件,你先把他两个add,然后在.gitignore文件中 配置了不跟踪这两个文件,那么命令不会生效.

所以,最好的做法就是在项目刚开始的时候,先添加.gitignore文件.当然,即使是发生了,还是有解决方法的,可以键入下述命令清除标记状态,然后先添加.gitignore,再添加文件即可:

git rm -r --cached . # 清除版本控制标记,.代表所有文件,也可指定具体文件

5.版本回溯

1.文件恢复git checkout

切换分支或恢复文件

$ git checkout -- filename     # 丢球工作区中的某个文件修改
$ git checkout -- .            # 丢弃工作区中的所有修改 
$ touch 2.txt
>$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
  2.txt

nothing added to commit but untracked files present (use "git add" to track)
   
$ git add 2.txt
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
  new file:   2.txt

$ git commit -m 'add 2.txt'
   [master 353e702] add 2.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 2.txt

$ git status
On branch master
nothing to commit, working tree clean

$ rm 2.txt
$ 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:    2.txt

no changes added to commit (use "git add" and/or "git commit -a")
   
$ git checkout 2.txt
Updated 1 path from the index

$ git status
On branch master
nothing to commit, working tree clean

$ ls
2.txt  

2.git reset

每次的更改都会在git中留下记录值HEAD也就是commit id.根据这个HEAD 可以跳回到原来的状态.

$ git reset  

可以通过git log来查看更改的HEAD

# 新建一个测试文件
$ touch 3.txt

# 编辑测试文件,并添加数字 1,2,3,4
$ vim 3.txt

$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
     3.txt



$ git add 3.txt


$ git commit -m "add 3.txt"
[master e38dbcb] add 3.txt
1 file changed, 4 insertions(+)
create mode 100644 3.txt


$ git status
On branch master
nothing to commit, working tree clean

# 在测试文件中新添加数字 5
$ vim 3.txt

$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
     modified:   3.txt

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


$ git add 3.txt



$ git commit -m 'add 5 in 3.txt'
[master 840106f] add 5 in 3.txt
1 file changed, 1 insertion(+)

$ git status
On branch master
nothing to commit, working tree clean

# 查看commit id
$ git log
commit 840106f762192b023f26abfd1e6c2a55b96379f5 (HEAD -> master)
 add 5 in 3.txt


$ ls
2.txt  3.txt  test.txt  test1


$ cat 3.txt
1
2
3
4
5


# 回溯文件的 commit id
$ git reset --hard e38dbcb124  # id号不用写全
HEAD is now at e38dbcb add 3.txt


$ ls
2.txt  3.txt  test.txt  test1
c

$ cat 3.txt
1
2
3
4

3.查看历史命令git reflog

$ git reflog   # 查看指令,但是不会永久保存,git会自己定时清理

4.查看某次提交的内容git show

$ git show "commit id"

5.查看分支版本号

$ git rev-parse 分支名

6.分支

1.分支的创建/切换

# 创建分支
$ git branch 分支名

# 查看分支
$ git branch 

# 切换分支
$ git checkout 分支名

# 创建分支并切换到这个分支
$ git checkout -b 分支名

示例:

# 创建分支1
$ git branch branch_1

# 查看所有的分支
$ git branch
branch_1
* master

# 创建分支2
$ git branch branch_2

# 切换分支2
$ git checkout branch_2
Switched to branch 'branch_2'

# 创建文件
$ touch 2.txt

$ vim 2.txt

# 分支2中查看到2个文件
$ ls
1.txt  2.txt

$ git add .
$ git commit -m "add 2.txt in branch_2"

# 切换到主分支
$ git checkout master
Switched to branch 'master'

# 查看到只有1个文件
$ ls
1.txt

# 查看所有的分区和所处的分区(* 为所在分区)
$ git branch
  branch_1
  branch_2
* master

GUI界面中查看更容易:

10216

2.分支合并

当我们修复完bug或者是开发新的特性后,需要合并回原理的主分支上.

$ git merge    # Join two or more development histories together 
$ git rebase   # Reapply commits on top of another base tip

3.分支删除

当分支完成自己的使命后,分支就不需要了,可以删除他

$ git branch -d 分支名

7.远程仓库

1.创建SSH KEY

为了演示方便使用gitee

如果本地用户主目录中没有.ssh 目录,则需要手动创建ssh_key

$ ssh-keygen -t rsa -C "youremail@example.com" # 使用默认值即可
$ cd .ssh/

$ ls
id_rsa    # 私钥,不能泄露
id_rsa.pub  # 公钥,需要上传给服务器

2.上传公钥

登录gitee,并上传ssh公钥

10127

3.新建一个远程仓库

如图:

10128

4.推送本地库到远程库

# 关联本地仓库和远程仓库
git remote add origin 远程仓库地址
# 使用git 地址
>$ git remote add origin git@gitee.com:ningwenyan/test.git

$ git remote -v
origin  git@gitee.com:ningwenyan/test.git (fetch)
origin  git@gitee.com:ningwenyan/test.git (push)

之后,可以正常的git pushgit pull进行推送

$ git push -u origin master  
>#  -u参数 作为第一次提交使用, 
# 作用是把本地master分支和远程master分支关联起来(设置默认远程主机), 
# 后续提交不需要这个参数!

其他命令

git remote set-url origin 远程仓库地址
># 也可以先删除origin后再添加
git remote rm origin    # 删除仓库关联
git remote add origin 远程仓库地址 # 添加仓库关联

windows系统添加用户名密码错误修改方法:可以在控制面板中找到凭据管理器 删除错误的用户名密码,然后重新登录.

本电脑不知是不是因为输错密码的缘故,弹出错误提示如下

To gitee.com:ningwenyan/test1.git
>! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@gitee.com:ningwenyan/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

解决办法:使用git pull 合并分支

git pull -u -f  origin master  # 第一次加-f 后续就不用添加了

5.从远程仓库克隆

远端新建仓库

10129

执行如下命令

$ git clone git@gitee.com:ningwenyan/test2.git
Cloning into 'test2'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (4/4), done.

$ ls
test2/

$ cd test2/

$ ls
README.en.md  README.md

8.标签

打标签的作用,就是给项目的开发节点,加上语义化的名字,也即功能版本的别名. 打上标签名的同时,写上附带信息,可以方便项目日后维护过程中的回溯和复查.

另外,也可以通过标签记录,大致了解当前项目的向下兼容性,API的修改和迭代情况.

1.创建标签

$ git tag -a "tagname" -m "comment" "commit_id"
# -a 标签名
# -m 备注信息
# commit_id 提交id

示例:

$ git tag -a 'v0.1.0' -m "初始" 

类似v0.1.0遵从一个简单的规范

  • 主版本号: 当你做了不兼容的API修改
  • 次版本号: 向下兼容的功能性增加
  • 修订号: 向下兼容的问题修正

2.查看所有标签

$ git tag

3.查看具体标签信息

$ git show tagname

4.删除本地标签

$ git tag -d tagname


文章作者: 文彦
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 文彦 !
评论
  目录