Sometimes right after you perform a commit in git you realize you made a mistake. For me it is usually that I commit a file I didn't want to or wasn't ready to.
The good news is that as long as you haven't pushed it to a remote repository it is relatively easy to fix.
Just perform the following steps:
$ git reset HEAD~
# Make the necessary changes
$ git add .
$ git commit -c ORIG_HEAD
While not really necessary for writing a simple application I like to add GitHub actions to projects. This helps to automate the building and testing of changes to ensure that we don't accidently introduce known defects.
In the root directory of your git repo do the following:
$ git checkout -b workflow
Switched to a new branch 'workflow'
$ git branch
main
* workflow
$ mkdir -p .github/workflows
$ cd .github/workflows
$
GitHub Actions uses YAML syntax to define all of the necessary elements of a workflow. To enable the workflow they are stored in the .github/workflows direction of the repository.
Create workflow file
For this project we are going to create simple dotnet.yaml to enable a dotnet core workflow which will build and test the project.
First we want to give the workflow a name. This is the name that will appear on the GitHub Actions tab. If no name is provided then GitHub will use the name of the file.
name: .NET CI
The next step is to define some events that will trigger the workflow. I only want to trigger the workflow when changes are pushed to the main branch or when a pull request to the main branch is made.
By running the workflow when there is a pull request I can ensure that the code properly compiles and passes any tests before merging with the main branch.
Once code has been pushed to the main branch we run the workflow as well to make sure that the merges did not break anything.
By limiting the trigger to the main branch changes can be made on feature branches without triggering the workflow. This is useful since GitHub actions is billable by time used and we want to minimize the amount of time spent to only those actions that are important.
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
Now that we have determined what will trigger the workflow to run we need to define what the workflow will do. This can be one or more jobs. For this case we only need a single job.
Here we create the job build and give it a more descriptive name of Build and Test. This particular job we want to execute on the latest version of ubuntu.
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
The last part of our workflow is going to be the steps necessary to execute the job. These steps are executed in the order that they appear. Each step in a job executes on the same environment and the results of each step is available to subsequent steps.
The first line steps is used to group all of the steps for the job.
The next line is the uses keyword. This retrieves another action. It is basically including additional steps from an external source. In this case from the community action actions/checkout@v2. This step will check out the code from the repository so that it is available to the environment.
The next step includes another community action called actions/setup-dotnet@v1. This is used to setup the environment to be able to use the dotnet tools. This step includes a few other keywords also. The first is the name parameter which we have used previously. This simply provides a friendly name for the step. The other keyword is the with keyword. This provides input to the action. In this case it is indicating the version of dotnet to be used.
Now that we have the environment setup and ready we can peform the steps necessary to actually build and test the project. Again we have the familiar name keyword used to provide a friendly name to the step.
There are two new keywords that we are using for each of these steps. The run keyword is used to specify a command to be executed. The working-directory is used to set the base directory where the command should be executed.
The dotnet restore command will restore any packages needed to build the project.
dotnet build --no-restore will build the project without attempting to perform the restore. We don't need to restore anything since we completed that in the previous step.
Once the project has been compiled we will want to run any tests to ensure that everything is working as we expect. This is accomplished by executing dotnet test --no-build --verbosity normal.
- name: Restore dependencies
run: dotnet restore
working-directory: ./src
- name: Build
run: dotnet build --no-restore
working-directory: ./src
- name: Test
run: dotnet test --no-build --verbosity normal
working-directory: ./src
Here is the entire file.
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Restore dependencies
run: dotnet restore
working-directory: ./src
- name: Build
run: dotnet build --no-restore
working-directory: ./src
- name: Test
run: dotnet test --no-build --verbosity normal
working-directory: ./src
Push workflow to repository
Now that the workflow file has been created it is time to push it up to the GitHub repo by performing the following steps.
Verify current branch
Add workflow file
Commit workflow file
Push to remote branch
$ git branch
main
* workflow
$ git add .github/workflows/dotnet.yaml
$ git status
On branch workflow
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .github/workflows/dotnet.yml
Untracked files:
(use "git add <file>..." to include in what will be committed)
$ git commit -m "Add dotnet.yaml workflow"
[workflow 9caee5a] Add dotnet.yaml workflow
1 file changed, 29 insertions(+)
create mode 100644 .github/workflows/dotnet.yml
$ git push origin workflow
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 708 bytes | 708.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'workflow' on GitHub by visiting:
remote: https://github.com/iesoftwaredeveloper/SimpleCmdLine/pull/new/workflow
remote:
To github.com:iesoftwaredeveloper/SimpleCmdLine.git
* [new branch] workflow -> workflow
Create pull request
Now that we have pushed our changes to the remote we will want to create a pull request so that they can be merged into the main branch. This will do a few things.
Initiate the process of merging code
Initiate the new workflow
After initiating the pull request you will see that the workflow is triggered. This is because a pull request to main was made.
Once the workflow has completed the status of the workflow will be showed in the pull request. Wait until it shows completed and is green. If for some reason it does not complete successfully you will want to review the code changes and make any necessary updates to get the workflow passing as green.
Wth a successful completion of the workflow you can complete the pull request.
Conclusion
Your done. You have successfully added a simple dotnet workflow to your github project.
Using git as a Source Code Managment (SCM) tool is a great way to manage source code. While creating a example console application to demonstrate how to use System.CommandLine I documented most of what I was doing. I had originally included a lot of detail in that documentation.
After completing the documentation I decided that while it might be useful to me or someone else in the future, having all of that information in a single post was just too much. I decided to break up the content into smaller more managable parts. This is one of those parts.
Now is a good time to initialize your source repository. I am going to use a git repository to manage the source. If you are using a different source code management (SCM) tool to manage your source then be sure to use the respective commands for you tool. The steps are basically the same for all SCM tool.
Ensure that your are in the root directory for your new project and initialize the repository.
$ cd ~/SimpleCmdLine
$ git init
Initialized empty Git repository in /Users/iesoftwaredeveloper/repos/SimpleCmdLine/.git/
$
Add a .gitignore and README
To help ensure that we avoid committing files that we don't usually want in our git repos we should create a .gitignore file. Fortunately, dotnet can help us create a simple .gitignore that will accommodate some common files when developing using Visual Studio. If you are using Visual Studio Code the same .gitignore will also apply. If you are using a different Integrated Development Environment (IDE) or using a simple text editor then you will still benefit from creating the .gitignore using this method. Many of the items are created as part of the dotnet commands.
To create a dotnet focused .gitignore using the dotnet new gitignore command. While we are here I will create a basic README.md as well.
Note: The readme template is not installed by default. If you do not have it installed then dotnet will search NuGet for a matching template. I installed the template from author Rodolpho Alves named "Readme (Markdown)". You can install it using the command dotnet new -i ARDC.Commons.Templates::0.2.1 This is entirely optional and you can certainly just manually create your own README.md
$ dotnet new gitignore
The template "dotnet gitignore file" was created successfully.
$ dotnet new readme
The template "Readme (Markdown)" was created successfully.
$ git add .gitignore
$ git add README.md
$
Add initial template files
Now that we have initialized the git repo and added a .gitignore, go ahead and add the intial files created by template and commit them. Since there are only two of files I will add them individually. Once the files are added we can commit the changes to the repo.
$ git add src/Program.cs
$ git add src/SimpleCmdLine.csproj
$ git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitignore
new file: README.md
new file: src/Program.cs
new file: src/SimpleCmdLine.csproj
Untracked files:
(use "git add <file>..." to include in what will be committed)
$ git commit -m "Initial commit"
You could add all of the files in the directory using git add . or git add src to add the files in the src directory.
Create branch and add remote
Now that we have made our first commit we can push our local repository to a remote. I want to make sure that the current branch which is the default is named main to match the default branch name I use on my remote git repository. In this case it is, but if your git instance still uses a default branch by some other name this will ensure it is named main.
Once we have (re)named the local branch we can add the remote and push it to the remote repository.
Be sure to use your username for user and whatever you named your remote repository for repo
# Rename current branch to main (forcefully)
git branch -M main
# Set the new remote
git remote add origin git@github.com:user/repo.git
# Verify the new remote
git remote -v
> origin git@github.com:user/repo.git (fetch)
> origin git@github.com:user/repo.git (push)
Now that we have made our intial commit and set the remote we can push the changes to the remote.
$ git push -u origin main
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 16 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 3.97 KiB | 3.97 MiB/s, done.
Total 7 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:iesoftwaredeveloper/SimpleCmdLine.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
$
Conclusion
You now have a local repository and can push it to a remote repository.