【git】使用教程、经验、手册

官方教程

如果觉没有目录得看得难受,可以在这看:Pro git 2

速查

  1. commit前一定要先 pull

  2. 如果commit后,push时发现有内容没pull,那么要进行merge,校验完改动后生成一次merge commit。不想进行merge则用下列办法取消本地的commit,pull以后再提交

git reset --soft <index>
  1. 如果准备用 commit --amend 修改上一次commit,那先别push,如果已经push,则用 push --force。 最好是别用 commit --amend,而是另起commit

  2. 如果pull时,发现有人用过 commit --amend,那么只能强制覆盖本地。

git reset --hard origin/master



一、git介绍

从个人角度上来说,git可以干嘛?

  • 管理github等代码托管平台上的仓库,如果要做开源项目,必须要用到git,公司项目代码保存也是git或svn

  • 下载github代码,还是觉得下zip方便...

  • 版本控制,这才是git的正确用途,也是其初衷。比如你写代码,写着写着觉得写错了,想回到以前的某个状态,你再ctrl+Z得多麻烦,git就能帮你解决此问题



二、git安装&获取仓库

  • 安装好git第一步,设置自己的身份信息。Win10右键文件资源管理器即可调出git bash,使用的linux shell习惯
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
# 换行问题:
git config --global core.autocrlf input
# 密码永久保存(明文):
git config --global credential.helper store
# 查看信息
git config --list
# 将git commit默认的文本编辑器从nano改为vim
git config --global core.editor vim
  • 第二步,有代理就设置代理
# 设置
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy https://127.0.0.1:7890
# 查看
git config --global http.proxy
git config --global https.proxy
# 取消
git config --unset http.proxy
git config --unset https.proxy
  • 获取git仓库
# 本地建立仓库: 进入一个文件夹
git init  # 此文件夹就会被存放仓库

# 克隆(下载)远程仓库,会新建目录,后面可以再追加一个目录名用于重命名
git clone https://github.com/*/*  # https
git clone git@github.com:*/*      # ssh
git clone ssh://git@{ip|domain_name}:port/.../repositories.git
linux建议使用SSH,方便 push,而Windows使用https比较方便,后面<a href="#五、远程仓库">远程仓库时</a>会说



三、记录每次更新到仓库

3.1 追踪文件

git的文件有三种状态(位置): 已修改、暂存区、仓库

  • 一个新文件或一个仓库中的文件被修改,那它就处于已修改状态;

  • 使用 git add 命令可以追踪新文件、添加已修改文件到暂存区;

  • 最后使用 git commit -m “” 命令提交暂存区的文件到仓库,他默认需要一个注释,可以帮助你回忆你这次修改的内容,github也会显示此注释



3.2 查看文件状态

  • git status

    status 能显示未追踪的文件、新追踪还没commit的文件、已修改的文件等, -s 选项能查看简况

  • git diff

    diff 只能查看仓库中 被修改后 还未add的文件,它能查看文件内容做了哪些修改



3.3 提交文件到仓库

常规入库流程: add ——> commit -m

优点是能分批,把不同的文件打上不同的注释。shell中可以使用反斜杠 \ 来提交多行注释

如果不想多打一行 add * 命令,又没有新追踪文件,可以使用 commit -a -m ""

能提交所有被修改过的被追踪(仓库中)的文件,但是不推荐使用 -a,因为当你想要撤销操作的时候很麻烦



3.4 移除文件、取消跟踪、重命名和移动

删除文件的两种办法:

  • git rm ,再 commit

  • 如果直接在文件管理器删除了文件,又修改了被追踪的文件,最后 add ——> commit -m

    你会发现,用 status 查看,删除文件的这一步还是没被提交,解决方法是:

    文件资源管理器删除文件,再 commit -a -m ""

取消跟踪,即从仓库中删除记录,但仍将文件保留在硬盘上,后续记得加入.gitignore

  • git rm --cached

重命名和移动:

  • git mv ,不要使用文件资源管理器移动或重命名,git无法跟踪。git mv 其实是 rm + add



3.5 忽略追踪某些文件

如果不希望某些文件被追踪,可以新建 .gitignore 文件,用于存放忽略规则,当你将此文件追踪、提交后,规则就生效

当规则生效后,你不应当使用 add * ,它无法追踪任何文件。而应该使用 add .

忽略追踪规则的格式如下

  • 所有空行或者以#开头的行都会被 Git 忽略。

  • 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。

  • 匹配模式可以以(/)开头防止递归。

  • 匹配模式可以以(/)结尾指定目录。

  • 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。

glob即简化的正则表达式,让我们看看一些例子以方便理解:

# 忽略所有的 .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



3.6 不再更新已追踪的文件

如果文件已经被commit,那么.gitignore不会生效

应该使用

# 不再追踪某个文件
git update-index --skip-worktree <file>
# 恢复追踪某个文件
git update-index --no-skip-worktree <file>

这个只在本地生效



四、撤销操作、日志与版本回退

除非要回退某个文件到之前的某个版本,否则无需撤销操作,继续修改继续提交即可

4.1 回滚已修改文件

  • 当你的某个文件处于工作区时,如果你修改后觉得不妥,想撤销操作,回到最近一次提交的版本

    git checkout -- <file>

  • 当你的文件被add到暂存区,想要将其退回到工作区时

    git reset HEAD <file>

    git restore --staged <file> 文档里说的是reset,但是status提示的是restore 。参考

    没必要将文件退回到工作区,不commit,继续修改和add即可。除非要checkout



4.2 commit后的回滚、追加、修改

  • 查看git日志、提交历史

    git log commit后面一段很长的字符串为索引,(HEAD -> master)意思是HEAD是一个指针,他总指向最近一次提交

    用 -p 参数可以查看更仔细的日志,包含每次提交的改动细节

    用 -3 等数字可以限制只输出最近几次提交的日志,q 退出

  • 当你commit提交文件时遗漏了某些文件,或者注释有误

    下列命令会把暂存区的都提交进上一次commit,而且还可以用i来修改注释,:wq保存退出,git log查看日志

git commit --amend
# 简写
git commit --am
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend -m ""  # 会将暂存区文件提交,且两次提交只有一次记录,采用后者的注释
  • 当你commit、push提交的文件有误,你想撤销commit操作时

    • 简单安全的做法是修改后再次提交

    • 如果要回到上一次提交的版本,可以撤销commit操作,但这可能存在风险

git revert HEAD  
# HEAD 指向最近一次提交,你也可以通过log获取索引来撤销之前的某次commit
# 会生成一次 commit 日志
# :q 返回终端
git push origin master
  • git reset 撤销编辑、撤销提交

    首先我们要了解Git 保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照。如下图

    此时本地仓库对应的是commit4,git reset 可以让本地仓库对应的指针变为commit3或是commit1等之前的版本,当然,也可以变为commit4之后的某个commit,如commit5

    Git 的分支,其实本质上仅仅是指向提交对象的可变指针。参考

    • git reset --hard HEAD 将暂存区、工作区中的内容恢复成上一次提交的版本(快照),换句话说你没commit的内容都会被擦除。如果你刚commit,想撤销这次commit,那么可以把HEAD换成其它索引(危险!会丢失工作内容,建议采取下面的--soft)

    • git reset --soft <index> 将HEAD指向指定的索引,即回退到某个版本,假设从4回到3,那么3往后的操作会被放到暂存区。参考

    reset和分支有关,如果操作后无法push,可以使用 -f 强制push



五、远程仓库

创建仓库后,使用clone即可将仓库克隆到本地,后续还能使用pull

但是push需要身份验证

Windows会直接跳转网页要求认证,后续无需认证。使用https比较方便,而且Windows挂梯子扶墙也比较容易

Linux建议使用SSH链接,使用https链接每次都需要输入账号密码,或需要配置文件,而且https会被墙,相比之下ssh就能流畅访问

linux使用ssh连接github步骤

  • 生成ssh密钥
ssh-keygen # 生成ssh key,默认即可,一直回车,最后会生成一对公钥和私钥文件
# -t 指定密钥类型,默认是 rsa ,可以省略。
# -C 设置注释文字,比如邮箱。

cat /root/.ssh/id_rsa.pub # 将公钥内容复制
  • github添加公钥

    登录 GitHub,打开 Personal settings 页面,选择 SSH and GPG keys 选项添加

  • 测试

    ssh -T git@github.com

如果之前 clone 了 https 的链接,导致origin是https的,更改origin的方法是:

# 查看远程仓库地址
git remote -v
# 删除
git remote rm origin
# 添加
git remote add origin [url]



六、分支 & 远程分支

# 查看本地分支
git branch  # -a 查看所有分支,包括远程
# 切换分支
git checkout branch_name

当前分支有修改未commit时无法切换分支,要么commit,要么checkout文件到之前提交的状态

# 新建分支,带有主分支(当前分支)的commit历史
git checkout -b new_branch_name

# 从远程仓库下拉新分支
git checkout -b new_branch_name origin/branch_name
# 新建空白分支
git checkout --orphan emptybranch
# 此时分支中有主分支的所有文件,且都在暂存区
# 此时分支还看不到,需要commit后才能看到新分支
git rm -rf .
echo 1 > readme.md
git add .
git commit -m 'new branch'
# 提交新分支到远程仓库,正常提交
git push origin new_branch_name
# 删除本地分支
git branch -d branch_name
# 删除远程分支
git push --delete origin branch_name

# 重命名本地分支
git branch -m branch_name new_branch_name

重命名远程分支:先删除,再推送一个新的上去



七、子模块-嵌套git项目

如果想在主项目中使用某个子项目,应该使用git submodule

如果你直接在主项目中克隆子项目,不删除子项目的.git文件夹的话,你没法把这个改动commit

如果你删除了子项目的.git文件夹,你没法再从上游更新子项目,当这个子项目不是你创建、维护的话,这很尴尬,子项目没法做版本控制



7.1 在项目中新建submodule

从远程拉取一个子项目到主项目

git submodule add <url>
git commit -m 'add submodule'
# git push origin master

对本地来说,运行git submodule add,会自动把子项目的代码克隆到本地,并且在主项目创建.gitmodules文件

但是注意:当你push主项目时,子项目的代码不会被push,只会 push .gitmodules 文件,以及空的子模块文件夹

在GitHub中,如果子模块来自于GitHub,那么点击可以跳转到相应项目,否则无法点击



7.2 更新submodule到最新版本

# 更新子模块
cd <submodule>
git pull

# 或者
git submodule update --remote <submodule>



7.3 clone一个含submodule的项目

git clone --recurse-submodules <url>
git clone <url>
# 这时submodule文件夹内为空
git submodule update --init
# 这时更新子模块



7.4 嵌套的设计理念

有时可能会觉得submodule的设计略有不便,比如我就想直接嵌套一个git项目,其中的代码就要被我copy在主项目中,即使是主项目的远程仓库也要有copy

我想更新子项目就更新,对方删库了也不影响我

但是抱歉,git并不能直接实现上述目的

目前能做到的是,fork一份要用到的目标子项目,再引用你fork的项目,这样即使对方删库,也不影响你,想更新就同步你的fork仓库

git嵌套的设计理念我认为就是单独管理主项目和子项目,主项目中引用子模块就只能引入和从远程更新本地代码,即使你修改了子项目的代码,也是推到子项目的远程仓库中

也就是说,主项目不关心子模块内部的改动.gitmodules中就记录一个名字和url,

而对于下列需求十分不友好,因为它就不是这样设计的:

在修改子模块代码并让主项目记录这一修改



7.5 嵌套与远程仓库

前面说过:当你push主项目时,子项目的代码不会被push,只会 push .gitmodules 文件,以及空的子模块文件夹

虽然 .gitmodules 文件中只有名字path和url,但实际上,git会记住你使用的submodule的版本

只要你未执行git submodule update --remote,就未更新你submodule的版本,即使被引用的项目有更新版本

当你重新 clone 你的主项目时(submodule也被clone),其中的submodule还会停留在你之前设定的版本



八、搭建git服务器,创建私人远程仓库

如果觉得GitHub访问慢,或者过于私人代码不想放海外,不想放别人的仓库中,即使是GitHub私人仓库(Copilot能忽略License用所有公有代码来训练,谁知道会不会窃取私有仓库,虽然大多数人的代码也没太大价值😏)

那么想在家里和公司同步一些个人的项目,可以选择使用公网服务器搭建私人仓库

其实所谓的git服务器,并不需要像web服务器那样运行一个后台软件,它的构成是git客户端+ssh服务,本地通过ssh连接后,通过git命令来推拉远程仓库

如果想像GitHub那样有web可视化管理,可以选择安装gitlib、gogs、gitea,但是需要安装数据库之类的,而且web和ssh+git的设计理念不同,web是代码托管,你无需考虑服务器内部的样子,事实上你的代码在服务器内部并不是按原本的结构存储。而ssh+git服务器上的目录、文件和你本地是一模一样的。

这里示范前者,git客户端+ssh服务,无web,通过ssh连接,而不能像GitHub那样支持https

本人的服务器是Rocky Linux 8,首先服务器确保已经安装了git,使用git --version检查

接着是配置git,参考官方文档



8.1 创建用户

groupadd git
useradd git -g git -d /home/git -s /usr/bin/git-shell

创建用户组git,创建用户git,指定用户组git,home目录为/home/git,指定shell为git-shell,这是一个受限的shell工具,方便将用户 git 的活动限制在与 Git 相关的范围内,提高安全性,但是就无法使用git用户ssh登录,以及su git了。



8.2 配置ssh,开启RSA认证

vi /etc/ssh/sshd_config

确保其中有这几项

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

意思是允许通过密钥登录,本地电脑中必须生成密钥对,想要登录的远程主机的目标用户的home目录下的.ssh/authorized_keys文件中必须保存着本地ssh密钥对的公钥,每行保存一个,可供多个机器远程登录



8.3 本地生成ssh密钥,上传远程服务器

在本地机器上,如是Windows,呼出gitbash

cd ~
# 检查,如果没有id_rsa id_rsa.pub
ls -la .ssh
# 生成
ssh-keygen -t rsa -C "xxx@xxxmail.com"
# 回车回车回车
# 检查
ls -la .ssh
cat .ssh/id_rsa.pub

拷贝公钥内容,粘贴到远程服务器的/home/git/.ssh/authorized_keys中去



8.4 创建远程仓库

目前不知道怎么在没有远程仓库的情况下,直接推本地仓库到远程服务器并进行创建仓库操作

目前只能先在远程中创建,然后再把本地的推上去

新远程仓库:

# 因为不能su git,所以得分几步
cd /home/git
# 创建名为xxx的仓库,Linux下目录名为xxx.git,clone到Windows文件夹名为xxx
git init --bare xxx.git
chown -R git:git !$

# 也可以用下面的,一句话,用git用户创建
su -s /bin/bash -c "git init --bare /home/git/xxx.git" git

可以整理成脚本链接到环境变量中

#!/bin/bash
su -s /bin/bash -c "git init --bare /home/git/$1" git

chmod +x gitinit && ln -s /root/gitinit /usr/bin/gitinit

本地克隆:

git clone git@192.168.1.66:java-mvel-ctf.git
# 如果不是22端口
git clone ssh://git@{ip|domain_name}:port/home/git/repositories.git

如果本地已有仓库,设置远程地址:git remote add origin git@192.168.3.60:git-test.git



九、标签 tag

一个版本可以有多个标签,GitHub上每个标签都能发布一个release

本地标签操作

# 在当前分支版本打标签
git tag <tagName>
# 列出所有标签
git tag -l
# 删除标签
git tag -d <tagName>

远程标签操作

pull默认不拉取标签

# 拉取标签
git pull --tags
# 推送标签
git pull <origin> <master> --tags <tagName>
# 删除远程标签
git push origin :v1.0

删除远程标签也可以用git push --delete origin <tagName>,但是不推荐,因为会误删分支



十、换行符

Linux下换行符为LF,即\n,Windows下为CRLC,即\r\n

推荐git仓库中都为LF,从使用上来说,Windows中\n不会报错和影响显示,但是Linux中\r\n会影响显示以及可能报错

可以配置git

git config --global core.autocrlf input  

input提交时转换为LF,检出时不转换

还有选项true,提交时转换为LF,检出时转换为CRLF;false提交检出均不转换

也可以通过在仓库中用.gitattributes文件配置



十一、取消缓存用户密码

当我们切换GitHub用户时,遇到这个问题

管理员身份运行

git config --global --unset credential.helper

即可,后续只需更改~/.gitconfig中的credential.helper即可



posted @ 2021-06-08 16:51  云牧青  阅读(143)  评论(0编辑  收藏  举报