这年头git基本都是项目开发的标配,以前恰好碰到了就花了两天时间系统学习了下。本文内容基原本自如下tutorial:Learn Git(建议直接去看原文,由于这个网站是有更新的)。这个是我看过对git进行版本控制和项目协做原理讲解最清楚的文档,就记下比较加深理解和记忆。css
Git是一种分布式版本控制系统(Distributed Version Control System),这是与以前流行的CVS,SVN之类的存在中央库的系统明显差别,即在git中每一个开发者的库都是完整的。git相比以前的VCS具备如下性能更强也更灵活,更安全(SHA1哈希算法)。在以后的why git for your organization模块里面大力安利了一波git给包括开发者,市场,管理,设计师,客户支持,人力资源一大波吃瓜群众。这里就不细说了,能够本身去看。html
git在windows,linux,mac os平台上均可用,所以无论你在哪一个平台上进行开发,只要使用git能对源码进行很好的管理。以ubuntu系统为例:前端
$ sudo apt-get update $ sudo apt-get install git
至于windows系统的话直接下载安装包安装便可。
通常在安装完git以后会顺便把本身的git帐号和邮箱设为默认值,简化之后的操做。linux
$ git config --global user.name "Emma Paris" $ git config --global user.email "eparis@atlassian.com"
git init
命令用于创建新的库。这既能够将已经存在可是并未版本化的项目转化为git库,也能够新建一个新的空库。所以这个命令是开始新项目的时候的第一个git命令,而且一个项目这个命令只须要一次(以后会用git clone将现存的库复制到本机的库中)。执行这个命令之后在项目的根目录下会产生一个.git的子目录,这里包含了一切关于这个库元数据(metadata)。好比:git
$ git init <directory>
这个命令将会在指定的目下下新建一个git库,这个文件夹下面除了.git没有别的内容。github
$ git init --bare <directory>
而指定--bare参数则会新建一个空的git库可是省略了工做目录(没有.git文件夹,本来git中的内容直接在新产生的文件夹中,所以通常文件名中会自带.git后缀,好比my-project.git)。共享库通常都是用带--bare标签新建的。
为何共享库须要用--bare创建
对于须要共享的中央库,若是库是non-bare的,那么在push branch时可能会覆盖库中在本机上作的一些修改;而若是时bare的,由于没有工做目录,因此不可能在库中编辑文件以及commit(以后会讲这个git的核心命令),也就不存在这个问题。因此通常中央库时bare的,而各开发者的本地库时non-bare的。
正则表达式
以前也提到了,这个命令用于复制现存的库。复制后的库的操做将彻底独立于原来的库,而在复制的同时会自动产生一个名为origin的远程连接指向原来的库,方便之后两个库之间的一些交互操做。于git init相似,这个命令在一个项目中也通常只须要执行一次。算法
$ git clone <repo> # 指定将库复制到当前文件夹 $ git clone <repo> <directory> # 将指定库复制到指定文件夹 $ git clone ssh://john@example.com/path/to/my-project.git # john是当前开发者的用户名
原始库能够在本地也能够在远程机器上经过http或者ssh连接获取。(ssh的端口可能会被某些防火墙block,因此通常会用http;可是用ssh来链接github时不用输入密码,更方便一些)。
git的项目协做模式:每一个开发者的库都是彻底的库,不须要像SVN那样经过中间库而互相之间能够push和pull commit。
shell
这个命令可让你直接经过命令行配置当前库的一些参数。ubuntu
$ git config user.name <name> # 定义当前库全部commit所用的用户名 $ git config --global user.name <name> # 定义当前用户全部commit使用的用户名 $ git config --global user.email <email> # 定义当前用户全部commit使用的email $ git config --global alias.<alias-name> <git-command> # 建立git命令别称(懒无止境) $ git config --system core.editor <editor> # 定义文本编辑器来给当前机器用户调用git commit之类的命令时使用 $ git config --global --edit # 直接用文本编辑器打开全局配置文件
PS:这些参数也能够在一下文件中找到:
项目开发必然包含是编辑-阶段缓存-提交这一流程。git add命令将当前工做目录中的一些改动保存到缓存区域,在正式提交(git commit)以前并不会影响库中的是实质内容(至关因而工做目录和项目历史之间的缓存区)。所以这一命令的使用很是常态化,每编辑修改一个或几个互相相关文件就能够git add,而后用git commit生成一个高度相关的快照。
$ git add <file> # 缓存全部指定文件中的变更 $ git add <directory> # 缓存指定文件夹中的变更 $ git add -p # 开启交互式缓存环节容许选择文件中具体那些变更存入缓存区
最后一个命令的操做方式在开启交互环境的时候会展现:y:缓存当前变更块;n:忽略当前变更块;s:将当前变更块分的更小;e:手动编辑变更块;q:退出交互环境。
而git commit命令则是提交缓存区中的快照到项目历史中,每个提交的快照均可以认为是项目的一个安全版本。除了显式命令以外,git是不会主动修改任何一个提交的快照。
$ git commit # 打开文本编辑器让你输入本次提交的快照的描述信息 $ git commit -m <message> # 直接输入的字符串做为提交的描述信息 $ git commit -a # 提交工做目录下全部改动的快照。注意:这里只包括以前用git add追踪过的文件
在git中commit的快照是保存在本地库中的,于以前的SVN保存在中央库这一点是明显的差别。与git add的缓存区相似,能够将本地库视为要编辑的代码和中央库之间的缓冲区。这种方式带来的优点有不少:好比能够将一次功能更新分解成多个commit,让相关的commit聚在一块儿,方便提交中央库以前对本地的commit历史进行整理。
git的一大核心特征就是commit的是快照而非SVN中的差别。git每次commit都将文件的全部内容都存快照中;而SVN每次保存的是文件中改动的地方。所以git对各commit快照的操做不须要整合之类的步骤,直接对目标commit进行操做便可。
具体操做实例:
$ git add hello.py $ git commit # 在编辑器中输入如下信息 #Change the message displayed by hello.py # #- Update the sayHello() function to output the user's name #- Change the sayGoodbye() function to a friendlier message
通常输入信息的格式为第一行是不超过50各字母的总结,空一行,而后是具体改动的说明。
若是当你一个功能开发到一半忽然有一个紧急任务要立刻作(码农平常),那么这个时候就须要用git stash这个命令把上次commit到目前的改动先隐藏起来使其不影响别的开发任务,等到你完成以后调出这个隐藏部分而后继续开发直至下次commit为止。
$ git status # 显示上次commit与当前状态下的有差别文件路径(有改动的,新添加的,以及未被追踪的) On branch master # 有改动的分支 Changes to be committed: new file: style.css Changes not staged for commit: modified: index.html $ git stash Saved working directory and index state WIP on master: 5002d47 our new homepage #保存stash到本地,将HEAD指向最近一次commit HEAD is now at 5002d47 our new homepage $ git status # 这种状态下就能够进行随意操做-好比新建commit,切换branch等,以后有须要再切回到stash的分支继续操做便可 On branch master nothing to commit, working tree clean $ git stash pop # 弹出以前最近的stash On branch master Changes to be committed: new file: style.css Changes not staged for commit: modified: index.html Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a) $git stash apply # 与pop相似,只是这边弹出的stash只是一份拷贝。所以能够将这个stash用于多个分支。 On branch master Changes to be committed: new file: style.css Changes not staged for commit: modified: index.html
在默认状况下,git stash只会stash已经在缓存区域的变更(staged changes)和正在被git追踪的的文件中的变更(Unstaged changes),并不会stash工做副本下unstaged文件和被git定义忽略的文件(以后会在gitigore部分有介绍)。因此若是在以前的栗子中添加一个新文件可是没有用git add命令stage,那么这个就是untracked文件不会被stash。可是若是在stash命令中加入-u(--include-untracked)标签,那么未被追踪的文件也会被stash;而用-a(--all)标签则会把被git忽略的文件也stash。
$ script.js $ git status On branch master Changes to be committed: new file: style.css Changes not staged for commit: modified: index.html Untracked files: script.js # ———————————————————————————————————————— $ git stash Saved working directory and index state WIP on master: 5002d47 our new homepage HEAD is now at 5002d47 our new homepage $ git status On branch master Untracked files: script.js # ------------------------------------------------------------------------------- $ git stash -u Saved working directory and index state WIP on master: 5002d47 our new homepage HEAD is now at 5002d47 our new homepage $ git status On branch master nothing to commit, working tree clean
对多个stash进行操做
stash的使用次数并无限制,所以能够有创建多个stash。默认状态下stash被认为是创建stash时分支和commit顶部的WIP(work in process),经过git stash list能够查看全部的stash。若是stash个数比较多,能够用git stash save在stash时添加注释信息以便后续调用时查看。须要回到哪一个stash状态的时候用git stash pop + stash id便可。
$ git stash list stash@{0}: WIP on master: 5002d47 our new homepage # 5002d47是创建stash时最近的commmit id,master是stash时的分支名,stash@{0}就是stash的id stash@{1}: WIP on master: 5002d47 our new homepage stash@{2}: WIP on master: 5002d47 our new homepage $ git stash save "add style to our site" Saved working directory and index state On master: add style to our site HEAD is now at 5002d47 our new homepage $ git stash list stash@{0}: On master: add style to our site stash@{1}: WIP on master: 5002d47 our new homepage stash@{2}: WIP on master: 5002d47 our new homepage $ git stash pop stash@{2}
在不肯定stash到底作了哪些改动的时候能够用git stash show来查看具体改动信息。
$ git stash show # 差别汇总 index.html | 1 + style.css | 3 +++ 2 files changed, 4 insertions(+) $ git stash -p # -p/--patch标签用于显示具体差别 diff --git a/style.css b/style.css new file mode 100644 index 0000000..d92368b --- /dev/null +++ b/style.css @@ -0,0 +1,3 @@ +* { + text-decoration: blink; +} diff --git a/index.html b/index.html index 9daeafb..ebdcbd2 100644 --- a/index.html +++ b/index.html @@ -1 +1,2 @@ +<link rel="stylesheet" href="style.css"/>
部分stash
用git stash -p/--patch命令将会迭代文件中的每一处改动块来决定是否要stash这个部分。
$ git stash -p diff --git a/style.css b/style.css new file mode 100644 index 0000000..d92368b --- /dev/null +++ b/style.css @@ -0,0 +1,3 @@ +* { + text-decoration: blink; +} Stash this hunk [y,n,q,a,d,/,e,?]? y diff --git a/index.html b/index.html index 9daeafb..ebdcbd2 100644 --- a/index.html +++ b/index.html @@ -1 +1,2 @@ +<link rel="stylesheet" href="style.css"/> Stash this hunk [y,n,q,a,d,/,e,?]? n
操做模式与以前的git add相同。
从stash处建立新分支
若是当前分支的变更偏离了stash中的变更,那么在调用stash时代时候就极可能产生冲突。这个时候就须要用git stash branch建立新的分支来加载stash中的变更。
$ git stash branch add-style stash@{1} # 从创建stash时的commit处创建并切换到新的分支add-style,而后载入stash中的变更。 Switched to a new branch 'add-stylesheet' On branch add-stylesheet Changes to be committed: new file: style.css Changes not staged for commit: modified: index.html Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)
删除stash
若是以前储存的stash不要了能够用git stash drop/clear来清楚。
git stash drop stash@{1} # 删除stash@{1}分支 Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb) git stash clear # 删除全部stash
stash实际上是特殊的commit。.git/refs/stash中储存了一个特殊的标签指向最近新建的stash,而以前创建的stash则是经过当前stash标签的引用日志(reflog)进行指向。因此当指向stash@{n}的时候实际上是指向了当前stash标签的第n条引用日志。而当stash命令执行的时候,会根据状况新建2或3条commit,同时.git/refs/stash文件中会更新一个指针用于指向新创建的commit。此外因为是commit,因此能够经过git log(后面会讲)来查看stash的历史记录。
$ git log --oneline --graph stash@{0} *-. 953ddde WIP on master: 5002d47 our new homepage # 新的commit用于存储当前工做目录下被追踪的文件 |\ \ | | * 24b35a1 untracked files on master: 5002d47 our new homepage # 新的commit用于存储当前工做目录下未追踪的文件(这个commit只有在工做目录下存在未追踪的文件,同时--include-untracked或--all标签也同时使用的时候才会被创建) | * 7023dd4 index on master: 5002d47 our new homepage # 新的commit用于存储缓存区(git add) |/ * 5002d47 our new homepage # HEAD指针指向的以前存在的最近的一次commit
在stash以前工做目录的状态通常以下所示:
而当stash命令执后的状态以下:
带--include-untracked标签
带--all标签
git把工做目录下的文件分为3类:tracked(追踪的)-以前有stage(git add)或者commit记录的文件;untracked(未追踪的)-还没有stage和commit的文件;ignored(忽略的)-被git特地忽略的文件。通常被忽略的文件包括第三方文件(各类包),源文件可以产生的文件或文件夹,编译后的文件(.pyc),运行过程当中产生的日志文件(.log),隐藏的系统文件(.DB_store),我的的IDE配置文件等。而这些被忽略的文件的模式则是存储在.gitignore文件中。.gitignore文件能够存在多个,发生冲突的时候本地文件夹的.gitignore的配置会覆盖库根目录下的,根目录下的则会覆盖系统层面的,所以为了方便期间通常都是只在库的根目录下放一个。忽略文件的模式采用正则表达式规则,具体能够看这里,下面举几个经常使用的栗子:
**/logs # 当前库下全部名为logs目录下的文件(双*用于匹配当前库下面的任何文件夹),好比logs/debug.log,/build/logs/foo.log *.log # 当前库下全部log后缀的文件,好比logs/debug.log, foo.log !important.log # 除此之外的全部文件,与前一命令一块儿使用时则是表示除了important.log文件之外的全部log文件都会被忽略
须要注意的时.gitignore文件位于根目录下,所以能够被stage和commit到版本迭代中。若是只是想定义本身所需的忽略文件并不想commit到代码库中,能够将忽略规则添加到.git/info/exclude文件中,这个文件不会被stage,所以避免了可能被commit到公共库的状况。
若是须要将本机下全部库都设置相同的忽略规则,那么就能够用$ git config --global core.excludesFile .gitignore
命令,而这同时也就不须要考虑把.gitignore 文件放在哪的问题了。
若是须要忽视以前commit的文件,须要用git rm命令将文件重库中删除而后再添加相应规则到.gitignore文件中。
$ echo debug.log >> .gitignore $ git rm --cached debug.log # --cached表示只删除库里的文件而保留工做目录下的。若是不用则两个地方都会被删掉 rm 'debug.log' $ git commit -m "Start ignoring debug.log"
若是须要commit被忽略的文件,能够在git add的时候加上-f/--force标签;也能够用以前提到的!来指定进行例外文件。
$ cat .gitignore *.log $ git add -f debug.log $ echo !debug.log >> .gitignore #----------------------------- $ cat .gitignore *.log !debug.log $ git add debug.log
若是须要stash被忽略的文件,如以前所说,须要在git stash时添加--all标签。
而当你不肯定某个文件因为哪一个规则被忽略时,能够用git check-ignore命令查看忽略文件的规则。
$ git check-ignore -v debug.log .gitignore:3:*.log debug.log # 格式未忽略文件的规则:规则所在行;规则;忽略的文件
工做目录和缓存区的状态包括staged变更(存到缓存区),还未staged的变更以及还没有被追踪的文件,而那些被忽略的文件信息并不会有所显示。因此git status的输出通常以下:
# On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # #modified: hello.py # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # #modified: main.py # # Untracked files: # (use "git add <file>..." to include in what will be committed) # #hello.pyc
在commit以前及时git status能够防止一些偶然操做致使commit一些想要的变更。
git log只能用来查看commit的历史记录,而后选择须要炒做的commit快照。
$ git log #以默认格式输出commit历史 $ git log -n <limit> # 限制输出最近<limit>个commit $ git log --oneline # 将每个commit的信息压缩到一行中显示,很方便查看大量commit $ git log --stat # 增长显示具体变更的文件和每一个文件增减的行数 $ git log -p # -p/--patch具体显示每一个commit的改动信息 $ git log --author="<pattern>" # 显示某位开发者的commit,匹配信息能够是字符串也能够是正则表达式 $ git log --grep="<pattern>" # 显示某种模式的commit,匹配信息能够是字符串也能够是正则表达式。 $ git log <since>..<until> # 显示从since到until之间的commit,能够是commit ID,分支名称(master..some-brance),HEAD指针(HEAD~2:当前commit的往前数第二个commit) $ git log <file> # 显示某个文件相关的commit $ git log --graph # 用文字图的形式显示commit $ git log --decorate # 增长显示commit的分支名或者标签名
注意commit ID为40为的SHA1检验和(好比3157ee3718e180a9476bf2e5cab8e3f1e78a73b7),这样用于确保ID的惟一性和检验commit的完整性。
这些命令都能用来对历史commit进行处理,可是原理和效果都不太相同。
git checkout
这个命令的对象能够有3种:文件,commit,分支(checkout分支主要能够是用来切换分支用,在以后有具体介绍在这里就先跳过)。checkout commit时使整个工做目录都回归到选择的commit的状态且并不对目前的状态有任何影响;而checkout文件则是将具体文件回到特定commit时的状态而不影响工做目录下的其余文件。要注意的时checkout commit命令只是看一个只读操做,在查看旧版本或者以前的commit的时候不会对当前库有任何不良影响,所以是一个十分安全的操做。
$ git checkout <commit> <file>
commit能够用commit哈希码或者标签(tag)做为指定变量,但此时HEAD指针将会处于分离的状态(在正常状态时HEAD指针是指向某一个分支的最前端,而当checkout命令调用时,HEAD指针将会指向给定的commit)。
$ git log --oneline # 假设当前工做分支为master b7119f2 Continue doing crazy things 872fa7e Try something crazy a1e8fb5 Make some important changes to hello.py 435b61d Create hello.py 9773e52 Initial import $ git checkout a1e8fb5 # 切换到a1e8fb5的commit状态,此时查看编译甚至修改文件都不会对以前分支的状态有任何影响 $ git checkout master # 切回以前的分支继续开发
而当checkout的对象为文件时,则会确实影响当前库的状态。当你从新commit到文件以前的版本时,也就将文件的状态退回到了特定版本。
$ git checkout a1e8fb5 hello.py # 将hello.py文件的状态切换到a1e8fb5 commit状态,文件确实发生改动 $ git checkout HEAD hello.py # 将hello.py文件状态切回到最近的状态
git revert
git revert回到以前的状态的工做方式是新建一个commit而后把须要回归的commit的状态快照复制到这个commit。这样作的好处就是以前commit的历史记录仍旧完整,使协做时不至于commit历史记录改变出现冲突。
# Edit some tracked files # Commit a snapshot $ git commit -m "Make some changes that will be undone" # Revert the commit we just created $ git revert HEAD # 回到了commit以前的状态
git reset
相比于git revert能保存commit历史的这种相对安全的方法,git set的工做方式是指向要回归的commit,并将如今的状态到须要回归的commit之间全部的commit快照都删除,所以调用git reset时候是直接改动了commit的历史记录,使用的时候(尤为是御别人协做的时候)须要格外当心。通常状况下只在本地库中使用git reset命令,而避免在共享的公共库上面进行这项操做。
$ git reset <file> # 移除缓存区中的特定文件,但并不会改变工做目录的状态。 $ git reset # 将缓存区状态回归到最近一次的commit状态,但不会改变工做目录的状态(也就是有机会git add回去以前的状态) $ git reset --hard # 将缓存区和工做目录都回归到以前commit的状态(消去上次commit以后的全部变更) $ git reset <commit> # 将缓存区状态回归到指定的commit状态,但并不改变工做目录的状态 $ git reset --hard <commit> # 将缓存区和工做目录都回归到特定commit的状态(消去指定commit以后发生的全部变更)
基于git reset 和git revert的操做方式,通常前者用于本地的撤销操做,然后者用于共享的commit的撤销操做。
若是在公共库中进行reset操做就会出现如下情况,git会认为你新建了分支,须要用merge操做进行整合。
下面两个栗子讲如下git reset最多见的用途:
1.删除缓冲区的特定文件(git add的时候不当心加错了)
# Edit both hello.py and main.py # Stage everything in the current directory $ git add . # Realize that the changes in hello.py and main.py # should be committed in different snapshots # Unstage main.py $ git reset main.py # Commit only hello.py $ git commit -m "Make some changes to hello.py" # Commit main.py in a separate snapshot $ git add main.py $ git commit -m "Edit main.py"
2.删除本地commit历史(掩盖本身曾经作过的一些蠢到没朋友的一些测试)
# Create a new file called `foo.py` and add some code to it # Commit it to the project history $ git add foo.py $ git commit -m "Start developing a crazy feature" # Edit `foo.py` again and change some other tracked files, too # Commit another snapshot $ git commit -a -m "Continue my crazy feature" # Decide to scrap the feature and remove the associated commits $ git reset --hard HEAD~2 # 回归开发crazy feature以前的commit状态,并销毁痕迹
git clean
git clean会移除工做目录下未被追踪的文件(避免了用git status查看状态来一一确认须要删除的未追踪文件,很是方便)。须要主要的是这个命令跟rm命令同样是不可撤销的,使用的时候须要考虑清楚。而git clean命令也常常御git reset --hard命令一块儿使用,由于后者能只能对追踪的文件进行操做,二者一块儿使用可以确保搞那个钱工做目录回到特定的版本状态,这在项目编译后须要把编译文件去掉进行打包操做时特别有用。
$ git clean -n # 显示会被清除的文件,但并无实际运行。(方便确认) $ git clean -f # 删除为追踪的文件(除非把用git config --global 命令把clean.requireForce设置为false,-f是必须加的),但并不会删除未追踪的文件夹以及忽略的文件 $ git clean -f <path> # 删除指定文件夹下的未追踪文件 $ git clean -df # 删除未追踪的文件和文件夹 $ git clean -xf # 删除当前目录下未追踪和忽略的文件
与以前的删除操做相似,git也提供了一些修改commit历史的命令,虽然这可能会致使一些内容的损失。
git commit --amned
这个命令直接用新的commit快照来替换以前的commit(注意时替换而非修改),这让咱们可以很方便的修正一些有问题的commit快照。
正如git reset同样,这个命令也不要用来修正已经共享的commit,由于这至关于以前的commit被删掉了,若是别人的新功能依赖以前共享的commit那就很容易产生冲突。
# Edit hello.py and main.py $ git add hello.py $ git commit # Realize you forgot to add the changes from main.py $ git add main.py $ git commit --amend --no-edit # 不改变以前的commit的信息,在忘了添加文件到缓存区的时候特别有用。
git rebase
这个命令是把某个分支以新的commit的形式整个移到另外一个分支的最前端。因为有新建commit的操做,也就对分支的历史有所改动。效果以下:
git rebase <base> # 对象能够是分支ID,标签(tag),HEAD指针
这个命令主要用于保持一个线性的项目开发历史。当你须要把一个分支的新功能merge到master分支上,用rebase命令产生的历史就会如上图所示保持线性,之后查看的时候很是清晰。rebase也是把上游公共库的变更整合到本地库的常见作法(直接用merge可能会产生打乱原有commit的顺序,当你查看的时候可能会不明因此),可是与以前git commit --amend 和git reset命令同样,git rebase命令也须要避免在已经共享的commit上面。
# Start a new feature $ git checkout -b new-feature master # 从master分支新建并切换到该分支 # Edit files $ git commit -a -m "Start developing a feature" # Create a hotfix branch based off of master $ git checkout -b hotfix master # 发现有个问题须要hotfix下,就从master新建了hotfix分支 # Edit files $ git commit -a -m "Fix security hole" # Merge back into master $ git checkout master $ git merge hotfix # 修复完成后把hotfix分支整合到master分支 $ git branch -d hotfix # 删除hotfix分支 $ git checkout new-feature # 切换到new-feature分支 $ git rebase master # 把new-feature分支移动到master分支的最前端保持线性历史(由于以前插入了hotfix的commit,若是这届合并的话new-featrue的历史就会在hotfi以前了) $ git checkout master $ git merge new-feature
git rebase -i
-i标签是指进行交互式的rebase操做,能够对commit历史进行分割,改动,删除等操做,而不是一股脑把全部commit都移动到一个分支最前端。这就给了开发者很大的自由,在开发的时候在本机上能够随便commit,只要在提交公共库以前用这个命令把commit调整好、去掉过期的commit、保持每一个commit都是有意义的(装逼神器)。
# Start a new feature $ git checkout -b new-feature master # Edit files $ git commit -a -m "Start developing a feature" # Edit more files $ git commit -a -m "Fix something from the previous commit" # Add a commit directly to master $ git checkout master # Edit files $ git commit -a -m "Fix security hole" # Begin an interactive rebasing session $ git checkout new-feature $ git rebase -i master # 在new-feature分支上有两个commit pick 32618c4 Start developing a feature # pick是命令,若是须要执行别的操做用别的命令便可 pick 62eed47 Fix something from the previous commit pick 32618c4 Start developing a feature squash 62eed47 Fix something from the previous commit # squash命令即表示这个commit在rebase的时候会被去掉(在git log的时候能够查看到) # 保存关闭编辑器后开始rebase $ git checkout master $ git merge new-feature
git reflog
git用名为reflog的机制追踪每一个分支最前端的更新状态,所以每当HEAD指针的状态有变化(好比切换分支,pull变更,重写历史,增长commit)就有新的条目被加到reflog中。在重写历史之后,reflog包含了关于分支的旧状态,让你在须要的时候回到这些状态。注意的是git reflog只是8追踪状态变动操做。
$ git reflog # 查看本地库的reflog 0a2e358 HEAD@{0}: reset: moving to HEAD~2 # 最近的活动 0254ea7 HEAD@{1}: checkout: moving from 2.2 to master c10f740 HEAD@{2}: checkout: moving from master to 2.2 $ git reflog --relative-date # 增长显示reflog的相对日期信息(好比2 days ago) $ git reset --hard 0254ea7 # 使用git reset命令就能够回到以前的commit状态
到这里为止就是一些在git上创建项目,对项目进行基本的开发操做所需的最多见的命令。下一步就须要讲git进行项目协做时所须要的一些经常使用命令。