GitHub hosts open source projects that have multiple contributors. Only a few maintainers have read-write access to the repository, so how do people contribute suggested changes?

The answer is by copying the repo to their own GitHub account, making changes and submitting a pull request to the maintainers of the original project. This post explains the steps.

CONTRIBUTING ON GitHub

Forking a repo

A fork is a clone of the repo on the same hosting provider site (i.e. GitHub). You can view all the forks from the repo home page by clicking on Insights > Forks

As an example of how forks are used, the Hugo repository on GitHub contains code for a static website generator. The maintainers of the project have write access and can push changes, but other GitHub users have read access.

Any GitHub contributor can suggest changes by first forking the repo into their own GitHub account. The Fork button at the top-right of the home page clones the Hugo repo to a copy that appears under the contributors GitHub account. The contributor now has write access to the forked copy, but it isn’t that convenient to work directly on GitHub. They need to clone the fork to a GIT repo on their development workstation.

Cloning a fork

The contributor clones the forked repo to a local GIT repo using git clone <SSH or HTTP address of fork repo>. By default, this clone will track a single remote repo called origin (the fork) that will aceept pushed updates. But how does the local repo keep track of the primary Hugo repo, and how are contributor changes pushed to the original source?

Adding a second remote

While the contributor is working on their local changes, the original Hugo repo on GitHub is also getting updates from other contributors. Any conflicts need to be resolved locally rather than expecting the maintainers of the repo to deal with them. So how does the contributor stay up-to-date while working locally on their changes?

The local workstation repo already has a remote (origin, the forked repo on GitHub). Adding the original Hugo repo as a second remote allows the local repo to pull chages from other contributors. This second remote is usually called upstream.

❯ git remote -v # show current remote repos
origin  https://github.com/myaccount/myfork.git (fetch)
origin  https://github.com/myaccount/myfork.git (push)
❯ git remote add upstream https://github.com/sourcerepo/sourceproject.git # Add a second remote pointing to upstream

How to push changes to upstream

The final piece of the puzzle, is how to get the contributor’s changes into the upstream repo without having write access.

GIT itself doesn’t offer a solution to this, but GitHub does hence it’s popularity for open source projects.
First the contributor pushes their local repo changes to the GitHub fork (origin) using standard GIT commands. Next the contributor creates a pull request asking the maintainers of the upstream source repo to pull changes from the fork. The pull request is a messaging system that describes the changes and enables differencing checks.

The maintainers of the upstream repo can review and comment on the changes, possibly asking for changes before pulling and merging them into the original repo.

Using GIT Diff and Blame

DIFF and BLAME are useful when reviewing a pull request or the project history.

git blame shows the file history on a line-by-line basis.
For each line, it displays the last commit where a line was changed, who made the change and when.

❯ git blame .\index.md
cf6ff2bb (GD 2021-05-05 22:09:05 +0100   1) ---
cf6ff2bb (GD 2021-05-05 22:09:05 +0100   2) author: GD
cf6ff2bb (GD 2021-05-05 22:09:05 +0100   3) ---
cc0e10d2 (GD 2021-05-11 15:55:25 +0100   4) **This is the first post in a series on creating a graph database CMDB.**
cf6ff2bb (GD 2021-05-05 22:09:05 +0100   5)
7c78446d (GD 2021-05-24 19:50:01 +0100   6) Part 1: This article
7c78446d (GD 2021-06-24 21:03:19 +0100   7) Part 2: How to export computer information from Microsoft Active Directory using PowerShell, for use in a Neo4j CMDB

git diff shows the differences between commits or between the git areas (working directory, index, repo). For example, to show the differene between the current commit and back two commits:

> git diff HEAD HEAD~2 # show the difference between the current position of HEAD and 2 commits before HEAD
diff --git a/content/blog/gitnotes/index.md b/content/blog/gitnotes/index.md
index 10fa938..cc16e9f 100644
--- a/content/blog/gitnotes/index.md  
+++ b/content/blog/gitnotes/index.md
@@ -14,48 +14,31 @@ 

-The version control system GIT can seem complex, but an understanding of the internal working can help with day-to-day use and is essential to get yourself out of an unexpected state. This article covers the basics of how git works, exploring the files in the object database and laying a foundation for you to explore futher on your own.
+An understanding of git internals helps with day-to-day use and is essential if you need to get yourself out of an unexpected state. This article covers the basics of how git works, allowing you to explore further on your own.

The first line shows the diff command diff --git...
The next line is git metadata that isn’t normally needed index 10fa938..cc16e9f 100644
The next two lines show assign symbols to the two versions of the index.md file i.e changes from HEAD are marked with “—” and tchanges from HEAD~2 are marked with “+++”

--- a/content/blog/gitnotes/index.md  
+++ b/content/blog/gitnotes/index.md

The next line represents the header of a hunk (portion) of the file showing the lines that have been modified. In this case, 48 lines were removed at line 14 and 31 lines added at line 14. Realistically, when lines are removed and added at the same location it is a modification of the lines.

@@ -14,48 +14,31 @@

Finally, the actual lines that are removed and added are displayed. The “-” at the start of the line means it was removed. The “+” at the start of the line means it was added. The line was actually edited to change some of the words.

-The version control system GIT can seem complex...
+An understanding of git internals helps...

Another way to view the differences is using the --color-words option. This shows the changes in-line using red for removed and green for added i.e.

git diff --color-words HEAD HEAD~2

What else can you compare with GIT DIFF?

> git diff # show uncommited changes since the last commit
> 
> git diff --cached # compare the repo HEAD to the index
>
> git diff feature1 main # compare two branches

How to see a diff of every commit

The git log command has an option to diff every commit. This obviously produces a lot of output.

> git log --patch

How to compare the list of commits between two branches

Rather than looking at the changes in the commits. You will sometimes want to just look at the history of commits and understand which are only in one branch compared to another. git log can also help here:

> git log feature1..main --oneline # Compare the feature1 branch to main showing the commits only in main



This article was originally posted on Write-Verbose.com