Repository: PrefectHQ/prefect

Issue:
Allow to use non master branches in GitHub storage 
## Current behavior
<!-- Please describe how the feature works today -->

Currently, there is no way to use branches other than master for GitHub storage


## Proposed behavior
<!-- Please describe your proposed change to the current behavior -->

Similar to GitLab storage use a `ref` parameter and then pass it to `get_contents()` method (supported by [github API](https://pygithub.readthedocs.io/en/latest/github_objects/Repository.html#github.Repository.Repository.get_contents)) here: https://github.com/PrefectHQ/prefect/blob/4c764ddb8b121d81857a5954cd70fa7930bcca5a/src/prefect/environments/storage/github.py#L79



## Example
<!-- Please give an example of how the enhancement would be useful -->

Default use: `GitHub(repo, path=path)` defaults to master branch
For development/testing:  `GitHub(repo, path=path, ref="my-branch")` looks for files in "my-branch"



Discussion:

Resolving patch:
diff --git a/src/prefect/environments/storage/github.py b/src/prefect/environments/storage/github.py
--- a/src/prefect/environments/storage/github.py
+++ b/src/prefect/environments/storage/github.py
@@ -31,14 +31,18 @@ class GitHub(Storage):
     Args:
         - repo (str): the name of a GitHub repository to store this Flow
         - path (str, optional): a path pointing to a flow file in the repo
+        - ref (str, optional): a commit SHA-1 value or branch name. Defaults to 'master' if not specified
         - **kwargs (Any, optional): any additional `Storage` initialization options
     """
 
-    def __init__(self, repo: str, path: str = None, **kwargs: Any) -> None:
+    def __init__(
+        self, repo: str, path: str = None, ref: str = None, **kwargs: Any
+    ) -> None:
         self.flows = dict()  # type: Dict[str, str]
         self._flows = dict()  # type: Dict[str, "Flow"]
         self.repo = repo
         self.path = path
+        self.ref = ref
 
         super().__init__(**kwargs)
 
@@ -46,7 +50,7 @@ def __init__(self, repo: str, path: str = None, **kwargs: Any) -> None:
     def default_labels(self) -> List[str]:
         return ["github-flow-storage"]
 
-    def get_flow(self, flow_location: str = None) -> "Flow":
+    def get_flow(self, flow_location: str = None, ref: str = None) -> "Flow":
         """
         Given a flow_location within this Storage object, returns the underlying Flow (if possible).
         If the Flow is not found an error will be logged and `None` will be returned.
@@ -55,6 +59,8 @@ def get_flow(self, flow_location: str = None) -> "Flow":
             - flow_location (str): the location of a flow within this Storage; in this case,
                 a file path on a repository where a Flow file has been committed. Will use `path` if not
                 provided.
+            - ref (str, optional): a commit SHA-1 value or branch name. Defaults to 'master' if not
+                specified
 
         Returns:
             - Flow: the requested Flow
@@ -76,7 +82,7 @@ def get_flow(self, flow_location: str = None) -> "Flow":
         repo = self._github_client.get_repo(self.repo)
 
         try:
-            contents = repo.get_contents(flow_location)
+            contents = repo.get_contents(flow_location, ref=ref or self.ref)
             decoded_contents = contents.decoded_content
         except UnknownObjectException as exc:
             self.logger.error(
diff --git a/src/prefect/serialization/storage.py b/src/prefect/serialization/storage.py
--- a/src/prefect/serialization/storage.py
+++ b/src/prefect/serialization/storage.py
@@ -124,6 +124,7 @@ class Meta:
         object_class = GitHub
 
     repo = fields.String(allow_none=False)
+    ref = fields.String(allow_none=False)
     path = fields.String(allow_none=True)
     flows = fields.Dict(key=fields.Str(), values=fields.Str())
     secrets = fields.List(fields.Str(), allow_none=True)


Test patch:
diff --git a/tests/environments/storage/test_github_storage.py b/tests/environments/storage/test_github_storage.py
--- a/tests/environments/storage/test_github_storage.py
+++ b/tests/environments/storage/test_github_storage.py
@@ -15,11 +15,14 @@ def test_create_github_storage():
 
 
 def test_create_github_storage_init_args():
-    storage = GitHub(repo="test/repo", path="flow.py", secrets=["auth"])
+    storage = GitHub(
+        repo="test/repo", path="flow.py", ref="my_branch", secrets=["auth"]
+    )
     assert storage
     assert storage.flows == dict()
     assert storage.repo == "test/repo"
     assert storage.path == "flow.py"
+    assert storage.ref == "my_branch"
     assert storage.secrets == ["auth"]
 
 
@@ -87,5 +90,5 @@ def test_get_flow_github(monkeypatch):
     assert f.name not in storage
     flow_location = storage.add_flow(f)
 
-    new_flow = storage.get_flow(flow_location)
+    new_flow = storage.get_flow(flow_location, ref="my_branch")
     assert new_flow.run()