git拾遗

整理一些git中非常有用且自己又容易忘记的命令,仅供参考。

github上fork代码后,从自己的代码库拉下代码。如何保持自己库中的代码和原代码的更新保持一致呢?

*步骤:在 Fork 的代码库中添加上游代码库的 remote 源,该操作只需操作一次即可。

  1. 在 Fork 的代码库中添加上游代码库的 remote 源,该操作只需操作一次即可。

如: 其中 upstream 表示上游代码库名, 可以任意。

git remote add {upstream} git@github.com:spring-projects/spring-framework.git

  1. 将本地的修改提交 commit
  2. 在每次 Pull Request 前做如下操作,即可实现和上游版本库的同步。

​ 3.1 : git remote update upstream

​ 3.2 : git rebase upstream/{branch name}

需要注意的是在操作3.2之前,一定要将checkout到{branch name}所指定的branch,

如: git checkout develop

  1. push 代码到 github

git push origin {branch name}

git在本地新建分支并与远程库建立关联的几种方法

  • git checkout --track origin/remote_branch(推荐)

  • 基于远程分支“remote_branch”,创建一个叫“remote_branch”的本地分支。

git checkout -b remote_branch origin/remote_branch

  • git clone -b {remote_branch} git@github.com:spring-projects/spring-framework.git

  • git branch remote_branch , git checkout remote_branch, git pull origin remote_branch

    1. git branch --set-upstream-to=origin/<branch> {remote_branch}

git设置提交代码时显示的提交人信息

git config —global user.name laphi

git config —global user.email laphi@laphilee.com

生成git帐号关联邮箱的rsa:git ssh-keygen -t rsa -C laphi@laphilee.com

这里不强制要求用git生成rsa,直接用不和邮箱信息关联的rsa也完全可以。

git删除远程分支

如果一不小心把本地的临时分支push到server上去了,想要删除。怎么办?

git branch -r -d origin/branch-name只是删除的本地对该远程分支的track,不能删除远程服务器(如github,gitlab等)上的该分支。正确的方法应该是这样:git push origin :branch-name冒号前面的空格不能少,原理是把一个空分支push到server上,相当于删除该分支。

或者用命令git push origin --delete <branchName>

删除不存在对应远程分支的本地分支

假设这样一种情况:

  1. 我创建了本地分支b1并pull到远程分支 origin/b1
  2. 其他人在本地使用fetch或pull创建了本地的b1分支;
  3. 我删除了 origin/b1 远程分支;
  4. 其他人再次执行fetch或者pull并不会删除这个他们本地的 b1 分支,运行 git branch -a 也不能看出这个branch被删除了,如何处理?

使用下面的代码查看b1的状态:

1
2
3
4
5
6
7
8
9
10
11
12
$ git remote show origin
* remote origin
Fetch URL: git@github.com:xxx/xxx.git
Push URL: git@github.com:xxx/xxx.git
HEAD branch: master
Remote branches:
master tracked
refs/remotes/origin/b1 stale (use 'git remote prune' to remove)
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)

这时候能够看到b1是stale的,使用 git remote prune origin 可以将其从本地版本库中去除。

更简单的方法是使用这个命令,它在fetch之后删除掉没有与远程分支对应的本地分支:

git fetch -p

重命名远程分支

在Git中重命名远程分支,其实就是先删除远程分支,然后重命名本地分支,再重新提交一个远程分支。

1
2
3
xiaosi@Q:~/code/qt$ git branch -av
* dev 8d807de MOD
master f600e50 code change during build remotes/origin/HEAD -> origin/master remotes/origin/dev 8d807de MOD remotes/origin/master f600e50 code change during build

删除远程分支:git push --delete origin dev 重命名本地分支:git branch -m dev develop 推送本地分支:git push origin develop

设置git区分文件名大小写

git 默认是不区分文件名大小写的,当我们不小心把文件名的大小写写错了,想改过来,会发现push不起作用。

譬如当你创建一个文件后,叫 readme.md 写入内容后 提交到线上代码仓库。然后你在本地修改文件名为Readme.md 接着你去提交,发现代码没有变化.git status无任何提示信息。

这里有两种解决方法

  1. 配置git使其对文件名大小写敏感git config core.ignorecase false

  2. 在本地仓库把文件删除,提交,然后push到远程仓库,然后再在本地重新添加正确文件名的文件,然后再push。

删除

1
git rm readme.md

push到远程仓库

1
2
git commit -m 'readme.md'
git push origin <my_branch>

重新添加

1
git add Readme.md

提交

1
2
git commit -m 'Readme.md'
git push origin <my_branch>

这里推荐使用第一种方法,一劳永逸。

rebase

使用rebase和其他分支直接合并(不推荐,会有很多冲突)

假设你现在基于远程分支“origin”,创建一个叫“mywork”的分支。

1
$ git checkout -b mywork origin
img

img

现在我们在这个分支做一些修改,然后生成两个提交(commit).

1
2
3
4
5
$ vi file.txt
$ git commit
$ vi otherfile.txt
$ git commit
...

但是与此同时,有些人也在“origin”分支上做了一些修改并且做了提交了. 这就意味着“origin”和“mywork”这两个分支各自“前进”了,它们之间“分叉”了。

img

img

在这里,你可以用“pull”命令把“origin”分支上的修改拉下来并且和你的修改合并; 结果看起来就像一个新的“合并的提交”(merge commit):

img

img

但是,如果你想让“mywork”分支历史看起来像没有经过任何合并一样,你也许可以用 git rebase:

1
2
$ git checkout mywork
$ git rebase origin

这些命令会把你的“mywork”分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到“.git/rebase”目录中),然后把“mywork”分支更新到最新的“origin”分支,最后把保存的这些补丁应用到“mywork”分支上。

img

img

当’mywork’分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除. (请查看 git gc)

img

img

现在我们可以看一下用合并(merge)和用rebase所产生的历史的区别:

img

img

在rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决 冲突;在解决完冲突后,用git-add命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行:

1
$ git rebase --continue

这样git会继续应用(apply)余下的补丁。

在任何时候,你可以用--abort参数来终止rebase的行动,并且“mywork” 分支会回到rebase开始前的状态。

1
$ git rebase --abort

使用rebase来合并当前分支commit,然后再和其他分支merge(推荐)

  1. git rebase -i HEAD~8

合并最近的8次commit。

  1. git rebase -i i870cs

“i870cs” 为不参与合并的最后一个commit

注:commit排序为倒序。即最新的commit在最上面。

从第二行开始,将pick改为s(s, squash = use commit, but meld into previous commit )

wq保存并退出。

如果有冲突,修改冲突后

1
2
git add .
git rebase --continue

如果想放弃rebase,执行git rebase --abort

将rebase同步到远程:git push origin <your-branch>

标签(tag)

当代码写到一个里程碑版本的时候,为了方便日后查看版本以及代码回滚,这时候需要打tag

创建标签:

git tag v1.4-lw。此为轻量级标签,无需任何参数。

(推荐使用带附注的标签)git tag -a v20170725 -m "打标签"。此处的-a表示含附注类型的标签,而 -m 选项则指定了对应的标签说明。

或者根据指定的commit打tag:git tag -a v20170725 -m "打标签" dd98asd

将标签同步到远程(和操作普通分支没有区别):git push origin v20170725

查看所有标签列表:git tag,或者如果你只对某些特定的标签感兴趣,可以用git tag -l 'v1.4.2.*'

可以用git show <tagname>查看标签信息:

1
2
3
4
5
tag v20170725
Tagger: laphi <laphi@laphilee.com>
Date: Tue Jul 25 09:39:27 2017 +0800
我的tag

移除gitignore中已经被忽略的文件或目录

问题: 在初始化git仓库的时候没有创建.gitignore文件来过滤不必要提交的文件, 后来却发现某些文件不需要提交, 但是这些文件已经被提交了, 这时候创建.gitignore文件忽略这些文件时, 发现ignore的规则对那些已经被track的文件无效.

其实.gitignore文件只会忽略那些没有被跟踪的文件, 也就是说ignore规则只对那些在规则建立之后被新创建的新文件生效. 因此推荐: 初始化git项目时就创建.gitignore文件.

但是如果是一个老的项目里面新添加的.gitignore,很有可能会出现上面我们提到的问题。如何把git提示“ignored tracked with git”的文件忽略掉呢?可使用如下命令:

命令:git rm --cached -r 文件/文件夹

eg. git rm --cached -r ../biz/myproject.iml

选择性合并

场景: 某天你正在做一个新的需求,突然有一天产品告诉你说有一个新特性需要提前上线,那么怎么办呢? 该cherry-pick上场了,cherry-pick会重演某些commit,即把某些commit的更改重新执行一遍。

git cherry-pick commit

注:这里的commit可以是同分支的commit,也可以是不同分支的。

Git 命令别名

如果觉得git命令太长,每次重复输入太麻烦,可以使用git别名,用你自己容易记住和使用的别名来为自己节省时间。

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

坚持原创技术分享,您的支持将鼓励我继续创作!