踩了很多坑,总结一下。首先有两种需求,第一种是本地的项目部署到Github上,第二种是将团队的项目拉到本地。
(初始)本地 -> GitHub
因为本地到Github有可能是第一次去推送代码,也有可能是你更改了拉下来的代码再推送,这里初始指的是前者,初次部署。
-
首先在GitHub创建一个空仓库,位置如下,三个地方都可以。
-
进去之后按照要求填写即可。
其中README文件,在这个文件里,可以写项目的相关信息,之后会出现在该仓库主页的下面的位置。
.gitignore选择你的语言即可,之后在这个文件里你可以写当你把本地代码上传代码至GitHub时,想要忽略上传的文件。
对于license,内容比较多,你选择MIT即可,它是最宽松的license,意味着完全开源,别人想怎么用就怎么用;与之相对GPL是最严的。
建议不要点README文件和.gitignore文件,因为你如果点了,当点击最下面创建仓库时,它会帮我们做一次初始提交。于是我们的仓库就有了README和.gitignore这两个文件。然后我们把本地项目关联到这个仓库时,我们在关联本地与远程时,两端都是有内容的。但是这两份内容并没有联系(可能本地推到远程时,会生成一个“码”类似的东西,来互相识别,而这里没有这个步骤。),当我们推送到远程(git push:failed to push some refs to)或者拉取,都会有还没有被跟踪的内容,所以推送和拉取总是失败。
或者刚开始就用我下面说到的将团队项目拉到本地的方式拉项目,这样就可以点呢些东西,但我觉得还是上面说的方式更正常些。
-
在本地IDEA中首先你需要在Terminal中输入git init,目的就是来初始化本地库,让本地可以被Git进行版本控制,以及Git的其他功能。完成后,会出现如下变化。
其中,红色代表创建之后没有add,没提交,不在版本控制范围之内,需要先add文件。
绿色代表add之后,但没有commit。
蓝色代表原本有一个文件,改动过后没有commit是蓝色的,提交之后,变成正常颜色(无色)。
黄色代表被.gitignore文件声明而忽略。
!!!注意:请先把.girignore拉到根目录下(demo),或者直接在根目录创建一个(下面会解释)。
-
之后开始进行git add和git commit操作。
首先解释git add,它的意思把目标文件添加到暂存区,暂存区有什么意义呢?不能直接commit吗?详情看我这篇文章,一定要结合图。
这里的话,你可以用:git add . git commit -m "备注"
也可以用右上角IDEA的快捷键(绿色对勾),直接commit。
这里要额外说一下,新建文件时IDEA会询问你是否将新的文件git add
如果你不点,在点击右上角commit时,左侧出现了“Unversioned Files”,中文就是没有被版本控制的文件,也就是没有add,如果你点了,这步就相当于git add。这正好也回答了上面为什么直接点commit快捷键,没有add,就能commit。
-
进行git push推送(使用HTTP方式)。
可以发现项目已经成功推送到Github上。
这里有一个问题,为什么我设置的.gitignore并没有忽略?
第一个原因可能是,在最初git add时并没有更改.gitignore。.gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。解决方法就是先把本地缓存删除(改变成未track状态),然后再提交:git rm -r --cached . git add . git commit -m 'update .gitignore'
还有一个原因,你要把.idea里的.gitignore移到根目录下,或者直接新建一个。如果.gitignore在.idea里,你所有配置的东西,都只会在.idea目录下生效。所以一定要记得把.gitignore拖到根目录下(demo)。
而且在没有git add文件时,你变换.gitignore,对应的文件会变黄(需要等一下才显示)。
忽略之后,commit时IDEA也会直接不显示。当然如果你不想动.gitignore(比如有时候只是一个比较特别的文件;或者你git clone下来时,远程没有的东西,就会显示在“Unversioned Files”,你也没必要改变你的.gitignore,只要别add就行,后面会说的),不add就行。
GitHub -> 本地
首先第一个问题,远程到本地到底是用git clone还是git pull。下面我分别为大家演示:
1)在Github没选REDEME或gitignore时,也就是空项目时,直接git pull(我们的标题时远程项目拉到本地,这个情况只是演示下)。
错误信息是说无法发现远程HEAD指针,这个HEAD指针是说,当前Git的“版本”(Git是版本管理的工具),可以看我这篇文章:GitBranching,结合图片会更清晰的明白HEAD是啥。
为什么会这样?很明显,因为你直接git pull,Github上你刚刚创的项目是空的,啥也没有,也就是没有初始的版本。如果你选了REDEME后gitignore是会有的,上面已经提到过了。
2)直接拉一个完整的项目,它是可以拉下来的,只不过目录不太对。
3)对比
clone | pull |
---|---|
clone是将整个工程复制下来,所以不需要本地是仓库(即没有.git文件夹) | pull需要先初始化本地文件夹作为一个仓库 |
clone出的项目可以自由切换远端已有的分支 | pull只能在当前分支 |
所以说git pull也能拉项目不过不方便。
下面正式开始说拉去远程项目的合理方式。
- 首先建议在“Project from Version Control”里使用IDEA提供的快捷clone方式。
不这样的话,如过你在terminal里输入git clone,你的项目就会像这样clone下来,而且你本地没有git,下面第二张图,还得git init。不过你init后,它会默认把Github上的文件add和commit了,本身没有的,而你本地有的都是红色,这样省的配置.gitignore了(直接用IDEA也是这样的)。
- 之后就可以开发代码了,开发完还是那一套add,commit,push。不过要注意的是,一般团队开发,你拉下来代码后,你应该在git branch xx,并且git checkout xx,在这个分支开发,开发完commit到这个分支,push也是push到这个分支(直接git push http… xx就可以),由管理员进行合并操作(因为管理员要检查呀什么的,详情请看Gitflow理念)。
下图push到了新分支new_branch,“Compare & pull request”就可以处理合并。
两个分支,master还是原来的。如果合并了这个new_branch也并不会删除,需要手动删除。
- 接下来试一下随便push一个分支(刚才是本地的new_branch push到远程的new branch)
看来名称与名称必须匹配。 - 我们在试一下,在push一个新建的分支,之前呢个compare & pull request变成什么样。出现了俩。
点这里的branch里也能合并(pull request),还能创建分支等。点tags可以创建tag,一般用来做发行版本。
- 下面我们看一下如何解决冲突。
首先看git pull时的冲突。我们远程更改文件。
记得下面点commit
我们本地目前在new_branch2上,我们直接把master pull到new_branch2,然后本地处理冲突。
可以发现,这里说“Automatic merge failed;fix conflicts and then commit”
由冲突的文件是这样的。这里的结构是这样的。处理冲突只需要留下你想要的,并把多余字符删除掉即可。之后主要要git add 这个文件,因为你可以看到这个文件变红了,你需要重新add。<<<<<<< HEAD 本地代码 ======= 拉下来的代码 >>>>>>>
你也可以用IDEA提供的可视化的方式,点击commit快捷键,然后点击“Resolve”
再点击“Merge”可以可视化的合并。
目前把远程的master和本地的new_branch2合并了,在push到master,看看会不会有冲突。可以看到并不能push(可以强制,但不建议)。
那如果本地new_branch2到远程new_branch2,成功。上面也验证过,这回再次验证本地和远程的branch名字必须一样,才能push。
如果你想本地new_branch2 push到远程master,网络上的解决方式是使用git rebase,简单来讲就是重写git的“历史”,直接搜索“non-fast-forward”就可以知道相关词条。我这里就不解释了,因为我觉得你就不应该把本地new_branch2 push到远程master。正常的开发方式,简单来讲应该是你把远程的master拉到本地,然后你进行开发,开发完成后commit时,你应该new一个新的开发分支,commit到这个分支上;之后push到远程新的开发分支上,然后在Github上发起合并请求(开发分支到master),处理合并请求因该是管理员的事情。详情见Gitflow理念。 - 这里我在说一下,你可能会觉得我在本地处理了冲突,在push上去,管理员合并时也会有冲突呀。是的,管理员合并过程中可能也会发生冲突,需要管理员联系成员了解情况后进行手动合并。
管理员的作用:
1)检查各个成员分支的代码有无问题
2)将成员分支的代码合并到master分支
3)合并发生冲突时,进行手动合并
总的来说,减少冲突的最好方式,就是口头约定好。
团队协作
由于自己只有一台电脑一个账户,日后工作有了经验在补充。
附录
1).gitignore的官方推荐(Java)(当然你可以自己加,比如这个并没有去掉.idea目录,和.iml文件)
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
# 可以加
*.iml
/.idea/
2)Git流程图
3)经常pull和push会报以下的错误,可以看这里:解决方式。简单概括原因就是,可能网不行,或者时SSL的问题,多试几次,要不换个网络。
3)SSH和HTTP的差别
简单来说,配置SSH后,你push代码时就不用输密码了;HTTP需要输入。
4)常用Git语句
1. git init:初始化,生成隐藏的.git目录(Mac下看不到,我记得Windows可以看到,可以使用ls -a查看隐藏目录)
2. git status:查看一些基本的信息
3. git add:添加到暂存区,这样你就可以选择性的提交,把add的提交
4. git rm --cached xxx:删除暂存区的文件
5. git commit -m "xxx":提交
6. git reflog:查看当前的版本,git log可以更详细
7. git reset --hard xxx版本号:穿越版本,本地文件将会改变
8. git branch -v:查看当前分支(不加-v,显示的信息少一些)
9. git branch xxx:创建分支
10. git merge xxx:什么时候会冲突 :首先只有commit后才能merge,两个merge的都改了同一个地方,才会冲突,不然不会。只会修改你所处的branch,呢个不会变动
11. clone就是本地仓库没有,完整的把项目下载下来,pull就是和你以前push的版本进行合并
12. git remote -v:查看远程仓库别名
13. git remote add xxx httpxxx:设置别名(先在github上创个仓库,然后在去IDEA关联)
14. git push 别名 分支名(你的):传到github
15. git pull HTTP 分支名(Github上的):拉取
16. git clone HTTP
17. git branch --delete release-1.0.0:删除分支
18. git rm xxx:删除git上的文件
19. git rm -f xxx:删除git上的文件夹