最近研究了一下git的用法。我看的教程来自[Git权威指南](http://www.worldhello.net/gotgit),这里做个总结。

0x00 与服务器连接

本地的项目应该如何与服务器连接呢?这时git clone,git fetch,git pull,git push,就将派上用场。

首先使用git clone <site>将服务器项目克隆到本地,就可以在本地对该项目进行编辑。如果需要与服务器的项目进行同步,使用git pull命令可以与服务器的数据同步,但是同步的时候可能会面临一些冲突(尤其在多人项目中)。如果想要推送本地项目到服务器,使用git push命令即可。

0x01 分支

分支的使用是git重要的一环,这里主要用到的命令是git branch,git checkout,git merge

我们不妨先创建一个文件,然后提交。

root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# echo "i am in master." > test
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# cat test
i am in master.
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git add test
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git commit -m "Commit on master,"
[master (root-commit) 82ed510] Commit on master,
 1 file changed, 1 insertion(+)
 create mode 100644 test
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git log
commit 82ed5102395eb575be4b666c4da7592569380fc6
Author: Loon <l470279614@yahoo.com>
Date:   Wed Nov 16 16:05:02 2016 +0800

    Commit on master,

然后使用git branch <new_branch>命令,在当前节点创建新分支(可以附加参数指定分支创建位置)。不附加参数的话,就会显示所有分支以及当前所在分支。然后再使用git checkout <branchname>切换到新分支。这就是git checkout改变HEAD指针的功能。

root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git branch loon
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git branch
  loon
* master
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git checkout loon
Switched to branch 'loon'
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git branch
* loon
  master

然后在文件中输入语句后,提交,切换回master分支。

root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# cat test
i am in master.
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# echo "i am in loon." >> test
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# cat test
i am in master.
i am in loon.
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git add -u
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git commit -m "Commit on loon."
[loon 1ab585a] Commit on loon.
 1 file changed, 1 insertion(+)
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git log
commit 1ab585ab2477d2e6c25749240038018ecc138fe4
Author: Loon <l470279614@yahoo.com>
Date:   Wed Nov 16 16:10:42 2016 +0800

    Commit on loon.

commit 82ed5102395eb575be4b666c4da7592569380fc6
Author: Loon <l470279614@yahoo.com>
Date:   Wed Nov 16 16:05:02 2016 +0800

    Commit on master,
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git checkout master
Switched to branch 'master'
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# cat test
i am in master.
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git branch
  loon
* master

可以看到,我们输入的语句消失了。接下来使用git merge合并分支。

root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git merge loon
Updating 82ed510..1ab585a
Fast-forward
 test | 1 +
 1 file changed, 1 insertion(+)
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git branch
  loon
* master
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# git log
commit 1ab585ab2477d2e6c25749240038018ecc138fe4
Author: Loon <l470279614@yahoo.com>
Date:   Wed Nov 16 16:10:42 2016 +0800

    Commit on loon.

commit 82ed5102395eb575be4b666c4da7592569380fc6
Author: Loon <l470279614@yahoo.com>
Date:   Wed Nov 16 16:05:02 2016 +0800

    Commit on master,
root@DESKTOP-I943ECH:/mnt/e/test/GitPrac# cat test
i am in master.
i am in loon.

我们分支的内容成功合并了。

0x02 冲突

前面说到git pull可能会产生冲突,首先对该命令的原理进行说明。git pull实际上相当于git fetch+git merge,即先获取服务器的版本库数据,然后执行merge合并操作。合并的时候就有可能与工作区的数据产生冲突了。

冲突一:原因是合并对象与当前对象内容不同。

譬如,存在

abcd
1234
defg
abcd
4567
defg

两个文本。执行merge操作时,会由于第二行不同而报错,具体的信息会在工作区文件中显示。 并且暂存区中,第三列的暂存区区编号会产生变化,存在冲突的文件会被放到3个暂存区中, 1是冲突文件修改前的副本 2是冲突文件当前分支中修改的副本 3是冲突文件在合并分支中的副本 可以通过:[1-3]:<filename>访问

放弃合并操作可以用git reset将暂存区重置

解决方案:

  1. 将冲突处改动后提交。提交将会是一个合并提交。
  2. 使用图形工具,可以用git mergetool查看支持的图形工具列表

冲突二:逻辑冲突

此种冲突并不会直接导致合并失败,但可能会导致程序编译错误,或者程序逻辑出现问题。 譬如某个头文件被改名,某个函数的返回值被改动。

冲突三:树冲突。多个用户改变了文件用户名。

比如user1将doc/README.MD改成readme后提交并push, user2将doc/README.MD改成README后提交并pull, 会发生冲突。

此时同样暂存区中会有变化。会有3个HASH相同但是文件名不同,暂存区不同的数据。 1是改名前的doc/README.MD 2是user1改名的readme 3是user2改名的README

工作区会同时存在README与readme

解决方案:

  1. 决定好最终的名字后,使用git rm命令,删除另外两个,再git add最终文件,可以看到暂存区中所有文件都变回0号区。
  2. 使用git mergetool命令交互式处理。