硬件

  • 一台能够安装OpenWRT(或者Linux系统的)路由器,我用的是一台老设备,Netgear WND3700V1。
  • 视你日常工作量大小,准备一个空间足够的U盘,最好是高速的,当然这个高速是指能匹配路由器USB口的标准就足够。

系统软件

成文时,OpenWRT的版本是18.06.0,其它版本应当也可以,OpenWRT挺早就支持git软件包了。下载地址在:http://downloads.openwrt.org/。也可能是我的问题,但至少看起来,这样一个纯技术网站,不FQ已经下载不到了。

因为各家路由设备的硬件复杂性,虽然都是同样的OpenWRT,不同的路由器仍然要下载自己硬件对应的版本。如果之前没有安装过OpenWRT的话,建议你在https://openwrt.org/toh/views/toh_fwdownload查询OpenWRT支持的设备列表,确认自己应当使用的版本。

OpenWRT的安装这里不讲,请参考官方相关文档。通常都是在自己路由器的管理界面使用软件更新功能,选择下载的固件文件,上传随后升级。
接着请根据自己家里网络的情况,配置上网设置各项目,保证基本路由功能工作正常。

管理路由器

OpenWRT18.06.0的默认管理方式是使用ssh,方法:ssh root@[IP地址]。根据路由器的FLASH大小,比较小的FLASH是默认没有WEB GUI界面的,比如我用的这台。所幸大多情况下使用命令行配置路由器效率更高,而且有些工作是使用GUI界面做不到的。

OpenWRT的默认账户用户名是root,没有密码,正常情况下第一次登陆会要求你修改密码。在一个连接公网的环境中,请尽早登陆修改密码。

配置镜像源

如果你不用FQ就能访问官方的源服务器的话,请跳过这一节内容。

OpenWRT使用opkg工具来管理扩展包。因为前面所说的原因,需要配置使用镜像源来保证所需软件包的安装。

中间碰到一个小麻烦是国外的镜像服务器,基本都使用了https协议,OpenWRT不能直接支持。国内的镜像大多倒是http协议,但镜像中又缺乏一些驱动包,无法驱动U盘。

所以如果找不到更好的完整源的话,只好把变更源这样一件小事分成两步来做。

opkg的源配置文件路径为:/etc/opkg/distfeeds.conf,首先做一个备份,然后你可以使用你喜欢的编辑工具修改,我通常都是vi。
把distfeeds.conf文件的内容修改为:

src/gz openwrt_core http://openwrt.proxy.ustclug.org/releases/18.06.0/targets/ar71xx/generic/packages
src/gz openwrt_kmods https://downloads.lede-project.urown.net/snapshots/targets/ar71xx/generic/kmods/4.9.117-1-e017c397f3c6ba06dc921b136a63fb36
src/gz openwrt_base http://openwrt.proxy.ustclug.org/releases/18.06.0/packages/mips_24kc/base
src/gz openwrt_luci http://openwrt.proxy.ustclug.org/releases/18.06.0/packages/mips_24kc/luci
src/gz openwrt_packages http://openwrt.proxy.ustclug.org/releases/18.06.0/packages/mips_24kc/packages
src/gz openwrt_routing http://openwrt.proxy.ustclug.org/releases/18.06.0/packages/mips_24kc/routing
src/gz openwrt_telephony http://openwrt.proxy.ustclug.org/releases/18.06.0/packages/mips_24kc/telephony

这里面使用了两个源,分别是:http://openwrt.proxy.ustclug.orghttps://downloads.lede-project.urown.net

接着在OpenWRT命令使用opkg update命令,只要网络没有问题,可以完成源目录包的更新,当然在https的那个源会报错,先不用管。

通常的情况下,每次进行包安装工作之前进行一次opkg update就够了,这是下载软件源中的所有目录索引到本地。路由器关机、或者云端的源内容发生了变化才需要重新执行。

随后安装https协议所需的软件包:

opkg install libustream-openssl  ca-bundle ca-certificates

接着再做一次opkg update,这一次,应当所有的源都可以拿到目录包了。

如果你有更好的http源,配置https访问这一步可以省略。

至此,opkg包管理工具算配置完成。喜欢使用GUI界面的话,这时候可以使用下面命令安装:

opkg update
opkg install luci

安装U盘并设置自动加载

如果只是当做私有云盘使用,U盘的格式可以随意。但如果打算用作git仓库以及用以弥补路由器可怜的FLASH存储,则必须使用Linux专有格式,比如EXT4。所以准备用在路由器上的U盘你要提前做好备份,因为后面的安装会重新格式化U盘。

首先是安装加载U盘所需的各项驱动和相关支持工具:

#假设你已经做过opkg udpate
opkg install block-mount e2fsprogs kmod-fs-ext4 kmod-usb3 kmod-usb2 kmod-usb-storage

随后使用ext4格式,重新初始化U盘:

#注意这一步会清掉U盘上现有的所有内容
mkfs.ext4 /dev/sda1

接着将U盘设置为路由器启动后自动加载:

block detect > /etc/config/fstab 
uci set fstab.@mount[0].enabled='1' && uci set fstab.@global[0].check_fs='1' && uci commit 
/sbin/block mount && service fstab enable

这时候可以使用mount命令检查一下U盘是否加载成功(不需要重启),如果输出信息中,通常是在最后一行,如果有类似下面信息表示U盘加载成功了:

/dev/sda1 on /mnt/sda1 type ext4 (rw,relatime,data=ordered)

在我实验的时候,有一个U盘无论如何无法自动加载成功,猜测同U盘型号或者具体硬件及OpenWRT版本的支持有关系。就不去深究原因了,碰到这种情况可以使用启动脚本的方式解决,首先执行一次mkdir /mnt/sda1,然后在/etc/rc.local文件最后一行增加:

mount /dev/sda1 /mnt/sda1

以后重启将会自动加载U盘。

安装git工具包

这一步对于新款路由器实在不是事儿,使用opkg一条命令就搞定:

opkg install git

对于我这款老路由器来讲是个大麻烦,因为这款WND3700这款路由器只有4M的FLASH,相当于硬盘的存储空间。而git软件包压缩之后是4.3M,完全盛不下。

这时候刚才安装的EXT4格式的U盘就起作用了,我使用手工安装的方式把git安装到U盘上,这样多大的软件包都不算问题了。

首先下载git软件包:

cd /mnt/sda1/
wget http://openwrt.proxy.ustclug.org/releases/18.06.0/packages/mips_24kc/packages/git_2.16.3-1_mips_24kc.ipk

注意下载路径是跟你所使用的路由器版本有关的,比如上面的下载地址表示OpernWRT18.06.0版本,跑在mips_24kc的芯片上。根据这些信息,你要寻找自己路由器可用的软件包,平常这件事情是由opkg帮你做的。

下载完成后,手工解压取出文件:

tar xzvf git_2.16.3-1_mips_24kc.ipk
#上面的解压完成通常会出来3个文件,我们只使用其中的data.tar.gz文件。
mkdir ipks
cd ipks
tar xzvf ../data.tar.gz
cd ..
# 删除3个解压出的临时文件
rm control.tar.gz data.tar.gz  debian-binary

所有的文件都保存在/mnt/sda1/ipks/usr路径下,我们还需要手工完成安装,才能够运行:

ln -s /mnt/sda1/ipks/usr/bin/git /usr/bin/
ln -s /mnt/sda1/ipks/usr/bin/git-receive-pack /usr/bin/
ln -s /mnt/sda1/ipks/usr/bin/git-upload-archive /usr/bin/
ln -s /mnt/sda1/ipks/usr/bin/git-shell /usr/bin/
ln -s /mnt/sda1/ipks/usr/bin/git-upload-pack /usr/bin/
ln -s /mnt/sda1/ipks/usr/lib/git-core/ /usr/lib/
ln -s /mnt/sda1/ipks/usr/share/git-core/ /usr/share/

第一,ln命令会保持每一处链接文件的同步性,也就是说,不论你改动了哪一处,其它的文件都会发生相同的变化;
第二,ln的链接又分软链接和硬链接两种,软链接就是ln –s 源文件 目标文件,它只会在你选定的位置上生成一个文件的镜像,不会占用磁盘空间,硬链接 ln 源文件 目标文件,没有参数-s, 它会在你选定的位置上生成一个和源文件大小相同的文件,无论是软链接还是硬链接,文件都保持同步变化。
1. 目录只能创建软链接
2. 目录创建链接必须用绝对路径,相对路径创建会不成功,会提示:符号连接的层数过多 这样的错误
3. 在链接目标目录中修改文件都会在源文件目录中同步变化
4. 用ls -l命令去察看,就可以看到显示的link的路径了
5. 删除软链接:rm –rf 软链接名称(请注意不要在后面加”/”,rm –rf 后面加不加”/” 的区别可自行去百度下)
6. 修改软链接:ln –snf  [新的源文件或目录]  [目标文件或目录]

此时git已经可以使用了。接下来我们建立工作目录:

mkdir /mnt/sda1/prjs
ln -s /mnt/sda1/prjs/ /

/prjs目录是我们的主要存储目录。因为路由器只有一个root账号,也就不用考虑额外的权限问题。

今后所有的git仓库,都可以在/prjs路径下另外建目录来保存。我们来建立一个测试仓库来验证工作是否正常:

mkdir /prjs/test
cd /prjs/test
git init --bare

好了,至此路由器上的所有准备都已经完成。今后增加新的git仓库,使用新的仓库名称,重复上面最后一个建立test仓库的操作就可以。

测试路由器上的git仓库

回到我们的工作电脑上,随意建立一个工作目录,测试路由器上的git仓库是否工作正常,下面假设我们路由器的IP地址为192.168.1.1,请修改成自己路由器的正确地址。

mkdir testgit
cd testgit
git init .
echo "test information" > abc.txt
echo "测试信息" > abc1.txt
git add .
git commit -m "something new"
git status
git remote add origin root@192.168.1.1:/prjs/test/
git push --set-upstream origin master //之后就可以直接使用git push提交代码
git push origin master (提交到远程库)
git log (查看历史提交记录)

git remote rm origin //远程配置删除
git push --set-upstream  [远程主机名] [远程分支名]
git push -f master master 强制推送本地master到远程master

$ git fetch origin master //从远程的origin仓库的master分支下载代码到本地的origin master
$ git fetch <远程主机名> <分支名>
$ git log -p master.. origin/master//比较本地的仓库和远程参考的区别
$ git merge origin/master //把远程下载下来的代码合并到本地仓库,远程的和本地的合并

最后的git push执行后,需要输入路由器root账号密码,随后如果显示类似下面信息,就表示成功了:

Counting objects: 2, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 231 bytes | 231.00 KiB/s, done.
Total 2 (delta 0), reused 0 (delta 0)
To root@192.168.1.1:/prjs/test/
   570db28..5ab2627  master -> master

git常用命令

git clone 非标准的ssh端口(非22)端口
git clone ssh://git@hostname:port/.../xxx.git

hostname:可以是主机的IP地址也可以是域名,域名会自动通过DNS进行解析

port:端口号

git add -Agit add .以及git add -u

在功能上看似很相近,但还是存在一点差别

  • git add . :他会监控工作区的状态树,使用它会把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的文件。
  • git add -u:他仅监控已经被add的文件(即tracked file),他会将被修改的文件提交到暂存区。add -u 不会提交新文件(untracked file)。(git add --update的缩写)
  • git add -A:是上面两个功能的合集(git add --all的缩写)

下面是具体操作例子,方便更好的理解(Git version 1.x):

git init
echo Change me > change-me
echo Delete me > delete-me
git add change-me delete-me
git commit -m initial

echo OK >> change-me
rm delete-me
echo Add me > add-me

git status
# Changed but not updated:
#   modified:   change-me
#   deleted:    delete-me
# Untracked files:
#   add-me

git add .
git status

# Changes to be committed:
#   new file:   add-me
#   modified:   change-me
# Changed but not updated:
#   deleted:    delete-me

git reset

git add -u
git status

# Changes to be committed:
#   modified:   change-me
#   deleted:    delete-me
# Untracked files:
#   add-me

git reset

git add -A
git status

# Changes to be committed:
#   new file:   add-me
#   modified:   change-me
#   deleted:    delete-me

总结:

  • git add -A 提交所有变化
  • git add -u 提交被修改(modified)和被删除(deleted)文件,不包括新文件(new)
  • git add . 提交新文件(new)和被修改(modified)文件,不包括被删除(deleted)文件
git initgit init --bare的区别
  • 使用命令git init,就会生成.git目录以及其下的版本历史记录文件,这些版本历史记录文件就存放在.git目录下;
  • 使用命令"git init --bare"(bare汉语意思是:裸,裸的)初始化的版本库(暂且称为bare repository),不再生成.git目录,而是只生成.git目录下面的版本历史记录文件,这些版本历史记录文件也不再存放在.git目录下面,而是直接存放在版本库的根目录下面;就是说,这个版本库里面的文件都是.git目录下面的文件,把原本在.git目录里面的文件放在版本库的根目录下面;
git命令之git remote的用法
git remote rm origin //远程配置删除
git remote add origin https://github.com/***/WebCrawlers.git //重新添加
git remote  //不带参数,列出已经存在的远程分支
git  remote -v //列出详细信息,在每一个名字后面列出其远程url
    origin git://github.com/schacon/ticgit.git
git init
git add xxx
git commit -m 'xxx'
git remote add origin ssh://software@172.16.0.30/~/yafeng/.git
git push origin master 
git remote show origin
git clone ssh://software@172.16.0.30/~/yafeng/.git

$ git remote show origin
root@192.168.1.1's password:
* 远程 origin
  获取地址:root@192.168.1.1:/prjs
  推送地址:root@192.168.1.1:/prjs
  HEAD 分支:master
  远程分支:
    master 已跟踪
  为 'git pull' 配置的本地分支:
    master 与远程 master 合并
  为 'git push' 配置的本地引用:
    master 推送至 master (最新)

origin 这样一来,我就可以非常轻松地从这些用户的仓库中,拉取他们的提交到本地.请注意,上面列出的地址只有 origin 用的是 SSH URL 链接,所以也只有这个仓库我能推送数据上去

添加远程仓库

要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,运行 git remote add [shortname] [url]:
$ git remote
   origin
$ git remote add pb git://github.com/paulboone/ticgit.git
$ git remote -v
   origin git://github.com/schacon/ticgit.git

pb git://github.com/paulboone/ticgit.git现在可以用字串 pb 指代对应的仓库地址了.比如说,要抓取所有Paul 有的,但本地仓库没有的信息,可以运行

$ git fetch pb
remote: Counting objects: 58, done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 44 (delta 24), reused 1 (delta 0)
Unpacking objects: 100% (44/44), done.
From git://github.com/paulboone/ticgit
* [new branch] master -> pb/master
* [new branch] ticgit -> pb/ticgit

现在,Paul 的主干分支(master)已经完全可以在本地访问了,对应的名字是 pb/master,你可以将它合并到自己的某个分支,或者切换到这个分支,看看有些什么更有趣的
fetch更新本地仓库两种方式:
//方法一
$ git fetch origin master //从远程的origin仓库的master分支下载代码到本地的origin master
$ git log -p master.. origin/master//比较本地的仓库和远程参考的区别
$ git merge origin/master//把远程下载下来的代码合并到本地仓库,远程的和本地的合并

//方法二
$ git fetch origin master:temp //从远程的origin仓库的master分支下载到本地并新建一个分支temp
$ git diff temp//比较master分支和temp分支的不同
$ git merge temp//合并temp分支到master分支
$ git branch -d temp//删除temp
有三种方法可以实现忽略Git中不想提交的文件:
  • 在Git项目中定义.gitignore文件

这种方式通过在项目的某个文件夹下定义.gitignore文件,在该文件中定义相应的忽略规则,来管理当前文件夹下的文件的Git提交行为。.gitignore 文件是可以提交到公有仓库中,这就为该项目下的所有开发者都共享一套定义好的忽略规则。在.gitingore 文件中,遵循相应的语法,在每一行指定一个忽略规则。如:

*.log
*.temp
/vendor
  • 在Git项目的设置中指定排除文件

这种方式只是临时指定该项目的行为,需要编辑当前项目下的 .git/info/exclude文件,然后将需要忽略提交的文件写入其中。需要注意的是,这种方式指定的忽略文件的根目录是项目根目录。

  • 定义Git全局的 .gitignore 文件

除了可以在项目中定义 .gitignore 文件外,还可以设置全局的git .gitignore文件来管理所有Git项目的行为。这种方式在不同的项目开发者之间是不共享的,是属于项目之上Git应用级别的行为。这种方式也需要创建相应的 .gitignore 文件,可以放在任意位置。然后在使用以下命令配置Git:

# git config --global core.excludesfile ~/.gitignore
  • .gitignore忽略规则简单说明
#               表示此为注释,将被Git忽略
*.a             表示忽略所有 .a 结尾的文件
!lib.a          表示但lib.a除外
/TODO           表示仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
build/          表示忽略 build/目录下的所有文件,过滤整个build文件夹;
doc/*.txt       表示会忽略doc/notes.txt但不包括 doc/server/arch.txt

bin/:           表示忽略当前路径下的bin文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件
/bin:           表示忽略根目录下的bin文件
/*.c:           表示忽略cat.c,不忽略 build/cat.c
debug/*.obj:    表示忽略debug/io.obj,不忽略 debug/common/io.obj和tools/debug/io.obj
**/foo:         表示忽略/foo,a/foo,a/b/foo等
a/**/b:         表示忽略a/b, a/x/b,a/x/y/b等
!/bin/run.sh    表示不忽略bin目录下的run.sh文件
*.log:          表示忽略所有 .log 文件
config.php:     表示忽略当前路径的 config.php 文件

/mtk/           表示过滤整个文件夹
*.zip           表示过滤所有.zip文件
/mtk/do.c       表示过滤某个具体文件

被过滤掉的文件就不会出现在git仓库中(gitlab或github)了,当然本地库中还有,只是push的时候不会上传。

需要注意的是,gitignore还可以指定要将哪些文件添加到版本管理中,如下:
!*.zip
!/mtk/one.txt

唯一的区别就是规则开头多了一个感叹号,Git会将满足这类规则的文件添加到版本管理中。为什么要有两种规则呢?
想象一个场景:假如我们只需要管理/mtk/目录中的one.txt文件,这个目录中的其他文件都不需要管理,那么.gitignore规则应写为::
/mtk/*
!/mtk/one.txt

假设我们只有过滤规则,而没有添加规则,那么我们就需要把/mtk/目录下除了one.txt以外的所有文件都写出来!
注意上面的/mtk/*不能写为/mtk/,否则父目录被前面的规则排除掉了,one.txt文件虽然加了!过滤规则,也不会生效!

还有一些规则如下:
fd1/*
说明:忽略目录 fd1 下的全部内容;注意,不管是根目录下的 /fd1/ 目录,还是某个子目录 /child/fd1/ 目录,都会被忽略;

/fd1/*
说明:忽略根目录下的 /fd1/ 目录的全部内容;

/*
!.gitignore
!/fw/ 
/fw/*
!/fw/bin/
!/fw/sf/
说明:忽略全部内容,但是不忽略 .gitignore 文件、根目录下的 /fw/bin/ 和 /fw/sf/ 目录;注意要先对bin/的父目录使用!规则,使其不被排除。

温馨提示:如果你不慎在创建.gitignore文件之前就push了项目,那么即使你在.gitignore文件中写入新的过滤规则,这些规则也不会起作用,Git仍然会对所有文件进行版本管理。简单来说出现这种问题的原因就是Git已经开始管理这些文件了,所以你无法再通过过滤规则过滤它们。所以大家一定要养成在项目开始就创建.gitignore文件的习惯,否则一但push,处理起来会非常麻烦。

  • Git忽略规则(.gitignore配置)不生效原因和解决
第一种方法:
.gitignore中已经标明忽略的文件目录下的文件,git push的时候还会出现在push的目录中,或者用git status查看状态,想要忽略的文件还是显示被追踪状态。
原因是因为在git忽略目录中,新建的文件在git中会有缓存,如果某些文件已经被纳入了版本管理中,就算是在.gitignore中已经声明了忽略路径也是不起作用的,
这时候我们就应该先把本地缓存删除,然后再进行git的提交,这样就不会出现忽略的文件了。

$ git check-ignore -v HelloWorld.class  //忽略规则查看

解决方法: git清除本地缓存(改变成未track状态),然后再提交:
[root@kevin ~]# git rm -r --cached .
[root@kevin ~]# git add .
[root@kevin ~]# git commit -m 'update .gitignore'
[root@kevin ~]# git push -u origin master

需要特别注意的是:
1).gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。
2)想要.gitignore起作用,必须要在这些文件不在暂存区中才可以,.gitignore文件只是忽略没有被staged(cached)文件,
   对于已经被staged文件,加入ignore文件时一定要先从staged移除,才可以忽略。

第二种方法:(推荐)
在每个clone下来的仓库中手动设置不要检查特定文件的更改情况。
[root@kevin ~]# git update-index --assume-unchanged PATH  //在PATH处输入要忽略的文件
git库所在的文件夹中的文件大致有4种状态
Untracked:
未跟踪, 此文件在文件夹中, 但并没有加入到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

Git 状态 untracked 和 not staged的区别
1)untrack     表示是新文件,没有被add过,是为跟踪的意思。
2)not staged  表示add过的文件,即跟踪文件,再次修改没有add,就是没有暂存的意思

自动验证

如果不希望每次git push都输入路由器密码,可以把自己电脑的公钥存储到路由器备案,以后就不需要输入密码了,首先拷贝公钥到路由器:

scp ~/.ssh/id_rsa.pub root@192.168.1.1:~/

接着在路由器上执行:

cat id_rsa.pub >> /etc/dropbear/authorized_keys

可以使用ssh来测试是否生效,ssh root@192.168.1.1之后,如果不再要求输入密码直接登录了路由器,表示自动验证生效了。

git stashgit stash pop

git stash 可用来暂存当前正在进行的工作, 比如想pull 最新代码, 又不想加新commit, 或者另外一种情况,为了fix 一个紧急的bug, 先stash, 使返回到自己上一个commit, 改完bug之后再stash pop, 继续原来的工作。

基础命令:

$git stash
$do some work
$git stash pop

进阶:

git stash save "work in progress for foo feature"

当你多次使用’git stash’命令后,你的栈里将充满了未提交的代码,这时候你会对将哪个版本应用回来有些困惑

git stash list命令可以将当前的Git栈信息打印出来,你只需要将找到对应的版本号.

例如使用git stash apply stash@{1}就可以将你指定版本号为stash@{1}的工作取出来

当你将所有的栈都应用回来的时候,可以使用git stash clear来将栈清空。

git stash          # save uncommitted changes
# pull, edit, etc.
git stash list     # list stashed changes in this git
git show stash@{0} # see the last stash 
git stash pop      # apply last stash and remove it from the list

git stash --help   # for more info

工作区、暂存区、版本库、远程仓库

Git本地有四个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)、git仓库(Remote Directory)。文件在这四个区域之间的转换关系如下:
1090617-20181008211557402-232838726.png

  • Workspace: 工作区,就是你平时存放项目代码的地方
  • Index / Stage: 暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
  • Repository: 仓库区(或版本库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
  • Remote: 远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换
    git工作流程

    git的工作流程一般是这样的:
    1. 在工作目录中添加、修改文件;
    2. 将需要进行版本管理的文件放入暂存区域;
    3. 将暂存区域的文件提交到git仓库。

因此,git管理的文件有三种状态:已修改(modified),已暂存(staged),已提交(committed)

git文件的四种状态

版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。

GIT不关心文件两个版本之间的具体差别,而是关心文件的整体是否有改变,若文件被改变,在添加提交时就生成文件新版本的快照,而判断文件整体是否改变的方法就是用SHA-1算法计算文件的校验和

  • Untracked:未跟踪, 此文件在文件夹中, 但并没有加入到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

下面的图很好的解释了这四种状态的转变:
1090617-20181008212245877-52530897.png

  • 新建文件--->Untracked

  • 使用add命令将新建的文件加入到暂存区--->Staged

  • 使用commit命令将暂存区的文件提交到本地仓库--->Unmodified

  • 如果对Unmodified状态的文件进行修改---> modified

  • 如果对Unmodified状态的文件进行remove操作--->Untracked

git四个区域常用命令
  1. 新建代码库
    # 在当前目录新建一个Git代码库
    git init
    # 新建一个目录,将其初始化为Git代码库
    git init [project-name]
    # 下载一个项目和它的整个代码历史
    git clone [url]
  2. 查看文件状态
    #查看指定文件状态
    git status [filename]
    #查看所有文件状态
    git status //显示工作区文件状态
  3. 工作区<-->暂存区
    # 添加指定文件到暂存区
    git add [file1] [file2] ...
    # 添加指定目录到暂存区,包括子目录
    git add [dir]
    # 添加当前目录的所有文件到暂存区
    git add .
    #当我们需要删除暂存区或分支上的文件, 同时工作区也不需要这个文件了, 可以使用(⚠️)
    git rm file_path
    #当我们需要删除暂存区或分支上的文件, 但本地又需要使用, 这个时候直接push那边这个文件就没有,如果push之前重新add那么还是会有。
    git rm --cached file_path
    #直接加文件名   从暂存区将文件恢复到工作区,如果工作区已经有该文件,则会选择覆盖
    #加了【分支名】 +文件名  则表示从分支名为所写的分支名中拉取文件 并覆盖工作区里的文件
    git checkout
  4. 工作区<-->资源库(版本库)
    #将暂存区-->资源库(版本库)
    git commit -m '该次提交说明'
    #如果出现:将不必要的文件commit 或者 上次提交觉得是错的  或者 不想改变暂存区内容,只是想调整提交的信息
    #移除不必要的添加到暂存区的文件
    git reset HEAD 文件名
    #去掉上一次的提交(会直接变成add之前状态)   
    git reset HEAD^ 
    git reset --hard [commit ID]
    #去掉上一次的提交(变成add之后,commit之前状态) 
    git reset --soft  HEAD^
    工作区和暂存区的区别 git diff
    工作区和版本库的区别 git diff HEAD
    暂存区和版本库的区别 git diff --cached
    git log --oneline --graph
  5. 远程操作
    # 取回远程仓库的变化,并与本地分支合并
    git pull
    # 上传本地指定分支到远程仓库
    git push
  6. 其它常用命令
    # 显示当前的Git配置
    git config --list
    # 编辑Git配置文件
    git config -e [--global]
    #初次commit之前,需要配置用户邮箱及用户名,使用以下命令:
    git config --global user.email "you@example.com"
    git config --global user.name "Your Name"
    #调出Git的帮助文档
    git --help
    #查看某个具体命令的帮助文档
    git +命令 --help
    #查看git的版本
    git --version

git push大文件出错

对象计数中: 2854, 完成.
Delta compression using up to 4 threads.
fatal: Out of memory, malloc failed (tried to allocate 306991617 bytes)
error: 远程解包失败:eof before pack header was fully read
error: 无法推送一些引用到

解决方案

禁用多线程压缩以节省内存: git config pack.threads 1
除了其他内存限制选项外,比如新的Git中的 core.bigfilethreshold

或者打开.git文件夹下config文件,修改线程

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    packedGitLimit = 1024m
    packedGitWindowSize = 1024m
[branch "master"]
[remote "origin"]
    url = root@192.168.1.1:/blog/
    fetch = +refs/heads/*:refs/remotes/origin/*
[pack]
    threads = 1
    deltaCacheSize = 1024m
    packSizeLimit = 1024m
    windowMemory = 1024m