十分钟捋完 GIT 命令

git学习路线

  • 常见概念
  • 常用指令
  • 常见的场景下的操作

常见概念

分区

git是一种分布式的代码管理工具,每一个git终端用户就拥有一个本地代码版本仓库。

他的代码分区也是相对比较复杂:

  • 工作区(workspace):用户工作区,直接修改的代码就是工作区代码。
  • 缓存区(index/stage):用户缓存区,工作区代码add以后,进入缓存区。
  • 本地仓库(local repository):本地版本的仓库,缓存区代码commit以后,进入本地仓库。
  • 远程仓库(remote repository):在服务器上的代码仓库,本地仓库代码push以后,进入远程仓库。

以上各个分区对初学者有点懵,其实只要记住几个基本操作就能对应不同分区:

  • 工作区:
  • 缓存区:add
  • 本地仓库:commit
  • 远程仓库:push

概念

远端(remote):远程仓库,服务器端仓库,push以后到达。
commitId:顾名思义,就是做完git commit后,得到的一个SHA-1 Hash值。
当前分支(current branch):就是工作区当前切换到的一个分支,通过命令git branch可以查看。
HEAD:可以理解为一个游标,指向你在操作的某个commitId版本。新的commitId会加在HEAD后面,然后HEAD指向新的commitId
FETCH_HEAD:记录远端仓库各个分支的HEAD

常用指令

建议申请一个远程仓库,然后手动试一下。抛去了不常用的命令,以及不常用的参数。

git config

顾名思义,配置相关的一个命令。

常见用法:

  • git config --global credential.helper store:保存密码
  • git config --global user.name <name>:用户
  • git config --global user.email <email>:邮箱
  • git config --global core.autocrlf true:行尾设置,windows用true
  • git config --global alias.<alias-name> <git-command>:设置命令缩写

git clone

将远程仓库复制到本地。

常见用法:git clone <repository> [<directory>]

git clone https://github.com/xxxxx/xxxx

git init

将指定文件夹设置为一个git仓库。

常见用法:git init <directory>

mkdir gitteset
cd gittest
git init

git add

将文件放入缓存区,可以指定文件,也可以全部。

常见用法:git add <filename>git add .

git commit

将缓存区的文件,提交到本地仓库。

常见用法:git commit -m <msg>git commit -F <file> -m <msg>

# 假设在之前的gittest下
git status -s
touch a.java
git status -s
git add a.java
git status -s
git commit -m "add a.java"
git status -s

git push

将本地仓库的代码,提交到远程仓库。

常见用法:

  • git push:推送当前工作分支到他的远端仓库和远端分支。
  • git push <remote> <branch>:推送<branch>分支,而不是当前分支。不存在则新建。
  • git push <remote> <branch_local>:<branch_remote>:跨分支推送。不存在则新建。
  • git push <remote> HEAD:使用HEAD推送当前分支。不存在则新建。
  • git push <remote> HEAD:<branch_remote>:使用HEAD跨分支推送。不存在则新建。

注意push前最好拉取远端代码,否则他人提交的代码会导致你"非快进更新(non-fast forward)"。

git push
git push origin testpush
git push origin testpush:testpush2
git push origin HEAD
git push origin HEAD:testpush3

git checkout

可以签出分支,也可以签出某个分支某个版本的某个文件。

常见用法:

  • git checkout <branch>:签出某个分支,HEAD移到分支的commitId上。
  • git checkout <filename>:签出某个文件,从缓存区。(一般场景是你修改/删除了这个文件,但是没有add)
  • git checkout <branch> <filename>:签出其他分支的某个文件。
  • git checkout -m <branch>:切换分支,并合并。(一般场景是你当前分支的修改内容会被目标分支覆盖)
  • git checkout -b <new_branch>:新建分支,如果是-B,那就是强行开新分支(同名分支会被覆盖)。

试一试:

# 建分支
git checkout -b testb  #创建分支
git checkout -b testb  #提示已存在
git checkout -B testb  #重值分支
# 有修改内容会丢失,不能切换分支
echo 'this is testb' >> b.txt && git add . && git commit -m "b.txt"   #加个b文件
git checkout master           #签出分支master
echo 'this is testb' >> b.txt     #master新建个b
git hash-object b.txt
git checkout testb       #切换分支失败,因为b的信息会丢失
# 虽然有修改内容,但是可以在切换的分支重保留
git checkout testb b.txt   #签出b文件,其实两个文件内容相同
git hash-object b.txt       #通过hash值的比较,可以看到两个文件虽然内容相同,但是hash不同
git checkout testb      #签出成功,因为这个b.txt文件是testb分支的文件,所以修改的内容直接保留了。

结论:checkout失败,就是尝试将修改内容带到目标分支失败,原因有:

  1. 已跟踪的文件,目标分支没有相同hash的同名文件。
  2. 未跟踪的文件,目标分支已有不同hash的同名文件。

git fetch

从其他仓库下载东西。

常见用法:

  • git fetch [<remote> ]:所有的fetch指令都会更新FETCH_HEAD,只不过根据参数可能是:所有远端、一个远端、一个分支
  • git fetch <remote> <remote_branch>:<local_branch>:只有指明了本地分支,才会拉取分支代码。
# 所有fetch指令都会更新 FETCH_HEAD
rm .git/FETCH_HEAD && git fetch && cat .git/FETCH_HEAD &&\
rm .git/FETCH_HEAD && git fetch origin  && cat .git/FETCH_HEAD &&\
rm .git/FETCH_HEAD && git fetch origin master && cat .git/FETCH_HEAD
# 具体到本地分支,会拉取分支代码;
# 注意不要fetch到当前分支,会提示:fatal: 拒绝获取到非纯仓库的当前分支
rm .git/FETCH_HEAD && git fetch origin testb:testb && cat .git/FETCH_HEAD
git branch -av

git merge

将多个commit版本的内容,合并到当前分支。
注意:两个版本merge时,强烈要求所有内容已经commit。

常见用法:

  • git merge <branch_1> <branch_2> .... <branch_n>:将多个分支,合并到当前分支。
  • git merge -s <branches> <strategy>:使用合并策略,简单来说:
    • recursive:默认值,递归三路合并算法。首先找到同一个commitId祖先。然后分析冲突,a随祖先,b不随祖先,那就保留b。
    • ours:如果有冲突,自动应用我方代码。
# 构造一个测试环境
# 新建 testmerge1 testmerge2 分支,其中包含一个log文件
git checkout master && echo "this is point a" > log && git add . && git commit -m "test merge step 1" &&\
git checkout -B testmerge1 && git checkout -B testmerge2
# 两个分支都修改这个文件,然后merge
git checkout testmerge1 && echo "branch 1 change" >> log && git add . && git commit -m "test merge step 2"
git checkout testmerge2 && echo "branch 2 change" >> log && git add . && git commit -m "test merge step 3"
git merge testmerge1  # 合并失败,显然系统无法判断该留哪个
git reset --hard HEAD   # 回退到合并前
git merge -s ours testmerge1  # 合并成功,产生一个新commit

合并失败的原因,是按照递归三路合并算法,找到他们的祖先 step 1,然后发现两个分支都不随祖先,系统无法取舍。

git pull

拉取远端<remote>分支<branch>代码,和当前本地分支进行合并。
其命令可以理解为 git fetch + git merge

常见用法:

  • git pull <remote> <branch>:默认都是拉取到当前分支(并进行merge)。
# 构造一个环境,通过update文件来查看commit版本
git checkout master && rm * && echo "1111">>update && echo "2222">>delete && git add . && git commit -m "1" && git push
# 增删改,提交,上传,服务器update=11112222
rm delete && echo 2222 >> update && echo "add">>insert && git add . && git commit -m "1"&& git push
# 本地退回一个版本,master和HEAD都指向上一个版本。update=1111
git reset --hard HEAD~ && cat update
# 拉取代码,因为远端版本更新,直接更新了本地。update=11112222
git pull origin master:master && cat update

###### 下面测试本地版本更高的时候
# 再提交一个版本,但不发到远端
echo 33333 >> update && git add . && git commit -m "1"
# 拉取代码,由于本地版本更高,会提示"Already up-to-date"
git pull
# 指定本地分支,提示"(非快进式)"
git pull origin master:master

###### 下面测试本地版本和远端分岔了的情况,这在多人合作开发中常见
# 新开个仓库,模拟一下其他用户的操作,远端update 变成111122224444
git clone xxxxxxxxxxxx  folder2 && cd folder2
echo 4444 >> update && git add . && git commit -m "1" && git push
# 回到自己的仓库,拉取代码,提示:
# 自动合并 update
# 冲突(内容):合并冲突于 update
# 自动合并失败,修正冲突然后提交修正的结果。
git pull

# 禁招,轻易别用;强行(--force -f)拉取/推送,覆盖自己/他人的commit。
git pull -f origin master:master
git push -f origin master

git reset

重置HEAD到某一个commitId

常见用法:

  • git reset <commitId> [<filename>]:移动HEADcommitId

选项:

  • --soft:不处理工作区、缓存区;
  • --mixed:默认值;不处理工作区,重置缓存区;
  • --hard:处理工作区、重置缓存区;所有跟踪文件被处理。未跟踪(新增)代码会被保留。
  • --merge:和--hard类似,但是未被git add的修改内容,会保留下来。
  • --keep:和--hard类似,但是如果有差异文件(两个版本中不同)被修改了,则命令失败。

其中--hard选项经常用来放弃当前分支中的所有修改。

# 签出master分支,在该分支上,commitId为: 5ea663c (head) 4ee69b7
# 两个分支都有一个update文件,内容分别是 1111 2222
git checkout master  
# 重置
git reset --hard 5ea663c && touch a && git add a && echo abc>>update && git status
# soft测试,可以看到工作区update文件和暂存区a文件没有任何变化
git reset --soft 4ee69b7 && git status
# 重置
git reset --hard 5ea663c && touch a && git add a && echo abc>>update && git status
# mixed测试,可以看到工作区update文件没变化;暂存区被清了
git reset --mixed 4ee69b7 && git status
# 重置
git reset --hard 5ea663c && touch a && git add a && echo abc>>update && git status
# hard测试,可以看到工作区update被更新了、a文件被删除了,暂存区清了。
git add a && git reset --hard 4ee69b7 && git status
# 重置
git reset --hard 5ea663c && touch a && git add a && echo abc>>update && git status
# merge测试,由于update未进暂存,被拒绝了。git add后,效果和hard一样。
git reset --merge 4ee69b7 && git status
# 重置
git reset --hard 5ea663c && touch a && git add a && echo abc>>update && git status
# 测试keep,由于update是差异文件,并且被修改了,命令失败。
git reset --keep 4ee69b7 && git status

git stash

常见用法:

  • git stash:将当前未commit的信息放入stash栈
  • git stash pop:将栈顶的存储信息弹出。
  • git stash apply:使用栈顶的存储信息,但是不弹出。
  • git stash list:显示栈中列表
  • git stash save $name:以名字形式进栈
  • git stash drop $name:按名字索引,删除某个存储信息。
  • git stash clear:清空存储信息。

猜你喜欢

转载自blog.csdn.net/weixin_36572983/article/details/106340607
今日推荐