-
Notifications
You must be signed in to change notification settings - Fork 305
Git Good at Git Advanced Operations
Previous sections detailed the setup and basic use of Git and TortoiseGit, and this section will detail some of the more advanced operations, such as resolving merge conflicts, cleaning untracked files, using stash/save, generating revert commits, and rebasing and cherry-picking commits. To do this, we’ll primarily use two of TortoiseGit’s features: Diff, and Log.
An untracked file is any file that exists in your local repository, but has yet to be committed. Git Revert is a powerful tool for cleaning up extra code you used for testing, but it only operates on tracked files. This is because untracked files don’t exist within the repository’s history, and so if Git were to restore them to the last commit, it’d simply delete them. Since that’s not necessarily desirable, untracked files are cleaned up by a separate function - Git Clean.
- Right click the source code’s folder and open the TortoiseGit menu.
- Select “Clean up”
The Git Clean menu is fairly straightforward. Like Git Revert, all changes made with Git Clean are permanent, because they are made to uncommitted files. Config files are untracked, and will be deleted when you run Git Clean. You should back them up before running Git Clean.
Dreammaker is an essential tool for coding Byond, but it lacks support for Git. Fortunately, TortoiseGit includes a menu to see what files have changed since your last commit, and a text editor to highlight those changes in each file. This guide will specifically cover resolving merge conflicts, but Diff is also useful for reviewing changes made by a commit.
- Right click the source code’s folder, open the TortoiseGit menu, and select “Diff”
- Tortoisegit will open the Diff menu, which shows all changed files since the last commit. Modified files are highlighted in blue, deleted files are highlighted in purple, and conflicting files are highlighted in red. Untracked files are shown in black in a section below all tracked files.
- You can double-click any file to open a text editor included with TortoiseGit, which will automatically highlight changes.
Right-clicking highlighted blocks will allow you to perform special functions, such as putting the new code above or below the old code. It is important to note that this text editor is NOT a Byond compiler, and you should recompile your code in Dreammaker to ensure that it does so cleanly.
You will invariably run into merge conflicts at some point while using Git. A conflict occurs when you try to push changes onto a branch where other changes have been made since the last time you pulled from it.. This most commonly occurs when two pull requests modify the same file: the pull request that gets merged second will get a conflict in that file, because Git can no longer tell what version of the file to apply the changes to (Or less commonly, the section the changes are being applied to is no longer what Git is expecting to apply them to). It’s possible to resolve conflicts manually, by opening each conflicting file, finding the sections demarcated by “>>>>>>> commit hash” and “<<<<<<<<< master”. However, finding these sections in large files can be quite challenging, and may require multiple passes to find them all. Fortunately, the Diff menu is a very effective tool for resolving conflicts.
- Switch to the branch with a PR experiencing conflicts.
- Attempt to pull from the upstream remote. Git will throw an error, but allow you to open the Diff menu, where the conflicting files will be highlighted in red.
- Double click each conflicting file, and navigate to each section highlighted on the scroll bar in red.
- Resolve the conflict by selecting which block to use as a base, then adjusting it as needed. The text editor will look a little different, displaying three windows:
The top left is the base, the top right contains the changes you’re applying, and the bottom is the net result of those changes.
As you can see, both branches are trying to affect the same section. The base branch has some code that wasn’t there when changes to the local branch were made, and the ??????
in the merged section represents Git not knowing how to resolve this difference. To resolve the dispute, you should right click the highlighted section and select whichever of the options best represents how you want to resolve the conflict. You can always add more changes later!
Once you’ve resolved all conflicts in a file, you need to tick ‘Resolved’, and save the file. When you return to the Diff menu, the file will now be marked ‘modified’.
Another particularly useful feature of TortoiseGit is the Log menu. The Log menu shows the history of commits, in chronological order, made to a branch. It also differentiates between commits made directly to the branch, and those merged from another branch. Reading history can be useful, but the Log menu also allows actions to be performed on selected commits, such as making revert commits, rebasing, or cherry-picking.
- Right click the source code’s folder and open TortoiseGit’s menu.
- Select “Show log”
- This will open the Log menu, which initially displays the commit history of your current branch. You can right-click on specific commits to perform various actions.
- You can change the branch shown by clicking on the branch name in the top left of the Log menu:
- This will open another menu which lists all branches on your local repository. There is a drop-down menu on the left that allows you to view branches on remotes as well.
- Simply select the branch whose commit history you want to view in the Log and press Ok!
Once you press ‘commit’, all changes added to that commit are permanently stored in Git’s memory. Trying to use the Revert menu that TortoiseGit provides won’t display any committed files, because there haven’t been any changes to those since the last commit. To undo any committed changes, you have to make another commit that undoes them. To do this, we’ll need to use the Log menu.
- Open the Log menu
- (Optional) Navigate to the branch with the commit to be reverted, if it is not your current branch.
- To revert a particular commit, right click it and select “Revert change by this commit”
- You can then select ‘Ok’, which will allow you to make other changes before creating the commit, or ‘Commit’, which will open the Commit menu. If you need to revert a merge commit, you’ll need to select which of the two parents to revert to.
In the event that you make commits to the wrong branch, don’t panic! It’s very easy to forget to check what branch your local repo is on before you go and remove cats, and accidentally commit that to your master branch. Fortunately, Git allows us to “Rebase” commits, or to take a commit and rewrite its history. Changing the history of one commit also changes the history of any commits made onto the same branch, so some caution is advised.
- Right click the source code’s folder and open the TortoiseGit menu.
- Select “Rebase”
- This will open the Rebase menu. You need to select an ‘upstream’ branch, which you want to rebase commits to. The top box will then display all commits on your current branch that aren’t on the upstream.
- You can right click individual commits and select whether to rebase them (“Pick”), skip them, make changes to them, or squash them with the commit below, which combines the two commits into a single one.
- Once you’ve selected each commit you want to rebase, press “Start Rebase”. The Rebase menu will replace “Revision Files” and “Commit Message” with “Log”, which will show the progress Git has made in rebasing, and will indicate if any conflicts show up that need to be resolved before you can proceed.
- Once the rebase is complete, you can press “Done”. The commits selected are now added to the upstream branch, and you can switch to it and push those changes to your remote repo or continue working.
If Rebase is a chainsaw, lopping off the entire history of a commit tree, Cherry-picking commits is more akin to pruning clippers. Rebase rewrites the history of a commit, but sometimes you want to copy a commit instead. To do this, you cherry-pick the commit, which is done from the Log menu. It is important to note that you cannot select what branch you cherry-pick onto, it will be applied to your current branch, so you should switch to the branch you wish to copy the changes onto before starting.
- Right click the source code’s folder, open the TortoiseGit menu, and select “Show Log”
- Select the branch you wish to cherry-pick from
- Select the commits you want to cherry-pick
- Right click and select “Cherry-Pick selected commits”
- This will open the Rebase menu, but only the selected commits will appear, and the upstream branch is locked to HEAD, which is your current working branch. As with rebasing, you can skip or edit particular commits.
- Press “Continue” and Git will proceed with copying the selected commits onto your active branch, following the same procedure as a rebase.
When pulling from a remote, Git will often throw an error if any tracked files have uncommitted changes, or if any untracked files are present. Sometimes, you’re fine to discard those changes, and can revert and clean. But sometimes, you have code that’s still being developed, and isn’t yet ready for a commit. In that case, you’ll want to use Stash/Save, which saves all changes to tracked files, and optionally untracked files, onto a stack structure.
- Right click the folder your source code is in and open the tortoisegit menu.
- Select Stash Save
- Enter a label for this entry. If you plan on reusing code within it, it’s usually a good idea to indicate what branch the code belongs to and what function it serves.
- (Optional) Tick “include untracked,” to stash untracked files as well as tracked ones.
- Click Ok and it will automatically save all changes to a stack structure.
Stash/Save creates a stack of all saves. It’s most useful when pulling from a remote, because you can stash everything, pull, then pop the changes back off. Popping saves off the stack is just as easy as saving them to it:
- Right click the source code’s folder and open the tortoisegit menu
- Select “Stash Pop” instead of “Stash Save”. TortoiseGit will then automatically pop the latest save onto the working tree.
If any conflicts occur, tortoisegit will optionally open the Diff menu, from which you can easily resolve conflicts.
Popping the latest save is plenty useful, but sometimes you’ll want to stash/save changes so you can switch projects. It’s possible that by the time you come back to your current project, you’ll have stash/saved more changes in a similar manner, and the work for the project you want to get back to is buried somewhere in the stack. This is where the label becomes important, as tortoisegit also includes a “Stash List” menu, where you can view and manage all the saves you’ve pushed onto the stack.
- Right click the source code’s folder and open the tortoisegit menu
- Select “Stash List”
- The Action column shows which branch it was originally stash/saved onto. The Message column shows what message you included. The Date column shows when it was stash/saved.
- Right-click on the save you want to manipulate.
Most of the options are more appropriate to use on commits, but the two important ones here are “Delete Ref…”, which allows you to delete the save from the stack, and “Stash Apply”, which functions exactly like Stash Pop, except that it isn’t limited to the top of the stack. “Delete Ref…” will give a confirmation message, and like Git Revert and Git Clean, are permanent. “Stash Apply” will operate automatically, much like Stash Pop.