import { addBanner, addArticle, addTitle, addHeader, addParagraph, addClassParagraph, addSubHeader } from '/scripts/article.js'; import { addInset, addInsetList, addInsetCodeListing, addInsetBulletList } from '/scripts/inset.js'; import { addImageWithCaption, addButtonGroup } from '/scripts/visuals.js'; import { addSidebar } from '/scripts/sidebar.js'; import { addSyntax } from '/scripts/code.js'; const heading = document.querySelector(".heading"); const global = document.querySelector(".global_menu"); const local = document.querySelector(".local_menu"); const sidebar = document.querySelector(".sidebar"); const main = document.querySelector(".main_content"); heading.append(addTitle("Programming Fundamentals: Version Control with Git")); heading.append(addParagraph("Christina Truong - LinkedIn Learning")); heading.append(addParagraph("Chapter 3 - Git and Graphical Suser Interfaces")); main.append(addSubHeader("Using GUIs")); main.append(addParagraph("A GUI may seem like it's a better or easier option for working with Git and it probably is the case. Unless you are short of space, there certainly isn't any real reason not to install one, but there are a couple of things which may lead you to decide that you don't need one. For one thing, you can do anything with a command line that you can do with a GUI and more. In addition, once you learn how to use the command line, the difference between using different hosting services is relatively small compared to using different GUI's. That being said, bear in mind the fact that there are different command line options which all use the same git commands, but will have different commands for tasks such as creating directories, navigating around and so on. For that reason, you may well decide to stick to a single command line option and a Linux shell is a good choice for that, in my opinion unless you are already familar with a Windows Command prompty and don't want to learn a different shell.")); main.append(addParagraph("This applies if you are a Windows 10 user as well, because you can use a Linux Shell in Windows, I believe this is true from Windows 10 onwards so it should apply if you upgrade to Windows 11. You need to enable the Windows Subsytem for Linux (search for Programs in the task bar, and then click the link for Add Programs or Features, scroll down to Windows Subsystem for Linux and select) and install the Linux Shell, I think Ubuntu is the only option and you can get it from the Windows store. If you are using a Mac, you already have access to a Linux shell so you won't need to do this. The advantage is that you can use the same shell on a Windows system or a Linux/Mac system which means you only need to learn how to use one shell.")); main.append(addParagraph("The other reason you might not want to use a GUI specifically designed for Git is that you may just not need to. You may already be using a GUI that integrates with Git, I guess most modern development GUIs do nowadays. Examples of GUIs that you might be using that integrate with Git include Dreamweaver, Visual Code and Android Studio. There is a learning overhead here in that you may need to learn exactly how it integrates with Git, but that's probably going to be true of a Git GUI anyway.")); main.append(addParagraph("If you want to make a properly informed decision on which option is the best, you would probably want to try that option so I guess the best advice is to try a variety of options and decide what works best for you. On the other hand, if you already have an option that you can use and are comfortable with, there is no harm in sticking with it but bear in mind the fact that you may be missing out on a better option if you don't try diffrent options.")); main.append(addSubHeader("nstall GUI")); main.append(addParagraph("The GUI we are looking at in this course is SourceTree which you can download from sourcetreeapp.com. The actual process of installing it is pretty much standard. When installing it, you can connect it to your BitBucket account. You can also add thhe BitBucket account, or an account for another Git hosting service after installation. You can also set your global name and email address here which we did earlier with the git config command so you can leave them blank here unless you want to change the values.")); main.append(addParagraph("When you run the app for the first time, if you didn't connect the app to your BitBucket account, you will be asked again if you want to do that but, at this point, you will be able to select a different hosting service so that will give you the opportunity to connect TreeSource to your git hosting account, whatever hosting service you use.")); main.append(addParagraph("To do that, you will click on the gear icon, select Accounts and then Add. The default option is BitBucket but you can click the drop down arrow to select a different service. You will be asked to specify SSH or HTTPS as a connect method and assuming you haven't set up an SSH key, you will select the HTTPS option. Finally, click Connect Account.")); main.append(addParagraph("If you are connecting to a BitBucket account, you will be taken back to the browser for authorisation. Click Open Sourcetree. In the Source Tree Accounts dialog there is a username field which is initially empty, but when the account is connected, it will display your BitBucket username.")); main.append(addParagraph("Once SourceTree is connected to an account on BitBucket or whatever hosting service you are using, we can call up a list of respositories. If we click on Remote, we should see the list of remote repos and we can clone them from here if needed (in this case, all of the remote repos should already have been cloned to the local machine so that won't be necessary). We can aslo click on local to see a list of local repositories but this list will be empty, initially, because the local repos are not added automatically.")); main.append(addParagraph("There are several ways we can add local repos. We can select the New drop down menu and then Add Existing Local Repository. We can also add them by simply dragging a folder over to the local list and dropping it in. If you have a folder that contains a number of repos, we can have Source Tree scan that directory and add any respositories that it finds there. Our repos should all be in the git-projects folder and if we scan that directory, we should then see a list of repositories similar to the list of remote repos. The most significant difference would be that it also includes project-a, which was created as a local repo only so, unless you later added it to the remote repos, you won't see it in that remote list. I also added a repo that isn't in this folder as part of the earlier challenge so this wouldn't be added when I scan the git-projects folder.")); main.append(addParagraph("If we click the gear icon and then Accounts, we can see the author details we added with the git config command under the general tab. If the option to Allow Sourcetree to modify your global Mercurial and Git configuration files is selected, we would be able to change those details here.")); main.append(addParagraph("There are a lot of other options here but most of them are outside the scope of this course. However, with out basic config set, that's enough to allow us to work with SourceTree and we can revisit the configuration later if we need to.")); main.append(addSubHeader("Working with a Respository")); main.append(addParagraph("In SourceTree, it's easy to move from one local repo to another simply by selecting it in the local list. We can also create a new respository, either locally or remotely by selecting the New drop down menu. We have already seen a couple of these options, Add Existing Local Repository and Scan Directory. There is also an option to Clone from URL and this is what we were doing when we used the git clone command earlier. If you select this option, as well as providing the URL of the remote repo, you will also be asked to provide the Destination Path, in other words, the directory you want to clone the remote repo to. You can type the path to that directory in the box or you can click the breadcrumbs to open a File Open dialog box and navigate to it. When we used the got clone command from the command line, it clones the repo to the directory you are in, the current directory, so there was no need to provide a path for it.")); main.append(addParagraph("The name of the repo defaults to the name of the remote repo. This is the name of the repo as it is displayed in SourceTree so you can change it if you want to.")); main.append(addParagraph("There are also options to Create Remote Repository and Create Local Repository so you can create a remote repo directly from TreeSource, you don't need to sign in to BitBucket first.")); main.append(addParagraph("When you select the Create Local Repository, you are asked to provide the destination path and again, you can navigate to the folder using the File Box. You can also type the path in manually but as far as I am aware, SourceTree won't automatically create the directory for you so if you need to create it, using the File Box is the best option. For example, we can use it to navigate to the git-projects and we will create a local repo called project-c. Since this folder doesn't exist yet, we can click the New Folder to create it. Another option we have when creating a local repo in this way is that we can select an option to create the remote repo at the same time. You have the option of giving the remote repo a different name from the local repo, but it is generally better to keep them the same. Of course, creating both the local and remote repos simultaneously also connects them so you can immediately start pushing and pulling between them.")); main.append(addParagraph("It may also be worth pointing out, in case it isn't obvious, but the repos we create here are really just repos created in a different way. We have used SourceTree as a tool to allow us to carry out the tasks that we previously performed from the command line, so we can easily switch between the two. For example, we could open a command line, navigate to the project-c directory, and then work in that directory as if the repo had been created from the command line. Similarly, if we want to work in BitBucket, we will see that the project-c repo is there too and we can work with it as if it had been created in BitBucket. The only proviso to this is that this interchangeability is one way so if you, for instance, create a repo at the command line, it won't automatically appear in TreeSource. You would still have to add it as we added the repos from the git-projects folder earlier.")); main.append(addSubHeader("")); main.append(addParagraph("If we make some changes in a project, this will be shown as a notification in SourceTree showing the number of files that have been changed. We can double click on the project and this will bring up the changes for us. We can also inspect the individual files to see exactly what changes have been made. This view of the file highlights lines in red (for deleted lines) and green (for new lines).")); main.append(addParagraph("The list of files in this view may also be displayed with a question mark for amended files or a minus sign for deleted files.")); main.append(addParagraph("There are some options to configure this view. For example, we can select the grey down menu at the top of the file list and select Tree view which will show you the files in the context of the directory structure rather than as flat list of files. Another useful option is Split view staging which will split the file list, showing files which have been staged in the top list and unstaged files in the working directory in the bottom list. You check the box labelled Unstaged files to move them all to the staging area or you can select files to be staged individually.")); main.append(addParagraph("Deselecting the files in the Staged files list will move them back to the Unstaged files list. To get a better idea of how this works, let's say that we have deleted a file (so it displays a minus sign in the Unstaged files list). If we leave this in the Staged files list and then push these changes to the remote repo, the file is then gone from the project. If we want to add it back in, it would have to be undeleted (this would probably be a matter of restoring it from the recycle bin on Windows). If the file can't be retrieved, you may have to recreate it.")); main.append(addParagraph("If we decide, when looking at the list of files in SourceTree, that we want to keep the file, we can either send it back to the Unstaged files list or just not move it to the Staged files list. However, it is important to remember that doing this will not undelete the file, it simply means that we are not syncing the change in the remote repo. If the file is in the Unstaged files list, we can click the breadcrumbs next to the filename which provides us with several options including Discard file and Remove file. The Discard file option is the one we are interested in here but I mention the Remove file option because it really sounds like the same thing so I'm not sure what the difference is.")); main.append(addParagraph("In any case, selecting Discard file will undelete the file. You may want to read that again! It does sound counter-intuitive to select Discard file in order to undelete it, but what you're doing is discarding the change. Since the change in the file is to delete, you are discarding the, you might say, Delete action or reversing. Hence, the result is that the file is undeleted. It will then be removed from the list of files in SourceTree since it is no longer a change and so does not appear in the lists of staged or unstaged files.")); main.append(addParagraph("In most cases, perhaps all, you will want to send all your changes to the remote repo so you should get to the point where all of the files have been moved from the unstaged to the staged list. We can now add a commit message to the box at the bottom. There is also a button that can be clicked to Push changes immediately to origin/master which can be selected and then we can press commit. Remember that the git commit command we used at the command line only commits the changes to the local repo. We need an additional git push command to sync the changes to the remote repo so we can think of this in the same way. The commit button commits the changes to the local repo so this is the equivalent of the git commit command. Selecting the option to Push changes immediately to origin/master is equivalent to also running the git push command. There is also a button to pull or push the changes so if you don't check the option when committing the files, you can push to the remote repo later. You can also use the pull command to add any changes from the remote repo into your local repo. In addition, you can also fetch files from the remote repo by clicking the fetch button.")); main.append(addParagraph("You might think, understandably, that pull and fetch are essentially the same thing but in git, they are different commands. Whereas pull will get files from the repo including any changed files and integrate these will your local repo, fetch only gets the files. It doesn't make any changes to the local repo so you can use it to download the files if you just want to check them out before deciding whether to integrate the changes into your local repo with a pull command.")); main.append(addSubHeader("What is Git Branching")); main.append(addParagraph("A branch is essentially a fork of the code although it is not intended to lead into a new line of development. If it were, you would most likely fork it off in to an entirely new repo. The idea is that you can develop code separately from the main branch so if you are adding some experimental code, for instance, you can create a new branch and add the code there without affecting the main branch so if the experimental code causes problems, it hasn't caused these in the main branch making it easier to discare the code.")); main.append(addParagraph("The most likely reasons for creating a new branch would be to add a new feature or to debug the code so these are referred to as feature or debug branches respectively. Git doesn't make any technical distinction between these branches so you can work on any branch as if it were the main branch. If you complete a feature or a fix on one of these branches, you can then merge the branch back into the main or master branch.")); main.append(addParagraph("Large teams and/or large projects can have a lot of branches, but even if you are working on code yourself, it can be beneficial to have different branches in your project. For example, I sometimes decide to make changes to my website nad this can be a small change like trying a different font or it can be a major change like changing the layout for most of the pages. In the past, my approach has been to copy the website or take what I could from it and create a new set of pages that I could experiment with and then, if I like the changes, I would replace the old site with the new one and actually, this is a very rudimentary form of branching. It works well enough and I can't say whether using different branches in Git would be a more or less efficient option. Since it is a personal project and my primary goal is learning web development, this inclines me to think that Git is the better option simply because it provides me with experience in working with Git which may be benficial in the future. It also allows me to make a more informed decision on whether Git is a better option and will help me make a similar decision on future projects.")); main.append(addParagraph("Having said that, I don't make significant changes to my site too often so while I will certainly use Git, I'm not too sure yet about whether I will use different branches. However, I may decide to create some additional branches simply for the learning experience.")); main.append(addParagraph("A good example of this may also help to clarify the benefits of developing with different branches. As an example, let's take a look at my page covering the Hungarian alphabet. This has changed quite a bit over time as I experiment with different colour schemes, font-sizes and so on. If I create a new branch, and remember we are working with Git which is a distributed VCS, so a new branch would (I assume) be a complete copy of the site, I can then develop the two in parallel before deciding which is the better design. This would allow me to go further with the development since I could develop it over time and then just merge that branch back in to the main branch if I like the new design or delete if I don't.")); main.append(addParagraph("Again, I could have done this by simpy designing two copies of the site in parallet but I think that, as an example, this helps me to understand the process and the motivation for working with Git a little better so I think it was worth exploring it.")); main.append(addSubHeader("Working with Branches")); main.append(addParagraph("Creating a new branch is really easy bot in TreeSource and directly in BitBucket. You simply click on branches from within the project, provide a descriptive name. There are two commiy options, you can either select the working copy parent which is essentially just the latest copy of the project, or you can branch from a specific commit. In other words, you can select a different point in the version history to create the branch from. I would imagine that it would be very rare to do that, but one example of where you might would be if, for instance, you have made some changes that take your project in a particular direction and you decide to experiment to see how things would have worked if you took it in a different direction. You may very well find that it is easier to do that if you branch off from a point in the project before these projects were made so that you can more accurately compare the two versions.")); main.append(addParagraph("There is also an option, checked by default to Checkout new branch so if you select that option, your local repo will sync with the new branch. I guess that in the majority of cases, this would not make any difference because the new branch should be identical to the old branch at this point. I'm not sure if this means that byt default, any updates will be passed to this new branch (so in essence, the local repo is connected to the new branch in the remote repo), but you can specify the branch that you push changes to with a push command.")); main.append(addParagraph("In SourceTree, under branches we can see the different branches listed, this may be a little clearer now there is a second branch, and we can switch between them. We can also call up a context menu by right-clicking on the branch name and selecting Checkout to check out that branch. You will want to ensure you have the correct branch checked out before you make a change to the file.")); main.append(addParagraph("As a matter of interest, I have tried to do this manually without SourceTree. It is interesting to note that the course covered both the Command Line and GUIs, but branches are only covered under GUIs. Creating a branch without SourceTree is easy enough because you can do that in BitBucket. You can also do it from the command line with a git branch command like this")); main.append(addSyntax("git branch branch_name")); main.append(addParagraph("Switching to a different branch is easy enough as well and we can do that with a git checkout command like this")); main.append(addSyntax("git checkout branch_name")); main.append(addParagraph("You can find more information on working with branches in the command line on the Geek Stuff website.")); main.append(addParagraph("For the purpose of this exercies, I had created a branch for my website project which I called redesign-alphabet-page. I made sure that I had committed and push all the relevant changes to the remote repo first and then I checked out this new branch. Actually, this is something I need to be careful with because when I checked out the new branch, I got a notification in Dreamweaver telling me that my open files had been modified outside of Dreamweaver. I guess this is becaise I made a few changes to the files after I had created my new branch so checking out the new branch is effectively reverting to a slightly earlier version of these. To be safe, it's probably best not to be editing the files when you are creating a new branch like this. In my case, of course, I am writing this page whilst doing exactly that but it shouldn't really be a problem as long as I don't ask Dreamweaver to reload the files because I can just save these again and those changes will become future updates on the new branch.")); main.append(addParagraph("I will now add the files in the project and commit them and then push them back to the remote repo. Once that is done, I can go back to BitBucket and see that the changes I have made now to this page have been uploaded to the remote repo on the new branch. Here, we can click on Commits in the left hand menu and we will see the latest commit there and this is shown in the image below.")); main.append(addImageWithCaption("./images/bit_bucket12.png", "The list of commits in BitBucket showing the latest commit to the new branch")); main.append(addParagraph("Notice that on the most recent commit we have this branch symbol and the name of the branch after the commit message so that tells us that the commit was made to the right branch. This is listing the commits on all branches. If we select just the master branch, we won't see the most recent commit since it wasn't made on the master branch. If we switch to the new branch, we would normally expect to see all the commits there. In my case, the last update on the master branch was made after I had created the new branch so I don't see that commit under the new branch. Remember, the new branch was created after the first two commits, actually, you can see this in graphical form to the left of the list of commits wjere we see a green dot mext to the first two commits. If we trace the branch diagram upwards, we can see that it splits after the second commit and we have an orange dot which is on the branch that split away (actually, that's the master branch so it's really the branch we split away from) but it is not on the other branch. This branch terminates after the third commit indicating that no further commits have been added to that branch. However, we can see that there is a dot on the other branch next to the fourth commit. Notice that on the course video, when Christina lists all of the branches in BitBucket, she only sees one branch line with the last commit showing her new branch name. This is because she has five commits compared to my four. Her first four commits were made on the master branch and she then created the new branch and made an additional commit to the new branch so when she lists commits for the master branch only, she sees the four commits on a sinngle branch line. When she looks as the the branch she named theme-updates, she can see all of the commits from the master branch with the new commit added on to the end. She doesn't have tis situation where each branch has a commit that the other doesn't have so she doesn't see a divergence in her branch lines.")); main.append(addParagraph("I guess that in a real life project, you must expect to have different branches having different commits like this, but it does illustrate a danger in working with these branches in that you should probably make sure your branch is up to date before you create a new branch from it otherwise you may get the branches confused. The nature of my project means that since I am updating this page, for example, on the new branch I am kind of stuck with it since if I were to delete the new branch without merging updates back to the main branch, I will lose the latest updates to this page, perhaps to others as well. It's perhaps worth pointing out that with the new branch, we don't have a new directory so we are updating the same files regardless of which branch we are working on. This seems like a source of problems to me. For example, if you have different branches with different updates, merging these back together could possibly mean losing some of your edits but I will worry about that when we come to look into merging branches next. The most important thing for me to remember is that this current branch contains all of the latest updates to my site and the master branch does not.")); main.append(addParagraph("This might seem like a strange thing to say given that we have already seen that the master branch had a commit that isn't in the redesign-alphabet-page. Bit remember that this was because I had made changes to this file after creating the new branch which I then saved and added to the master branch. Those changes were, in a sense, added to the new branch as soon as I saved the files again, they're just not committed to the remote repo until I did the first commit and push on the new branch. So the changes are in both branches, it's just that they are included in differnet commits. As soon as I committed files to the new branch, it then became the only branch that has all of the latest updates.")); main.append(addParagraph("Hoever, it's also important to understand that this divergence was accidental but we can sometimes legitimately have different branches that each contain different commits so the visual aid in BitBucket could be really useful. You can easily switch between the branches in BitBucket if you need to check the differences between the two branches. Just remember to commit any changes before you do switch branches.")); main.append(addSubHeader("Merging Branches")); main.append(addParagraph("If you are using multiple branches, you will probably have one called main or master which is the designated as the central repo. That's where the code that is to become part of the final product is stored and it is normally that branch that you will want to merge other branches in to.")); main.append(addParagraph("For exampl, let's say that we have a branch called main and a second branch called feature. We have completed the changes in the feature branch and we want to merge it back in to the main branch. The first step is to ensure that you have checked out the feature branch. If you are using SourceTree, you will see a black outline next to the branch that you currently have checekd out so if this is not next to the feature branch, you should check that out. You also should ensure that all changes have been committed before you go ahead. You can then click on the Merge icon. You should then select the commit to highlight it, this indicates which commit to merge with the main branch.")); main.append(addParagraph("There are also several options at the bottom of the screen. The first, Commit merge immediately (if no conflicts) if selected means that assuming that there are no conflicts in the code, so SourceTree will just go ahead and merge the code into the main branch. The second, Include messages from commits being merged in merge commit is fairly self-explanatory and it is recommended that you select it so that the messages you created for the commits in the feature branch will be retained. The third, Create a commit even if merge resolved via fast-forward should also be selected although its function is not explained in the course. The fourth option should not be selected and again, it is not covered in this course.")); main.append(addParagraph("So you want to select the first three options and click ok. If we look at the commit history, we will see that there was a branch in the code, a new commit was made on that branch and then the branch linked back into the main branch creating another commit. I imagine that in practice, there may also have been subsequent commits on the main branch so this could be a bit more complicated!")); main.append(addParagraph("These changes are happening in the local repo so and we can see this in SourceTree where the main branch is shown as being two steps ahead. We would also see something similar at the command line if we executed a git status command at this point. To push these up to the remote repo we can press the push button and decide whether we want to push the main branch only or the feature branch. In most cases, you would only push the main branch because the feature branch is now finished with. The changes made in the code have been added to the main branch.")); main.append(addParagraph("In ButBucket, we can now see the full commit hostory there including the commit that was made on the feature branch merged back to the main branch.")); main.append(addParagraph("If the feature branch is bo longer needed, we can delete it by right-clicking on it in SourceTree and selecting Delete. We can then select the Force delete option which will delete the branch regardless of its status with respect to merge or push. In other words, it would delete the branch even if it hasn't been merged with the main branch or whether it has umcommitted changes. In our example, the branch has been merged and there are no outstanding changes so it would make no difference whether this is selected or not so we will leave it unselected. You should really only select Force delete if you want to delete a branch without merging it with main. An option we probably do want to select is Delete remote branch so that the branch is deleted both from the local repo and from the remote repo.")); main.append(addParagraph("This type of workflow should be sufficient for small projects or for a single developer, but you can learn more about advanced branching workflows or using branches from the command line from the Atlassian tutorial Comparing Workflows which is one of a number of tutorials available on atlassian.com")); main.append(addSubHeader("Challenge: Putting it all Together")); main.append(addParagraph("In this example, we are creating a new branch, making some changes on it, committing it and then merging it back to the main branch and deleting the new branch. I've already done most of this with the redesign-alphabet-page branch. Making changes is not really required since I have changed this page, for example, since the branch was created so all I need to do now is commit any changes, merge the two branches and delete the redesign-alphabet-page branch. Before I start, git status looks like this.")); main.append(addInsetCodeListing(["H:\Documents\website>git status", "On branch redesign-alphabet-page", "Your branch is up to date with 'origin/redesign-alphabet-page'.", "", "Changes not staged for commit:", " (use \"git add <file>...\" to update what will be committed)", " (use \"git restore <file>...\" to discard changes in working directory)", " modified: webdevelopment/versioncontrolwithgit/guis.html", "Untracked files:", " use \"git add <file>...\" to include in what will be committed)", " webdevelopment/versioncontrolwithgit/images/bit_bucket12.png", "", "no changes added to commit (use \"git add\" and/or \"git commit -a\")"])); main.append(addParagraph("So we can see that we are on the redesign-alphabet-page branch, not very well named since I didn't even amend the alphabet page on this branch, and we can also see that there are no changes staged for commit. I will save this file, then commit the changes and complete the merge. When it is done, I will run the git-status command again to show that we are back on the main branch.")); main.append(addParagraph("It actually proved to be a bit trickier to merge both branches because there was a conflict which I guess is because the master branch had a commit that wasn't on the redesign-alphabet-page branch. The process for merging from the command line seems to be to check out the destination branch first (that is, the master branch).")); main.append(addSyntax("git checkout master")); main.append(addParagraph("You can then merge the redesign-alphabet-page branch into the master with")); main.append(addSyntax("git merge redesign-alphabet-page")); main.append(addParagraph("The image shown below is from BitBucket and it shows how the new branch was created before being merged back in to the master branch.")); main.append(addImageWithCaption("./images/bit_bucket14.png", "The branches in BitBucket showing the commits on each and the merging")); main.append(addParagraph("I guess an important lesson from this is that you need to be careful about what is in each of your branches. Finally, the command to delete the redesign-alphabet-page is")); main.append(addSyntax("git branch -d redesign-alphabet-page")); main.append(addParagraph("I am now going to commit all of the latest changes and push them to the remote repo so that I know that it is up to date with the files currently in Dreamweaver and then I will rerun the git status command so that when I insert the output of that command in to this page, it will then become the first change for the next commit and it should show no unstaged changes.")); main.append(addInsetCodeListing(["H:\Documents\website>git status", "On branch master", "Your branch is up to date with 'origin/master'.", "", "nothing to commit, working tree clean"])); main.append(addParagraph("So that looks pretty clean although this branch will start to show at least one modified file as soon as I save this file. The important thing is that we now have just one branch and it is up to date.")); addSidebar("programming");