Python Package Best Practices (..
/)
(../02- (../04-
git/[Link]) functi
style/i
Using GitHub
Overview
Teaching: 30 min
Exercises: 5 min
Questions
How do I use git and GitHub?
Objectives
Explain reasons to use GitHub.
Securely accessing GitHub
During the setup for this workshop, we generated an SSH key and added it to our GitHub account. The SSH key will allow us to
authenticate our identity to GitHub, allowing us to access to our remote repositories. For the purposes of this workshop, an SSH key is
a good way to quickly and conveniently get set up using GitHub. If you continue further development using GitHub after this workshop,
you may want to consider alternatives.
GitHub has added a feature called Personal Access Tokens (PATs) that allow for more fine-grained security control over your access.
Instead of one key that has all the permissions on your account, you can define multiple tokens that have a different set of
permissions. GitHub has good documentation for generating and using a PAT ([Link]
github/keeping-your-account-and-data-secure/creating-a-personal-access-token).
1. Create new repo on GitHub
Putting your repository on GitHub.
Now, let’s put this project on GitHub so that we can share it with others. In your browser, navigate to [Link] ([Link]
Log in to you account if you are not already logged in. On the left side of the page, click the green button that says New to create a
new repository. Give the repository the name molecool .
Note for the last question, “Initialize this repository with a README”. We will leave this unchecked in our case because we have an
existing repository. (As described by GitHub, “This will let you immediately clone the repository to your computer. Skip this step if
you’re importing an existing repository.”) If you were creating the repository on GitHub, you would select this. There are also options for
adding a .gitignore file or a license. However, since cookiecutter created these for us, we will not add them.
Click Create repository .
Now, GitHub very helpfully gives us directions for how to get our code on GitHub.
Before we follow these directions, let’s look at a few things in the repository. When you want to be able to put your code online in a
repository, you have to add what git calls remotes . Currently, our repository has no remotes. See this by typing
Bash
$ git remote -v
2. Push local repo onto GitHub
You should see no output. Now, follow the instructions on GitHub under “…or push an existing repository from the command line”
Bash 不不⽤用type,直接在Github webpage 上copy
$ git remote add origin git@[Link]:YOUR_GITHUB_USERNAME/[Link]
$ git branch -M main
$ git push -u origin main 这⼀一command 把local的repo,main 状态 push 到 Github origin中
The first command adds a remote named origin and sets the URL to our repository. The word origin here is simply a word that is
a shortcut for the location of our repository. We could have called it anything (like pickle , or banana , or anything we wanted), but
origin is used by convention. Now, whenever we say origin , git knows that we really mean
git@[Link]:YOUR_GITHUB_USERNAME/[Link] .
The second command changes our primary branch name from master to main . GitHub recently decided (as of June 2020) to switch
the name of your main branch from master to main . However, the git software will still name your primary (or first) branch
master . After the second command, you will no longer see master when using the command git branch (instead seeing main ).
The third command copies (or “pushes”) everything which we have tracked using git to origin . The word main means we are
pushing the main branch.
Now if you refresh the GitHub webpage you should be able to see all the new files you added to the repository.
Working With Multiple Repositories
One of the most potentially frustrating problems in software development is keeping track of all the different copies of the code. For
example, we might start a project on a local desktop computer, switch to working on a laptop during a conference, and then do
performance optimization on a supercomputer. In ye olden days, switching between computers was typically accomplished by copying
files via a USB drive, or with ssh , or by emailing things to oneself. After copying files, it was very easy to make an important change
on one computer, forget about it, then resume work with the original code version on another computer (having forgotten to reapply the
important change). Of course, when collaborating with other people such problems get dramatically worse.
Git greatly simplifies the process of maintaining multiple copies of a code development project. Let’s see this in action by making
another clone of our GitHub repository. For this next exercise you must first navigate out of your project folder.
Bash
$ cd ../
$ git status
Before continuing to the next command, make sure you see the following output:
Output
fatal: Not a git repository (or any of the parent directories): .git
If you do not get this message, do cd ../ until you see it.
Next, make another copy of your repository. We’ll use this to simulate working on another computer.
Bash
$ git clone git@[Link]:YOUR_GITHUB_USERNAME/[Link] molecool_friend
$ cd molecool_friend
Check the remote on this repository. Notice that when you clone a repository, the source is automatically recorded as origin , and
you do not have to add the remote the way we did when we created the repository locally.
Bash
$ git remote -v
Output
origin git@[Link]:YOUR_GITHUB_USERNAME/[Link] (fetch)
origin git@[Link]:YOUR_GITHUB_USERNAME/[Link] (push)
Create the file [Link] in this new directory and make it contain the following.
I added this file from a new clone!
Now we will commit this new file:
Bash
$ git status
Output
On branch main
Your branch is up to date with 'origin/main'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
[Link]
nothing added to commit but untracked files present (use "git add" to track)
Bash
$ git add .
$ git status
git add
Here, we’ve used git add . instead of git add [Link] . Using this command will add all untracked or changed files.
Output
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: [Link]
Bash
$ git commit -m "Adds [Link]"
$ git log
Now push the commit:
Bash
$ git push
If you check the GitHub page, you should see the [Link] file.
Now change directories into the original local clone, and check if [Link] is there:
Bash
$ cd ../<original clone>
$ ls -l
To get the newest commit into this clone, we need to pull from the GitHub repository:
Bash
$ git pull origin main
Output
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From [Link]:YOUR_GITHUB_USERNAME/molecool
* branch main -> FETCH_HEAD
2ac4843..754da2b main -> origin/main
Updating 2ac4843..754da2b
Fast-forward
[Link] | 1 +
1 file changed, 1 insertion(+)
create mode 100644 [Link]
Now we can actually see [Link] in our original repository.
Exploring History
In your original repository, open the [Link] file and add the following line to the end of the file.
I added this file from a new clone!
This line doesn't add any value.
When working on a project, it is easy to forget exactly what changes we have made to a file. To check this, do
Bash
$ git diff HEAD [Link]
Output
diff --git a/[Link] b/[Link]
index 166776a..a634bfb 100644
--- a/[Link]
+++ b/[Link]
@@ -1 +1,3 @@
I added this file from a new clone!
+This line doesn't add any value.
+
“HEAD” just means the most recent commit. To compare against the commit just before the most recent commit, add “~1” to end of
“HEAD”:
Bash
$ git diff HEAD~1 [Link]
Output
diff --git a/[Link] b/[Link]
new file mode 100644
index 0000000..a634bfb
--- /dev/null
+++ b/[Link]
@@ -0,0 +1,3 @@
+I added this file from a new clone!
+This line doesn't add any value.
+
If we want to compare against a specific commit, we can first do “git log” to find the commit’s ID, and then do:
Bash
$ git diff *commit_id* [Link]
Another problem that we sometimes encounter is wanting to undo all of our changes to a particular file. This can be done with
Bash
$ git checkout HEAD [Link]
$ cat [Link]
Output
I added this file from a new clone!
Of course, you could also replace HEAD here with HEAD~1 or a specific commit ID.
Ignoring Files
Sometimes while you work on a project, you may end up creating some temporary files. For example, if your text editor is Emacs, you
may end up with lots of files called <filename>~ . By default, Git tracks all files, including these. This tends to be annoying, since it
means that any time you do git status , all of these unimportant files show up.
We are now going to find out how to tell Git to ignore these files, so that it doesn’t keep telling us about them ever time we do
git status . Even if you aren’t working with Emacs, someone else working on your project might, so let’s do the courtesy of telling
Git not to track these temporary files. First, lets ensure that we have a few dummy files. Make empty files called [Link]~ and
[Link]~ in your repository using your text editor of choice.
While we’re at it, also make some other files that aren’t important to the project. Make a file called [Link] in
molecool/data using your text editor of choice.
Now check what Git says about these files:
Bash
$ git status
Output
On branch main
Your branch is up to date with 'origin/main'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
[Link]~
molecool/data/[Link]
molecool/data/[Link]
[Link]~
nothing added to commit but untracked files present (use "git add" to track)
Now we will make Git stop telling us about these files.
Earlier, when we looked at the hidden files, you may have noticed a file called .gitignore . Cookiecutter created this for us, however,
GitHub also has built in .gitignore files you can add when creating an empty repository.
This file is to tell git which types of files we would like to ignore (thus the name .gitignore )
Look at the contents of .gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$[Link]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.[Link]
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
...
Git looks at .gitignore and ignores any files or directories that match one of the lines. Add the following to the end of .gitignore :
# emacs
*~
# temporary data files
*.in
*.out
Now do “git status” again. Notice that the files we added are no longer recognized by git.
Bash
$ git status
Output
On branch main
Your branch is up to date with 'origin/main'.
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: .gitignore
no changes added to commit (use "git add" and/or "git commit -a")
We want these additions to .gitignore to become a permanent part of the repository:
Bash
$ git add .gitignore
$ git commit -m "Ignores Emacs temporary files and data directory"
$ git push
One nice feature of .gitignore is that prevents us from accidentally adding a file that shouldn’t be part of the repository. For
example:
Bash
$ git add data/[Link]
Output
The following paths are ignored by one of your .gitignore files:
data/[Link]
Use -f if you really want to add them.
It is possible to override this with the -f option for git add .
Conflict Resolution
Now we will make a few new edits to [Link] :
Add a dummy header and footer the [Link] , so that it looks like this:
***************************************
This is the start of [Link]
***************************************
I added this file from a new clone!
***************************************
This is the end of [Link]
***************************************
Now commit and push this edit.
Bash
$ git add [Link]
$ git commit -m "Adds a new line to [Link]"
$ git push
Now switch over to the friend clone.
Bash
$ cd ../molecool_friend
We are going to add another line to [Link] , so that it looks like this:
I added this file from a new clone!
Now I added a new line!
Now try committing and pushing the change:
Bash
$ git add [Link]
$ git commit -m "Adds another line to [Link]"
$ git push
Output
To [Link]:YOUR_GITHUB_USERNAME/[Link]
! [rejected] main -> main (fetch first)
error: failed to push some refs to '[Link]:YOUR_GITHUB_USERNAME/[Link]'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
The push failed, because the friend clone is not up-to-date with the repository on GitHub. We can fix this by doing a pull:
Bash
$ git pull
Output
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 3), reused 5 (delta 2), pack-reused 0
Unpacking objects: 100% (6/6), done.
From [Link]:YOUR_GITHUB_USERNAME/molecool
754da2b..de54818 main -> origin/main
Auto-merging [Link]
CONFLICT (content): Merge conflict in [Link]
Automatic merge failed; fix conflicts and then commit the result.
Unfortunately, the pull also failed, due to a conflict . To see which files have the conflict, we can do:
Bash
$ git status
Output
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
modified: .gitignore
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: [Link]
The conflict is in [Link], so let’s open it up:
***************************************
This is the start of [Link]
***************************************
I added this file from a new clone!
<<<<<<< HEAD
Now I added a new line!
=======
***************************************
This is the end of [Link]
***************************************
>>>>>>> 12651a37de10d61d9e9eea31c260c15b7ef3b5d4
The conflict is shown within the <<<<<<< and >>>>>>> bits. The part before the ======= is what we added in the commit in the
molecool_friend clone, while the part after it comes from the original local clone. We need to decide what to do about the conflict,
tidy it up, and then make a new commit. Edit [Link] so that it reads:
***************************************
This is the start of [Link]
***************************************
I added this file from a new clone!
Now I added a new line!
***************************************
This is the end of [Link]
***************************************
Bash
$ git add .
$ git commit -m "Fixed merge conflicts in [Link]"
$ git push
This time everything should work correctly. Generally speaking, your procedure when ready to commit should be:
Bash
$ git commit -m "Commit message"
$ git pull
$ <fix any merge conflicts>
$ git push
More GitHub Features
Navigate to the GitHub page for your project. Click on [Link] . Here you can see the file and make changes to it. Click the edit
button, which looks like a small pencil near the upper right of the file text box. Add a line that says “I added this line from the GitHub
web interface!”, so that the file looks like:
***************************************
This is the start of [Link]
***************************************
I added this file from a new clone!
Now I added a new line!
I added this line from the GitHub web interface!
***************************************
This is the end of [Link]
***************************************
Scroll to the bottom of the page and write the message “Added a line to [Link] from the web interface.” for this commit. Then, click
the green “Commit changes” button at the bottom left. You should now see that your change appears in the text box.
Click the “Blame” button to find out who is responsible for each line of code. Click the “History” button to see a list of all commits that
affected this file. You can click on a commit to see exactly what it did.
Go back to the main project page, and click the “commits” button. Here you can see a list of all the commits for this project. Clicking
them reveals how they changed the code.
The “Issues” tab lets you create discussions about bugs, performance limitations, feature requests, or ongoing work that are shared
with everyone else who is working on the project. Try filling out a quick issue now. Then comment and close the issue.
More Tutorials
If you want more git , see the following tutorials.
Basic git
Software Carpentry Version Control with Git ([Link]
GitHub 15 Minutes to Learn Git ([Link]
Git Commit Best Practices ([Link]
Key Points
You can use GitHub to store your project online where you or others can access it from a central repository.
You can use GitHub to store your projects so that you can work on them from multiple computers.
(../02- (../04-
git/[Link]) functi
style/i
Copyright © 2018–2021 The Molecular Sciences Software Institute ([Link]
Edit on GitHub ([Link] /
Contributing ([Link] /
Source ([Link] / Cite ([Link]
Python 3 GitHub Education/python-package-best-practices/blob/gh-pages/CITATION) / Contact ([Link]
Using a MolSSI modification of The Carpentries style ([Link] version 9.5.0
([Link]
1. 上传到GitHub
打开GitHub,创建⼀一个新repo 叫molecool
$git remote -v. (Add remote 功能) 3. 多个Repo conflict
$git remote add origin 在molecool上作出改变,push
git@[Link]:FeiQuantumSoftware/ 再在molecool_friend上改变,push,⽆无法成
[Link](赋予GitHub的repo:molecool ⼀一 功,因为molecool_friend out-of-date. 先
个url地址和简写origin) pull,up-to-date,但是也会失败,
$git branch -M main (origin的main branch) manually fix the file, 再 push。 整体上就
$git push -u origin main (把local repo上传到 是:
origin main branch上)
$git commit -m””
2. 多个Repo $git pull
返回cd ../ 创造另⼀一个Repo copy Fix error
$git clone $git push
git@[Link]:FeiQuantumSoftware/
[Link] molecool_friend
$git remote -v 4. ignore ⽆无⽤用file
直接source⾃自动是origin,不不⽤用像上⼀一个要附上
remote地址 5.直接在origin Github上改动
在molecool_friend 上创造[Link],做checkpoint 在GitHub中创建⼀一个repo,把local的dir
并push: copy到repo⾥里里
$git add . ;git status : git commit -m $git remote -v
“message”; git log; git push $git remote add origin(我们把github上的
repo地址叫做origin) ___address___here__
回到原molecool上,ls 看是否有[Link] file, 没 $git branch -M main
有 $git push -u origin main
$git pull origin main 现在有了了