git 常用操作

349 阅读8分钟

常用操作

image.png

一、git clone

远程操作的第一步,就是从远程主机克隆一个版本库,这是就要用到git clone命令

git clone <版本库的网址>

该命令会在本地主机生成一个目录,与远程主机的版本库同名。如果要指定不同的目录名,可以将目录名作为git clone 命令的第二个参数。

$ git clone <版本库的网址> <本地目录名>

二、git remote

为了便于管理,git 要求每个远程主机都必须指定一个主机名。git remote 命令就用于管理主机名。(远程可以有多个主机,每次提交要指定主机名) 上面的命令获得的主机名是:origin 默认的主机名是origin,可以用git remote add 添加主机。

git remote add <主机名> <网址>

查看所有的远程主机

git remote -v

查看指定的远程主机

git remote show <主机名>

重命名指定的远程主机

git remote rename <原主机名> <新主机名>

删除指定的远程主机 (删除后需要重新添加主机)

git remote rm <主机名>

image.png

三、git fetch

一旦远程版本库有了更新(git 术语叫做commit),需要将这些更新取回本地,这时就要用到git fetch 命令。

取回远程主机的所有分支

git fetch  // 忽略主机名,默认origin
git fetch <远程主机名>

取回远程主机的指定分支

  git fetch <远程主机名> <分支名>          

注意:git fetch 后面可以没有参数,默认取回远程分支的所有分支到本地, 如果git fetch 后面要跟指定分支的话,必须加上<远程主机名>

git fetch    // 拉取远程所有分支               
git fetch <远程主机名> <分支名>    // 拉取远程指定分支

image.png

四、git branch

在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动"追踪"origin/master分支。

Git也允许手动建立追踪关系。


git branch --set-upstream master origin/next

查看本地所有分支

git branch

查看远程所有分支

git branch -r

查看远程+本地的所有分支

git branch -a

当开始从远程版本库clone下来仓库到本地时,会把远程仓库的分支自动拉下来,远程仓库的分支带 origin/ 前缀

image.png

git branch -a // 查看当前本地仓库的所有分支

image.png 本地新建一个分支:test1,再git branch -a, 看到本地新建的test1分支,但并没有带对应origin前缀的远程分支,说明没有和远程分支建立关联 image.png
此时,git push 推送这个本地没有建立和远程分支关联的分支 image.png
执行 git push --set-upstream origin test1, 可以看到在本地仓库创建了和远程仓库相关联的origin/test1分支,并且在远程仓库添加了一个test1分支 image.png

image.png

此时在远程仓库修改master的代码 image.png 在本地的test1分支使用merge命令

git merge origin origin/master 
git merge origin/master 
git merge master

发现没有将最新的master merge下来,提示已经是最新的了,因为此时的 origin/master 还是当时和本地建立关联的用于推送的远程分支,没有被更新。再执行 git fetch

git fetch origin master
git fetch

image.png
取回了最新的远程的master 到本地的origin/master,此时查看分支信息 image.png 本地的 origin/master已经更新,但是本地的mater没有更新,在test1分支进行 merge 操作

git merge master

以上没有变化,因为master 还是之前的master,git fetch 被更新的是 origin/master。

执行以下命令,发现 test1 终于合并了远程的 master 分支的最新信息

git merge origin origin/master 
git merge origin/master

image.png
此时master 分支当前的版本号还是上一次的 image.png
切换到 master分支,执行git pull, 发现master的绑定版本变了,和origin/master一致了

image.png

image.png

五、git pull

git pull 命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并,等同于先做 git fetch 再做 git merge

取回远程主机的某个分支,与本地的某个分支合并

git pull <远程主机名> <远程分支名>:<本地分支名>

比如:取回origin主机的next分支,与本地的master分支合并,需要写成下面这样。

git pull origin next:master

如果远程分支是与当前分支合并,则冒号后面的部分可以省略。

git pull origin next

如果当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名。(拉取当前分支对应的远程分支)

git pull origin

上面命令表示,本地的当前分支自动与对应的origin主机"追踪分支"(remote-tracking branch)进行合并。 如果当前分支只有一个追踪分支,连远程主机名都可以省略。(可能会有两个追踪分支?是因为远程有两个仓库源吗?)

git pull  // 一般当前分支都只有一个和远程建立连接的追踪分支,一般也只是想pull当前的分支,所以常规操作就是在当前分支 git pull, 拉取远程的该分支,合并到当前分支。

如果合并需要采用rebase模式,可以使用--rebase选项。

$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>

如果远程主机删除了某个分支,默认情况下,git pull 不会在拉取远程分支的时候,删除对应的本地分支。这是为了防止,由于其他人操作了远程主机,导致git pull不知不觉删除了本地分支。

但是,你可以改变这个行为,加上参数 -p 就会在本地删除远程已经删除的分支。

git pull -p

git pull -p 只会删除跟远端建立连接的并且远端已经删除的分支 git branch -D 只会删除本地对应的分支,不能删除对应的跟远端建立连接的分支

注意: git pull, git fetch 都是对远程仓库的操作,后面可以不加参数,如果要指定分支的话,需要加主机名(origin) 直接git pull <分支名> 会提示如下错误 image.png

六、git push

git push命令用于将本地分支的更新,推送到远程主机。它的格式与git pull命令相仿。

git push <远程主机名> <本地分支名>:<远程分支名>

注意:git pull是<远程分支>:<本地分支>,而git push是<本地分支>:<远程分支>。

如果省略远程分支名,则表示将本地分支推送与之存在"追踪关系"的远程分支(通常两者同名),如果该远程分支不存在,则会提示和远程分支建立追踪关系,会在远程主机新建对应的有追踪关系的分支。

image.png

如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。

$ git push origin :master
# 等同于
$ git push origin --delete master

上面命令表示删除origin主机的master分支。

如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。

git push origin

上面命令表示,将当前分支推送到origin主机的对应分支。

如果当前分支只有一个追踪分支,那么主机名都可以省略。

git push

如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push

 git push -u origin master

上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。

不带任何参数的git push,默认只推送当前分支。

还有一种情况,就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要使用--all选项。

git push --all origin

上面命令表示,将所有本地分支都推送到origin主机。

image.png

image.png

如果远程主机的版本比本地版本更新,推送时Git会报错,一般要求先在本地做git pull合并差异,然后再推送到远程主机。这时,如果你一定要推送,可以使用--force选项。

git push --force origin 

上面命令使用--force选项,结果导致远程主机上更新的版本被覆盖。除非你很确定要这样做,否则应该尽量避免使用--force选项。 最后,git push不会推送标签(tag),除非使用--tags选项。

git push origin --tags

git fetch 从远端拉下来 origin/分支名的分支,然后在本地 git chechout <分支名>,会创建和远端关联的对应的分支,修改本地的这个分支的代码,commit 提交,本地的分支的commit hash发生了变化,对应的远端的origin 分支对应的还是开始建立连接的版本,此时git push 将本地的分支推送到远端,这时对应的远端的origin 分支的版本跟本地的版本保持一致了 image.png image.png

image.png

思考:为什么要在本地创建 origin/分支名 这样和远端建立连接的追踪分支? origin/分支名 的分支代表着本地分支对应的远端分支的当前的版本, git fetch 拉取的是远端分支,只更新本地对应的远端分支,如果没有这个分支,拉取下来又不想合并的代码放到哪个分支呢?git commit 提交的只是当前本地的分支,本地对应的origin分支不会变化,这样push的时候才会合到对应的origin分支上,把对应的origin 分支推送到远端,并更新本地 origin对应的远端的最新版本,push推送的是本地的origin 分支,pull拉取的远端的origin 分支,本地的分支只是给我们开发用的。

六、git revert

对于版本的回退,我们经常会用到两个命令

  1. git reset
  2. git revert 那这两个命令有何区别呢? 假如我们的系统现在有如下几个提交

image.png

Git如何优雅的进行版本回退?

其中:A 和 B 是正常提交,而 C 和 D 是错误提交。现在,我们想把 C 和 D 回退掉。而此时,HEAD 指针指向 D 提交(5lk4er)。我们只需将 HEAD 指针移动到 B 提交(a0fvf8),就可以达到目的。

只要有 git 基础的朋友,一定会想到 git reset 命令。完整命令如下:

git reset --hard a0fvf8

image.png Git如何优雅的进行版本回退?

而这个时候,远程仓库的 HEAD 指针依然不变,仍在 D 提交上。所以,如果直接使用 git push 命令的话,将无法将更改推到远程仓库。此时,只能使用 -f 选项将提交强制推到远程仓库:

git push -f

采用这种方式回退代码的弊端显而易见,那就是会使 HEAD 指针往回移动,从而会失去之后的提交信息。将来如果突然发现,C 和 D 是多么绝妙的想法,可它们已经早就消失在历史的长河里了。

而且,有些公司(比如良许的公司)明令禁止使用 git reset 命令去回退代码,原因与上述一样。所以,我们需要找到一个命令,既可以回退代码,又可以保存错误的提交。这时,git revert 命令就派上用场了。

git revert

git revert的作用通过反做创建一个新的版本,这个版本的内容与我们要回退到的目标版本一样,但是HEAD指针是指向这个新生成的版本,而不是目标版本。

使用 git revert 命令来实现上述例子的话,我们可以这样做:先 revert D,再 revert C (有多个提交需要回退的话需要由新到旧进行 revert):

git revert 5lk4er
git revert 76sdeb

image.png

这里只有两个提交需要 revert,我们可以一个个回退。但如果有几十个呢?一个个回退肯定效率太低而且容易出错。我们可以使用以下方法进行批量回退:

git revert OLDER_COMMIT^..NEWER_COMMIT

OLDER_COMMIT(要撤销的版本的开始位置) NEWER_COMMIT(要撤销的版本的结束位置) 从开始到结束的版本都会被撤销, 这里必须加 ^..

git revert -n commitId

加 -n 不会被加入到暂存区,需要手动提交
不加 -n 会自动被加入暂存区然后进入提交页面,撤销几次就会进入几次提交页面

这时,错误的提交 C 和 D 依然保留,将来进行甩锅的时候也有依可循。而且,这样操作的话 HEAD 指针是往后移动的,可以直接使用 git push 命令推送到远程仓库里。而这种做法,正是企业所鼓励的。

Git删除本地远程已经删除的origin/* 分支

1. git pull -p
2. git fetch -p
3. git remote prune origin

Git批量删除本地分支

删除分支命令 删除一条分支:

git branch -D branchName

删除当前分支外的所有分支:

git branch | xargs git branch -d

删除分支名包含指定字符的分支:

git branch | grep ‘dev*’ | xargs git branch -d

↑ 该例将会删除分支名包含’dev’字符的分支。

命令解释

| 管道命令,用于将一串命令串联起来。前面命令的输出可以作为后面命令的输入。

git branch 用于列出本地所有分支。

grep 搜索过滤命令。使用正则表达式搜索文本,并把匹配的行打印出来。

xargs 参数传递命令。用于将标准输入作为命令的参数传给下一个命令。

管道命令与xargs命令的区别:

管道是实现“将前面的标准输出作为后面的标准输入 xargs是实现“将标准输入作为命令的参数

例如:删除本地带 yujj前缀的所有分支

git branch | grep 'yujj*' | xargs git branch -d(-D)