Git的几个基础概念

  1. 工作区(working tree)
    git代码库文件夹里当前在文件系统里能看到的内容.

  2. 暂存区(index or stage)
    保存在.git文件夹中
    add时就是把工作区的文件添加到暂存区,多次add会覆盖之前的add,最终commit时为最终add的内容

    每次add实际上git也是有记录的,但不像commit后那样细致,若丢失了文件也可以尝试找回.
    未add的内容发生丢失通过git无法找回.

  3. 本地仓库(repository)
    保存在.git文件夹中,仓库中保存每次commit的具体内容

  4. 远程仓库(remote)
    一般指托管在互联网或其他网络中的某个git仓库的版本库,比如Github
    通过网络即可经过远程仓库同步不同本地仓库的内容.
    关联单个远程仓库时,远程仓库默认名称是origin.
    可以有多个远程仓库,使用多个远程库时,需要用不同的名称来标识不同的远程库

.gitignore 文件

把要忽略的文件名或文件夹填进去,Git就会自动忽略这些文件和文件夹..gitignore模板

git常用命令

代词解释

后续命令介绍中出现这些代词都是需要使用实际情况中的内容进行替换,其他一般都是命令本身的内容

  1. xxx 指需要自己自定义输入的指定内容
  2. url 远程仓库的url
  3. gitCmd 代指git命令,比如add log commit等都是gitCmd
  4. file 需要操作的文件相对于.git所在位置的相对路径
  5. folderName 文件夹名称
  6. commitId commit操作后由git生成的id
  7. branchName 分支名称,主分支自动创建为master 其他分支由自己创建时命名.在git中HEAD表示当前所在的分支.
    如果出现在remoteName/后肯定是指远程分支名称
  8. localBranchName 本地分支名称,在易混淆时特别注明
  9. remoteName 远程仓库名称,未配置时默认为origin
  10. remoteBranchName 远程分支名称,在易混淆时特别注明
  11. tagName 标签名称
  12. eg: exempligratia 举例

1.代码库初始化、获取代码库

# 将当前所在目录初始化为git代码库 
git init

# 新建一个文件夹并将其初始化为git代码库
git init folderName

# 下载对应项目和它的整个代码历史,生成的文件夹与项目同名
# git clone url

# 下载对应项目的内容到指定文件夹中
git clone url folderName

# 下载指定分支
git clone -b branchName url

clone默认会把远程仓库整个下载下来,但只会在本地默认创建一个master分支
切换到别的分支需要在本地进行创建分支并关联到远程分支后进行同步.
git pull remoteName remoteBranchName:newLocalBranchName一步完成

clone支持HTTP(s)、SSH、Git、本地文件协议、ftp(s)、rsync等多种协议.
通常来说,Git协议下载速度最快,SSH协议用于需要用户认证的场合.
某些只开放http端口的内部网络无法使用ssh协议而只能用http(s).
clone后会记录首次使用的协议并用于后续,需要修改可到.git目录下的config文件中对url后的内容进行修改.

2.配置

–global 代表配置当前用户的全局配置,配置文件放在用户主目录下.gitconfig中
–system 系统中对所有用户都普遍适用的配置,windows在Git的安装目录下的mingw64/etc/gitconfig,一般没有修改权限,linux在/etc/gitconfig
都不加代表只配置当前git仓库,配置文件放置在.git/config

# 查看config相关的命令
git config

# 显示当前的Git配置
git config --list

# 编辑Git配置文件,默认vim
git config -e

# 设置提交代码时的用户信息
git config user.name "xxx"
git config user.email "xxx@xxx.xxx"

# 设置http(s)代理
git config http.proxy http://ip:port
git config https.proxy https://ip:port

# 配置socks5代理
git config http.proxy socks5://ip:port
git config https.proxy socks5://ip:port

# 设置对应网站
git config http.https://github.com.proxy https://ip:port
git config https.https://github.com.proxy https://ip:port
git config http.https://github.com.proxy socks5://ip:port
git config https.https://github.com.proxy socks5://ip:port

# 取消http(s)代理
git config --unset http.proxy
git config --unset https.proxy

# 设置换行符是否自动转换 true会在提交文件时自动将CRLF转换为LF 在获取文件时自动将LF转为CRLF
git config core.autocrlf false

# 检查文件是否混用了不同风格的换行符
# false – 不做任何检查 warn – 在提交时检查并警告 true – 在提交时检查,发现混用则拒绝提交
git config core.safecrlf true

# 为某个命令配置别名
git config alias.xx gitCmd
git config alias.st status

# 将非常显眼和完整的log命令配置为 lg
git config alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

# 设置push不带参数时默认采用的方式
# 只推送当前分支叫做simple方式,还有matching方式会推送所有有对应的远程分支的本地分支
# Git 2.0版本之前,默认采用matching方法,之后默认采用simple方式
git config push.default matching
git config push.default simple

# windows下修改文件权限
# 查看文件权限
git ls-tree HEAD
# 添加运行权限
git update-index --chmod=+x xxx.sh

3.增加、删除、重命名/移动

# 添加当前目录的所有文件到暂存区
git add .

# 添加指定文件到暂存区
git add file1 file2 ...

# 添加指定目录到暂存区,包括其子目录
git add dir

# 添加每个变化前,都会要求确认,对于同一个文件的多处变化,可以实现分次提交
git add -p

# 强制添加到Git 例如文件被加入了.gitignore
git add -f file

# 删除工作区文件,并且将这次删除放入暂存区
# 这个命令必须是在add以后才能够执行的,没有add时不会被git关注
# 但add以后还是无法删除,文件与版本库中不一致也无法删除,需要添加参数
# -f 从工作区和暂存区删除文件,未被commit过的文件不再有任何记录(add过的内容可以找回),曾经commit过的文件在之后commit后会被删除
# --cached 停止追踪指定文件,但该文件会保留在工作区
git rm file1 file2 ...

# 重命名和移动文件是同一种操作,并且将这个操作放入暂存区
# 若直接移动未通知git git会认为出现新文件 之前的文件被删除
# eg: git mv file1.txt source/file1.txt
git mv oldFile newFile

4.提交

提交时若未添加-m参数,会打开文本编辑器,默认vim,强制退出会提交失败,或填入信息后提交成功

# 提交暂存区内容到本地仓库
git commit -m "xxx"

# 提交暂存区的指定文件到仓库区
git commit file1 file2 ... -m "xxx"

# 提交工作区自上次commit之后的所有变化直接到本地仓库
git commit -a -m "xxx"

# 显示所有diff信息,并进入vim,若完成输入后会自动提交
git commit -v

# 使用一次新的commit,替代上一次提交
# 如果代码没有任何新变化,则用来改写上一次commit的提交信息
git commit --amend -m "xxx"

# 重做上一次commit,并包括指定文件的新变化
git commit --amend file1 file2 ...

5.分支

# 列出所有本地分支
git branch

# 列出所有远程分支
git branch -r

# 列出所有本地分支和远程分支
git branch -a

# 新建一个分支,但依然停留在当前分支,新建的分支指向最后的commit
git branch branchName

# 新建一个分支,并切换到该分支 相当于 git branch branchName 然后 git checkout branchName
git checkout -b branchName

# 切换到指定分支并更新工作区
git checkout branchName

# 切换到上一个分支
git checkout -

# 新版本的Git提供了新的switch命令来切换分支
# 创建并切换到新的分支
git switch -c branchName

# 切换到已有的分支
git switch branchName

# 新建并切换到一个分支,并将远程仓库的某个分支与本地分支建立联系并获取
git checkout -b branchName remoteName/branchName

# 新建一个分支,指向指定commit
git branch branchName commitId

# 将当前分支与对应本地分支关联
git branch --track branchName

# 建立追踪关系,在现有分支与指定的远程分支之间
git branch --set-upstream-to=remoteName/remoteBranchName branchName

# 合并指定分支到当前分支
git merge branchName

# 禁用快速合并,合并时会自动创建一个新的commit
# 合并分支在没有冲突时是快速合并Fast-forward,快速合并模式在删除分支后,会丢掉分支信息
# 非快速合并时Git就会在merge时生成一个新的commit.从分支历史上就可以看出分支信息
git merge --no-ff -m "xxx" branchName

# 在当前分支上,合并远程仓库的对应分支
git merge remoteName/branchName

# 合并一个特定的commit到当前分支, 会自动为当前分支做一次新的提交
# 比如某个分支上的bug修正提交合并到当前的分支中,某个公共模块的修改提交后更新到分支
git cherry-pick commitId

# 删除分支 被合并过的分支才可以这样删除
# 删除分支时,当前分支不能停留在要删除的分支上,要切换到其他任意分支,再去删除目标分支
git branch -d branchName

# 强制删除某个分支 未被合并的分支被删除的时候需要强制
git branch -D branchName

# 删除远程分支
git push remoteName --delete branchName1 branchName2 ...
git branch -dr remoteName/branchName

6.标签 tag

Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针,标签是指向commit的死指针,分支是指向commit的活指针 分支可以移动,标签不能移动
因为commit的编号较长,所以引入了 tag 它跟某个commit绑在一起
标签不是按时间顺序列出,而是按字母排序的

# 列出所有tag
git tag

# 新建一个tag在当前commit
git tag tagName

# 新建一个tag在指定commit
git tag tagName commitId

# 删除本地tag
git tag -d tagName

# 删除远程tag
git push remoteName :refs/tags/tagName

# 创建带有说明的tag
git tag -a tagName -m "xxx" commitId

# 查看tag信息
git show tagName

# 提交指定tag
# 默认情况下,git push 命令并不会传送标签到远程仓库服务器上,在创建完标签后必须显式地推送标签到远程服务器上
git push remoteName tagName

# 提交所有tag
git push remoteName --tags

# 新建一个分支,指向某个tag
git checkout -b branchName tagName

7.查看信息,当前状态,提交历史,差异,本地操作历史

显示过长时会进入特殊查看模式,使用回车查看下一行 d键下一页 q退出

# 显示有变更的文件
git status

# 显示当前分支的版本历史
git log

# 显示过去5次提交
git log -5

# 使用其他格式显示历史提交信息
# 可用的选项包括 oneline、short、full、fuller 和 format
git log --pretty=xxx

# 仅显示 SHA-1 校验和所有 40 个字符中的前几个字符
git log --abbrev-commit

# --pretty=oneline --abbrev-commit 合用的简写
git log --oneline

# 显示每次提交的文件修改统计信息,哪些文件发生了变动,变动几处
git log --stat

# 显示每次提交所引入的差异,以补丁格式展示改变的位置
git log ---patch
git log -p

# 查看最近两次详细修改内容的diff
git log -p -2

# 显示指定文件相关的每一次diff
git log -p file

# 在日志旁用ASCII图形(树形图)显示分支与合并历史
git log --graph 让整个仓库的历史版本呈现出一种树结构 一般

# 展示分支 合并 以及其相关的tag 历史
git log --graph --all --decorate --oneline

# 日期格式化
git log --date=format:'%Y-%m-%d %H:%M:%S'

# 根据关键词搜索提交历史,
git log -S xxx

# 显示某个commit之后的提交中的提交说明包含输入内容的提交
git log commitId --grep xxx

# 显示某个文件的版本历史,包括文件改名
git log --follow file
git whatchanged file

# 展示某个文件在移动过程中的历史
git log --stat -M --follow file

# 显示所有提交过的用户,按提交次数排序
git shortlog -sn

# 显示指定文件是什么人在什么时间修改过
git blame file

# 显示差异
# 当暂存区无文件时,显示工作区和当前分支最后提交的差异
# 当暂存区有文件时,显示工作区与暂存区之间的差异
git diff

# 展示有差异的文件名称
git diff --name-only

# 展示差异的具体文件和文件中修改的数量
git diff --stat

# 展示差异时仅用颜色表示不同 红色为删除 绿色为添加
git diff --color-words

# 展示差异时的样式变为 {+增加的内容+} [-删除的内容-]
git diff --word-diff

# 比较当前文件和暂存区文件差异
git diff file

# 比较暂存区和本地仓库的差异
git diff --cached

# 显示对应文件暂存区和本地仓库的差异
git diff --cached file

# 显示工作区与本地仓库中某个分支的差异
git diff branchName

# 展示对应分支最后2次提交的差异
git diff branchName~ branchName

# 比较并显示两次提交之间的差异
git diff commitId1 commitId2

# 根据两次提交的差异生成对应名称的差异文件
git diff commitId1 commitId2 --name-only | xargs tar -zcvf xxx.tar.gz

# 显示今天你写了多少行代码
git diff --shortstat "@{0 day ago}"

# 显示最近一次提交的差异
git show

# 显示某次提交的元数据和内容变化
git show commitId

# 显示某次提交发生变化的文件
git show --name-only commitId

# 显示某次提交时,某个文件的差异
git show commitId:file

# 显示本地仓库最近几次操作
git reflog

# 查看指定本地仓库的操作历史
git reflog branchName

8.远程同步

# 显示所有远程仓库,会显示可以抓取和推送的远程仓库的地址.
# 如果没有推送权限,就看不到push的地址,但有push地址也不代表能够push,因为push时会验证
git remote -v

# 查看指定远程仓库状态
git remote show remoteName

# 增加一个新的远程仓库并指定命名
git remote add remoteName url

# 删除添加的远程地址
git remote remove remoteName

# 远程主机的改名
git remote rename remoteName newRemoteName

# 下载远程仓库的所有变动,获取所有分支的更新
git fetch remoteName

# 取回指定远程仓库对应分支的更新
git fetch remoteName branchName

# 获取远程仓库中与本地仓库当前分支有追踪关系的分支的更新,并合并到对应分支
# 等同于先做git fetch,再做git merge
git pull

# 抓取远程仓库所有分支更新并合并到本地,不要快速合并
git pull --no-ff

# pull更新时完全参照远程仓库的改动,包括删除分支的操作也进行.
# 为了防止在远程仓库中分支已经被删除的情况下本地分支更新时不会被直接删除,pull不会删除对应本地分支.
# -p 可以放弃这个限制,等同于 git fetch --prune remoteName git fetch -p
git pull -p

# 取回远程仓库的变化,并与当前分支合并
git pull remoteName branchName

# 取回远程主机的对应分支,与本地的对应分支合并
git pull remoteName remoteBranchName:localBranchName

# 强行将远程分支的指定分支与本地当前分支合并
# 用于远程仓库的分支与本地仓库的分支不相关拒绝合并(refusing to merge unrelated histories)时
git pull remoteName branchName --allow-unrelated-histories

# 向远程仓库中推送更新,需要只管理一个远程仓库,并且分支之间存在追踪关系
git push

# 强制push 会以当前本地仓库为准,覆盖掉远程仓库所有内容,慎用
git push --force

# 向指定远程仓库推送本地仓库中所有分支的变化,需要本地分支与远程仓库的分支之间存在追踪关系
git push remoteName

# 强行推送当前分支到远程仓库,即使有冲突
git push remoteName --force

# 将本地对应分支推到远程,如无对应远程主分支则创建,可以用于初始化远程仓库
git push -u remoteName branchName

# 不管是否存在对应的远程分支,将本地的所有分支都推送到远程仓库,远程仓库不存在分支时建立分支.
git push --all remoteName

# 将本地指定分支推送到指定远程仓库的指定分支
git push remoteName localBranchName:remoteBranchName

# 向指定远程仓库推送本地仓库中指定分支的变化,需要本地分支与远程仓库的分支之间存在追踪关系
git push remoteName localBranchName

# 删除指定的远程分支,等同于推送一个空的本地分支到远程分支.相当于git push remoteName --delete branchName
git push remoteName :branchName

9.撤销

# 撤销所有工作区修改,即把暂存区覆盖到工作区,工作区和暂存区不同的内容都会丢失
git checkout

# 恢复暂存区的指定文件到工作区,若暂存区不存在会从版本库中恢复到暂存区和工作区
git checkout file

# 恢复某个commit的指定文件到暂存区和工作区
git checkout commitId file

# 恢复暂存区的所有文件到工作区,暂存区不存在会从版本库中恢复
git checkout .

# 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变
git reset file

# 把版本库中的对应分支的最新版本转移到暂存区
git reset branchName

# 重置当前分支的暂存区为对应commit
git reset commitId

# 将指定文件在暂存区的修改回退到指定的版本
git reset commitId file

# 重置暂存区与工作区,与当前分支的最后提交保持一致,即放弃所有本次修改和add
# 注意 --hard会充值暂存区和工作区,未add的工作区变动无法找回
git reset --hard

# 重置暂存区与工作区到对应分支的上个版本,增加^的数量表示上多少个版本,比如上上个版本branchName^^
git reset --hard branchName^

# 重置暂存区与工作区到对应分支的上n个版本,比如之前100个版本branchName~100
git reset --hard branchName~n

# 重置暂存区与工作区到对应的commit
git reset --hard commitId

# 重置当前分支的commit为指定commit,暂存区和工作区不变
git reset --keep commitId

# 将对应commit的内容替换为当前暂存区的内容
git revert commitId

# 暂时将未提交的变化移除,稍后再移入(一个额外的暂存),多次stash会多次记录不会覆盖.
git stash

# 恢复暂存的内容 删除暂存内容
git stash pop

# 列所有stash
git stash list

# 恢复暂存的内容 恢复后,stash内容并不删除
git stash apply

# 删除暂存区
git stash drop

找回之前add的内容

多次add后未commit,想找回中间某次add的内容

git fsck --lost-found

该命令会在.git/lost-found/other生成每次add并未被commit的内容
若add数量不多可以直接到该位置对生成的内容进行查看

若数量过多,可以尝试如下命令

script
find .git/objects -type f | xargs ls -lt | sed 60q

显示最近修改的60个文件,显示具体的修改时间,数量可自行修改

10.其他

# 显示git版本
git --version

# 显示对应指令的帮助信息
git help gitCmd

# 生成一个可供发布的压缩包
git archive

# 显示 git gui
git citool

# 删除工作目录中Untracked的状态的文件或目录
# 未添加到git,且不在.gitignore中的,都是Untracked的状态
git clean

# 让Git显示颜色
git config color.ui true

# 针对文件检查ignore文件
git check-ignore -v file

# 生成新的ssh key
# 生成时可以选择是否输入passphrase,设置passphrase后,每次与远程仓库通信(比如GitHub)都会要求输入passphrase
ssh-keygen

# 带参数的生成ssh key
# -t 是密钥的类型,默认rsa 还有 dsa
# -C 用于识别这个密钥的注释,注释你可以输入任何内容,一般输入邮箱,仅仅是识别用
ssh-keygen -t rsa -C "your_email@example.com"

# You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).Please, commit your changes
git cherry-pick --abort
git pull

GUI工具

SourceTree

Github Gitee

操作出现Connection closed by remote host可能是IP被劫持
查看是否有代理或vpn造成,没有时可尝试修改host,在host中对域名指定确定ip

发起一个pull request:

  1. 在自己的账号下Fork克隆一个对应仓库
  2. 从自己的账号下clone仓库
  3. 修改并提交到自己仓库
  4. 在网站中发起pull request