当前位置:   article > 正文

git实战_source 分支和dest分支

source 分支和dest分支

Git是一个分布式的版本控制系统。Linux kernel源码管理就是通过git管理的。Linux源码最开始用社区版的bitkeeper管理源码,后来bitkeeper社区版不再开源了。Linus觉得CVSSVN都还有需要改进的地方,就从头开发了一个分布式的版本控制系统git。鉴于“git详解系列”文章已经达到了不可企及的高度。这篇文章主要从实践的角度出发,更多的介绍git操作。

常见的版本控制系统还有IBMclearcaseSVNCVS等。假设你有个文件,需要不停地修改,然后还需要追踪文件的每一修改记录,需要方便的取出任一次修改记录或者恢复到任一次修改。这时你需要一个版本控制系统,通常也就变更控制系统,用来专门记录你的每一次变更。对于软件开发人员来说版本控制系统经常是指源码管理系统,上边提到的几个都是经常用到的源码管理系统,不过它们都是集中式的版本控制系统,而Git是一个分布式的控制系统,所以在概念方面要比其他几个系统复杂一些。

分布式版本控制系统和集中式的版本控制系统的区别在于,集中式的版本控制系统都有一个集中的源码库,所有的人都修改这个集中源码库的文件。分布式的版本控制系统不必有一个中央的源码库,所有的源码都在本地源码库中进行追踪和管理。需要的时候才上传到中央服务器。集中式的版本控制系统,中央服务器可能成为单点故障,导致不能工作。分布式的版本控制系统,每一个本地的源码都是一个独立的源码库,即使在飞机上,不能连接网络,还是可以照常工作。


1 Git config

Git配置存在三个级别,取决于我们需要这些配置怎么样应用于我们的系统。

第一种,系统配置。应用于这台电脑的任何用户。这种配置不太经常用,现在的操作系统都是多用户的,每一个用户应该有一个git的配置。对于家庭电脑,这个系统就一个人用,那是没有问题的。如果是公司的电脑,可能有多个人在使用,那么系统配置就不合适了。在linux系统上系统级的配置的配置文件一般在/etc/gitconfig,对于windos系统,系统级别的配置一般在Program Files\Git\etc\gitconfig。配置方式:git config --system

第二种,用户配置。这种配置只对一个具体的用户生效。这种配置是经常使用的配置git的方式。在linux系统上这种配置的配置文件通常在你的home目录下的.gitconfig文件中。在widnows上这种配置的配置文件也在home目录$HOME\.gitconfig文件。配置方式git config --global

第三种,项目配置。这种级别的配置文件时针对一个项目的具体配置。这种配置文件在my_project/.git/config目录。配置方式git config

常用的git 配置。这里以用户配置为例,其他的类似。

  1. git config --global user.name “zsli”
  2. git config --global user.email "zsl6658@126.com"
  3. git config --global core.editor “vim”
  4. git config --global color.ui true
  5. git config --list

2 git init

初始化一个仓库。git init。将在项目的目录下创建一个.git的隐藏文件夹,这个文件夹里边存放了git管理这个项目的所有信息。包括刚才上边提到的项目级别的config目录,保存了项目的配置。同时还包括HEADbranches,description,hooks,info,objects,refs等几个目录。

git的基本工作步骤:

1,做出更改,vim first_file.txt

2,增加更改,git add first_file.txt

3,提交更改,git commit -m ‘Initial commit’

Git commit log最佳实践:

1,包含bugid类似的信息。

2,一个简短的描述,描述commit的概要信息。

3,详细的描述。

3 Git concepts

版本树

Git使用三个版本树的模式管理源码,而其他的基本都使用两棵版本树的方式管理源码。

两棵版本树

仓库和工作目录。从仓库获取源码,在本地工作目录编辑修改,然后提交到仓库。不停重复这个工作一直到任务完成。

三课版本树

Git中增加一棵版本树,一个staging index树。从仓库获取源码到本地工作目录,做出修改,这时git不是直接提交到仓库,而是先提交到staging index。其他的版本管理工具中如果修改一个bug,今天修改了一个bug,但是还没有修改完成,明天还要修改几个文件。这时你就需要commit两次。在git中你可以先把今天的修改addstaging index中,明天修改完成后,把明天的修改一块添加到staging index中,然后一次commit

Git 工作流程

新建一个文件 file.txt

Git add file.txt

Git commit file.txt


最开始三棵版本树上的文件的版本是相同的。这时我们对工作目录的文件作出修改。

这时工作目录的文件变成v2了。当我们执行了git add file.txt后,我们就把工作目录的修改暂存到了staging index中。这时版本如下:

这时我们提交修改。git commit file.txt。版本变成如下:

这时文件的三棵版本树的版本又一致了。Git的工作流程就是修改文件,增加修改,然后提交修改。不停地重复这个工作。

Hash values

git是如何引用版本变更中的任何一个快照状态的呢?Git为每一个变更都会生成一个checksum,使用SHA-1生成checksum40个十六进制字符。比如:c905d813e590157d816bbd3603bcef10ad03e166。每一个文件或者目录的变更都对应一个checksum值,所有的checksum之间连接起来,表示修改顺序。

HEAD指针

HEAD指针始终指向了当前仓库的分支,在我们做出修改,然后提交修改的过程中,HEAD指针是在变化的。它也是我们最初从仓库的那个分支开始的指针,就是我们checkout的地方,也是下一个commit的父指针。HEAD是我们理解分支的一个重要概念。比较拗口和难理解。

举个栗子。HEAD就像录音机的录音头,当我们按下录音时,HEAD指向开始录音的地方。当我们结束录音,然后再开始录音,这时HEAD就指向了第二次录音的位置。始终指向我们开始工作的地方。对应于git就是我们上次commit的地方,当我们再次commit的时候,git会移动HEAD到最新的地方。对于两个不同的分支也是一样的情况,始终指向当前分支的开始工作的地方。

上边我们提到.git/HEAD文件。这时一个文本文件,里边记录了HEAD指针的位置。比如:

ref: refs/heads/master

这是一个指针,说明HEAD指向refs/heads/master中的变更。查看refs/heads/master,里边是一个checksum

c905d813e590157d816bbd3603bcef10ad03e166

查看git log:

  1. commit c905d813e590157d816bbd3603bcef10ad03e166
  2. Author: shunliz <zsl6658@126.com>
  3. Date: Sun Sep 8 09:39:23 2013 +0800
  4. Initial commit

可以看到,这个checksum就是我们最新的一次提交的checksum

HEAD就是当前分支对应到仓库中的一个指针。

4 git status

git status用来查看当前git的状态。下边给出三个文件的变化状态。仔细观察文件不同变化状态以及git stauts的输出。第一行指示当前分支,第二行开始显示各种状态的文件列表。任何时候先看看git status是一个好的习惯。

  1. $ vim first.txt
  2. $ vim second.txt
  3. $ vim third.txt
  4. $ git status
  5. # On branch master
  6. # Untracked files:
  7. # (use "git add <file>..." to include in what will be committed)
  8. #
  9. # first.txt
  10. # sencod.txt
  11. # third.txt
  12. nothing added to commit but untracked files present (use "git add" to track)
  13. $ git add first.txt
  14. $ git status
  15. # On branch master
  16. # Changes to be committed:
  17. # (use "git reset HEAD <file>..." to unstage)
  18. #
  19. # new file: first.txt
  20. #
  21. # Untracked files:
  22. # (use "git add <file>..." to include in what will be committed)
  23. #
  24. # sencod.txt
  25. # third.txt
  26. $ git commit -m 'first.txt commited'
  27. [master adf64aa] first.txt commited
  28. 1 file changed, 1 insertion(+)
  29. create mode 100644 first.txt
  30. $ git status
  31. # On branch master
  32. # Untracked files:
  33. # (use "git add <file>..." to include in what will be committed)
  34. #
  35. #sencod.txt
  36. # third.txt
  37. nothing added to commit but untracked files present (use "git add" to track)
  38. $ git add .
  39. $ git status
  40. # On branch master
  41. # Changes to be committed:
  42. # (use "git reset HEAD <file>..." to unstage)
  43. #
  44. # new file: sencod.txt
  45. # new file: third.txt
  46. #
  47. $ git commit -m 'add other two file'
  48. [master 3ef326c] add other two file
  49. 2 files changed, 2 insertions(+)
  50. create mode 100644 sencod.txt
  51. create mode 100644 third.txt
  52. $ git status
  53. # On branch master
  54. nothing to commit (working directory clean)

5 git diff 

git diff 默认对比staging index和当前工作目录的内容。带有+号的是当前工作目录增加的内容,带有-号的是staging的被删除内容。

  1. $ git diff
  2. diff --git a/sencod.txt b/sencod.txt
  3. index 8a68632..41bfa64 100644
  4. --- a/sencod.txt
  5. +++ b/sencod.txt
  6. @@ -1 +1 @@
  7. -Second file contentx
  8. +modified second line of txt file

这个时候如果我们执行git add sencod.txt,再执行git diff。我们将什么都看不到。因为git diff默认是查看staging和工作目录的差别。Sencod.txt已经暂存,这时diff什么也看不到。那么如何查看staging和仓库的差别呢?

  1. $ git diff --staged
  2. diff --git a/sencod.txt b/sencod.txt
  3. index 8a68632..41bfa64 100644
  4. --- a/sencod.txt
  5. +++ b/sencod.txt
  6. @@ -1 +1 @@
  7. -Second file contentx
  8. +modified second line of txt file

(1.7之前用git diff --cached)

git diff filename可以查看某一个文件的差别。适用上边两种情况。 

6 Git undo

git checkout -- filename 撤销工作区的修改

git reset HEAD filename撤销暂存,保留工作区的修改。

git reset --hard filename 撤销暂存,撤销工作区的修改。

git reset --soft只修改指针指向,暂存和工作区不做修改。

7 查看git

git ls-tree 查看目录树

  1. $ git log
  2. commit 462d5fe241b10b193ada252e7b8ccb2b6c08e6d9
  3. Author: shunliz <zsl6658@126.com>
  4. Date: Sun Sep 8 12:12:18 2013 +0800
  5. asdfasdfasdfasdf
  6. commit 3ef326c1e033ecab192e7207fbd1dbd93a6cab95
  7. Author: shunliz <zsl6658@126.com>
  8. Date: Sun Sep 8 10:59:38 2013 +0800
  9. add other two file
  10. commit adf64aa26eba3ccfd53ea4b4ab7d8aa8ac241c63
  11. Author: shunliz <zsl6658@126.com>
  12. Date: Sun Sep 8 10:56:42 2013 +0800
  13. first.txt commited
  14. commit c905d813e590157d816bbd3603bcef10ad03e166
  15. Author: shunliz <zsl6658@126.com>
  16. Date: Sun Sep 8 09:39:23 2013 +0800
  17. Initial commit
  18. $ git ls-tree 462d5fe241b10b
  19. 100644 blob a135e5a18155983180a484700b0dc0ff4afd1632 first.txt
  20. 100644 blob dba0775758f0948f5f02f7caa2db7bbc16f7f290 first_file.txt
  21. 100644 blob 41bfa64572b77c8d11ad9566de6be7610179f6d6 sencod.txt
  22. 100644 blob 569bde967162f309235160276df47422bb09232d third.txt
  23. $ git ls-tree HEAD
  24. 100644 blob a135e5a18155983180a484700b0dc0ff4afd1632 first.txt
  25. 100644 blob dba0775758f0948f5f02f7caa2db7bbc16f7f290 first_file.txt
  26. 100644 blob 41bfa64572b77c8d11ad9566de6be7610179f6d6 sencod.txt
  27. 100644 blob 569bde967162f309235160276df47422bb09232d third.txt
  28. $ git ls-tree HEAD^ (=git ls-tree HEAD^1
  29. 100644 blob a135e5a18155983180a484700b0dc0ff4afd1632 first.txt
  30. 100644 blob dba0775758f0948f5f02f7caa2db7bbc16f7f290 first_file.txt
  31. 100644 blob 8a686325f3551d8d8d2738b0ac7380b56f0cd4aa sencod.txt
  32. 100644 blob 569bde967162f309235160276df47422bb09232d third.txt
  33. $ git ls-tree HEAD^^ (=git ls-tree HEAD^2
  34. 100644 blob a135e5a18155983180a484700b0dc0ff4afd1632 first.txt
  35. 100644 blob dba0775758f0948f5f02f7caa2db7bbc16f7f290 first_file.txt
  36. $ git ls-tree HEAD^^^ (=git ls-tree HEAD^3
  37. 100644 blob dba0775758f0948f5f02f7caa2db7bbc16f7f290 first_file.txt

git show 可以查看任何东西,目录树,commitlog等等

  1. $ git show HEAD^1
  2. commit 3ef326c1e033ecab192e7207fbd1dbd93a6cab95
  3. Author: shunliz <zsl6658@126.com>
  4. Date: Sun Sep 8 10:59:38 2013 +0800
  5. add other two file
  6. diff --git a/sencod.txt b/sencod.txt
  7. new file mode 100644
  8. index 0000000..8a68632
  9. --- /dev/null
  10. +++ b/sencod.txt
  11. @@ -0,0 +1 @@
  12. +Second file contentx
  13. diff --git a/third.txt b/third.txt
  14. new file mode 100644
  15. index 0000000..569bde9
  16. --- /dev/null
  17. +++ b/third.txt
  18. @@ -0,0 +1 @@
  19. +Third file content
  20. $ git show 41bfa6457
  21. modified second line of txt file
  22. $ git show sencod.txt
  23. commit 462d5fe241b10b193ada252e7b8ccb2b6c08e6d9
  24. Author: shunliz <zsl6658@126.com>
  25. Date: Sun Sep 8 12:12:18 2013 +0800
  26. asdfasdfasdfasdf
  27. diff --git a/sencod.txt b/sencod.txt
  28. index 8a68632..41bfa64 100644
  29. --- a/sencod.txt
  30. +++ b/sencod.txt
  31. @@ -1 +1 @@
  32. -Second file contentx
  33. +modified second line of txt file
  34. $ git show 462d5fe24..ef3ed93dbd
  35. commit ef3ed93dbdf57a48e325240cdb31b2a846b5daa8
  36. Author: shunliz <zsl6658@126.com>
  37. Date: Sun Sep 8 15:38:20 2013 +0800
  38. more commit
  39. diff --git a/sencod.txt b/sencod.txt
  40. index f05f181..17ddfeb 100644
  41. --- a/sencod.txt
  42. +++ b/sencod.txt
  43. @@ -1,2 +1,4 @@
  44. modified second line of txt fil
  45. e
  46. +
  47. +more add commit
  48. commit a58af56f31db6ee9261c3dbf1665ee41e4214159
  49. Author: shunliz <zsl6658@126.com>
  50. Date: Sun Sep 8 15:37:37 2013 +0800
  51. another commit
  52. diff --git a/sencod.txt b/sencod.txt
  53. index 41bfa64..f05f181 100644
  54. --- a/sencod.txt
  55. +++ b/sencod.txt
  56. @@ -1 +1,2 @@
  57. -modified second line of txt file
  58. +modified second line of txt fil
  59. +e
  60. $ git show --since=2013-08-24
  61. commit ef3ed93dbdf57a48e325240cdb31b2a846b5daa8
  62. Author: shunliz <zsl6658@126.com>
  63. Date: Sun Sep 8 15:38:20 2013 +0800
  64. more commit
  65. diff --git a/sencod.txt b/sencod.txt
  66. index f05f181..17ddfeb 100644
  67. --- a/sencod.txt
  68. +++ b/sencod.txt
  69. @@ -1,2 +1,4 @@
  70. modified second line of txt fil
  71. e
  72. +
  73. +more add commit

8 Git branch

git中,分支是廉价的。在其他的源码管理系统中,如果需要在另外一个分支fix一个bug,这时我们需要把那个分支checkout下来,然后fix bug,然后提交。这时就存在两份code。而在git中,你只要保存一份code,然后创建不同的分支,然后fix bug在一个分支,开发新feature在一个分支,试验一个idea在另外一个分支。各个分支之间互不干扰,只需要在各个分支之间切换就ok。比如我们正在开发一个新的feature,这时线上突然发现一个重大bug需要fix,这时其他的源码管理系统就需要把线上的那个分支取下来,然后fix bug,然后提交。如果我们需要试验一下我们的想法,我们还需要再copy下来一份代码在里边试验。在git中就不需要这么麻烦,我们可以创建不同的分支。Fix bug 我们可以git checkout  -b bug123 master,fix bug,然后commit我们的修改。然后git checkout master继续我们的新feature的开发。这时如果我们有一个新的想法需要验证一下,我们可以git checkout -b ideaxxx master,实现我们的想法,然后验证。验证通过后,我们可以把ieadxxx的代码mergemaster上边来。

从上边已经可以看到git分支的强大。下边就看一下git的一些分支操作。

git branch显示当前机器的所有分支列表。Git默认的当前分支为master分支。*表示的是当前的分支。

git branch xxxx创建一个xxx的新分支。

git checkout xxx 切换到一个xxx分支。

git checkout -b xxxx 创建一个新分支同时切换到新分支。

git diff master..xxxx 对比masterxxx分支。

git diff master^..xxxx 对比master分支的前一个提交和xxx分支。

git branch -m newxxxx重命名一个分支。

git branch -d xxxx删除一个分支。必须在其他分支上才能删除需要删除的分支,不能删除当前正在操作的分支。如果需要删除的分支上有没有commit的内容,这时需要-D才能删除分支。

git merge sourcebranch destbranch source分支上的变更合并到dst分支。Dest分支如果是source分支的祖先,将会发生一个fast forward合并,如果dest分支上边的HEAD有新的提交,已经不用与source分支的checkout时,这时将发生一个真正的合并操作。

分支合并过程中如果发生冲突,这时就需要解决冲突。编辑发生冲突的文件,里边通过<<<<<<<<<HEAD>>>>>>>>>>>>>>source标记冲突。<<<<<<<HEAD 标记合并的目标分支的内容,>>>>>>>>>>>>>>source标记源分支的代码。有三种方法解决冲突:

1,放弃merge操作。git merge --abort

2,手动解决冲突,然后提交。手动决定是需要source还是dest分支上的内容,然后git add 修改后的文件,然后git commit xxxx

3,使用一个merge工具合并冲突。常用的vimdiff, opendidff等。具体看以参考工具说明。

merge是一项头疼的工作。

减少merge的策略:

1,尽量短小的代码行。

2,尽量保证commit短小和集中在一个方面。

3,注意你的代码编辑器增加的不必要的空格,tab和换行等内容。

4,经常merge。如果不经常merge,攒在一起merge将是一项让人崩溃的事情。

5,经常地merge master分支的内容到你的开发分支,这样保证你的开发分支不会和master分支相差太远,减少将来mergemaster的工作量。

9 Git remote

Git是一个分布式的版本控制系统,可以和远程的其他人合作。我们可以把别人的内容拖下来,然后在别人的基础上工作。也可以把我们的工作分支发布出去,别人可以基于我们的分支工作。要使用这些特性,就需要用到git的远程分支。

本地的分支提交到远程分支的过程,本地和远程分支的变化。

从远程分支fetch更新下来内容,分支的变化。

远程分支情况下的工作流程:

1,本地做出修改。然后本地commit

2,获取远程分支的最新更新,使你的origin/master分支更新。

3,合并你的本地的commitorigin/master

4push你的更新到远程服务器。

git remote显示所有远程服务器列表。

git remote add origin https://github.com/openstack/nova.git增加一个远程服务器。

git push -u origin master把本地的master分支push到远程的origin服务器。

git clone https://github.com/openstack/nova.git nova克隆一个远程服务器上的代码到nova目录。

git fetch https://github.com/openstack/nova.git 获取远程服务器的更新。并不自动合并到本地的master分支。需要合并到本地master时,origin/master到本地master的合并和其他分支没有差别。

git pull http://github.com/openstack/nova.git 获取远程更新并自动合并到本地master,存在冲突时会提示冲突。解决后本地commit。然后再push到服务器。

git push origin remotebranch 创建远程分支。

git push oringin :remotebranch删除远程分支。

git push origin --delete remotebranch 删除远程分支。

————————————————————————————————————————————————————————————————————————————

Openstack相关技术交流请加群:314889201

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号