参考:http://www.open-open.com/lib/view/open1328069889514.html
出库
git clone 与 git pull的区别
[smbtest@localhost a]$ git init
[smbtest@localhost a]$ git clone [remote_repo_path]
[smbtest@localhost a]$git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# test/
nothing added to commit but untracked files present (use "git add" to track)
[smbtest@localhost a]$ git log
fatal: bad default revision 'HEAD'
[smbtest@localhost a]$ git branch
[smbtest@localhost a]$ git init
[smbtest@localhost a]$ git pull [remote_repo_path]
[smbtest@localhost b]$ git status
# On branch master
nothing to commit (working directory clean)
[smbtest@localhost b]$ git log
commit 4ab6b6d53b77ba41ca94a443a6d6cf00acdfcb42
…….
[smbtest@localhost git_study]$diff -r a/.git/ b/.git/
Only in b/.git/: FETCH_HEAD
Binary files a/.git/index and b/.git/index differ
Only in b/.git/: logs
Only in b/.git/objects/pack: pack-9a714c6fd30c1addc0648e809907bb09ebff0230.idx
Only in b/.git/objects/pack: pack-9a714c6fd30c1addc0648e809907bb09ebff0230.pack
Only in b/.git/refs/heads: master
[smbtest@localhost b]$ git branch
* master
由上可见,git clone只是简单的把远端库中的内容拷贝到本地,并没有建立分支,因此拷过来的内容还没有加入tracking,也没有log信息;而git pull自动建立了master分支,内容(包括log)与远端库一致。
即使是git clone,如果要进行库操作git init也是不可缺少的:
[smbtest@localhost c]$ git clone ssh://git@sny-jira.ads.finisar.com:7999/gpon/test.git
Cloning into 'test'...
remote: Counting objects: 671, done.
remote: Compressing objects: 100% (316/316), done.
remote: Total 671 (delta 287), reused 612 (delta 263)
Receiving objects: 100% (671/671), 801.00 KiB | 88 KiB/s, done.
Resolving deltas: 100% (287/287), done.
[smbtest@localhost c]$ git status
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
[smbtest@localhost c]$ git log
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
[smbtest@localhost c]$
基本入库
修改一个文件
假设修改了a.txt。
使用git status可以看到Changes not staged for commit下面有一个modified的文件
[smbtest@localhost a]$ 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: a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")git add
使用git add后,再用git status查看有一个Changes to be commited的文件
[smbtest@localhost a]$ git add a.txt
[smbtest@localhost a]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: a.txt
#
使用git commit后,git status内没有内容,git log可以看到新增一条log
[smbtest@localhost a]$ git commit -m "modify a.txt"
[master 22316f1] modify a.txt
1 file changed, 1 insertion(+)
[smbtest@localhost a]$ git status
# On branch master
nothing to commit(working directory clean)
[smbtest@localhost a]$ git log
commit 22316f1e002341ec33f58d7c82730527625237c0
Author:
Date: Sun Feb 2 10:49:03 2014 +0800
modify a.txt
使用git remote add,添加一个remote(本命令只需使用一次)
[smbtest@localhost a]$ git remote add origin2 ssh://xxx
使用git push,将本地修改推送到远端库
[smbtest@localhost a]$ git push
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 338 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://git@sny-jira.ads.finisar.com:7999/gpon/test.git
ed7f63f..22316f1 master -> master
增加一个文件
使用git status可以看到一个untracked files
[smbtest@localhost a]$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# a2.txt
nothing added to commit but untracked files present (use "git add" to track)
使用git add后,再用git status查看有一个Changes to be commited的文件
[smbtest@localhost a]$ git add a2.txt
[smbtest@localhost a]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: a2.txt
#
使用git commit后,git status内没有内容,git log增加了一条log
[smbtest@localhost a]$ git commit -m "add a2.txt"
[master 21a90f2] add a2.txt
1 file changed, 1 insertion(+)
create mode 100644 a2.txt
[smbtest@localhost a]$ git status
# On branch master
nothing to commit (working directory clean)
[smbtest@localhost a]$ git log
commit 21a90f2562c826230adfbcc5a1332a7f081344a9
Author:
Date: Sun Feb 2 11:01:06 2014 +0800
add a2.txt
直接使用git push将本地修改推送到远端库
[smbtest@localhost a]$ git push
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 284 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To ssh://git@sny-jira.ads.finisar.com:7999/gpon/test.git
22316f1..21a90f2 master -> master
删除一个文件
[smbtest@localhost a]$ git rm a2.txt
rm 'a2.txt'
[smbtest@localhost a]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# deleted: a2.txt
#
[smbtest@localhost a]$ git commit -m "delete a2.txt"
[master 3764a36] delete a2.txt
1 file changed, 1 deletion(-)
delete mode 100644 a2.txt
[smbtest@localhost a]$ git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 227 bytes, done.
Total 2 (delta 1), reused 0 (delta 0)
To ssh://git@sny-jira.ads.finisar.com:7999/gpon/test.git
21a90f2..3764a36 master -> master
小结
从上述操作可以看到,git的操作分为三个层次,stage、local repo和remote repo,其中git add和git rm用于将一个文件的修改(包括创建和删除)添加到stage,git commit用于将stage中记录的修改入库到local repo,git push则将本地库的修改推送到远端库,每个层次的操作都以前一层次的内容为基础——即stage内有内容才可以commit,local repo有内容才可以push。
入库撤销操作
git reset
使用git与svn很大的一个不同,是在开发过程中先在本地进行一系列的入库(仅commit不push),待整个功能确认完成后,一次性推送到远端库。当然在本地库操作过程中,不可避免地会碰到需要撤销本地库入库的情况。
git reset撤销stage和local repo的修改
使用git reset撤销commit,保留本地文件的修改和add的信息。
假设本地库中在删除delete a2.txt之后,保留了实现feature1.1/feature1.2/feature1.3的三次入库信息:
[smbtest@localhost a]$ git log
commit 8fd3cf3da8dcf0663150b29b4b7d844e83af097c
feature 1.3
commit 644ae1487dfbb6b81aae19049af0a97b93baa52e
feature 1.2
commit a37a3c5f6844aac058530f657c540221ef36807e
feature 1.1
commit 3764a36206944735ea3ee461c254e4c194b160ce
使用git reset [3764a36206944735ea3ee461c254e4c194b160ce],可以将commit信息回退到delete a2.txt时的状态——log最后一条是“delete a.txt”,status中的a.txt的修改还没有加入到stage:
[smbtest@localhost a]$ git log
commit 3764a36206944735ea3ee461c254e4c194b160ce
delete a2.txt
[smbtest@localhost a]$ 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: a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
然后按照基本入库步骤将feature1.1/feature1.2/feature1.3作为function1一次commit即可
[smbtest@localhost a]$ git add a.txt
[smbtest@localhost a]$ git commit -m "function 1"
[master 5ec3455] function 1
1 file changed, 5 insertions(+)
[smbtest@localhost a]$ git log
commit 5ec3455dae0c02537c2d9ff1e001b5da97e71d9a
function 1
git reset--soft撤销local repo的修改
假设入库function1以后,又有两次commit(feature2.1、feature2.2)
[smbtest@localhost a]$ git log -3
commit 40e8c12abff40aba66d8fa6ed4970a93890d755a
feature 2.2
commit f0aac7525f6cb0be069662b0b3c52e8edf411a62
feature 2.1
commit 5ec3455dae0c02537c2d9ff1e001b5da97e71d9a
function 1
使用git reset –soft,撤销最近的两次commit操作
[smbtest@localhost a]$ git reset --soft 5ec3455dae0c02537c2d9ff1e001b5da97e71d9a
[smbtest@localhost a]$ git log -1
commit 5ec3455dae0c02537c2d9ff1e001b5da97e71d9a
function 1
[smbtest@localhost a]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: a.txt
#
可以看到git log已经删除了最近两次commit,但是status内还保留了add a.txt的操作。之后入库只需直接commit即可。
git reset –hard撤销本地文件、statge、local repo的修改
git reset –hard不再赘述,其特征是本地文件也将恢复成指定HEAD的状态(所做修改被丢弃),慎用!
git revert
git revert将指定commit所包含的修改回退后再commit,从而撤销该次入库,其顺利执行的前提是涉及文件与其他commit不存在冲突。
[smbtest@localhost a]$ git log
commit c4b214aff15850d17b386b10cf2cd5e855f27f33
feature 2.3
commit 7e42cf823c6efe22dee4382a847a744914572e35
feature 2.2
commit cd342b2acc8bb7f4ca5f18900ea4526aa307618e
feature 2.1
[smbtest@localhost a]$ git revert 7e42cf823c6efe22dee4382a847a744914572e35
[master 04d7880] Revert "feature 2.2"
0 files changed
delete mode 100644 feature2.2
[smbtest@localhost a]$ git log
commit 04d788084fcfb3bbc79caa47350d7edd2d6e50a6
Revert "feature 2.2"
This reverts commit 7e42cf823c6efe22dee4382a847a744914572e35.
commit c4b214aff15850d17b386b10cf2cd5e855f27f33
feature 2.3
commit 7e42cf823c6efe22dee4382a847a744914572e35
feature 2.2
commit cd342b2acc8bb7f4ca5f18900ea4526aa307618e
feature 2.1
小结
git reset和git revert可以达到同样的效果,git reset主要用于push到远端库之前对本地文件和commit进行调整;git revert通过增加一次新的入库,恢复指定入库的修改,相对来说比较方便,但是需要避免冲突。
冲突操作
无关文件
a在function1之后入库了feature2.x,b在function1之后本地增加了feature3.1,此时b入库会提示错误:
[smbtest@localhost b]$ git push
To ssh://git@sny-jira.ads.finisar.com:7999/gpon/test.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'ssh://git@sny-jira.ads.finisar.com:7999/gpon/test.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
此时需要重新pull 一次远端库,获取到远端库的修改
[smbtest@localhost b]$ git pull origin master
From ssh://sny-jira.ads.finisar.com:7999/gpon/test
* branch master -> FETCH_HEAD
Merge made by the 'recursive' strategy.
0 files changed
create mode 100644 feature2.1
create mode 100644 feature2.2
create mode 100644 feature2.3
此时,可以看到log的变化(在feature 3.1之前增加了feature 2.x的commit log,之后增加了一条merge的log)
[smbtest@localhost b]$ git log
commit 006871f55dbabe3eb2852c5011b555f4cbddcb8b
Merge: 50b4877 c4b214a
Merge branch 'master' of ssh://sny-jira.ads.finisar.com:7999/gpon/test
commit 50b48770c13bac5b6e97088d6d071649f4d55b35
feature 3.1
commit c4b214aff15850d17b386b10cf2cd5e855f27f33
feature 2.3
commit 7e42cf823c6efe22dee4382a847a744914572e35
feature 2.2
commit cd342b2acc8bb7f4ca5f18900ea4526aa307618e
feature 2.1
最后再push。
从log上看,其实最后一条merge log属于一条冗余信息,我们当然知道应该要merge一下,如何避免这条冗余信息,可以参考git reset的使用。
相同文件
假设a在a.txt增加了feature 4.1,已入到远端库,b在a.txt增加feature 4.2,此时pull也会提示错误:
[smbtest@localhost b]$ git pull origin master
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ssh://sny-jira.ads.finisar.com:7999/gpon/test
* branch master -> FETCH_HEAD
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.
使用git status,可以看到自动merge失败的文件a.txt
[smbtest@localhost b]$ git status
# On branch master
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
使用git diff,可以查看具体的差异,03ef4d19eb8c2ad7b93ce7e486f6a01ab7e0856d是远端库的commit id。
[smbtest@localhost b]$ git diff a.txt
diff --cc a.txt
index 7e6411a,a32e92b..0000000
--- a/a.txt
+++ b/a.txt
@@@ -7,4 -7,4 +7,8 @@@ function
feature 1.3
function 4
++<<<<<<< HEAD
+ feature 4.2
++=======
+ feature 4.1
++>>>>>>> 03ef4d19eb8c2ad7b93ce7e486f6a01ab7e0856d
根据需要修改a.txt,git add,git commit后,push。