Ok, I’ll try it here and if it’s any good we can make this into Vassal’s official Git guide later.
On Windows, Git Bash is very good.
Some definitions:
-
Central repository - The central, the main repository, the one where development of Vassal happens, the one where we sync from to get our local code up to date, the one that is kind of like the SVN server in SVN, the one where we ultimately want our pull requests (PRs) to end up
-
github.com/vassalengine/vassal - The location of the central Vassal repository
-
Contributor - Person that partakes in Vassal development without having write access to the central repo, to github.com/vassalengine/vassal
-
github.com/contributor - The GitHub account of the contributor
Setting up, step 1: Create a fork of github.com/vassalengine/vassal, the result is:
Setting up, step 2: The contributor creates a clone of his fork on his local computer by running git clone:
(on posix systems) cd /home/contributor/developmentProjects
(on Windows) cd C:\Users\contributor\developmentProjects
git clone https://github.com/contributor/vassal.git
This creates a clone of the contributor’s repo in /home/contributor/developmentProjects/vassal or C:\Users\contributor\developmentProjects\vassal. This clone is yet another fully featured repository, like another SVN server, a third one after central and the contributor’s GitHub repo, but it points to the contributor’s repo on GitHub and knows that it is a kind of “child” of the contributor’s GitHub repo.
Setting up, step 3: Configure Git on the local computer to know the GitHub account
Set username according to: help.github.com/en/github/using … ame-in-git
Set commit email address according to: help.github.com/en/github/setti … il-address
Now some more definitions. The links between repositories have names, we want the local repository to link to both the contributor’s GitHub repo and to the central Vassal repo.
The remote is already known to the local repo since we cloned it from there, we can see it like this:
(on posix systems) cd /home/contributor/developmentProjects/vassal
(on Windows) cd C:\Users\contributor\developmentProjects\vassal
git remote -v
Setting up, step 4: Tell the local repo where the central Vassal repo is located.
Follow this: help.github.com/en/github/colla … for-a-fork
Or do this:
(on posix systems) cd /home/contributor/developmentProjects/vassal
(on Windows) cd C:\Users\contributor\developmentProjects\vassal
git remote add upstream https://github.com/vassalengine/vassal.git
Check if it worked:
git remote -v
This should show 2 lines with origin and another 2 lines with upstream now, e.g.:
origin https://github.com/contributor/vassal.git (fetch)
origin https://github.com/contributor/vassal.git (push)
upstream https://github.com/vassalengine/vassal.git (fetch)
upstream https://github.com/vassalengine/vassal.git (push)
So much for the repositories / repos. Now the branches. Git branches are per repository. The central repo has a branch called master. This is the trunk of the SVN server, in SVN terms. This is the branch where Vassal development happens, the branch where all our commits have to end up.
The contributor’s repo on GitHub also has a branch called master. And the contributor’s repo on the local computer also has a branch called master. Three repositories, one master branch in each:
We now have two different workflows. One is for keeping the master branches in sync, the other is for doing code changes and getting them into the central master branch.
First let’s make sure we are in sync, we do this regularly, usually after we see that there are new commits in central master and our other 2 master branches fell behind. Since we (the contributor) do not have write access to the central repo, we can only read from the master branch. We never do any commits into this branch, instead what we do regularly is this:
Staying in sync, step 1: Make changes to central/master known to the local repo:
git fetch upstream
Staying in sync, step 2: Make sure we have the master branch selected (make sure local changes are all committed before this, more about this later):
git checkout master
Staying in sync, step 3: Sync central/master with our local master:
git merge upstream/master
Staying in sync, step 4: At this point our local master and central/master are in sync, now let’s update our GitHub master as well by pushing our local master to origin:
git push origin refs/heads/master:master
Now our own two master branches are in sync with central/master.
Next, the workflow for actually changing the code. This is best done right after syncing the master branches, to make sure we build upon the latest commits in master.
Changing code, step 1: Create a new branch in the local repo and switch to it. Let’s call it bugfix-12345:
git checkout -b bugfix-12345
Changing code, step 2: Change code. Commit it to the local branch. Change some more, commit again. As often as we want. At this point we’re only working in our local branch, the outside world does not know anything about our local branch and the commits in it.
(change ClassA.java)
git add ClassA.java
git -m 'changes to ClassA'
(change ClassB.java and ClassC.java)
git add ClassB.java ClassC.java
git -m 'changed ClassB and ClassC'
(change ClassA.java ClassB.java and ClassC.java again)
git add ClassA.java ClassB.java ClassC.java
git commit -m 'a third round of changes'
Each commit consists of 2 steps, the files that go into the commit have to be added first, then comes the actual commit. Files that were not added do NOT end up in the commit. To see which files are added, which are not, and which files are not tracked by git at all:
git status
Pro tip, Step 2b: Now is a good time for a “git rebase” if we want to change history i.e. reword commit messages, smash several commits into one, change the order of the commits.
Changing code, step 3: Now we think we are ready with the changes we wanted to do and we want to get them into central/master by doing a pull request (PR). First we push our local branch, which so far is not known outside of our local computer, to our GitHub repo:
git push -u origin bugfix-12345
Changing code, step 4: Now we log into our GitHub account on the GitHub website, open up our repository, and see how GitHub noticed that we just pushed a new branch and since it knows that our GitHub repo is a fork of another repo, it is smart enough to offer us to create a PR from this branch. We do this, we push the green button that creates a new PR, verify that it shows something like this:
contributor wants to merge N commits into vassalengine:master from contributor:bugfix-12345
We write a few words into the description (or don’t write) and confirm.
Changing code, step 5: As usual, we have forgotten some detail, or someone else has a good idea how to make our code change even better, we log into our GitHub account a while later, check our PR and see that some changes were requested. We change to our local branch again, in case we switched away from it in the meanwhile:
git checkout bugfix-12345
We apply the requested changes, commit them and push them to GitHub:
(apply changes)
git commit -a -m 'applied requested changes'
git push -u origin bugfix-12345
We look at our PR on GitHub again and see that GitHub is smart enough to add our new commits to the existing PR.
This can go back and forth several times, more changes can be requested, we repeat step 5, and so on. At some point the PR will be accepted and closed. GitHub will then offer us to delete the branch, this is the branch on GitHub not the local one.
Changing code, step 6: Accept GitHub’s proposal and delete the branch “bugfix-12345” on GitHub. There will be a button “Delete branch” at the bottom of the PR on GitHub.
Changing code, step 7: Delete the branch locally:
git branch -d bugfix-12345
Additional info:
When using graphical git clients, each of the above commands maps to an action in the graphical client, e.g.:
- “git fetch upstream” → in the IntelliJ git client that’s a button with two arrows circling each other with a popup info saying “fetch all remotes”
- “git checkout -b bugfix-12345” → right-click on the master branch, click on “create branch…”, enter “bugfix-12345”
- “git checkout bugfix-12345” → right-click the branch bugfix-12345, click on “checkout branch”
- “git push -u origin bugfix-12345” → right-click the branch bugfix-12345, click on “push” or “push…”
For commiting changes, the graphical git clients usually offer a convenient view where the files to be commited can be seen and each file can be marked to include it or exclude it from the commit. Example, here I have changed 3 files, but only want to add 2 of them to the commit, the 3rd file will keep my changes but will not be added to this particular commit, I want to commit it later for some reason:
[attachment=0]commit.png[/attachment]
This concludes the instructions for using Git/GitHub.
Now some additional tips.
Pro tip 1: practice interactions between git repos locally by creating 2 or more git repos on the local filesystem, then create branches, commit, push/pull branches etc:
cd /home/user/tmp
mkdir gitrepo-main
cd gitrepo-main
git init .
echo "first file" > first.txt
git add first.txt
git commit -m "first commit"
cd ..
git clone gitrepo-main/ ./gitrepo-clone1
cd gitrepo-clone1
git checkout -b bugfix-1
echo "\na second line of text" >> first.txt
git commit -a -m "added second line to first.txt"
git push -u origin bugfix-1
(.... etc)
Pro tip 2: For neat ascii-art view of the branches and commits, do this:
git config --global alias.lg1 log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
git config --global alias.lg2 log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
git config --global alias.tree log --graph --decorate --pretty=oneline --abbrev-commit
git config --global alias.lg !git lg1
Then in any git repo:
git lg
git lg1
git lg2
git tree
Pro tip 3: When working on Vassal modules, even when they are not uploaded anywhere, why not create a local git repo underneath the module and use git to track all changes, be able to go back to previous versions, find out what exactly changed and when, maybe even branch and try out different things while keeping the other variations?
cd anyDirectoryWithFilesToTrack
git init .
(change files, commit, branch, look at commit history etc.)