你可能不知道的Git使用方法

使用Git已有很长一段时间,遇到一些痛点问题,而且大都是网上难以直接查到的,故总结于此。

1.两幅重要的图

基础构成
命令原理

以上两幅图对理解Git的原理十分重要。

2.基础命令

首先是一些基础命令,这些命令经常使用,而少为人知。

  • git add -Agit add --all 把包括修改、增加、删除都全部加入暂存区。等同于 git add .git add -u两个命令。

  • git add -p 一段段地把修改提交到暂存区,每一个修处改都会提示你是否加入暂存区。可以按照想要的方式把所有修改分成多个commit。

  • git commit -am 把已经加入暂存区(Stage)的文件的更改提交到本地版本库,无论这些更改是否已经加入暂存区。与git commit -m的区别在于后者只能向本地版本库提交已经加入暂存区的更改。如果只是改动某些代码,而没有增加或者删除文件,使用git commit -am一个命令就可以替代git add --allgit commit -m两个命令。

  • git commit --amend 修改最后一次commit的提交信息。注意,是最后一次,也就是HEAD指向的commit。

  • git branch -vv 显示本地分支与远程分支的对应关系。执行git push(没有带分支参数)时代码被提交到对应远程分支,就是依据该对应关系。这里需要注意Git的simple和matching模式,后者会一次性提交所有的对应关系的分支的代码到远程分支,前者只会提交当前所在分支。

  • git stashgit statsh pop 主要用来暂存当前的工作。如果需要git pull又不想把当前的修改提交commit,则可以先使用git stash把修改暂存。该命令运行完后工作区是干净的,此时再使用git pull拉新代码。完事了后使用git statsh pop恢复之前的工作状态。

  • git reflog 显示曾经的commit。如果我们使用git reset将HEAD指向某个过去的commit了,此时要想回到最开始的commit,使用git log是无法查到最开始的commit的。但是也不要慌,git reflog能给你回到最开始的commit的机会,它会显示所有的提交记录。

3.使用场景

根据一些常见的场景给出我自己的解决方法。

3.1 基于远程分支建立本地分支

你可能刚入职。你的新同事突然丢过来一个地址A,让你git clone一下代码。接着他又丢过来一个分支名dev0.1,让你基于该分支进行开发。如果之前只会在master上git pullgit push,此时就可能有点不知所措了。

你可能首先想到如何把远程的dev0.1分支clone下来,因为执行git clone A之后,你再用git branch查一下,发现本地只有master分支。

这里需要纠正一个问题。git clone A实际上把所有的分支都从远程拉下来了,但是git branch只显示那些与远程保持了追踪(tracked)的分支。并且git clone A还会创建本地master分支并将其与远程(origin)的master建立追踪(tracked)关系。于是我们最开始使用git branch就只显示master了。

那么,问题来了。既然所有分支都已经拉下来了,我们如何切入dev0.1分支并进行开发呢?其实很简单:

git checkout dev0.1

这个命令的含义是将dev0.1分支从本地版本库取到工作区来(参考上面的两幅图中的第二幅),并将工作区切换到该分支。此时一个本地名为dev0.1的分支与远程(origin)的dev0.1分支就建立了追踪关系。我们就可以基于dev0.1进行开发了。试试git branch看看会不会显示出dev0.1

假如远程分支中并没有一个叫dev0.1的分支,我们运行以上命令,就会发现这样的错误提示:

error: pathspec 'dev0.1' did not match any file(s) known to git.

此时我们可以看看到底有哪些远程分支,请使用git branch -r。当然git branch -a显示的信息就多一些,它显示全部本地分支和远程分支。

但我通常并不这样做。而是用以下命令:

git checkout -b dev origin/dev0.1

它的含义是新建一个本地分支dev,且让这个分支与远程dev0.1分支保持追踪关系。这样做的好处在于可以自己取一个本地分支名。

3.2 分支开发模式同步Master分支代码

你可能基于本地的dev0.1分支写了一些代码,测试后并提交到本地仓库中了。你们团队代码主干分支是master,且基于这个分支进行发布。这就面临着一个问题,你的新写的代码如何提交到主干分支上。

1.如果的本地dev0.1分支与远程(origin)dev0.1分支保持了追踪关系,且如果你们团队使用类似github/gitlab这样的git仓库托管服务,则可以直接在本地dev0.1分支上操作:

  • git pull origin dev0.1拉下远程代码,以防有更新。 如果git是simple模式,则可以直接使用git pull[目前git2.0及以上版本都默认为simple模式]。
  • 如果有更新则会自动合并,合并如果失败,则会要求手动处理冲突。处理完后将这次修改提交到本地仓库。
  • 使用git push origin dev0.1向远程仓库dev0.1分支提交代码。git 2.0及以上版本直接git push即可。
  • 在github/gitlab的界面上操作,由dev0.1分支向master分支提交merge请求。负责master分支维护的同事合并你的分支代码到master即可。

2.如果本地dev0.1分支是基于master分支新建的,即在本地master上使用git checkout -b dev0.1命令---它会创建一个dev0.1的本地分支,并切换到该分支,但它不会设置与远程分支的追踪关系。这时候如何将该分支的新代码合并到master分支呢?

  • 首先dev0.1分支要合并到本地master上去。先使用git checkout master切换到主干分支,在主干分支上操作。
  • 合并dev0.1分支。使用git merge dev0.1 --no-ffgit merge dev0.1命令。这两者的区别可用以下图片说明:
两个命令的区别

前者带有分支记录,后者没有。

  • 然后将master分支的代码提交到远程master:git pull拉新代码,解决冲突,git push推到远程。
  • 如果dev0.1分支没用处了,就可以直接删掉:git branch -d dev0.1
3.3 将工作区恢复成干净的状态

如果开发了一阵子,修改了一些代码,但没控制好,把工作区搞成了一堆乱麻。这时候就想,要是能把工作区恢复成最开始的样子就好了。

  • 首先确定要恢复成的最初状态。一般来讲就是将工作区恢复成当前本地仓库中HEAD所指向的commit。不过如果你之前提交到本地的一些commit你也不想要了,那么先用git log查一下你要恢复到的commitID,复制下来。

  • 使用git reset --hard HEAD/commitID命令。运行完毕之后,用git status查一下状态。一般状态下会显示

nothing to commit, working directory clean

但是如果你最开始时新增了一些文件,且没有将其加入暂存区,那么就不是这种提示了。你需要把你新增的那些文件删掉,git status才会恢复成以上状态。主要原因是git reset无法重置那些没有加入暂存区的更改。

如果你只是需要把某个文件B恢复成仓库里上一次提交的状态,那么有以下两种可能:1.这个文件没有任何修改提交到暂存区;2.这个文件有一部分修改提交到暂存区了,但是想把暂存区的修改也恢复成HEAD指向的版本。

  • 1情况下直接使用git checkout B恢复工作区的文件B。
  • 2情况下先使用git reset HEAD B撤销暂存区里面对B的修改,再使用git checkout B恢复工作区中的修改。
3.4 修改某次的提交信息

这个场景并不常见,而有的时候又一定用的到。例如你开发一段时间了,却发现公司的gitlab要求你push的时候必须使用公司的邮箱,而你之前的commit都用的是你自己的邮箱。我之前就遇到过这个问题,在这儿记录一下解决方案。

首先,git commit --amend只能对最新提交的Comment内容或邮箱的修改,并不能对中间提交的Comment或者邮箱进行修改。如果只是修改最新提交的信息:

  • git commit --amend 直接进入修改提交信息的模式。
  • git commit --amend --author="chenyi <chenyi@xxx.com>" 可以修改作者信息。

如果需要修改中间某一次的提交信息,则需要按照一定的方法操作。以下是一个修改示列。

原始记录

如上图,第二个提交的邮箱同其他提交不一样,我们需要将它修改成与其他一样的。

  1. 先进入第二个提交:git rebase -i preCommitID,这里preCommitID就是第二个提交的下面的一个ID,即ff4e24

进入修改模式

我们可以看到,列表里面显示了我们想要修改的commit的ID,即c1c6685。将其前面的pick更改为edit,保存并退出。

提示

当我们从第2步的编辑过程中退出后,git会提示我们可以用的两个命令git commit --amendgit rebae --continue。这两个命令在后面都会用到。

修改模式

我们目前已经处于c1c6685commit上了。此时我们只需要使用git commit --amend --author="chyoo <chyoo1991@gmail.com>"修改该提交的作者信息。上图就是运行该命令后进入修改的界面。

退出之后的结果
退出第4步的修改模式之后,git给的提示信息。接下来我们只需要运行git rebase --continue继续rebase就可以完成目标了。

3.5 将Commit记录变成直线模式

通常很多人合作写代码时,希望将远程master分支维护成直线的形式,这样commit干净明确,检查问题时能省不少事。而一般合并最新代码时用的git pull会将生成一个merge commit,这将导致推送到远程分支的代码也是各种分支交叉,一点也不干净明确。

那么,该如何实现这个目的呢?

首先这里要上一份干货,就是git mergegit rebase的区别,需要注意到git pull实际上是调用git merge进行代码的合并。->干货在此

从干货文章中我们可以发现,能够使用git rebase命令用打补丁的方式来实现commit保持直线的目的。我们这样操作:

  1. git fetch origin master 用这个命令将远程(origin)的master分支最新提交取到本地。

  2. git rebase origin/master 使用rebase 进行pack打补丁,将我们自己提交的本地代码以补丁的方式放在最新代码的后面。这个过程中可能会出现冲突,修改完了之后使用git rebase --continue继续pack,直到完成rebase。如果出现无法解决的问题,想回到最开始,可以使用git rebase --abort

  3. git push提交代码到远程master分支。

这里要求开发协作的每一个人都用这种方式操作和提交代码,这样才能保持远程master分支的干净整洁和直线性。

->这一篇文章讲了为什么这样做的原理。

3.6 为一个本地仓库设定多个远程仓库

这个看起来是有点奇怪的需求。不过前不久gitlab的员工删除了它们的数据库,导致很大部分项目受影响,这让我们觉得如果能多一份代码保障或许更好。

使用git clone时,会自动设定远程地址,一般都是以origin指代。如果我们有特殊需求,需要将代码提交到另一个远程仓库,这时就要设定新的远程仓库地址了。

git remote add hegel http://xxxx.git 这个命令就可以给当前的本地库设置一个远程仓库hegel。以后我们想推拉代码到这个远程库时,就需要用git push hegel mastergit pull hegel master了。

4.快捷设定

有一些比较有用的设定,能在写命令时少了很多麻烦。

  1. 全局设置user和email
  • git config --global user.name "chenyi"
  • git config --global user.emali "chenyi@xxx.com"
  1. 给常用命令起一个简单的名字
  • git config --global alias.co checkout
  • git config --global alias.st status
  • git config --global alias.br branch
  • git config --global alias.ci commit

后续就可以使用git co/git ci等命令了,是不是简洁了很多?

3.更好看的git log

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

配置了这个之后,使用git lg简直眼前一亮。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容