• git基础使用


    Git版本控制

    安装与概述

    安装

    # ubuntu
    sudo apt-get update
    sudo apt-get install git
    
    # mac
    brew install git
    

    Git本地仓库

    - Directory:根目录,由Git管理的一个目录,包含我们的工作区和Git仓库信息。
    - Workspace:工作区,即项目的根目录,但不包括.git目录。
    - .git: Git版本库目录,保存了所有的版本信息。该目录会由git初始化仓库的时自动生成。
    - Index/Stage(阶段;舞台): 暂存区,工作区变更,先提交到暂存区,再从暂存区提交到本地仓库。
    - Local Repo: 本地仓库,保存了项目所有历史变更版本。
      	- HEAD指针: 表示工作区当前版本,HEAD指向哪个版本,当前工作区就是哪个版本;通过HEAD指针,可以实现版本回退。
    - Stash(存放;贮藏): 工作状态保存栈,用于保存和恢复工作区的临时工作状态(代码状态)。
    

    创建查看

    初始

    cd existing_folder
    git init
    

    查看

    查看状态

    git status  # 显示工作区状态
    git status -s # 显示缩略信息
    

    查看日志

    git log  # 产看历史版本的所有信息(包括用户名和日期)
    git log --graph --pretty=oneline  # 用带参数的git log,输出的信息会短一些
    
    git log --oneline  # 美化后的日志输出
    git log --stat  # 产看提交的简略统计信息
    
    git log -p -2  # 查看最近2次提交的引入差异
    git log --since="2021-01-01" --until="2021-06-06" # 查看一段儿时间的日志
    
    git reflog (HEAD@{移动到当前版本需要多少步})
    
    # 搜索
    git log -S ZLIB_BUF_MAX --oneline  # 想找到ZLIB_BUF_MAX常量是什么时候引入的,-S选项来显示新增和删除该字符串的提交
    git log -L :git_deflate_bound:zlib.c  # 想查看zlib.c文件中git_deflate_bound函数的每一次变更        
    

    查看差异

    git diff [文件名]  # 将工作区中的文件和暂存区的进行比较
    git diff [本地库历史版本] [文件名]  # 将工作区中的文件和本地库历史记录比较,不带文件名的话,会比较多个文件
    git diff  # 查看当前与暂存区之间的文件差异
    git diff --staged  # 查看已暂存与最后一次提交的文件差异
    
    # 说明:
    # 减号表示: 本地仓库的代码
    # 加号表示: 工作区的代码
    

    查看其他

    git show		# 显示各种类型的对象
    
    git blame filename   # 查看每一行的修改人以及commit-id
    git show commit-id   # 查看详细的修改提交记录
    

    搜索

    # 很方便地从提交历史、工作目录、甚至索引中查找一个字符串或者正则表达式。
    
    git grep -n gmtime_r  # 查找工作目录的文件,-n选项数来输出 Git 找到的匹配行的行号
    git grep -c gmtime_r  # 不想打印所有匹配的项,-c或--count选项输出概述的信息, 其中仅包括那些包含匹配字符串的文件,以及每个文件中包含了多少个匹配
    git grep -p gmtime_r *.c  # 关心搜索字符串的上下文,-p或--show-function选项来显示每一个匹配的字符串所在的方法或函数
    

    定位bug提交

     # 启动二分法查找
    git bisect start 
    
    # 告诉git当前commit是good/bad,git会自动调整到二分处理范围的那个commit
    git bisect bad  # 告诉系统当前所在的提交是有问题的
    git bisect good <good_commit>	# 告诉系统已知的最后一次正常状态是哪次提交
    # git会发现在good和bad之间检出中间的提交,此时执行测试,查看问题是否还存在
    # 若不存在问题,说明问题在这个提交之后,告诉git,然后git会继续寻找
    git bisect good
    # 若存在问题,说明问题这个提交及之前,git会继续缩小范围
    git bisect bad
    # 直到缩减范围至一个good与bad紧挨时可以确定产生bad的commit
    
    # 重置HEAD指针到最开始的位置
    git bisect reset
    

    管理修改

    修改

    • 添加
    git add path1  # 添加文件内容至索引
    git add .  	# 添加所有变动的文件至索引
    
    • 移动
    git mv file_from file_to # 移动或重命名一个文件、目录或符号链接
    
    • 删除
    git rm 	文件	# 从工作区和索引中删除文件
    git branch -d 分支名  # 删除一个已合并的分支(非当前分支)
    git branch -D 分支名  # 强行删除分支(未合并则丢失修改)
    
    git clean  # 去除冗余文件或清理工作目录
    git clean -f -d  # 移除工作目录中所有未追踪的文件已经空的子目录
    
    • 记录
    git commit -m '修改注释'    # 记录变更到仓库
    git commit --amend  # 若是上次commit后未push,直接使用则修改注释重新提交,添加其他文件使用则合并上次的commit使用这次的注释
    git reset --soft HEAD^  # 撤销上次commit,不撤销add,再次commit时作用等同amend
    

    注意事项

    使用commit命令,漏写参数 -m 选项,则git会默认使用GNU Nano的编缉器打开 .git/COMMIT_EDITMSG 文件。可做两种处理方式:

    - 第1种: 可以按 ctrl+x 退出即可, 然后再重新执行 git commit并指定 -m 选项提交代码
    - 第2种: 在打开的Nano编缉器中输入提交的注释说明, 再按 ctrl + o 保存, 接着按回车确认文件名, 最后再按ctrl + x退出, 回去之后,git就会提交之前的代码了。
    
    • 标记
    git tag						# 查看标签
    
    git tag -a tag-name -m tag-info  # 创建附注标签
    git tag -a tag_name commit-id  # 对以往的记录进行标签
    
    git tag tag-name  			# 创建轻量标签/查看标签内容
    git tag tag-name commit-id  # 对以往的记录进行标签 
    
    git pull --tags  			# 拉取所有标签
    
    git push origin tag-name 	# 推送某个标签
    git push --tags			 	# 推送所有标签
    
    git tag -d tage-name		# 删除本地标签
    git push origin :refs/tags/tag-name  # 删除远程标签
    
    git checkout tag-name  # 签出标签指向的版本
    

    回退

    git log  # 查看历史提交版本,只能看到当前版本之前的版本
    git reflog  # 查看所有的历史版本
    
    # 工作区回退到某个版本
    git reset --hard <commit版本号>
    选项说明:
    hard  重置: 本地仓库HEAD指针、暂存区、工作区
    mixed 重置: 本地仓库HEAD指针、暂存区  【默认值】
    soft  重置: 本地仓库HEAD指针
    
    # 例子
    git reset --soft HEAD^  # 撤销上次commit,不撤销add
    git reset --hard <commit-id>  # 撤销上次commit的内容
    git reset --hard HEAD^		# 后退1步(一个^表示后退一步)
    git reset --hard HEAD^^		# 回退到上上个版本
    git reset --hard HEAD~2		# 后退2步(~后的数字n是后退n步)
    git push -f  # 强制提交
    

    撤销

    # 场景1: 改乱了工作区的代码,想撤销工作区的代码修改
    git checkout -- <file>  # 撤销指定文件的修改
    git checkout -- .		# 撤销当前目录下所有修改
    
    # 说明:git checkout会用本地仓库中的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。 
    
    # 场景2: 改乱了工作区的代码,提交到了暂存区,同时撤销工作区和暂存区修改:
    # 方法一: 
    # 撤销暂存区修改
    git reset HEAD <file>     # 撤销暂存区指定文件的修改
    git reset HEAD            # 撤销暂存区所有修改
    # 撤销工作区的代码修改
    git checkout -- <file>    # 撤销指定文件的修改
    git checkout -- .		  # 撤销当前目录下所有修改
    # 方法二:
    # 同时撤销暂存区和工作区的修改:
    git reset --hard HEAD
    

    分支管理

    常用分支

    - master 主分支: 该分支是非常稳定的,仅用来发布新版本,不会提交开发代码到这里
    - develop 开发分支: 不稳定的,团队成员都把各自代码提交到这里。当需要发布一个新版本,经测试通过后,把dev分支合并到master分支上, 作为一个稳定版本,比如v1.0
    - featrue 功能分支: 团队每个人负责不同的功能,分别有各的分支,在各自的分支中干活,适当的时候往 dev开发分支合并代码。
    

    查看

    git branch -a			# 所有分支
    
    git branch  			# 本地分支, 当前分支有*
    git branch -v 		# 查看每个分支的最后一次提交
    git branch --merged # 查看已经合并到当前分支的分支
    git branch --no-merged # 查看尚未合并到当前分支的分支
    
    git branch -r  		# 远程分支
    git remote show origin  # 查看远程分支详细情况
    
    

    切换

    git branch dev	   	# 创建分支 (开发分支)
    git checkout dev   	# 切换本地已存在的分支f1
    # 创建+切换
    git checkout -b dev # 创建+切换分支
    git branch --set-upstream-to=origin/develop dev  # 追踪分支
    # 创建+切换+远程
    git checkout -b f1 origin/f1  # 跟踪拉去远程分支f1,在本地起名为f1,并切换至分支f1
    

    合并

    先合并后解决冲突

    指令

    git checkout master  # 切换至要合并到的分支master
    git merge develop  # 合并需要合并的分支到当前分支
    # ---有冲突时,解决冲突
    git status  # 查看冲突文件
    git add .
    git commit -m 'merge ...'
    # ---完成合并
    git push master
    

    说明

    # 步骤
    1.找到要合并的分支develop和当前分支master最近的共同祖先commit点
    2.若是这个点不是当前分支master最新的点,则会把当前分支masteer的最新的commit和要合并分支develop的最新的commit合并为一个新的commit,若有冲突,则需要解决冲突,提交解决冲突
    3.将以上共同祖先commit点后的所有提交点,按照提交时间(不是push时间)的先后顺序依次放到master分支上
    
    # 优缺点
    优点:操作简单,按照提交时间排序,提交点完整。
    缺点:节点过多,在主分支上有无明确意义节点(自动生成的merge记录),呈现非整条线性直线的关系。
    
    # 应用场景
    对公共仓库代码合并处理时使用
    在主分支进行冲突解决
    

    变基

    指令

    git checkout develop
    git rebase master 
    # ---有冲突,则解决冲突,提交记录
    git add .
    git commit -m 'merge...' 
    git rebase --continue
    # -----
    git push develop  # 更新远程仓库引用位置
    git checkout master
    git merge develop
    git push master
    

    说明

    # 步骤
    1.找到这两个分支(即当前分支develop和变基操作的目标基底分支master) 的最近共同祖先commitId
    2.对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件(patch)(这些补丁放到".git/rebase"目录中)
    3.将当前分支指向目标master分支最新commit, 最后以此将之前另存为临时文件的修改依序应用。 
    4.回到master分支,进行一次快进合并。
    
    # 优缺点
    优点:可以对某一段线性提交历史进行编辑、删除、复制、粘贴,提交历史干净简洁,形成线性提交历史。
    缺点:如果变基中要打散的提交被其他人正在开发,则会在此次变基提交后,其他人提送代码时需要合并此次变基操作,同时自己在变基后推送代码也需要合并他人的处理,造成工作繁琐且记录中有多条重复记录,造成混乱。
    
    摘录来自: Scott Chacon. “Pro Git。” Apple Books. 
    
    摘录来自: Scott Chacon. “Pro Git。” Apple Books. 
    
    # 应用场景
    合并未推送的本地修改分支至公共分支时
    在子分支进行冲突解决,注意适用于其他人没有使用变基中要改变的提交进行开发
    

    更详细指令

    git rebase -i  [startpoint]  [endpoint]
    
    # 参数
    -i:是--interactive,即弹出交互式的界面让用户编辑完成合并操作
    [startpoint] [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。
    # 交互指令
    pick:正常选中,保留该commit(缩写:p)
    reword:选中,保留该commit,但要修改该commit的注释(缩写:r)
    edit:选中,保留该commit, rebase时会暂停,允许修改这个commit(缩写:e)
    squash:选中,会将当前commit与上一个commit合并,(缩写:s)
    fixup:与squash相同,但不会保存当前commit的提交信息(缩写:f)
    exec:执行其他shell命令(缩写:x)
    drop:丢弃该commit(缩写:d)
    

    合并多个commit为一个完整commit

    # 查看提交历史
    git log
    # 对commit进行rebase操作
    git rebase -i HEAD~4  # 最近的4个进行处理
    git rebase -i commitId  # 对commitId后的所有commit进行处理
    # 对弹窗commands处理
    p/r/e/s/f/x/d
    # 编辑后保存退出,git 会自动压缩提交历史,
    wq
    # 如果有冲突,记得解决冲突后,使用 
    git rebase --continue # 重新回到当前的 git 压缩过程;
    git rebase --abort		# 放弃压缩命令
    # 推送到远程仓库
    git push -f
    

    将某一段commit粘贴到另一个分支

    git rebase [startpoint] [endpoint]  --onto [branchName]
    
    # 对要合并分支处理rebase
    git checkout develop
    git rebase  90bc0045b^ 5de0da9f2 --onto master
    git log  # 最新commit为0c72e64...
    git status  # 当前HEAD处于游离状态,指向内容正确但是master分支未改变,需要将master指向需最新commit
    # 对master处理
    git checkout master
    git reset --hard  0c72e64
    

    删除

    # 删除一个已合并的分支,注意,无法删除当前所在的分支,需要切换到其它分支,才能删除
    git branch -d 分支名
    
    # 如果分支还没有被合并,删除分支将会丢失修改。如果要强行删除,需要使用如下命令:
    git branch -D 分支名
    

    暂存

    # 保存
    git stash   		# 不添加备注
    git stash save demo # 添加备注,仅为了区分显示
    # 查看
    git stash list  # 查看stash了哪些存储
    git stash show # 显示做了哪些改动,默认show第一个存储stash@{0},显示其他存贮,后面加stash@{$num}
    git stash show -p # 显示第一个存储的改动,如果想显示其他存存储,命令:git stash show  stash@{$num}  -p 
    
    # 恢复
    git stash apply   # 应用某个存储,但不会把存储从存储列表中删除,默认使用第一个存储,即stash@{0},如果要使用其他个,git stash apply stash@{$num} 
    git stash pop  # 恢复之前缓存的工作目录,将缓存堆栈中的对应stash删除,并将对应修改应用到当前的工作目录下,默认为第一个stash,即stash@{0},如果要应用并删除其他stash,git stash pop stash@{$num} 
    
    # 删除
    git stash drop stash@{$num} # 丢弃stash@{$num}存储,从列表中删除这个存储
    git stash clear # 删除所有缓存的stash
    
    # 从贮藏创建一个分支
    git stash branch testchanges  # 以指定的分支名创建一个新分支,检出贮藏工作时所在的提交,重新在那应用工作,然后在应用成功后丢弃贮藏
    

    远程仓库

    SSH

    Git通信协议

    Git支持多种协议,包括SSH, https协议
    
    使用ssh协议速度快,一次配置无扰使用
    使用https速度较慢,而且每次通过终端上传代码到远程仓库时,都必须输入账号密码
    

    配置SSH密钥对

    # 查看秘钥对(.ssh)
    cd ~/.ssh/
    
    # 创建
    # 三次回车,生成.ssh目录,id_rsa (私钥)和id_rsa.pub (公钥)
    ssh-keygen -t rsa -C youremail@example.com
           
    # 查看id_rsa.pub公钥
    cat ~/.ssh/id_rsa.pub
        
    # 配置到远程仓库的后台ssh
    
    # 验证是否配置成功
    ssh -T git@github.com
    # 第一次,需要输入“yes”, 若返回类似 “Hi islet1010! You've successfully authenticated”,则配置成功。
    

    签名

    # 设置系统级别签名
    git config --global user.name [AAA]
    git config --global user.email [邮箱地址]
    cat .gitconfig
    
    # 查看全局设置
    git config --global --list 				
    
    # 取消全局配置
    git config --global --unset user.name	
    git config --global --unset user.email
    
    # 项目级别签名
    cd 项目文件夹
    git config user.name [AAA]
    git config user.email [邮箱地址]
    cat .git/config
    

    关联

    新建仓库

    git clone xxx  # xxx表示地址
    touch README.md
    git add README.md
    git commit -m "add README"
    git push -u origin master
    

    已存在的文件

    cd existing_folder
    git init
    git remote add origin xxx  # xxx表示地址
    git add .
    git commit -m "Initial commit"
    git push -u origin master
    

    已存在仓库

    cd existing_repo
    git remote rename origin old-origin
    git remote add origin xxx  # xxx表示地址
    git push -u origin --all
    git push -u origin --tags
    
    • 一份代码多个仓库

    多关联,即拉取也推送

    # 方法一:需要push两次,但是优点是可以pull两次
    git remote add origin2 地址2  # 在gitA项目中添加另一个gitB远程的地址,origin2可以自定义
    git pull origin2 master --allow-unrelated-histories   # 先拉取gitB地址上的数据,allow-unrelated-histories是为了解决冲突
    git push origin2 master  # 在gitA项目中把项目内容同步到gitB地址中
    # --实现推送--
    git push origin  master 
    git push origin2 master
    # --删除--
    git remote -v  // 查看此时的包括两个远程地址
    git remote rm origin2  // 删除gitB的远程地址
    git remote -v  //此时应该只有gitA的远程地址
    

    多推送,一拉取

    # 方法二:push一次,注意备用库中不能改主库中相同代码,避免冲突无法推送
    git remote set-url --add origin 地址   # 给origin添加一个远程push地址,这样一次push就能同时push到两个地址上面
    git remote -v # 查看是否多了一条push地址(这个可不执行)
    git push origin master -f    # 一份代码就可以提交到两个git仓库上了,如果第一次推不上去代码,可以使用强推的方式
    # --实现推送--
    git push
    # --删除--
    git remote set-url --delete origin 地址
    

    随意配置

    # 方法三:直接修改.git/config
    
    # 默认
    [remote "origin"]
    	url = 地址
    	fetch = +refs/heads/*:refs/remotes/origin/*
    
    # 多推送,多拉取
    [remote "origin"]
    	url = 地址
    	fetch = +refs/heads/*:refs/remotes/origin/*
    [remote "origin2"]
        url = 地址
        fetch = +refs/heads/*:refs/remotes/origin2/*
    
    # 多推送,一拉取
    [remote "origin"]
    	url = 地址
    	fetch = +refs/heads/*:refs/remotes/origin/*
    	url = 地址2	
    

    协同

    操作远程

    git remote show origin  # 查看远程分支情况
    git remote update  # 更新本地追踪显示的远程分支
    
    git remote prune origin --dry-run  # 查看远程哪些分支需要清理
    git remote prune origin		# 清除无效的远程追踪分支
    
    git remote rename pb paul  # 修改远程仓库pb为paul
    git remote remove paul  # 删除远程仓库paul
    

    远程->本地

    git fetch origin master  # 从远程获取最新版本,不会自动合并或修改当前的工作
    git log -p master..origin/master  # 比对本地master分支和origin/master分支区别
    git merge origin/master  # 对本地仓库的master和origin/master进行合并
    
    git pull origin master # 从远程获取最新版本,自动合并远程分支到到当前的工作
    git pull --rebase  # 把你的本地当前分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把本地当前分支更新为最新的"origin"分支,最后把保存的这些补丁应用到本地当前分支上。
    

    本地->远程

    # 查看本地记录的远程信息
    git remote -v  # 查看远程配置
    
    # 远程有此分支
    git checkout -b f1 origin/f1  # 跟踪拉去远程分支f1,在本地起名为f1,并切换至分支f1
    git branch --set-upstream-to=origin/develop dev  # 本地分支与远程分支未建立关联,需要先建立本地与远程分支的链接关系再拉取
    
    # 远程无此分支
    git push --set-upstream origin f1  # 若远程不存在此分支,创建新的远程分支,方法一:追踪push和pull
    git puh origin f1  # 方法二,只追踪push
    
    git push  		# 推送本地代码,更新远程引用和相关对象
    
    git push --force  # 强制本地覆盖远程
    
    git push origin --delete serverfix  # 本地推送删除远程分支(服务器会暂存一段儿时间待垃圾回收,故异常删除时可恢复)
    

    忽略

    本地远程

    • 概述

    .gitignore文件提供了可以忽略提交的文件配置,同时此文件会提交到git仓库中,会影响其他人。

    GitHub的示例配置文件:https://github.com/github/gitignore

    • 忽略规则:

    在git中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .gitignore 文件的方法。

    # 此为注释 – 将被 Git 忽略
    *.sample    # 忽略所有.sample 结尾的文件
    !lib.sample    # 但 lib.sample 除外
    /TODO    # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
    build/    # 忽略 build/ 目录下的所有文件
    doc/*.txt   # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
    
    • 规则不生效的解决办法

    把某些目录或文件加入忽略规则,按照上述方法定义后发现并未生效,原因是.gitignore只能忽略那些原来没有被追踪的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。那么解决方法就是先把本地缓存删除(改变成未被追踪状态),然后再提交:

    git rm -r --cached .
    git add .
    git commit -m 'update .gitignore'
    

    只本地

    .git/info/exclude 设置你自己本地需要排除的文件。不会提交到版本库中去,所以不会影响他人。

    # 进入/创建文件进行编辑
    vim .git/info/exclude
    # 输入忽略内容
    *.sample    # 忽略所有.sample 结尾的文件
    !lib.sample    # 但 lib.sample 除外
    /TODO    # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
    build/    # 忽略 build/ 目录下的所有文件
    doc/*.txt   # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
    
  • 相关阅读:
    Codeforces 722C. Destroying Array
    Codeforces 722D. Generating Sets
    【BZOJ】3436: 小K的农场
    数论四·扩展欧几里德
    数论三·约瑟夫问题
    数论二·Eular质数筛法
    #1287 : 数论一·Miller-Rabin质数测试
    树的维护
    可持久化线段树
    【NOIP2016】天天爱跑步
  • 原文地址:https://www.cnblogs.com/fhkankan/p/15064596.html
Copyright © 2020-2023  润新知