- 1. 服务器上搭建Git准备工作
- 2. 服务器上搭建Git流程和使用
- 3. git的基本概念 & 指令
- 4. Git分支
- 5. Git使用中遇到的错误
- 6. 工作使用git
- 7. git总结
- 8. github相关
自从租用了亚马逊AWS的服务器后,想通过Git来管理代码。以下记录了服务器上Git的搭建过程和Git的学习记录。安装过程省略,具体Git教程可以参考官网链接。
服务器上搭建Git准备工作
服务器密钥
没有ssh先创建
1 | sudo apt-get install openssh-server |
进入服务器用户(ubuntu)
1 | cd .ssh |
复制本地生成的公钥(id_isa.pub)到这个文件夹
本地电脑密钥的生成
1 | ssh-keygen -m PEM -t rsa -b 2048 -C <email> |
执行后本地电脑的.ssh下会产生 id_isa(私钥) 和 id_isa.pub(公钥) 文件
现在可以用4096加密:
1 | ssh-keygen -t rsa -b 4096 -C "user-xps" |
然后按回车键即可,不用输入密码
服务器登录密钥(初次登陆服务器设置)
服务器用户下将本地生成的 公钥(id_isa.pub) 复制到服务器.ssh下的authorized_keys 里面
git配置密钥
git用户下将本地生成的公钥(id_isa.pub)复制到git的.ssh下的authorized_keys里面
登录AWS
1 | ssh -i key.pem 用户名@ec2-3-19-55-120.us-east-2.compute.amazonaws.com |
设置权限
1 | chmod 600 authorized_keys |
服务器上搭建Git流程和使用
配置个人信息【1】
1 | git config --global user.name <username> |
登录服务器,在git用户下创建裸仓库(项目后面要加.git)【2】
1 | git init --bare /home/git/repositories/C/data_structure/.git |
在本地电脑上创建仓库【3】
1 | git init (当前项目路径下) |
将工作目录的所有文件增加到暂存区域后提交到git仓库【4】
1 | git add . |
commit后再对刚才提交文件修改【5】
1 | git checkout -- file # 会覆盖掉刚才的修改 |
链接远程仓库:(local -> remote) 【6】
1 | git remote add origin ssh://git@ssh.tyokyo320.com:/home/git/repositories/C/data_structure/.git |
同步到远程仓库【7】
1 | git push -u origin master |
克隆本地仓库:(不用再部署)
1 | # 这样会让用户和群组变成root 需要变更权限 |
克隆远程仓库
注意所在路径!(第一次clone 之后git pull)
1 | git clone ssh://git@ssh.tyokyo320.com:/home/git/repositories/C/data_structure/.git |
Git中.gitignore文件不起作用的解决(git清除本地缓存命令)
1 | git rm -r --cached .vscode |
git的基本概念 & 指令
工作区域,暂存区域,Git仓库
Working Directory (add)——> Stage(Index) (commit)——> Repository(HEAD)
Working Directory <——(checkout) Stage(Index) <——(reset) Repository(HEAD)
Git的工作流程
- 在工作目录中添加,修改文件
- 将需要进行版本管理的文件放入暂存区域
- 将暂存区域的文件提交到Git仓库
Git管理的文件有3种状态
- 已修改(modified)
- 已暂存(staged)
- 已提交(committed)
git add -A 和 git add . 的区别
- git add -A 提交所有变化
- git add -u 提交被修改(modified)和被删除(deleted)文件,不包括新文件(new)
- git add . 提交新文件(new)和被修改(modified)文件,不包括被删除(deleted)文件
git reset命令
- git reset --mixed HEAD~
- 移动HEAD的指向, 将其指向上一个快照(一个波浪线就是上一个快照)
- 将HEAD移动后指向的快照回滚到暂存区域
- git reset --soft HEAD~
- 移动HEAD的指向,将其指向上一个快照
- git reset --hard HEAD~
- 移动HEAD的指向,将其指向上一个快照
- 将HEAD移动后指向的快照回滚到暂存区域
- 将暂存区域的文件还原到工作目录
总结:
- 移动HEAD的指向(–soft)
- 将快照回滚到暂存区域([–mixed], 默认)
- 将暂存区域还原到工作目录(–hard)
- soft: 工作区域和暂存区都是当前版本的内容
- mix: 暂存区的内容是前一个版本的,工作区却是现在的版本,要想回到现在,必须add后再commit
git reset 版本快照的ID号
1 | # 回滚个别文件(注意这里HEAD不会改变) |
git reflog
查看历史所有的commit id
1 | git reflog |
查看历史提交
1 | git log |
比较暂存区域与工作目录
1 | git diff |
比较两个历史快照
1 | git diff 快照ID1 快照ID2 |
比较当前工作目录和Git仓库中的快照
1 | git diff 快照ID |
比较暂存区域和Git仓库中的快照
1 | git diff --cached [快照ID] |
修改最后一次提交
- 在实际开发中,可能会遇到以下两种情景:
- 情景1: 版本刚一提交(commit)到仓库,突然想起漏掉两个文件还没有添加(add)。
- 场景2: 版本刚一提交(commit)到仓库,突然想起版本说明写的不够全面,无法彰显你本次修改的重大意义。
- 执行带 --amend选项的commit提交命令,Git就会“更正”最近的一次提交。
1 | git commit --amend |
删除文件
- git rm 文件名
- 该命令删除的只是工作目录和暂存区域的文件,也就是取消跟踪,在下次提交时不纳入版本管理。
- 当工作目录和暂存区域的同一个文件存在不同内容时,执行
git rm -f 文件名
命令就可以把两个都删除。 - 如果只删除暂存区域的文件(保留工作目录的),那么你可以执行
git rm -cached 文件名
命令实现目的。
重命名文件
- git mv 旧文件名 新文件名
- ren/mv 旧文件名 新文件名
- git rm 旧文件名
- git add 新文件名
查看远程链接仓库
1 | git remote -v |
删除远程仓库链接
1 | git remote remove origin |
更改远程仓库链接
1 | git remote set-url origin ssh://git@ssh.tyokyo320.com:/home/git/repositories/C/data_structure/.git |
同时push到多个远程仓库
当有不止一个远程仓库时候,一次git push
又想同时push到多个远程仓库的时候:
首先需要添加第二个远程地址时使用以下命令:
1 | git remote set-url --add origin https://github.com/tyokyo320/bilibili-downloader.git |
查看远程分支:
1 | git remote -v |
添加完成后git push -u origin master
可以同时push到多个远程仓库
Git分支
创建分支
1 | git branch 分支名 |
切换分支
1 | # 切换分支后HEAD会指向这个分支 |
合并分支
1 | # 将指定的分支合并到主分支 |
删除分支
1 | git branch -d 分支名 |
Git的分支原理是通过指针实现的,所以删除分支后快照还是会留下的,创建和删除都是可以瞬间完成的,这也是Git的魅力。
匿名分支
准备工作: 新建工作目录, 用git init
初始化项目. 分别创建1.txt, 2.txt, 3.txt, 依次对三个文件执行git add
和git commit -m
命令.
1 | git log --decorate --oneline --graph --all |
执行git checkout HEAD~
返回上一个快照
1 | git checkout HEAD~ |
这一段话的意思是, 使用了checkout命令, 但是没有指定分支名, 所以git会创建一个叫做匿名分支(没有名字的分支)的东西, 当你切换到别的分支的时候, 在这个匿名分支中, 所做的所有操作, 提交都会被丢弃掉(3.txt不见了), 所以可以使用匿名分支来做一些实验.
执行git log --decorate --oneline --graph --all
1 | git log --decorate --oneline --graph --all |
再创建4.txt, 执行git add
和git commit -m
命令.然后执行git log --decorate --oneline --graph --all
命令
1 | git log --decorate --oneline --graph --all |
将 HEAD 指向切换到 master: git checkout master
.
1 | git checkout master |
说有一个没有连接到任何分支的提交(1920177 4.txt), 如果要保留为一个新的分支, 那么现在是最好的时机(因为现在有快照ID). 使用git branch <分支名> 1920177
”就可以创建分支.匿名分支用于实验一些有风险的提交, 从匿名分支切回master分支后, 匿名分支就找不到了.
checkout命令
- 从历史快照(或暂缓区域)中拷贝文件到工作目录
当给定某个文件名时,git会从指定的提交中拷贝文件到暂存区域和工作目录。比如执行git checkout HEAD~ README.md
命令,会将上一个快照中的 README.md 文件复制到工作区域和暂存区域中。
如果命令中没有指定具体的快照id,则将从暂存区域恢复指定文件到工作目录git checkout README.md
;
注意:之前命令中文件名前有两个横杠(–),这里又没有了。git提醒你写成git checkout --README.md
,是为了预防你恰好有一个分支叫做 README.md,那么它就搞不懂你要恢复文件还是切换分支了,所以约定两个横杠(–)后面跟的是文件名。反过来说,如果你确保没有一个 README.md 的分支,你直接写git checkout README.md
也是没有问题的
- 切换分支
首先知道git的分支其实就是添加一个指向快照的指针,其次还知道切换分支除了修改 HEAD 指针的指向,还会改变暂存区域和工作目录的内容。
checkout命令和reset命令
- 恢复文件
checkout 命令和 reset 命令都可以用于恢复指定快照的指定文件,并且他们都不会改变 HEAD 指针的指向。
它们的区别是:reset 命令只将指定文件恢复到暂存区域(–mixed),而checkout 命令是同时覆盖暂存区域和工作目录。
注意:也许你试图使用”git reset --hard HEAD~ README.md“ 命令让reset同时覆盖工作目录,但git会告诉你这是徒劳(此时reset不允许使用 --soft 或 --hard 选项)。
这样看来在恢复文件方面,reset 命令要比 checkout 命令更安全一些。
- 恢复快照(commit级别)
reset 命令是用来”回到过去“的,根据选项的不同,reset 命令将移动 HEAD 指针(–soft)->覆盖暂存区域(–mixed,默认)->覆盖工作目录(–hard)。
- 两者的区别
【1】对于 reset --hard 命令来说,checkout 命令更安全。因为checkout 命令在切换分支前会先检查一下当前的工作状态,如果不是”clean“的话,git不允许你这样做;而
reset --hard
命令则是直接覆盖所有数据。
【2】如何更新 HEAD 指向,reset 命令会移动 HEAD 所在分支的指向,而 checkout 命令只会移动 HEAD 自身来指向另一个分支。也就是,checkout只是HEAD指针跑到分支那儿去了,但是reset命令将HEAD指向的分支以及HEAD本身都切到了分支里,换句话说,原来的快照已经消失了。
Git使用中遇到的错误
git pull时遇到的错误
error: Your local changes to the following files would be overwritten by merge
方法1:如果你想保留刚才本地修改的代码,并把git服务器上的代码pull到本地(本地刚才修改的代码将会被暂时封存起来)
1 | git stash |
如此一来,服务器上的代码更新到了本地,而且你本地修改的代码也没有被覆盖,之后使用add,commit,push 命令即可更新本地代码到服务器了。
方法2: 如果你想完全地覆盖本地的代码,只保留服务器端代码,则直接回退到上一个版本,再进行pull:
1 | git reset --hard |
git push时遇到的错误
fatal: You are not currently on a branch
首先描述一下发生了什么:今天在学校本想开始写课题时,打开仓库发现前一次在家里用的PC写的代码没有同步到本地笔记本电脑上。想着无所谓先在本地笔记本电脑上写,写完上传回家同步一下就行了。晚上回到家用家里的PCgit push
的时候,发现在学校写的东西并没有同步过来。
看了git graph后发现,本地笔记本电脑上git push
以后,本地的master(HEADS)
跟远程的origin master
是分离的。
考虑了一下打算不采用风险较大的git push origin HEAD:master --force
,而是采用了风险较小的解决方案:从分离的HEAD创建一个临时分支,然后将该分支合并到master.
1 | git branch temp-branch |
1 | git log --decorate --oneline --graph --all |
检查一下发现恢复正常了,家里的PCgit pull
之后也同步了代码。最后我把创建出来的temp-branch
分支删除了。这是我今天采用的解决办法。
在网上查询了还发现了其他解决方法:
git status
查看所有变化的文件, 把有改动的先删除 ps: 这个是从别的网站粘贴的, 个人觉得单纯删除不保险, 注意, 注意, 注意, 这里最好是将自己的项目 copy 一份到本地其他地方作为备份git checkout master
回到主分支 ps:这里说白了就是回退到 master 主分支上这次修改的内容会消失git pull
保证一下本地是最新代码
然后将备份的内容paste就好了.
其实最开始在学校发现代码没同步的时候应该git pull
一下的。然后继续写,写完上传也没啥问题。结果自己当时想用之前学过的命令乱搞导致了一些麻烦。解决了这个问题之后,也是很奇怪当时为啥没有git pull
于是查了一下bash history
发现确实输入过这个命令,因为终端关闭了自己也忘记当时是怎么回事了。还是感觉git真的太强大了而自己真的还差的很远很远。
Commit your changes or stash them before you can merge
You can’t merge with local modifications. Git protects you from losing potentially important changes.
You have three options:
- Commit the change using
1 | git commit -m "My message" |
- Stash it
Stashing acts as a stack, where you can push changes, and you pop them in reverse order.
To stash, type
1 | git stash |
Do the merge, and then pull the stash:
1 | git stash pop |
- Discard the local changes
using
1 | git reset --hard |
or
1 | git checkout -t -f remote/branch |
- Or: Discard local changes for a specific file
1 | git checkout filename |
git push: fatal: the remote end hung up unexpectedly
1 | git push -u gitea |
git上传时,由于文件太大git push报错,解决方法如下
新建文件~/docker/nginx-proxy/conf/client_max_body_size.conf
1 | client_max_body_size 10G; |
然后重启容器即可解决
git push: fatal: the remote end hung up unexpectedly
与上面报错类似,再上个问题解决的情况下,再次出现了类似问题,这个问题只在mac上出现,主机Windows从未出现
1 | git push |
暂时解决方案如下:
1 | sudo nano /private/etc/host |
然后执行code .git/config
:把url中的https改为http:
1 | git push |
这样可以暂时解决问题
工作使用git
项目经理:
- 项目经理搭建项目的框架
- 搭建完项目框架之后,项目经理吧项目框架代码放到服务器
普通员工:
- 在自己的电脑上,生成ssh公钥,然后把公钥给项目经理,项目经理把它添加到服务器上面
- 项目经理会给每个组员的项目代码的地址,组员把代码下载到自己的电脑上
- 创建本地的分支dev,在dev分支中进行每天的开发
- 每一个员工开发完自己的代码之后,都需要将代码发布远程的dev分支上
两个重要的分支:
Master
:用户保存发布的项目代码,eg. V1.0, V2.0Dev
:保存开发过程中的代码
git总结
- Workspace:工作区
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库)
- Remote:远程仓库
新建代码库
1 | # 在当前目录新建一个Git代码库 |
配置
Git的设置文件为.gitconfig
,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)
1 | # 显示当前的Git配置 |
增加/删除文件
1 | # 添加指定文件到暂存区 |
代码提交
1 | # 提交暂存区到仓库区 |
分支
1 | # 列出所有本地分支 |
标签
1 | # 列出所有tag |
查看信息
1 | # 显示有变更的文件 |
远程同步
1 | # 下载远程仓库的所有变动 |
撤销
1 | # 恢复暂存区的指定文件到工作区 |
git commit后,想撤销怎么办
git reset --soft HEAD^
:不删除工作空间改动代码,撤销commit,不撤销git add .
git reset --mixed HEAD^
:不删除工作空间改动代码,撤销commit,并且撤销git add . 操作,和 git reset HEAD^ 效果是一样的
git reset --hard HEAD^
:删除工作空间改动代码,撤销commit,撤销git add .
其他
1 | # 生成一个可供发布的压缩包 |
github相关
GPG keys
GPG的功能十分丰富,这里主要是用它来对Git中的commit进行签名验证,主要步骤如下:
- 生成自己的GPG密钥
- 关联GPG公钥与Github,Gitea账户
- 设置利用GPG私钥对commit进行签名
- 可选步骤:信任Github的GPG密钥
参考网站:
其他设备上的关联:
1 | gpg --export-secret-key -a > secretkey.asc |
然后在另一台机器import:
1 | gpg --import secretkey.asc |
1 | shred secretkey.asc && rm secretkey.asc |
import之后,还需要让Git知道签名所用的GPG密钥ID:
1 | git config --global user.signingkey {key_id} |
可以设置Git为每次commit自动要求签名:
1 | git config --global commit.gpgsign true |
此时如果 uid 后面显示 [ unknown]
的话,可以 gpg --edit-key tyokyo320@gmail.com
:
1 | gpg> trust |
1 | gpg> save |
保存即可
GPG keys 报错
若报错为error: gpg failed to sign the data
,但是查看后发现我的GPG key并没有过期,解决方案如下:
1 | echo 'test'|gpg --clearsign |
在 ~/.zshrc
中添加 export GPG_TTY=$TTY
,执行 gpgconf --kill gpg-agent
,然后再执行 echo 'test'|gpg --clearsign
,会有输入密码界面
1 | echo 'test'|gpg --clearsign |