create a branch, add some files, push to remote repository
git branch branchName
echo "Some information"> test.txt
git add test.txt
git commit -m 'add text.txt'
git push origin branchName
list all local branches
git branch -a
checkout remote branch
There is a branch nameddev
in remote repository, you want to trace that:git branch -b dev origin/dev
delete remote branch
git push origin --delete
git push origin :
delete local branch
// -d means --delete
git branch -d branchName
// force delete, even is not merged
git branch -D branchName
Merge & Rebase
Here is a repository has a branch namedb1
, it has some commits A
, B
. A -- B [b1]
- Local Case A:
You check out b1, then do some work, your commit isC
, after your commit, your local repository will be:A -- B -- C [b1]
- Local Case B:
You create branch b2 from b1, then commit.A -- B [b1]
\
C [b2] - Local Case C:
You did nothing.A -- B [b1]
- Remote Case A:
At the same time, someone commited a change, namely commitD
, pushed the commit to repository server.A -- B -- D [remote b1]
\
----- C [local] - Remote Case B:
No commit has been pushed to remote before you push commitC
to remote. The remote remains:A -- B [b1]
$ git st
# On branch develop
# Your branch and 'origin/develop' have diverged,
# and have 1 and 2 different commit(s) each, respectively.
#
nothing to commit (working directory clean)
git fetch
Aftergit fetch
, your local repository will be one of the following status:Case A: Local Case A + Remote Case B
A -- B [b1]
\
C [b1]
Case B: Local Case B + Remote Case B
A -- B [b1]
\
C [b2]
Case C: Local Case C + Remote Case A
C [b1 remote]
/
A -- B [b1,local]
Case D: Local Case A + Remote Case A
A -- B -- D [b1]
\
---- C [b1]
Case E: Local Case A + Remote Case B
A -- B -- D [b1]
\
--- C [b2]
what is fast-forward
If the branch has not diverged, and HEAD
is behind, it can do fast-forward
.If
git merge
is called on a branch which can fast-forward, fast-forward
will be applied automaticallygit merge --ff-only origin/master
will try to use fast-forward
, abort if fast-forward is not possible.git merge in one branch
$ git merge
Case A: do nothing
Case B: do nothing
Case C: Fast-forward will be applied
A -- B -- C [b1,local/remote]
Case D: Merge, a new commit `E` will be created automatically.
A -- B -- D --- E [b1]
\ /
---- C [b1]
git merge two branches
$ git merge origin/b1
Case E:
A -- B ------ D [b1]
\ \
-- C -- E [b2]
git pull
git pull
= git fetch + git merge
git rebase in one branch
# Case E
$ git rebase
A -- B ------- D [b1,remote]
\
------ D -- C1 [b1,local]
git rebase in diffrent branches
# Case F
$ git rebase origin/b1
A -- B ------- D [b1,remote]
\
------ D -- C1 [b2,local]
git push force
Why?Usually, the command refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it.Case F, may need force push. If b2 has some pushed commits before
D
and C
pushed
A -- B -..... --- D [b1,remote]
\
-.... --- D -- C1 [b2,local]
$ git push origin b2 -f
$ git push origin b2 --force
$ git push origin +b2
------------------
Git分支操作
本文介绍日常中经常遇到的一些分支操作,并给出了详细解释。- 创建分支;
- 删除分支;
- 检出远程分支;
- git merge;
- git rebase;
- git force push;
- git fast-forward.
分支简单操作
最简单的用法
创建一个分支,添加文件,提交,推送。但是日常工作中往往比这个复杂得多。git branch branchName
echo "Some information"> test.txt
git add test.txt
git commit -m 'add text.txt'
git push origin branchName
列出所有分支
git branch -a
检出一个远程分支
远程有一个dev
分支,你想 check out 这个分支到本地:git branch -b dev origin/dev
开发告一段落,你把远程一些没用的分支删除:
git push origin --delete
git push origin :
删除本地分支:
// -d 是 --delete 选项的短选项
git branch -d branchName
// 强制删除
git branch -D branchName
Merge & Rebase
git pull
是非常笼统的一种操作,下面我们分析日常所有可能遇到的情况:假设代码库有一个分支
b1
, 当前有两次提交: A
, B
,如下: A -- B [b1]
- 本地可能发生的操作 A:
你检出b1
,修改了代码,然后提交,生成一个提交:C
A -- B -- C [b1]
- 本地可能的情况 B:
你从b1
建了一个新的分支b2
, 提交代码,生成一个提交:C
A -- B [b1]
\
C [b2] - 本地可能的情况 C:
本地代码无任何变动。嗯,这也算情况之一。A -- B [b1]
- 现在让我们看看远程的集中情况
远程情况 A:
在提交代码的期间,有人推送代码到了分支b1
, 这个提交称为:D
A -- B -- D [remote b1]
\
----- C [local] - 远程情况 B:
远程情况没任何变动。A -- B [b1]
在上面,A
, B
, C
, D
指代可以是一次提交,也可以是一系列提交。
git fetch
现在你将远程变动取到本地,这时,本地代码库有可能以下几种情况:Case A: 本地情况 A + 远程情况 B
A -- B [b1]
\
C [b1]
Case B: 本地情况 B + 远程情况 B
A -- B [b1]
\
C [b2]
Case C: 本地情况 C + 远程情况 A
C [b1 remote]
/
A -- B [b1,local]
Case D: 本地情况 A + 远程情况 A
A -- B -- D [b1]
\
---- C [b1]
Case E: 本地情况 A + 远程情况 B
A -- B -- D [b1]
\
--- C [b2]
什么是: fast-forward
在 git fetch
之后,如果本地分支和远程分支没有分叉,并且本地分支指向较旧脚本,那么,这个分支称为可以 fast-forward
;在
fast-forward
时,本地分支把指针指向最新的提交,并不会生成一个提交。如果分支可以
fast-forward
,执行 git merge
时,实际执行的是fast-forward
。如果不能,则合并,并自动产生一个提交。很多情况下,我们并不希望有这样的自动合并产生,因为他产生了一个自动提交,会让版本变得交叉,不清晰。
我们希望,能
fast-forward
就 fast-forward
, `,否则我们用rebase命令合并。可以这样:git merge --ff-only origin/master
fast-forward
, merge 操作会终止。git merge 合并一个分支
$ git merge
Case A: 没变化
Case B: 没变化
Case C: fast-forward
A -- B -- C [b1,local/remote]
Case D: 合并,并且自动生成一个提交E
A -- B -- D --- E [b1]
\ /
---- C [b1]
git merge 合并两个分支
当前在b2
上,合并远程 b1
的改动,对应 Case E$ git merge origin/b1
Case E:
A -- B ------ D [b1]
\ \
-- C -- E [b2]
图1
git pull
git pull
= git fetch + git merge
git rebase
只有当一个分支出现分叉,或者在不同的分之间,git rebase 才有意义。命令格式:git rebase 目标分支
- 把本地未推送的所有提交,放到暂存区。
- 然后将本分支的指针指向目标分支最新提交,即改变本地分支的基础,简称
变基
, 这个翻译真是太糟糕了。 - 然后将暂存区的本地未推送的提交挨个应用回本分支。
同一个分支的 rebase
# Case E
$ git rebase
A -- B ------- D [b1,remote]
\
------ D -- C1 [b1,local]
图2
C
暂存,然后指向 D
, 应用 C
,C
在 D
之前,变成了 C1
。注意这个和上面 egit merge
(图1)的区别。不同分支的 rebase
这其实和同一个分支类似,不过注意,不同分支 rebase 可能需要强制推送:# Case F
$ git rebase origin/b1
A -- B ------- D [b1,remote]
\
------ D -- C1 [b2,local]
强制推送: git push --force
为什么需要强制推送,官方文档:Usually, the command refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it.
Case F, 如果b2
在 D
和 C
之前,有其他的提交已经推送到服务器了,则需要强制推送,因为他们是从 B
开始分叉的。 pushed
A -- B -..... --- D [b1,remote]
\
-.... --- D -- C1 [b2,local]
$ git push origin b2 -f
$ git push origin b2 --force
$ git push origin +b2
--------------------
Some tips for git setup and git config
the ssh key
generate ssh key
cd ~/.ssh/
ssh-keygen -t rsa -C "changeme@xxx.com" -f filename
f
is not input, the file name of the public/pirvate rsa key pair files will be: id_rsa, id_rsa.pub.add ssh key
ssh-add ~/.ssh/xxx
list all added ssh key
ssh-add -l
you may run into this error when try ssh-add
:
Could not open a connection to your authentication agent.
eval `ssh-agent -s`
add ssh key permanently
Add the key path to~/.ssh/config
$ vim ~/.ssh/config
IdentityFile ~/.ssh/gitHubKey
IdentityFile ~/.ssh/xxx
git config
global config & repository config
The global setting is stored in~/.gitconfig
The config of repository is stored in
./.git/config
, in the repository directory.git config --global
will use global config, without --global
options will use try to use the config file ./git/config
in current directory.config user name & user email for every repository
You may work with multiple repositories, so it is a good practice to config user information for every repository.# for global setting
git config --global user.name xxx
git config --global user.email xxx@xxx.com
# for repository
git config user.name xxxx
git config user.email xxxx@xxx.com
git alias
Setup alias for convenience.#git st => git status
git config --global alias.st 'status'
#git co => git checkout
git config --global alias.co 'checkout'
#git lg to view commit log like network graph
git config --global alias.lg "log --all --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %C(bold blue)<%an>%Creset' --abbrev-commit"
#...
# whatever you like
--------------------
git配置问题: 多个 sshkey, 多个用户身份, git alias
ssh key
生成sshkey
cd ~/.ssh/
ssh-keygen -t rsa -C "changeme@xxx.com" -f filename
f
选项或者 f
选项为空,生成的私钥和公钥为: id_rsa
, id_rsa.pub
.添加 sshkey
ssh-add ~/.ssh/xxx
列出所有的 sshkey
ssh-add -l
执行 ssh-add
可能会遇到的问题:
Could not open a connection to your authentication agent.
解决办法:eval `ssh-agent -s`
机器重启又得重新添加 sshkey,如何永久添加 sshkey
把 sshkey 私钥的路径加入到~/.ssh/config
, 如下:$ vim ~/.ssh/config
IdentityFile ~/.ssh/gitHubKey
IdentityFile ~/.ssh/xxx
git config
全局配置和项目配置
全局配置信息在:~/.gitconfig
。项目配置在项目目录下的:
./.git/config
。git config --global
操作全局配置, 不带 --global
选项的话,会尝试相对于当前目录的: ./git/config
, 找不到的话,报错。为各个项目单独配置user.name
和 user.email
你可能会在不同的几个项目中工作,各个项目的用户名可能不同,为了保证日志的准确性和提交时无误,最好对各个项目设置 user.name
和 user.email
# for global setting
git config --global user.name xxx
git config --global user.email xxx@xxx.com
# for repository
git config user.name xxxx
git config user.email xxxx@xxx.com
git alias
使用快捷命令能带来很方便,输入命令更加快速,git lg
这个短命令配置,将日志图形化方式展现:#git st => git status
git config --global alias.st 'status'
#git co => git checkout
git config --global alias.co 'checkout'
#git lg to view commit log like network graph
git config --global alias.lg "log --all --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %C(bold blue)<%an>%Creset' --abbrev-commit"