1. 假定原作者的名称叫gittest, 我叫uniquejava.
原作者新建了一个项目叫nocrazy。 于是路径为gittest/nocrazy
做了两次提交 提交一: a.txt this is a 提交二:b.txt this is b.2. 我cyper某天fork了这个项目,于是有origin指向uniquejava/nocrazy, 并且新增一个upstream指向原作者gittest/nocrazy $ git clone https://git.oschina.net/uniquejava/nocrazy.git $ cd nocrazy ➜ nocrazy git:(master) $ git remote add upstream https://git.oschina.net/gittest/nocrazy.git ➜ nocrazy git:(master) $ git remote -v origin https://git.oschina.net/uniquejava/nocrazy.git (fetch) origin https://git.oschina.net/uniquejava/nocrazy.git (push) upstream https://git.oschina.net/gittest/nocrazy.git (fetch) upstream https://git.oschina.net/gittest/nocrazy.git (push) ➜ nocrazy git:(master) $ 3. gittest正常提交了一个新版本 c.txt this is c git log --oneline e63667b this is c 11f5850 this is b 1cbdb56 this is a
4. Cyper想把fork同步到和gittest一模一样,怎么办?
办法一(思考未试验):把自己的fork删除重新fork? 然后呢在本地git pull origin master 办法二: git fetch upstream git checkout master git merge upstream/master 方法二需要push才能到origin么。(yes) ➜ nocrazy git:(master) $ ll total 16 drwxr-xr-x 13 cyper staff 442B Aug 26 05:11 .git/ -rw-r--r-- 1 cyper staff 10B Aug 26 05:07 a.txt -rw-r--r-- 1 cyper staff 10B Aug 26 05:07 b.txt ➜ nocrazy git:(master) $ git fetch upstream remote: Counting objects: 4, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From https://git.oschina.net/gittest/nocrazy * [new branch] master -> upstream/master ➜ nocrazy git:(master) $ git diff ..upstream/master diff --git a/c.txt b/c.txt new file mode 100644 index 0000000..5da75cf --- /dev/null +++ b/c.txt @@ -0,0 +1 @@ +this is c 使用以上git diff命令可以看到author新增了一个c.txt文件。 ➜ nocrazy git:(master) $ git merge upstream/master Updating 11f5850..e63667b Fast-forward c.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 c.txt ➜ nocrazy git:(master) $ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working directory clean ➜ nocrazy git:(master) $ git fetch upstream ➜ nocrazy git:(master) $ git merge upstream/master Already up-to-date. ➜ nocrazy git:(master) $ git diff ..origin/master diff --git a/c.txt b/c.txt deleted file mode 100644 index 5da75cf..0000000 --- a/c.txt +++ /dev/null @@ -1 +0,0 @@ -this is c 通过以上可以看到git merge只是把upstream上的代码拉到(本地工作目录+本地仓库),需要我们push origin ➜ nocrazy git:(master) $ git push origin master Username for 'https://git.oschina.net': uniquejava Password for 'https://uniquejava@git.oschina.net': Counting objects: 3, done. Delta compression using up to 8 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 292 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To https://git.oschina.net/uniquejava/nocrazy.git 11f5850..e63667b master -> master ➜ nocrazy git:(master) $ ll total 24 drwxr-xr-x 14 cyper staff 476B Aug 26 05:21 .git/ -rw-r--r-- 1 cyper staff 10B Aug 26 05:07 a.txt -rw-r--r-- 1 cyper staff 10B Aug 26 05:07 b.txt -rw-r--r-- 1 cyper staff 10B Aug 26 05:14 c.txt 到这里, 步骤4验证结束。。。成功的将fork上的代码更新到最新版。 5. 假设上一步成功执行, 效果应该和我重新fork一遍最新的项目是一样的。
6. 重复3:即gitetst提交了一个新版本
d.txt this is d.7. 在6之前,Cyper因为要修复defect #1, 已经开始基于c.txt做修改。就没有来得及及时同步
cyper修改this is c变成this is c_cyper 然后正常的add, commit , (Cyper此时是否可以push?) ➜ nocrazy git:(master) ✗ $ git commit -m "[nocrazy-1] fix c." [master 77fd57f] [nocrazy-1] fix c. 1 file changed, 1 insertion(+), 1 deletion(-) 此时已经有了分歧。gittest上有新的提交, cyper也有新的提交。 cyper想基于最新的代码重新提交。7-1 假定cyper没有push他想先更新fork,然后基于 author最新的代码去做提交git fetch upstreamgit checkout mastergit merge upstream/master 这一步是用git rebase upstream/master还是用git merge upstream/master ===== ➜ nocrazy git:(master) $ git rebase origin/master(这步只是想验证base到当前base的情况,无效果) Current branch master is up to date. ➜ nocrazy git:(master) $ git fetch upstream remote: Counting objects: 4, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From https://git.oschina.net/gittest/nocrazy e63667b..380a8dd master -> upstream/master ➜ nocrazy git:(master) $ git rebase upstream/master First, rewinding head to replay your work on top of it... Applying: [nocrazy-1] fix c. ➜ nocrazy git:(master) $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working directory clean ➜ nocrazy git:(master) $ 以上这步做了什么???原来git rebase upstream/master把upstream上的代码拉到(本地工作目录+本地仓库),并且自动做了合并, 所以你的本了一下子多出来两个commit需要push, 因此有Your branch is ahead of 'origin/master' by 2 commits. ➜ nocrazy git:(master) $ git log --oneline 8530647 [nocrazy-1] fix c. 380a8dd this is d e63667b this is c 11f5850 this is b 1cbdb56 this is a 现在只需做push origin。。。就行了! ➜ nocrazy git:(master) $ git push origin master Username for 'https://git.oschina.net': uniquejava Password for 'https://uniquejava@git.oschina.net': Counting objects: 6, done. Delta compression using up to 8 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 566 bytes | 0 bytes/s, done. Total 6 (delta 1), reused 0 (delta 0) To https://git.oschina.net/uniquejava/nocrazy.git e63667b..8530647 master -> master 所以在发pull request 之前不要去做push . (如果在rebase之前就做了push,需要怎么补救???)到目前为止,cyper的远程仓库中是最新的代码,而原作者的代码不新,因为他的代码没有包含你的修改8. 发pull request 8-1, 假设gittest在你发pull request前,没有提交任何代码。。 过程很简单。 接下来gittest review,他点击某个代码变动行的前面加了一个comment: 少了一个标点符号 。。 如果你此时使用git fetch upstream会没有任何输出 然后你 ➜ nocrazy git:(master) $ git rebase upstream/master Current branch master is up to date. 这是因为你当前没有任何commit是需要rebase的, 因为所有commit都已经push到了origin. 除非。。 与时同时, gittest正常添加了一个新文件 e.txt this is e. 你重新fetch, ➜ nocrazy git:(master) $ git fetch upstream remote: Counting objects: 5, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From https://git.oschina.net/gittest/nocrazy 380a8dd..fd2e641 master -> upstream/master ➜ nocrazy git:(master) $ git diff ..upstream/master diff --git a/c.txt b/c.txt index 3af12b3..5da75cf 100644 --- a/c.txt +++ b/c.txt @@ -1 +1 @@ -this is c_cyper +this is c diff --git a/e.txt b/e.txt new file mode 100644 index 0000000..5641475 --- /dev/null +++ b/e.txt @@ -0,0 +1 @@ 可以看到,当前你的本地仓库和upstream的区别是。。你改了c文件而upstream加了e文件。。 你重新rebase ➜ nocrazy git:(master) $ git rebase upstream/master First, rewinding head to replay your work on top of it... Applying: [nocrazy-1] fix c. ➜ nocrazy git:(master) $ git status On branch master Your branch and 'origin/master' have diverged, and have 2 and 1 different commit each, respectively. (use "git pull" to merge the remote branch into yours) nothing to commit, working directory clean ➜ nocrazy git:(master) $ 这时和第一次有所不一样, ➜ nocrazy git:(master) $ git log --oneline 8c4c4b6 [nocrazy-1] fix c. fd2e641 this is e 380a8dd this is d e63667b this is c 11f5850 this is b 1cbdb56 this is a 查看一下有什么不一样 ➜ nocrazy git:(master) $ git diff ..origin/master diff --git a/e.txt b/e.txt deleted file mode 100644 index 5641475..0000000 --- a/e.txt +++ /dev/null @@ -1 +0,0 @@ -this is e 是因为你自己的远程仓库没有包含e文件。。。按照提示。 你需要做一次pull 但是pull会产生分支 。。 尝试一下然后立马撤销(http://stackoverflow.com/questions/1223354/undo-git-pull-how-to-bring-repos-to-old-state) ➜ nocrazy git:(master) $ git pull Merge made by the 'recursive' strategy. ➜ nocrazy git:(master) $ git log --oneline 9d7a324 Merge branch 'master' of https://git.oschina.net/uniquejava/nocrazy 8c4c4b6 [nocrazy-1] fix c. fd2e641 this is e 8530647 [nocrazy-1] fix c. 380a8dd this is d e63667b this is c 11f5850 this is b 1cbdb56 this is a ➜ nocrazy git:(master) $ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) nothing to commit, working directory clean 可见, git pull生成的commit history多么的混乱!(相对于当前的origin/master, 一下子多出了3条commit history)9d7a324 Merge branch 'master' of https://git.oschina.net/uniquejava/nocrazy8c4c4b6 [nocrazy-1] fix c.fd2e641 this is e 赶紧撤销并换成git rebase ➜ nocrazy git:(master) $ git show HEAD commit 9d7a324e5e562475b9585ed029817fc98d09a1d4 Merge: 8c4c4b6 8530647 Author: cyper <345343747@qq.com> Date: Wed Aug 26 06:11:07 2015 +0800 Merge branch 'master' of https://git.oschina.net/uniquejava/nocrazy 原来。。HEAD并不是指向远程仓库的head.. ➜ nocrazy git:(master) $ git show head ➜ nocrazy git:(master) $ git show HEAD ➜ nocrazy git:(master) $ git show master ➜ nocrazy git:(master) $ git show origin/master 。。。前三个信息都是指向本地仓库的头,是没一个commit id.最后一个是我想要的头,是我pull之前的commit id 所以有三种方法 git reset --hard HEAD^3 或git reset --hard origin/master 或者git reset --hard 8530647b重做第7步。。
➜ nocrazy git:(master) $ git rebase upstream/master First, rewinding head to replay your work on top of it... Applying: [nocrazy-1] fix c. ➜ nocrazy git:(master) $ git status On branch master Your branch and 'origin/master' have diverged, and have 2 and 1 different commit each, respectively. (use "git pull" to merge the remote branch into yours) nothing to commit, working directory clean ➜ nocrazy git:(master) $ 现在因为本地仓库才是最新的。。你需要force push到origin而不需要理pull操作。。。 ➜ nocrazy git:(master) $ git push origin master --force Username for 'https://git.oschina.net': uniquejava Password for 'https://uniquejava@git.oschina.net': Counting objects: 6, done. Delta compression using up to 8 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 569 bytes | 0 bytes/s, done. Total 6 (delta 1), reused 0 (delta 0) To https://git.oschina.net/uniquejava/nocrazy.git + 8530647...3e23afc master -> master (forced update) git rebase产生了完美的commit history: 3e23afc [nocrazy-1] fix c. fd2e641 this is e 380a8dd this is d e63667b this is c 11f5850 this is b 1cbdb56 this is a