Version Control Part 2 – GitHub and GitFlow Tutorial

Setting up GitHub

Create an account on GitHub by going to github.com and signing up. Once complete, click the profile circle on the top right. Most navigation items can be found through the pull down menu. Download a Git CLI, preferably (Git for Windows)[https://gitforwindows.org/], however, GitHub provides a CLI that is recently out of beta GitHub CLI.

Git for Windows

  1. Agree to the license
  2. Don’t change what components are to be installed, click next
  3. Choose “override the default branch name for new repositories” and ensure that the initial branch name is “main”, click next
  4. Use bundled OpenSSH, click next
  5. Keep default git pull behavior and click next
  6. Only use Git Credential Manager Core and click next
  7. Do not select experimental options and click install
  8. The program is called Git Bash and can be accessed from File Explorer in any folder by right clicking and selecting “Git Bash here”

If there are any additional options not specified here do not change the options just click next.

Create a personal access token

Follow these steps

Setting up the first repository

Click the plus left of the profile menu and choose “New Repository.” When naming a repository the autochecker will reject repository names already in use by the account, special characters and spaces will be automatically turned into “-” and generally should be easy to remember and type. Though a description is optional, it is still recommended to add a short one sentence description or pitch about the project.

Users can have unlimited public and private repositories. Public means visible to all, private means only visible to members of the repository. If there are features of interest that require a GitHub paid plan, consider checking out the GitHub Education Student Package, which is free to all university students to have a Pro plan without needing to pay. As ASU students, additional verification will likely be needed and student validation requests are usually resolved in less than a week.

Select “Add a README.md” to instantiate (put a file in) the repo(sitory). Instructions to clone, build, and run projects, along with project descriptions, FAQ or other pertinent information can usually be found in the README.md. It is good practice to always have one at the top level of a repo.

Do not select “Add .gitignore” as one is not need for this tutorial part. However, templates for specific languages exists. If another repo is created using a common language such as C or Java, consider including the .gitignore template to ensure object and binary files and folders are not pushed to the repo. Gitignore files remove “bloat” files from being committed as they are often binary files (unreadable by humans) or custom to the user (e.g. include paths such as C:/UserName/Documents/FolderName/ that are not usable by others).

Do not select “Choose a license” but generally open source projects operate on different levels of licenses, which instruct what users of open source work can and can’t do with them. MIT Licenses and GNU Public Licenses are the most common licenses, however, both dictate different restrictions to the code. Research what license works best for custom projects that are public (and private) facing.

Select “Create repository” to be taken to the new repo with a README.md file in it.

Cloning a repo can be done multiple ways, this tutorial will only describe through zip and HTTPS.

Cloning via HTTPS

Cloning via HTTPS will include a link back to the repo it came from and allow users to access past commit history. This is the preferred way of cloning repos unless SSH is necessary. GitHub used to require password verification, however, now it requires personal access tokens (PAT) which is more secure. To clone a repo, click the green button labelled “Code” to pull down the clone options. Ensure “HTTPS” is selected and click the clipboard icon to copy the URL. The URL can also be highlighted and copied.

  1. Navigate in Windows Explorer to find where to copy the repository to, in this case C:/UserName/Desktop.
  2. Right click in the folder in Windows Explorer and click “Git Bash here”
  3. In the terminal window that has appeared type git clone and paste the copied URL and hit enter. The command should look something like ```git clone https://github.com/username/repoName.git`

When first using the command line, terminal, or Git Bash to interact with GitHub, after the clone command is executed it will ask for a username, and then a PAT. If this has already been done, then it will not ask as the values may already be stored in cache through Git clients. Git for Windows and Git CLI will store these after the first use until it expires. Additional setup varies by the program.

In the Desktop folder there should now be a folder with the repo name. This is a local instance of the cloned repository.

Starting with an empty repo

When creating repo’s without a README.md, it is assumed there is an existing repo, or a repo will be created through the command line, terminal, or Git Bash. Follow the appropriate instructions depending on the context. Figure X shows a repo called tbd that was not initialized with a README.md and how to start a new repo from a local instance, link an existing repo, or link from another type of version control.

Deleting a repo

To delete a repo go to the repo, then settings, then scroll to the bottom of the options page. Deleting a repository requires the title and the account’s password to be entered to confirm the decision. Deleted repositories cannot be retrieved after deletion.

Pushing the first edits

From the local instance on Desktop, create a new text file and name it “FirstFile.txt” and put “hello world” in the file. Normal git workflow (gitflow) involves making changes, staging the changes by adding the files, writing a descriptive message about the changes, and then pushing the bundled changes and message in a commit. Make sure a Git Bash window is open in this repository folder.

  1. To see what files have been changed type git status into the Git Bash window.
  2. FirstFile.txt is not tracked yet due to it being a new file. To track the file ```git add FirstFile.txt`
  3. Entering git status will now show the file is tracked and staged (or ready) to be committed.
  4. Open FirstFile.txt and add a new line and “another hello world” to it. Save and close the file. For every change that occurs after a file has been added, the file needs to be re-added or a commit will not include those changes. Commits do not need to include all changes. Do not add the file yet.
  5. To complete the commit of the creation of a new file and “hello world” (not “another hello world”) enter git commit -m "added new file and hello world message". Commit messages should be short but descriptive such that another user or a future user can understand what edits occurred.
  6. To send the commit (the changes, the message) to GitHub where the repository is stored, enter git push. Commits don’t have to be sent and can be sent multiple at a time. However, it is not advised to not push commits once made, especially if there are other users on the repo.
  7. git status again to see that there are still changes that have not been committed. Repeat the process to commit the new changes. Run git status after to ensure that the working branch is clean or up to date meaning there are no new changes to commit.

Pulling down changes

GitHub has a decent UI, but it is best used for very quick fixes. Go back to the GitHub page for the repository created. The new file should now be visible. If not, refresh the page. Click “Add file” then “Create new file.”

Name the new file BrowserFile.txt because this file is being made through GitHub’s browser interface. Type “hello browser!” into the “Edit new file” window. Scroll to the bottom of the page to see “Commit new file” and give a short message in the smaller text field or leave it blank. Click “Commit new file.” If the field was left blank, “Create BrowserFile.txt” will be the commit message.

Go back to Git Bash in the repository folder and type git pull. This will “pull” the new file down from the repo and the folder will now have the new file BrowserFile.txt This is how changes can be updated in local instances. This only works if recent changes are pushed to the repository on GitHub. Push and pull changes often to reduce merge conflicts, especially when working with multiple users.

Handling Merge Conflicts

Merge conflicts happen often when there is more than one editor in a repository editing the same files in the same locations. It can also happen if editing files through the web (e.g. on GitHub’s UI) and through a local desktop instance at the same locations. Normally, Git (and therefore GitHub etc.) automatically manage conflicts, however, sometimes it needs human input.

An example case might be merging a development branch into main. Merges can be done through terminal commands or through pull requests through GitHub’s UI. The following example assumes a user is using the command line (or terminal). Proper gitflow is that merge conflicts are handled on the feature branch (branch to be merged into main) and then merged into main after resolving the conflict. The following example has found a merge conflict trying to merge the branch mundo into the main branch. The merge is then aborted, and a new merge is started from main into the mundo branch. Once the conflict is resolved, mundo is finally merged into main.

  1. Attempting to merge mundo into main. This assumes that the user has checked out the main branch.
  • (from main) git merge mundo (merge mundo into main)
  1. A merge conflict has been found! To cancel a merge run git merge --abort. Merges can be aborted in the middle of merge conflict resolutions (rebasing).
  2. First, checkout the mundo branch git checkout mundo then run git merge main. The following is what a merge conflict looks like in a file based on the most recent merge command:
def hello
<<<<<<< HEAD (aka current change aka changes from mundo)
  puts 'hello mundo'
======= (aka incoming change aka changes from main)
  puts 'hola world'
>>>>>>> main

In the above example, the changes in the main branch (‘hola world’) conflict with the changes from the branch mundo (‘hello mundo’). The changes in mundo are considered the “current change” or HEAD (think pointers), while the changes in main are considered the “incoming change” and both are separated by a series of ‘=’ symbols. HEAD will always be preceded by a series of ‘<’ while the conflict itself will be closed by a series of ‘>’ and the branch name (main). Merge conflicts will always appear in the order of current change to incoming change. Sometimes, rather than removing one of the other, the code may need to be a combination of both sources, it is not always the most intuitive, and it is often recommended to use editors that can help manage conflicts, like Visual Studio Code (VSC).

For now, we want to keep the changes in mundo, so we need to remove all indicators of a merge conflict, namely, the lines including ‘<’ and ‘>’.

def hello
  puts 'hello mundo'

Once all merge conflicts have been resolved (the lines indicated conflict exists have been removed) follow the process of committing changes from the start (add, add a message, push) and the conflict is complete. Now checkout the main branch, git merge mundo into main, and done!

Resources

https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories