Git 复习重新开始

2018-03-20  本文已影响0人  ismyshellyiqi
image.png
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
git init

//git add a.txt
git add .
git commit -m 'des'
git status
git log
//git log --pretty=oneline
git reset --hard HEAD^
git reset --hard HEAD^^
git reset --hard 'commit id'
git reflog

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file

场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库

rm a.txt
git status
//  1 确认要删除
git rm a.txt
git commit -m 'des'

// 2删错,想要回退
$ git checkout -- test.txt 

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。

先查看用户主目录下有没有.ssh 如果有进入,查看id_rsa(私钥),id_rsa.pub(公钥),使用的事公钥,

cat id_rsa.pub

如果没有.ssh,则需要创建

$ ssh-keygen -t rsa -C "youremail@example.com"
$ git remote add origin git@github.com:<your name>/learngit.git
$ git push -u origin master
Counting objects: 19, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (19/19), done.
Writing objects: 100% (19/19), 13.73 KiB, done.
Total 23 (delta 6), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

$ git push origin master
$ git clone
// 创建并且切换分支到dev
git checkout -b dev
//  等同于
git branch dev
git checkout dev
git status 
*dev
 master
git add . 
git commit -m 'des'

git checkout master
git merge dev
git checkout dev
// 删除dev分支
git branch -d dev

这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

git branch -b feature1

修改read.txt

git add .
git commit -m 'and'
git checkout master

在master read.txt也修改

git add .
git commit -m 'AND'
git merge dev

就会产生冲突

git status
<<<<<<< HEAD
Creating a new branch is quick AND simple.
=======
Creating a new branch is quick and simple.
>>>>>>> feature1

然后保留一个修改,删除另一个

git add .
git commit -m 'merge'
// 查看合并情况
git log --graph --pretty=oneline --abbrev-commit

// 删除分支feature1
git branch -d feature

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息

下面我们实战一下--no-ff方式的git merge:

首先,仍然创建并切换dev分支

git branch -b dev
// 修改一些文件
git add .
git commit -m 'done'
git checkout master

使用 --no-ff合并分支

git merger --no-ff -m '--no-ff merger test' dev
// 查看合并的状态
$ git log --graph --pretty=oneline --abbrev-commit
*   7825a50 --no-ff merger test
|\
| * 6224937 done
|/
*   59bc1cb conflict fixed
...

在dev分支开发是,工作到一半的时候,可能还需要一定时间才能完成(还未提交),但是此时此需要一个小时来解决一个Bug

可以是使用

git stash

把现在的工作现场保存起来在使用git status就会发现工作区是clear的
然后选定在哪个分支上进行修改bug,这里假设是在master分支上修改的

git checkout master
git branch -b issue101
// 假设已经修改了一些代码
git add .
git commit -m 'done'

// 合并
git checkout master
git merge --no-ff -m 'issue-101 fixed' issue101 

此时bug修改完毕,切换到dev分支

git checkout dev
git status

会发现dev分支的工作区是clear的

git stash list 
stash@{0}: WIP on dev: 6224937 add merge

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;

另一种方式是用git stash pop,恢复的同时把stash内容也删了

git stash pop
git stash list
//会发现是空的

你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

$ git stash apply stash@{0}

新的功能

git checkout -b feature2

一段时间后开发完成

git add .
git commit -m 'feature'
// 切回到dev分支
git checkout dev

由于种种原因 决定放弃这个功能(但是此时还没合并分支)

git branch -d feature2
error: The branch 'feature2' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature2'.
$ git branch -D feature1
Deleted branch feature1 (was 756d4af).

查看远程分支

git remote
origin

或者

git remote -v
origin  git@github.com:<name>/<project-name>.git (fetch)
origin  git@github.com:<name>/<project-name>.git (push)

上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。

A小伙伴:

git clone ......

克隆下来的项目只能看见master分支

git branch 
* master

现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:

git checkout -b dev origin/dev

A小伙伴就可在dev分支上进行修改等等,比如

git add .
git commit -m ''
git push origin master

就在此时,我要对同一个地方进行了修改,并且要提交

git add hello.py
git commit -m 'add python'
git push origin dev

会发现推送失败了;因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:

git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngit
fc38031..291bea8  dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

git branch --set-upstream dev origin/<branch>

还是失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接

$ git pull
Auto-merging hello.py
CONFLICT (content): Merge conflict in hello.py
Automatic merge failed; fix conflicts and then commit the result.

这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:

$ git commit -m "merge & fix hello.py"
[dev adca45d] merge & fix hello.py
$ git push origin dev
Counting objects: 10, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 747 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
291bea8..adca45d  dev -> dev

有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files ...,有强迫症的童鞋心里肯定不爽。

好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore

忽略文件的原则是:

忽略操作系统自动生成的文件,比如缩略图等;
忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
举个例子:

假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:

Windows:

Thumbs.db
ehthumbs.db
Desktop.ini
然后,继续忽略Python编译产生的.pyc、.pyo、dist等文件或目录:

Python:

*.py[cod]
*.so
*.egg
*.egg-info
dist
build

加上你自己定义的文件,最终得到一个完整的.gitignore文件,内容如下:

Windows:

Thumbs.db
ehthumbs.db
Desktop.ini

Python:

*.py[cod]
*.so
*.egg
*.egg-info
dist
build

My configurations:

db.ini
deploy_key_rsa

最后一步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status命令是不是说working directory clean。

使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。

有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:

$ git add App.class
The following paths are ignored by one of your .gitignore files:
App.class
Use -f if you really want to add them.

如果你确实想添加该文件,可以用-f强制添加到Git:

$ git add -f App.class

或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:

$ git check-ignore -v App.class
.gitignore:3:*.class    App.class

Git会告诉我们,.gitignore的第3行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。

小结

忽略某些文件时,需要编写.gitignore;
.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!

有没有经常敲错命令?比如git status?status这个单词真心不好记。

如果敲git st就表示git status那就简单多了,当然这种偷懒的办法我们是极力赞成的。

我们只需要敲一行命令,告诉Git,以后st就表示status:

$ git config --global alias.st status

好了,现在敲git st看看效果。

当然还有别的命令可以简写,很多人都用co表示checkout,ci表示commit,br表示branch:

$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch

以后提交就可以简写成:

$ git ci -m "bala bala bala..."

--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。

在撤销修改一节中,我们知道,命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区。既然是一个unstage操作,就可以配置一个unstage别名:

$ git config --global alias.unstage 'reset HEAD'

当你敲入命令:

$ git unstage test.py

实际上Git执行的是:

$ git reset HEAD test.py

配置一个git last,让其显示最后一次提交信息:

$ git config --global alias.last 'log -1'

这样,用git last就能显示最近一次的提交:

$ git last
commit adca45d317e6d8a4b23f9811c3d7b7f0f180bfe2
Merge: bd6ae48 291bea8
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Thu Aug 22 22:49:22 2013 +0800

merge & fix hello.py

甚至还有人丧心病狂地把lg配置成了:

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

来看看git lg的效果:

git-lg

image.png

为什么不早点告诉我?别激动,咱不是为了多记几个英文单词嘛!

配置文件
配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。

配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:

$ cat .git/config 
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = git@github.com:michaelliao/learngit.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[alias]
    last = log -1

别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。

而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:


$ cat .gitconfig
[alias]
    co = checkout
    ci = commit
    br = branch
    st = status
[user]
    name = Your Name
    email = your@email.com

配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置。

refusing to merge unrelated histories

解决方法

git pull --allow-unrelated-histories

通过廖雪峰老师的git教程,又重新学习了一遍

上一篇下一篇

猜你喜欢

热点阅读