原文来自:http://conw.net/archives/18/

(我自己的博客,点击链接查看文章最新版本)

Git是目前最流行的版本控制系统,这里以GitHub为例,介绍git的基本使用。

Git简介

如果在看这篇文章之前,你习惯把自己的代码保存在本地的话,那你就应该改变一下了。可能由于某些情况,我们会失去在本地保存的数据,那时候如果你突然想起来有很多很重要的代码还没有备份,那么此时你的内心一定是崩溃的,有了github,我们可以很方便的把代码上传到远程服务器,即使有一天你突然在另一个地方想用到这些代码,也不用担心,只要你能上网,一条命令就可以把代码下载下来了。
还有一些时候,你在改完一个功能的时候,突然想起来也许之前版本的还需要,但是你已经很手欠的把他们删掉了,没关系,在git的世界里,你是有后悔药可以吃的,可以很方便的回退到之前版本。
团队合作也是很重要的事情,但是在合作的过程中可能遇到各种各样的问题,这些在git上都得到了有效的解决。
git还有很多流弊的功能,在使用过程中挖掘吧。

如何使用Git

在Linux系统下(这里以Ubuntu为例),你可以直接安装git。
sudo apt install git
在Windows系统下,我通常用Cygwin,这里提供一个下载链接,包含了一些我个人的常用配置,压缩包里有使用说明,请先阅读一下。
链接: http://pan.baidu.com/s/1eRQzbEi 密码: 689t

现在你已经能打开一个终端,并且成功的运行git命令了。运行git命令后,可以看到如下界面:

netcon@conwlt ~
$ git
usage: git [--version] [--help] [-C <path>] [-c name=value]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>] These are common Git commands used in various situations: start a working area (see also: git help tutorial)
clone Clone a repository into a new directory
init Create an empty Git repository or reinitialize an existing one work on the current change (see also: git help everyday)
add Add file contents to the index
mv Move or rename a file, a directory, or a symlink
reset Reset current HEAD to the specified state
rm Remove files from the working tree and from the index examine the history and state (see also: git help revisions)
bisect Use binary search to find the commit that introduced a bug
grep Print lines matching a pattern
log Show commit logs
show Show various types of objects
status Show the working tree status grow, mark and tweak your common history
branch List, create, or delete branches
checkout Switch branches or restore working tree files
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
merge Join two or more development histories together
rebase Reapply commits on top of another base tip
tag Create, list, delete or verify a tag object signed with GPG collaborate (see also: git help workflows)
fetch Download objects and refs from another repository
pull Fetch from and integrate with another repository or a local branch
push Update remote refs along with associated objects 'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.

看到上述信息说明git安装成功,这时候我们要设置一下自己的信息。

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

例如我本人就是:

netcon@conwlt ~
$ git config --global user.email "netcon@live.com" netcon@conwlt ~
$ git config --global user.name "netcon"

项目仓库(Repository)

我们首先创建一个文件夹hello-git,并进入到该文件夹下:

netcon@conwlt ~
$ mkdir hello-git netcon@conwlt ~
$ cd hello-git/

接下来我们初始化一个仓库,使用git init命令即可:

netcon@conwlt ~/hello-git
$ git init
Initialized empty Git repository in /home/netcon/hello-git/.git/ netcon@conwlt ~/hello-git
$ ls -a
./ ../ .git/

可以看到运行git init后,在当前目录创建了一个.git文件夹,这个就是git用来管理版本库的,平时我们没事不要动它。
之后我们就在这个目录下写代码了,就像我们以前用IDE创建一个新工程一样。而这个目录就是一个版本库。

基本操作

首先我们来创建一个新文件hello.py,里面的内容只有一行print('Hello Git!')。这里推荐使用VIM,对其不太熟悉的也可以使用其他工具。在Linux下可以使用gedit,而在Windows下推荐使用Nodepad++,不建议使用记事本。编辑完成后可是使用git status命令查看当前状态。

netcon@conwlt ~/hello-git
$ vim hello.py netcon@conwlt ~/hello-git
$ git status
On branch master Initial commit Untracked files:
(use "git add <file>..." to include in what will be committed) hello.py nothing added to commit but untracked files present (use "git add" to track)

根据提示我们可以看到,git很聪明地发现我们编辑了hello.py文件,并且说它Untracked,要我们git add <file>。那么我们就按它说的做,然后再看一下状态:(其他的提示信息你可能觉得迷惑,我们先不管它们)

netcon@conwlt ~/hello-git
$ git add hello.py netcon@conwlt ~/hello-git
$ git status
On branch master Initial commit Changes to be committed:
(use "git rm --cached <file>..." to unstage) new file: hello.py

这次hello.py的状态已经是add之后的了,git提示我们可以commit它,也可以使用git rm --cached <file>使它返回还未add的状态。我们接下来commit它。

netcon@conwlt ~/hello-git
$ git commit -m 'create hello.py'
[master (root-commit) eb3a0b6] create hello.py
file changed, insertion(+)
create mode hello.py

git commit -m <commit message>命令中我们使用了-m参数,这个是快速添加commit message,不用这个参数的话会到一个文本编辑页面添加它,它使我们每次提交的介绍,方便以后查看以前的版本信息,和注释差不多。

那我们修改文件后会怎么样呢?我们把hello.py中的内容改成print('Hello conw.net!'),然后再查看状态:

netcon@conwlt ~/hello-git
$ git status
On branch master
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: hello.py no changes added to commit (use "git add" and/or "git commit -a")

git又很聪明地发现我们修改了文件,那我们能不能知道改了哪些内容呢?可以,使用git diff命令即可:

netcon@conwlt ~/hello-git
$ git diff
diff --git a/hello.py b/hello.py
index 4f013ae..7ba0fef
--- a/hello.py
+++ b/hello.py
@@ - + @@
-print('Hello Git!')
+print('Hello conw.net')

果然是很强大,需要注意的是这种提示仅限于这种文本文件,如果是二进制文件比如一个图片的话,那么git只是知道它修改了,但是不会提示它改了哪里的。接下来我们使用git add hello.pygit commit -m 'modify hello.py'提交修改。

netcon@conwlt ~/hello-git
$ git add . netcon@conwlt ~/hello-git
$ git commit -m 'modify hello.py'
[dev d441413] modify hello.py
file changed, insertion(+), deletion(-)

现在我们用到了5条git命令,用它们就可以简单的处用git了:
git init:初始化版本库
git status:查看版本库状态
git add <file>:把文件添加到暂存区(index)。
git commit:把暂存区中的文件提交到分支(branch)。
git diff:查看文件具体修改了哪里。

看了上面的几条命令,如果你觉得迷茫的话呢,那么就先来了解一些基本概念吧。

工作区与版本库

工作区就是我们编写代码所在的目录,我们都是直接操作这里面的内容的。
那么版本库是干什么的呢?简单来说,我们每次commit都生成了一个新的版本,Git可以管理我们之前各个版本的代码,这些操作都是依赖版本库的。我们先执行一下git log查看之前的版本:

netcon@conwlt ~/hello-git
$ git log
commit d441413cb8f76ed4a4cbea6cd3d2ee9342bc6156
Author: netcon <netcon@live.com>
Date: Sat Sep :: + modify hello.py commit eb3a0b68304f827f214f6fb567fafa8626f4f555
Author: netcon <netcon@live.com>
Date: Sat Sep :: + create hello.py netcon@conwlt ~/hello-git
$

可以很清晰地看到了我们这个项目之前的版本,看到之前的commit message,我们也想起来每个版本的细节了。
版本库中有暂存区(index)的概念,每次我们在工作区编辑好代码后,运行git add <file>命令,就是把修改后的文件提交到暂存区,我们可以多次修改文件、多次git add <file>,最后运行git commit统一把所有暂存区中的文件提交到分支,也就是创建了一个新版本,我们在git log能够看到。
我们提到了分支(branch),那它是什么意思呢?我们通过git log命令看到了项目之前的版本,就像一条时间线把这个项目的各个阶段连接起来,每次commit就是时间线上的一个节点,分支就是指向时间线中某个节点的指针。
一个项目仓库可以有多个分支,通常我们初始化仓库后默认创建的分支叫master,我们可以通过git branch <branch name>创建新分支,并且通过'git checkout '切换到指定分支。

netcon@conwlt ~/hello-git
$ git status
On branch master
nothing to commit, working directory clean netcon@conwlt ~/hello-git
$ git branch dev netcon@conwlt ~/hello-git
$ git checkout dev
Switched to branch 'dev' netcon@conwlt ~/hello-git
$ git status
On branch dev
nothing to commit, working directory clean

可以看到,我们最早是在master分支,然后创建并切换到了dev分支,我们目前的状态是这样的:

接下来我们在dev分支上做一些修改并commit:

netcon@conwlt ~/hello-git
$ vim hello.py netcon@conwlt ~/hello-git
$ cat hello.py
print('Hello conw.net')
print('This is dev branch') netcon@conwlt ~/hello-git
$ git add hello.py netcon@conwlt ~/hello-git
$ git commit -m 'add dev mark'
[dev 4edf04c] add dev mark
file changed, insertion(+)

现在的状态应该是这样的:

接下来我们切换到master分支,查看hello.py的内容,发现在dev分支进行的修改在这里果然不生效:

netcon@conwlt ~/hello-git
$ git checkout master
Switched to branch 'master' netcon@conwlt ~/hello-git
$ cat hello.py
print('Hello conw.net') netcon@conwlt ~/hello-git
$

我们尝试修改master分支并提交它:

netcon@conwlt ~/hello-git
$ vim hello.py netcon@conwlt ~/hello-git
$ cat hello.py
print('Hello conw.net')
print('This is master branch') netcon@conwlt ~/hello-git
$ git add hello.py netcon@conwlt ~/hello-git
$ git commit -m 'add master mark'
[master fbd0bf5] add master mark
file changed, insertion(+)

此时的状态就应该是这样的:

此时就能看出为什么要使用分支这个词了,也就是说,所谓的时间线,在逻辑上,并不是一条直线,而是一个树形结构的。
在上面例子中,不同分支上的代码是不一样的:

netcon@conwlt ~/hello-git
$ git status
On branch master
nothing to commit, working directory clean netcon@conwlt ~/hello-git
$ cat hello.py
print('Hello conw.net')
print('This is master branch') netcon@conwlt ~/hello-git
$ git checkout dev
Switched to branch 'dev' netcon@conwlt ~/hello-git
$ git status
On branch dev
nothing to commit, working directory clean netcon@conwlt ~/hello-git
$ cat hello.py
print('Hello conw.net')
print('This is dev branch') netcon@conwlt ~/hello-git
$

理解了工作区、版本库、暂存区、分支的概念,我们可以学习更多的git命令了。

版本回退

我们已经知道了git能保存我们之前每次commit后的代码,并且通过git log命令可以查看之前代码的每个版本,那么我们如何回到之前的某个版本呢?使用git reset --hard <commit id>即可。

netcon@conwlt ~/hello-git
$ git status
On branch dev
nothing to commit, working directory clean netcon@conwlt ~/hello-git
$ git log
commit 4edf04cd1223abf07e36ae5c2d878c243395ecc9
Author: netcon <netcon@live.com>
Date: Sat Sep :: + add dev mark commit d441413cb8f76ed4a4cbea6cd3d2ee9342bc6156
Author: netcon <netcon@live.com>
Date: Sat Sep :: + modify hello.py commit eb3a0b68304f827f214f6fb567fafa8626f4f555
Author: netcon <netcon@live.com>
Date: Sat Sep :: + create hello.py netcon@conwlt ~/hello-git
$ git reset --hard d441
HEAD is now at d441413 modify hello.py netcon@conwlt ~/hello-git
$ cat hello.py
print('Hello conw.net') netcon@conwlt ~/hello-git
$

注意这里的commit id我只输入了前几位,而不用全部输入,只要能标识唯一版本就可以,git会自动找到符合条件的分支。
这样我们就回到的之前的版本了,那么我们如何回到未来的版本(也就是add dev mark那个版本)呢?方法之一是找到未来版本的commit id,但是如果我们不小心已经把终端关掉找不到之前的commit了呢?还有另一个办法就是git reflog

netcon@conwlt ~/hello-git
$ git reflog
d441413 HEAD@{}: reset: moving to d441
4edf04c HEAD@{}: checkout: moving from master to dev
fbd0bf5 HEAD@{}: commit: add master mark
d441413 HEAD@{}: checkout: moving from dev to master
4edf04c HEAD@{}: commit: add dev mark
d441413 HEAD@{}: checkout: moving from master to dev
d441413 HEAD@{}: commit: modify hello.py
eb3a0b6 HEAD@{}: commit (initial): create hello.py netcon@conwlt ~/hello-git
$ git reset --hard 4edf
HEAD is now at 4edf04c add dev mark netcon@conwlt ~/hello-git
$ cat hello.py
print('Hello conw.net')
print('This is dev branch') netcon@conwlt ~/hello-git
$

我们在reflog的记录中找到了未来版本的commit id,我们又安全的回来了!
小技巧:我们可以使用git reset --hard HEAD^快速回到之前的版本,这个HEAD表示当前版本,HEAD^表示前一个版本,HEAD^^表示前两个版本~

GitHub

现在我们已经可以基本的使用git来管理我们的代码了,git是一个很先进的版本控制系统,相比于传统的SVN等,它又快又好用(快了不止一点,好用了不止一点)。目前还有很多免费的代码托管网站,可以用作我们的远程代码仓库。这里介绍的就是其中最牛逼的GitHub(https://github.com/)。
GitHub在中国有时可能访问异常,尽量使用https访问。
首先就是注册登录,无需多说。
登录后,点击右上角的头像选择Your profile,进入你的github主页。
我们先创建一个项目仓库(repository),创建完成后进入这个页面。

注意图中红框部分,我们选择HTTPS类型的地址,原因后面会说。
接下来我们把本地的代码push到github上。
我们回到本地仓库,把代码push到远程仓库前,要保证当前仓库有一个README.md文件,它是仓库的说明文件,我们先简单创建它:

netcon@conwlt ~/hello-git
$ echo "# hello-git" >> README.md netcon@conwlt ~/hello-git
$ git add README.md netcon@conwlt ~/hello-git
$ git commit -m 'create README.md'
[dev c1f1871] create README.md
file changed, insertion(+), deletion(-)

然后用git remote add <name> <url>设置一下远程仓库:

netcon@conwlt ~/hello-git
$ git remote add origin https://github.com/conwnet/hello-git.git

这里的name是origin,github上默认是这个名字,也可以改成其它的。然后我们用git push origin master即可:

netcon@conwlt ~/hello-git
$ git push origin master
Username for 'https://github.com': conwnet
Password for 'https://conwnet@github.com':
Counting objects: , done.
Compressing objects: % (/), done.
Writing objects: % (/), bytes | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/conwnet/hello-git.git
* [new branch] master -> master

我们成功把master分支push到了远程仓库。输入密码那里不可见,不过放心你的确是成功输入进去了。回到github选择刚才创建的项目,可以看到我们刚才编辑的两个文件:

由于代码可能多人合作,也可能我们在其他计算机上修改过。所以当前在本地的代码可能和在github的不一致,这样的话我们是无法直接push上去的,此时我们可以使用git pull origin master命令把远程代码和本地代码合并,如果发生冲突也会有相应提示,我们处理好冲突后就可以再push上去了。
关于远程仓库的两种地址问题:HTTPS地址是形如https://github.com/conwnet/hello-git.git这样的地址,它的特点是可以用帐号密码push和pull。而形如git@github.com:conwnet/hello-git.git的地址称为SSH地址,要使用这样的地址我们需要在Account Settings里面添加相应的SSH公钥,添加成功后不用每次验证密码,很方便,关于这方面的知识是可以自己去网上搜索,这里不再赘述。
另一个常用的操作是克隆(clone),我们可以使用git clone <url>命令把一个远程仓库复制到本地。

Git常用操作总结

git clone <url>:把一个远程仓库克隆到一个新文件夹
git init:创建一个新的本地仓库
git add <file>:把文件添加到暂存区(index)。
git mv <file1> <file2>:移动或者重命名文件
git rm <file>:删除暂存区和工作区的文件。
git status:显示当前分支的状态信息
git commit -m <commit message>:把暂存区的文件提交到分支
git branch <branch name>:创建新的分支
git checkout <branch name>:切换到指定分支
git diff <file>:显示文件修改了哪里
git log:显示当前分支的各版本信息
git reflog:显示当前分支的变动日志
git reset --hard <commit id>:回退(或者前进)到指定的版本
git remote add <name> <url>:添加一个远程库
git push <name> <branch name>:把本地的指定分支同步到远程仓库
git pull <name> <branch name>:把远程仓库的指定分支同步到本地

Coding.net进阶,使用Git管理代码的更多相关文章

  1. intelliJ IDEA之使用svn或git管理代码

    intelliJ IDEA之使用svn管理代码 1.VCS—>import into Version Control—>Share Project(Subversion) 2.点击+    ...

  2. 如何使用git管理代码

    如何使用Git管理代码 Git 是开发人员用来向代码库(msstash)中提交代码或者下载远端代码库中代码的工具. 如何使用git向代码库中提交我们修改后的代码呢? 1.如果是第一次使用git,那么需 ...

  3. Git管理代码

    使用Git管理代码 1. 分支管理模式 首先,master分支应该是非常稳定的,开发都在dev分支上,每个人都有自己的分支,时不时地往dev分支上合并就可以了.完成测试后,再把dev分支合并到mast ...

  4. 用开源中国(oschina)Git管理代码(整合IntelliJ 13.1.5)

    简介 开源中国提供了Git服务(地址:http://git.oschina.net/),在速度上比国外的github要快很多.使用了一段时间,感觉很不错.oschina git提供了演示平台,可以运行 ...

  5. VS Code使用Git管理代码

    Visual Studio Code(简称VS Code)是一个轻量级且强大的代码编辑器,后台是微软,支持Windows.Mac和Linux操作系统,拥有丰富的插件生态系统,可通过安装插件来支持C++ ...

  6. windows下使用git管理代码,其中出现的问题的解决办法

    和朋友共同开发一个小项目,所以就涉及到了代码管理这块,刚开始想到的是使用svn,但是外网访问svn的时候需要使用花生壳来弄一个动态的域名,中间出了很多错误,感觉有点麻烦,所以就想到看看还有别的管理代码 ...

  7. Jenkins进阶-获取git tags代码(2)

    配置Jenkins获取git tag代码的方式其实方法很多,目前我使用比较多的主要是通过Git Parameter 来配置动态的获取最新tags代码,主要我们首先需要安装一下Git Parameter ...

  8. 使用代码管理工具(git)管理代码的常用指令合集

    create a new repository on the command line echo "# test" >> README.md git init git ...

  9. 使用git管理代码的心得

    一.简易使用流程 首先下载安装git,点击Git Bash进入编辑界面,之后如下图进入目录并通过命令 git init 把这个目录变成git可以管理的仓库 接下来使用git add .命令将所有文件添 ...

随机推荐

  1. 58到家mysql数据库军规及解读分享

    一.基础规范 (1)必须使用InnoDB存储引擎 解读:支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 (2)必须使用UTF8字符集 解读:万国码,无需转码,无乱码风险,节省 ...

  2. NDK编译时两 .so之间调用问题

    Android C++(NDK)项目需要调用别人的代码,因此将其编译成了.so库,而自己的代码也编成了一个.so库. 结果编译成功,但是在运行时自己的.so调用别人的.so会失败,提示说没有正确传入参 ...

  3. 2017北京国庆刷题Day3 afternoon

    期望得分:100+0+30=130 实际得分:100+36.5+0=136.5 T3 一个变量写混了,丢了30.. 模拟栈 #include<cstdio> #include<cst ...

  4. 维护后面的position sg函数概念,离线+线段 bzoj 3339

    3339: Rmq Problem Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1160  Solved: 596[Submit][Status][ ...

  5. [BZOJ1911][BZOJ1912][BZOJ1913]APIO2010解题报告

    特别行动队 Description   这个好像斜率优化不是一般地明显了啊...只不过要分a的正负两种情况考虑是维护上凸还是下凸 /********************************** ...

  6. phpcms直接取子栏目的内容、调用点击量的方法

    子栏目里面的内容可以直接取,而不需要通过循环. {$CATEGORYS[$catid][catname]}//取子栏目的栏目名称 {$CATEGORYS[$catid][image]}//取子栏目的栏 ...

  7. 通过jquery.validate.js校验表单字段是否合法

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  8. AngularJs几种服务区别

    下面说说这几种函数之间的区别: 函数 定义 适合场景 provider(name, Object OR constructor() ) 一个可配置的.有复杂逻辑的服务.如果你传递了一个对象,那么它应该 ...

  9. HDU 1072 Nightmare (广搜)

    题目链接 Problem Description Ignatius had a nightmare last night. He found himself in a labyrinth with a ...

  10. NYOJ 141 Squares (数学)

    题目链接 描述 A square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-degre ...