从远程仓库(服务器)获取代码

本地没有仓库,新建仓库

拉去默认分支代码

如果本地没有代码,远程仓库有代码,则需要从远程仓库克隆代码。克隆仓库的命令格式是 git clone [url]。比如,要克隆 Git 的可链接库 libgit2,可以用下面的命令:

1
$ git clone https://github.com/libgit2/libgit2

这会在当前目录下创建一个名为 “libgit2” 的目录,并在这个目录下初始化一个 .git 文件夹,从远程仓库拉取下所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝。
如果你进入到这个新建的 libgit2 目录,你会发现所有的项目文件已经在里面了,准备就绪等待后续的开发和使用。

自定义本地仓库文件名

如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以使用如下命令:

1
$ git clone https://github.com/libgit2/libgit2 mylibgit

这将执行与上一个命令相同的操作,不过在本地创建的仓库名字变为 mylibgit。

拉取特定分支的代码

如果不想克隆默认分支的代码,可以克隆指定分支的代码:

1
2
3
4
5
6
7
8
9
$ git clone -b pages-aliyun https://gitee.com/dragon-li/front-end-doc

Cloning into 'front-end-doc'...
remote: Enumerating objects: 941, done.
remote: Counting objects: 100% (941/941), done.
remote: Compressing objects: 100% (463/463), done.
remote: Total 2633 (delta 615), reused 697 (delta 470), pack-reused 1692
Receiving objects: 100% (2633/2633), 21.79 MiB | 2.26 MiB/s, done.
Resolving deltas: 100% (1610/1610), done.

拉取指定标签的代码

git 允许直接克隆特定分支的代码,不过克隆好后,项目里没有分支,需要自己创建一个分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git clone -b V2.2 http://192.168.102.9/jas-paas/cloudlink-front-framework.git

Cloning into 'cloudlink-front-framework'...
remote: Counting objects: 14436, done.
remote: Compressing objects: 100% (3072/3072), done.
remote: Total 14436 (delta 11224), reused 14226 (delta 11075)
Receiving objects: 100% (14436/14436), 17.93 MiB | 4.70 MiB/s, done.
Resolving deltas: 100% (11224/11224), done.
Note: checking out 'eeea534cdae1f82c48c7b0de8f9993b54ffa065d'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

从信息中就可以看见,克隆特定标签的项目后,是没有分支的,需要进入项目目录后,使用命令创建一个分支:

1
git checkout -b V2.2

本地已经存在了仓库

拉取新分支代码

例如,本地就一个master分支,远程有2个分支(master,develop),把远程的develop拉取到本地:

1
2
3
4
5
6
7
# 本地的分支是干净的,也就是没有修改的文件
# 获取远程所有分支名字
$ git fetch
# 显示远程所有分支名字
$ git branch -a
# 提取远程新分支到本地
$ git checkout -b develop origin/develop

有多个远程仓库,拉取指定仓库

比如 远程仓库有2个: origin、github,默认仓库是 origin,如果想要来去 github 仓库的代码:

1
git pull github master

当前分支拉取别的分支代码

比如,当前是 test 分支,需要拉取 develop 分支代码,运行如下命令:

1
git pull origin develop

高级教程

使用 git rebase 合并多次 commit

使用 git log 查看一下历史:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ git log 

commit 3fa2e1a951ff823fbec625a96049e27ef35a85b8 (HEAD -> dev, origin/dev)
Author: yulilong <yulilong222q@outlook.com>
Date: Thu Nov 2 11:29:00 2017 +0800

合并提交测试3号,测试修改最后一次提交。在测试一下。

commit f526876def0b80676bfcf52937f78052e2d63955
Author: yulilong <yulilong222q@outlook.com>
Date: Thu Nov 2 11:27:20 2017 +0800

合并提交测试2号

commit 4d2b6ce4d5154c0b739e552e679bb7f4ce05fb2c
Author: yulilong <yulilong222q@outlook.com>
Date: Thu Nov 2 11:25:59 2017 +0800

合并提交测试一号

commit 9e791f38f4d5f472a371a8c147f37670185582f8
Author: yulilong <yulilong222q@outlook.com>
Date: Mon Oct 30 10:22:02 2017 +0800

这是dev分支上的合并提交测试

commit 4baf2a319c0de8f46630ba85db11cc4aebd1d2cd
Author: yulilong <yulilong222q@outlook.com>
Date: Fri Sep 29 10:20:08 2017 +0800

这是测试-a -m命令提交记录

如果想要合并最后三次的提交,可使用 git rebase -i HEAD~3git rebase -i 9e791f38f4d 命令来压缩。该命令执行后,会弹出一个编辑窗口,3 次提交的 commit 倒叙排列,最上面的是最早的提交,最下面的是最近一次提交。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 1 pick 4d2b6ce 合并提交测试一号
2 pick f526876 合并提交测试2号
3 pick 3fa2e1a 合并提交测试3号,测试修改最后一次提交。在测试一下。
4
5 # Rebase 9e791f4..3fa2e1a onto 9e791f3 (3 commands)
6 #
7 # Commands:
8 # p, pick = use commit
9 # r, reword = use commit, but edit the commit message
10 # e, edit = use commit, but stop for amending
11 # s, squash = use commit, but meld into previous commit
12 # f, fixup = like "squash", but discard this commit's log message
13 # x, exec = run command (the rest of the line) using shell
14 # d, drop = remove commit
15 #
16 # These lines can be re-ordered; they are executed from top to bottom.
17 #
18 # If you remove a line here THAT COMMIT WILL BE LOST.
19 #
20 # However, if you remove everything, the rebase will be aborted.
21 #
22 # Note that empty commits are commented out

修改第二行、第三行的第一个单词 pick 为 squash(这些命令什么意思下面的注释有说明)
然后保存退出,git 会压缩提交历史
如果有冲突,需要修改,修改的时候要注意,保留最新的历史,不然我们的修改就丢弃了
修改以后要记得敲下面的命令

1
2
$ git add .  
# git rebase --continue

如果你想要放弃这次压缩的话,执行以下的命令:

1
git rebase --abort

如果没有冲突,或者冲突已经解决,则会出现如下的编辑窗口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 1 # This is a combination of 3 commits.
2 # This is the 1st commit message:
3
4 合并提交测试一号
5
6 # This is the commit message #2:
7
8 合并提交测试2号
9
10 # This is the commit message #3:
11
12 合并提交测试3号,测试修改最后一次提交。在测试一下。
13
14 # Please enter the commit message for your changes. Lines starting
15 # with '#' will be ignored, and an empty message aborts the commit.
16 #
17 # Date: Thu Nov 2 11:25:59 2017 +0800
18 #
19 # interactive rebase in progress; onto 9e791f3
20 # Last commands done (3 commands done):
21 # squash f526876 合并提交测试2号
22 # squash 3fa2e1a 合并提交测试3号,测试修改最后一次提交。在测试一下。
23 # No commands remaining.
24 # You are currently rebasing branch 'dev' on '9e791f3'.
25 #
26 # Changes to be committed:
27 # modified: 1.txt
28 # new file: 5.txt
29 # new file: 6.txt

编辑好合并的提交信息后保存,可看见如下输出信息:

1
2
3
4
5
6
[detached HEAD 83d65c7] 三次合并提交的测试,成功了。
Date: Thu Nov 2 11:25:59 2017 +0800
3 files changed, 7 insertions(+)
create mode 100644 5.txt
create mode 100644 6.txt
Successfully rebased and updated refs/heads/dev.

最后把合并的记录强推到服务器中去:

1
2
3
4
5
6
7
8
git push -f
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 596 bytes | 596.00 KiB/s, done.
Total 5 (delta 1), reused 0 (delta 0)
To http://192.168.102.9/yulilong/test.git
+ 3fa2e1a...83d65c7 dev -> dev (forced update)

服务器合并提交前:

合并前

服务器合并后:

合并后

把一个文件从提交历史中彻底删除

有些人不经思考使用 git add .,意外地提交了一个巨大的二级制文件,你想将它从所有地方删除。也许你不小心提交了一个包含密码的文件,而你想让你的项目开源。filter-branch 大概会是你用来清理整个历史的工具。

如果想要从整个历史中删除 1.txt 文件,你可以在 filter-branch 上使用 --tree-filter 选项:

1
2
3
$ git filter-branch -f --tree-filter 'rm -f 1.txt' HEAD 
Rewrite 83d65c7b098e0ec1f14d9a332187632b49d2ad9f (5/5) (0 seconds passed, remaining 0 predicted)
Ref 'refs/heads/dev' was rewritten

如果执行命令的时候提示如下错误,删除 .git/refs/original/ 目录,或使用 -f 命令强制覆盖:

1
2
3
4
5
6
7
8
$ git filter-branch -f --tree-filter 'rm -f 1.txt' HEAD 
Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f

git filter-branch -f --tree-filter 'rm -f 1.txt' HEAD
Rewrite 83d65c7b098e0ec1f14d9a332187632b49d2ad9f (5/5) (0 seconds passed, remaining 0 predicted)
Ref 'refs/heads/dev' was rewritten

如果后悔删除了,可以使用如下命令恢复

1
2
$ git reset --hard refs/original/refs/heads/dev
HEAD is now at 83d65c7 三次合并提交的测试,成功了。

把删除后的项目提交到服务器

注意:一旦运行此命令,删除的文件不能找回

1
2
3
4
5
6
7
8
9
$ git push origin +dev         

Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (14/14), 1.40 KiB | 1.40 MiB/s, done.
Total 14 (delta 1), reused 0 (delta 0)
To http://192.168.102.110/user/test.git
+ 83d65c7...4b4da80 dev -> dev (forced update)

注意,分支名字前面的 + 号一定不能忘记,否则会报如下错误:

1
2
3
4
5
6
7
To http://192.168.102.110/user/test.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'http://192.168.102.110/user/test.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

推送之前要把服务器的分支保护去掉,否则会报如下错误:

1
2
3
4
remote: GitLab: You are not allowed to force push code to a protected branch on this project.
To http://192.168.102.110/user/test.git
! [remote rejected] dev -> dev (pre-receive hook declined)
error: failed to push some refs to 'http://192.168.102.110/user/test.git'

代码回退操作

只移动 HEAD(相当于取消上次提交)

1
2
3
$ git reset --hard HEAD^
或者
$ git reset --soft 99ad0ec

reset 做的第一件事是移动 HEAD 的指向。reset 移动 HEAD 指向的分支。
reset --soft 本质上是撤销了上一次 git commit 命令。当你在运行 git commit 时,Git 会创建一个新的提交。
并移动 HEAD 所指向的分支来使其指向该提交。当你将它 resetHEAD~ 时,其实就是把该分支移动回原来的位置,而不会改变索引和工作目录。

现在你可以更新索引并再次运行 git commit 来完成 git commit --amend 所要做的事情了。

移动 HEAD,更新 index

1
2
3
$ git reset HEAD~
或者
$ git reset --mixed HEAD~

它依然会撤销一上次提交,但还会取消暂存所有的东西。于是,我们回滚到了所有 git addgit commit 的命令执行之前。

移动 HEAD,更新 index,更新工作目录

1
git reset --hard HEAD~

必须注意,--hard 表示是 reset 命令唯一的危险用法,它也是 Git 会真正地销毁数据的仅有的几个操作之一。
其他任何形式的 reset 调用都可以轻松撤销,但是 --hard 选项不能,因为它强制覆盖了工作目录中的文件。
在这种特殊情况下,我们的 Git 数据库中一个提交内还留有该文件的 v3 版本,我们可以通过 reflog 来找回它。
但是若该文件还未提交,Git 仍会覆盖它从而导致无法恢复。

reset 命令会特定的顺序重写这三棵树,在你指定以下选项时停止:

  1. 移动 HEAD 分支的指向(若指定了 –soft,则到此停止)
  2. 使索引看起来像 HEAD(若未指定 –hard,则到此停止)
  3. 使工作目录看起来像索引