Git命令和配置技巧

此文主要介绍一切开发中常用的git命令和一些配置技巧(诸如git别名配置,log打印技巧,版本回退以及分支管理等)。

1.简介


Git与svn相比而言,Git的好处自然不用多说,Git完全分布式文件管理系统,加上其简单速度,可以高效管理类似 Linux 内核一样的超大规模项目。完全分布式的系统,让你可以在公交车上,火车上,家中,甚至在厕所都可以敲代码。何时何地你都可以敲代码,甚至不需要网络。好不好使,开不开心?换是SVN,SVN服务器挂了,全部人停止敲代码,停下来八卦去吧。

Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。这类系统(CVS,Subversion,Perforce,Bazaar 等等)每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容。如同下图所示:

但是,Git 并不保存这些前后变化的差异数据。实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快 照的索引。为提高性能,若文件没有变化,Git 不会再次保存,而只对上次保存的快照作一连接。工作方式类似下图:

对比可以发现,Git高效也在情理之中。
现在再简单介绍一下Git管理下文件的三种状态。对于任何一个文件,只要在Git管理下,那么该文件只有三种状态:已修改(modified),已暂存(staged)和已提交 (committed)。
已修改(modified): 文件被修改,但是还没有提交保存(也就是没有使用git add,此时使用git status显示为红色)。
已暂存(staged): 已修改的文件放入下次要提交的清单中(使用了git add后的状态,此时使用git status显示为绿色)。
已提交(committed): 该文件已经被安全地保存在本地数据库中(使用了git commit后,此时使用git status已经不存在该文件的任何信息)。
具体可以参考下面两幅图来理解。

2.配置用户信息


user和email,--global参数全局配置,当然你也可以不加此参数,不同的项目用不同的用户名和邮箱。

git config --global user.name Super
git config --global user.email 1342449****@163.com

3.配置全局别名


此配置在开发中相当重要,尤其是对于使用Terminal,习惯使用命令行的朋友,由于git不支持tab自动补全,每次想要看下工作目录 状态都要git status,相当耗时。除非你能确定你敲两个字母比六个字母用时少。

git config --global alias.st "status -s"
git config --global alias.ci "commit -m"
git config --global alias.aci "commit -a -m" // 跳过使用暂缓区,直接将git add和git commit合并为一条命令
git config --global alias.lg "log --color --pretty=format:'%Cred%h - %Cgreen%an %C(yellow)| %ad | %Creset%s' --graph" (自定义log)

第一条:git status是开发中使用最多最频繁的,至于-s 是简洁输入(Give the output in the short-format)
第二条:此条也使用频繁,但是我在开发中直接使用第三条跳过。
第三条:配置git aci 因为这样直接跳过使用暂存区域,对于已经跟踪的文件,我不要再此次使用git add加入暂缓区,然后再git commit提交到本地数据库,为了方便省事,直接将两条命令合并为一条,使用git aci "提交说明" 即可。省不省事,用下自然知道。
第四条:这里是我自定义的log信息,当然,一会看完本文你也可以自己格式化成自己喜欢的log格式。可以先看下效果,下图所示:


以后直接使用"git lg"即可,非常方便,显示简洁明了。

4.分支管理


git checkout -b dev origin/dev // 拉取远程开发分支到本地并且切换到开发分支
git push dev origin/dev
git branch new   // 创建新分支
git push origin new // 将new分支推送到远程(git push [remote-name] [branch-name])
git push origin :new   // 删除远程分支,注意冒号位置
git brach -d new // 删除本地分支,如果有没有merge的信息,确保该分支的确不用merge,直接使用-D强行删除
git merge dev   //  将dev分支合并到当前分支
git checkout master // 切换到主分支
// 其他不再一一列出

关于实际开发中,独立开发的话其实两个分支完全够用,一个主分支,一个开发分支。多人的话就按功能模块和人员来具体新建分支即可。由于这边由我一人负责整个项目,那么分支的话,我就建立了一个develop分支。发布版本时放到主分支处理即可。平时都在develop分支开发,如果此时发现线上版本有bug,那么只需要切换到master分支,修改bug,然后封版即可。处理好后继续回到开发分支开发就可以了。当然最好还是把刚才修改bug的代码merge到开发分支上。

还有一点使用技巧,也就是git stash的灵活使用。当我们正在当前分支编写代码,突然某人中断你的思路,提出某功能需修改且比较紧急,更烦人的是当前的代码已经开始编写,而且动用了好多文件,重要的是不想中途进行git commit提交。此时git stash就发挥作用了。

git stash // 暂时隐藏,之后就可以正常切换分支了,当前的修改内容只是保存并且隐藏起来
git stash pop // 回复到之前的工作状态,默认pop的是最近的一条,这样就可以愉快的继续编写当时被中断的代码了

git stash可以执行多次,我们可以使用git stash list命令来查看清单。当然还有好多命令,可以使用"git stash --help"来查看。

// git stash --help
usage: git stash list [<options>]
   or: git stash show [<stash>]
   or: git stash drop [-q|--quiet] [<stash>]
   or: git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
   or: git stash branch <branchname> [<stash>]
   or: git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
               [-u|--include-untracked] [-a|--all] [<message>]]
   or: git stash clear

其实关于git stash还有一个使用技巧,那就是如果当前改了众多文件,突然又不想改了,想恢复到原来的样子。那么可能你会使用"git checkout ."命令来取消所有的更改,但是有种情况并不好使,那就是你除了修改文件,还添加了一些文件或则拖入了一些文件到工程目录下,此时使用"git checkout ."然后再使用"git status"查看的时候,会发现工作区多出了尚未识别的文件(处于等待add的状态)。在这个时候,使用git stash是再好不过了,因为这样将所有git控制下的文件,包括之前的目录,全部还原到之前的状态(也就是说git stash把新增的文件也暂时隐藏起来)。如果想彻底删掉,那就再把所有stash的列表清空吧,直接"git stash list"看下,然后"git stash clear"。

还有一点,关于在Git服务器上删除分支,本地使用"git branch -a"依旧可以看到被删除问题。好比你的代码托管到了开源中国(OSChina),你通过网站,在线删除分支,就会出现这种问题,稍微有点强迫症的自然受不了。此时可以使用 "git fetch -p"使fetch之后删除没有与远程分支对应的本地分支。 当然也可以通过查看远程分支。使用命令"git remote show origin"显示如下:

YJTSuper:yjtim super$ git remote show origin 
* remote origin
  Fetch URL: [email protected]:lingsui/yjtim.git
  Push  URL: [email protected]:lingsui/yjtim.git
  HEAD branch: master
  Remote branches:
    dev                      tracked
    im                       tracked
    master                   tracked
    proV2.3.0                tracked
    refs/remotes/origin/test stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    master merges with remote master
    show   merges with remote master
  Local refs configured for 'git push':
    dev       pushes to dev       (up to date)
    im        pushes to im        (fast-forwardable)
    master    pushes to master    (up to date)
    proV2.3.0 pushes to proV2.3.0 (up to date)

我们可以看到分支origin/test 已经过期(stale),可以使用命令"git remote prune origin"同样可以处理。

5.远程地址切换


如果想要切换远程地址,千万不要重新再初始化一个git代码仓库,使用git add重新添加。这样的好处只有一点,所有历史提交信息全部清空,不再保留,"git clone"时文件变小,理所当然,历史记录全部清空了麽。如果确定不保留,也建议这样做,关键时,谁写的代码更改了哪些东西很重要呀,还是选择保留吧。使用下面的方法,一行代码搞定,并且保留了所有的commit记录。

git remote -v  // 查看远程地址
git remote set-url origin https://git.oschina.net/HaiShengHuo/xxx.git // 更换远程地址, 新建一个项目不添加任何文件  在本地直接push即可

6.查看某次提交修改的具体文件


方法一

git reflog 列出最新修改记录 也可以 git log --oneline
git log 00788a04 --name-status 找到对应版本号 执行

commit 00788a04f8d6dd834723c3479a0b5cdcfad8694a
Author: ZhiChao <13424490552@163.com>
Date:   Thu Mar 30 11:04:46 2017 +0800

    最后一条消息显示来源人

M       yjtim/IM/Chat/Controller/ConversationListController.m

commit a4b9129f1728dc10d5f6ab8c77c1b20ef7bb3d12
Author: ZhiChao <13424490552@163.com>
Date:   Wed Mar 29 17:49:44 2017 +0800

    隐藏被入群弹框

M       yjtim/IM/Chat/Controller/ChatDemoHelper.m

commit 1910008369d4ab264e7610997135a54d27fe22c7
Author: ZhiChao <13424490552@163.com>
Date:   Wed Mar 29 17:40:56 2017 +0800

    99+

M       yjtim/IM/EaseUI/EMUIKit/Views/conversation/toolbar/EaseImageView.m

git diff HEAD@{79} HEAD@{78} 具体某次修改的内容(具体某次内容和上次的内容进行比较)
git diff a4b9129f 00788a04 当然也可以使用版本号

这样假如之前修改过具体某些内容,以后还需要修改的话,找起来真的很方便.好比某些bug好久之后才发现,又要回头去修改,而修改总要找到对应的代码进行修改吧,这样几行命令就定位到具体文件和位置了,方便多了,节省很多时间.找代码有技巧,但是"找"终究还是很浪费时间.这也告诉我们,commit 提交命令很重要,需要认真写,不可为了省事而乱写

diff --git a/yjtim/IM/Chat/Controller/ConversationListController.m b/yjtim/IM/Chat/Controller/ConversationListController.m
index df0555e5..71822638 100644
--- a/yjtim/IM/Chat/Controller/ConversationListController.m
+++ b/yjtim/IM/Chat/Controller/ConversationListController.m
@@ -347,7 +347,7 @@ - (NSAttributedString *)conversationListViewController:(EaseConversationListView
             [attributedStr setAttributes:@{NSForegroundColorAttributeName : [UIColor colorWithRed:1.0 green:.0 blue:.0 alpha:0.5]} range:NSMakeRange(0, NSLocalizedString(@"group.atMe", @"[Somebody @ me]").length)];
         }
         else {
-            attributedStr = [[NSMutableAttributedString alloc] initWithString:latestMessageTitle];
+            attributedStr = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@:%@",[[YJTAddressList shareAddressList].userNameDict objectForKey:lastMessage.from],latestMessageTitle]];
         }
     }
     

方法二

直接使用git log 6b81a31033 -p 或则 git log -p 6b81a31033 其中6b81a31033为版本哈希值

commit 6b81a31033074ef279049e9cbf5944e3158d7510
Author: ZhiChao <13424490552@163.com>
Date:   Fri Apr 14 13:57:22 2017 +0800

    综合评价fixbug

diff --git a/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m b/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m
index 10ff4b31..cef73191 100644
--- a/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m
+++ b/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m
@@ -28,7 +28,7 @@ @interface YJTEvaDetailVC ()<YJTEvaDateSelectVCDelegate>
 @property (nonatomic, strong) NSArray *catListArray;
 @property (nonatomic, strong) YJTEvaSchoolYearModel *evaSchoolYearModel;
 
-
+@property (nonatomic, copy) NSString *formId;
  @property (nonatomic, copy) NSString *className;
  @property (nonatomic, copy) NSString *classId;
  @property (nonatomic, copy) NSString *tempClassId;
  @@ -262,6 +262,7 @@ - (void)rightBtnClick {
     editVC.evaListModel = self.evaListModel;
     editVC.catListArray = self.catListArray;
...

方法三

git log --stat 6b81a31033或者git log 6b81a31033 --stat 查看简洁文件变化

commit 6b81a31033074ef279049e9cbf5944e3158d7510
Author: ZhiChao <13424490552@163.com>
Date:   Fri Apr 14 13:57:22 2017 +0800

    综合评价fixbug

 yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m | 5 +++--
 yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaEditVC.h   | 1 +
 yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaEditVC.m   | 2 +-
 3 files changed, 5 insertions(+), 3 deletions(-)

7.忽略跟踪


git checkout .   清空所有更改
以下命令是我们在项目中已经添加了.gitignore  但是中途突然不想再跟踪某文件
此时发现简单的在.gitignore文件中添加要忽略的文件是不起效的,因为该文件已
经被track,我们还需要将其状态改为 未track(其实只需删除暂缓区文件然后将操作体检即可)
git rm --cached Podfile.lock  将Podfile.lock从暂缓区删除,不再跟踪

8.备份


备份的话好一些,每次新的版本打一次tag,查看起来还是挺方便。不过不用也行。我不爱使用这个。

git tag -a WeChat1.0 -m "version 1.0" :给版本打上标签
git tag : 查看所有的标签
git push origin WeChat1.0 : 将WeChat1.0 push 到默认分支

9.版本回退


git reset --hard HEAD // 没有提交的情况下进行版本回退
git reset --hard HEAD^ // 回退到上一个版本
git reset --hard HEAD^^ // 回退到指定回退到某个版本
git reset --hard 版本号(至少前5位) // 回退到前几个版本
git reset --hard~1
git revert c011eb3c20ba6fb38cc94fe5a8dda366a3990c61 // 注意该行命令 reset和revert有本质区别

注意:开发中一般托管代码到远程代码仓库,比如Github或则OSChina,加入本地已经使用git push到远程代码仓库,在本地使用git reset回退再push明显是不可行的。因为git reset直接回退到历史中的某个Hash值,但是使用git revert就不一样了。git revert将作为一次新提交(新的Hash值)而不是历史中的某个Hash值,此时再push到远程代码仓库情理之中。

10.日志


想回顾下提交历史,可以使用 git log 命令,其中有个--pretty 参数可以配置
git log --pretty=oneline
git log --pretty=format:"%h - %an, %ar : %s"
git log --pretty=format:"%h %s" --graph
git log --since=2.weeks
自己可以试一下,这里附上参数说明,自己可以随意配置,当然log字体颜色也都是可以修改的,不再细述。

选项 说明
%H 提交对象(commit)的完整哈希字串 %h 提交对象的简短哈希字串 .....................................................................................................
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串 %p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 -date= 选项定制格式) %ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示 %s 提交说明

时间和提交者过滤

选项 说明
-(n) 仅显示最近的 n 条提交....................................................................................................................................................
--since, --after 仅显示指定时间之后的提交。
--until, --before 仅显示指定时间之前的提交。
--author 仅显示指定作者相关的提交。
--committer 仅显示指定提交者相关的提交。

你一定奇怪_作者(author)_和_提交者(committer)_之间究竟有何差别,其实作者指的是实际作出修改 的人,提交者指的是最后将此工作成果提交到仓库的人。所以,当你为某个项目发去补丁,然后某个核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。我们会在第五章再详细介绍两者之间的细致差别。

11.忽略某些文件


文件 .gitignore 的格式规范如下:
• 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
• 可以使用标准的 glob 模式匹配。
• 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
• 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。星号(*)匹配零个或多个任意字符;[abc] 匹配 任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?) 只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配 (比如 [0-9] 表示匹配所有 0 到 9 的数字)。

# 此为注释 – 将被 Git 忽略
*.[oa]  Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现 的,我们用不着跟踪它们的版本
*~  Git 忽略所有以波浪符(~)结尾的文件,许多文本编辑软件 (比如 Emacs)都用这样的文件名保存副本
*.a # 忽略所有 .a 结尾的文件
!lib.a # 但 lib.a 除外
/TODO # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO build/ # 忽略 build/ 目录下的所有文件
doc/*.txt # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

更多 Git 教程系列文章: 

Git 的详细介绍请点这里
Git 的下载地址请点这里

猜你喜欢

转载自www.linuxidc.com/Linux/2017-11/148423.htm