62

I was wondering if anyone has used GitHub as a version control system, when writing a large document via TeXstudio or Texmaker?

RStudio for example has a plugin that allows R projects to be pushed and pulled from the GitHub repository, making it very easy to manage committed changes, and committing them to the actual repo.

Is there a way to achieve this easily with a LaTeX document 'project'?

0

7 Answers 7

41

You can run custom commands in Texmaker (User -> User Commands) as well as TeXstudio (Configure -> Build -> User Commands). With that it should be possible to call Git command line tools from within the editor. Moreover in TeXstudio, you can combine this with scripting and triggers, which allows you to automatically trigger these actions e.g. on file save.

If you tell me which git commands you need, I could provide example code.

Edit:

Below is an example for TeXstudio, in which the commands are called via scripting. Create the scripts at User Macros -> Edit Macros.... Since I'm not into git, I don't know if the actual git calls are correct, however it should illustrate the idea.

Pull:

Git pull command

A simple plain call to an external program. On first execution of the script TXS will ask you if you trust the script to execute external programs.

Push:

Git push command

This a bit more fancy. First, the script asks the user for a commit comment. Second, the trigger ?save-file means that the script is called everytime you save a file.

Of course, you can further extend the scripts according to your needs.

10
  • Thanks, just the standard push / pull and commit functionality.. May 5, 2013 at 12:23
  • I am getting an error being thrown: Not a git repository (or any of the parent directories): .git, but I have set up a .git repository, and can push and pull from command line. May 6, 2013 at 16:03
  • Probably need to set the working directory somehow May 6, 2013 at 16:30
  • There is currently no official way to set the working dir. However, you can try to hack around this: A second argument to runCommand is interpreted as main file of the project and its path is used as working dir. So you can try runCommand("git pull", "d:\\yourpath\\dummy.tex"). - Afaik dummy.tex doesn't even have to exist, but I'm not sure about this. May 7, 2013 at 17:24
  • did the trick with: buildManager.runCommand("git push origin master", editor.fileName()) May 7, 2013 at 19:51
13

There is an available script on TeXstudio_wiki for commit and push. It shows a drop menu for the user to select action of two; "commit" or "Commit with Push". You can run it manually or using a trigger like ?save-file or ?close-file

Here is the script

%SCRIPT
choisedialog = UniversalInputDialog(["Commit","Commit with Push"],"Git","choiseGIT")
choisedialog.setWindowTitle("Git")
choise = choisedialog.get("comment")
if (choisedialog.exec() != null) {
    if (choisedialog.get("choiseGIT") == "Commit") {
        dialog = new UniversalInputDialog()
        dialog.setWindowTitle("Git commit / push")
        dialog.add("Committed by TeXstudio", "Comment", "comment")
        dialog.add(true, "Commit all Files","allfiles")
            if (dialog.exec() != null) {
                comment = dialog.get("comment")
                if ((dialog.get("allfiles")) == true){
                    buildManager.runCommand("git commit -a -m \"" + comment + "\"", editor.fileName())
                }else{
                    buildManager.runCommand("git commit " + editor.fileName() + " -m \"" + comment + "\"", editor.fileName())
                }
    }
} else
    if (choisedialog.get("choiseGIT") == "Commit with Push") {
        dialog = new UniversalInputDialog()
        dialog.setWindowTitle("Git commit / push")
        dialog.add("Committed by TeXstudio", "Comment", "comment")
        dialog.add("master", "Branch", "branch")
        dialog.add(true, "Commit all Files","allfiles")
            if (dialog.exec() != null) {
                comment = dialog.get("comment")
                branch = dialog.get("branch")
                    if ((dialog.get("allfiles")) == true){
                buildManager.runCommand("git commit -a -m \"" + comment + "\"", editor.fileName())
                }else{
                buildManager.runCommand("git commit " + editor.fileName() + " -m \"" + comment + "\"", editor.fileName())
                }
                buildManager.runCommand("git push origin \"" + branch +"\"", editor.fileName())
            }
   }
}
6

In case you just need to commit from TeXstudio and are willing to do all things more complicate with a terminal or some other external tool, here a quick hack to get git into TeXstudio (basically by disguising it as svn):

1) In the preferences change the SVN command to you local git:

enter image description here

2) In your $HOME/.gitconfig set the following alias

[alias]
    ci = commit

3) Now you can happily commit with Check in... from the TeXstudio menu

enter image description here

This will execute the command

 /usr/local/git/bin/git ci -m "my commit message" "/pathtofile..."

4) To access this either assign a keyboard shortcut, add it to the menu bar or got to file->svn->check in...

enter image description here

7
  • where is the commit menu?
    – skan
    Nov 28, 2016 at 13:06
  • @skan see the edit, is this what you are looking for? Nov 28, 2016 at 13:11
  • I had tried that but when I use svn update I get the error "git: 'up' is not a git command." and other commands don't seem to do anything. I've already configured texstudio's option command -> svn -> git. Maybe I need to define some git alias?
    – skan
    Nov 28, 2016 at 13:14
  • @skan As written in the first line of my answer this is "just need to commit", no other functionalities. Nov 28, 2016 at 13:17
  • OK, but if you commit is because you could want to fetch/pull that commits.
    – skan
    Nov 28, 2016 at 13:19
4

Complementing the other answers, I changed their macros in order to (i) show the output of Git commands at the message panel of TeXstudio by using > txs:///messages; (ii) call xterm1 for the Git commands that need input, such as a password; and (iii) use the great tool Git LaTeXdiff to generate PDF diffs of the last pulled revision and the previous one, or the last pulled revision and the working directory.

1. xterm seems to be available on most Linux-based operating systems. See https://stackoverflow.com/a/1105033/2448553

Git pull:

%SCRIPT
buildManager.runCommand("xterm -e \"git pull; read -n1\"", editor.fileName())

Diff pulled as PDF (requires Git LaTeXdiff):

%SCRIPT
fileNameWithPath = editor.fileName()
fileName = fileNameWithPath.substring(fileNameWithPath.lastIndexOf("/") + 1)
buildManager.runCommand("git latexdiff --main " + fileName + " -b --ignore-latex-errors --latexopt \"-shell-escape\" HEAD~1 > txs:///messages", editor.fileName())

Diff working file as PDF (requires Git LaTeXdiff):

%SCRIPT
fileNameWithPath = editor.fileName()
fileName = fileNameWithPath.substring(fileNameWithPath.lastIndexOf("/") + 1)
buildManager.runCommand("git latexdiff --main " + fileName + " -b --ignore-latex-errors --latexopt \"-shell-escape\" HEAD -- > txs:///messages", editor.fileName())

Git commit added:

%SCRIPT
dialog = new UniversalInputDialog()
dialog.setWindowTitle("Git commit")
dialog.add("-m \"Committed within TeXstudio\"", "Comment: -m \"line0\" -m \"line1\" ...", "comment")
if (dialog.exec() != null) {
    comment = dialog.get("comment")
    buildManager.runCommand("git commit " + editor.fileName() + " " + comment + " > txs:///messages", editor.fileName())
}

Git commit all tracked:

%SCRIPT
dialog = new UniversalInputDialog()
dialog.setWindowTitle("Git commit all")
dialog.add("-m \"Committed within TeXstudio\"", "Comment: -m \"line0\" -m \"line1\" ...", "comment")
if (dialog.exec() != null) {
    comment = dialog.get("comment")
    buildManager.runCommand("git commit -a " + comment + " > txs:///messages", editor.fileName())
}

Git push:

%SCRIPT
buildManager.runCommand("xterm -e \"git push origin master; read -n1\"", editor.fileName())

Git status:

%SCRIPT
buildManager.runCommand("git status > txs:///messages", editor.fileName())

Git diff:

%SCRIPT
buildManager.runCommand("git diff HEAD > txs:///messages", editor.fileName())
6
  • 1
    @kassem and alessander-botti-benevides. These scripts work great for committing tracked files with single line comments. How do I do multi-line comments? Typing \n in the text field did not work.
    – Harsh
    Nov 25, 2017 at 18:11
  • 1
    @Harsh, can you please try the solution explained here ? It would work in case you want a predefined number of lines in your comments. Nov 25, 2017 at 18:23
  • @Harsh, I just changed the answer with a more general solution. Can you confirm that it works? Nov 25, 2017 at 19:14
  • Yes, it works perfectly. edit [I was about to mention the space, but it seems you fixed it on your own.] :)
    – Harsh
    Nov 25, 2017 at 19:58
  • This solution you mentioned allows multiple paragraphs but not exactly single linebreaks. But at least its better than a one-line comment and should be good enough for most cases. Thanks a lot.
    – Harsh
    Nov 25, 2017 at 20:14
0

It happened to me that the scripts here failed when doing the push because I have no username or password. Just in case somebody had the same problem, here is the solution:

git config --global credential.helper cache

And then making a push with git, it will ask you for a username and password and after that it will save the data into your pc so you never have to put them again.

More info: https://help.github.com/articles/caching-your-github-password-in-git/

0

The other answers already show how to pull, diff, commit, push, commit and push and what not.
Here I present a script to initialise an already existing TeX 'project' folder as a git repo.
This script will init git, configure name/email and optionally setup remote. After running this script with any file in your project open, you can start to commit to your project.

Git Init

%SCRIPT
buildManager.runCommand("git init" , editor.fileName())

namedialog = new UniversalInputDialog()
namedialog.setWindowTitle("Author Details")
namedialog.add("A U Thor", "Author Name: ", "name")
if (namedialog.exec() != null) {
    name  = namedialog.get("name")
    namestr  = " \""+name+"\" "
    buildManager.runCommand("git config user.name " + namestr + " > txs:///messages", editor.fileName())
}

emaildialog = new UniversalInputDialog()
emaildialog.setWindowTitle("Author Details")
emaildialog.add("author", "Email:", "emailid")
emaildialog.add("example.com", "@", "domain")
if (emaildialog.exec() != null) {
    emailid  = emaildialog.get("emailid") 
    domain   = emaildialog.get("domain")
    email = emailid + "@@" + domain
    emailstr = " \""+email+"\" "
    buildManager.runCommand("git config user.email " + emailstr + " > txs:///messages", editor.fileName())
}

remotedialog = new UniversalInputDialog()
remotedialog.setWindowTitle("Setup Remote")
remotedialog.add(false, "Set remote now?","remotechoice")
remotedialog.add("https://github.com/USERNAME/REPOSITORY.git", "Remote Git URL: (ex https://github.com/USERNAME/REPOSITORY.git)", "remotegiturl")
if (remotedialog.exec() != null) {
    if ((remotedialog.get("remotechoice")) == true){
        remotegiturl = remotedialog.get("remotegiturl")
        buildManager.runCommand("git remote add --track master origin " + remotegiturl + " > txs:///messages", editor.fileName())
    }
}

Take a look at this answer if you are not sure where to put the above code.

0

Having tried Tim Hoffman's and Kassem's solutions, I found that the code isn't working entirely as intended:

  1. The macro will not commit and upload in one run when I tested it. I believe this issue is related to Tim Hoffmann's answer to another post. Essentially buildManager.runCommand() will not wait for the previous command to finish before executing the next.
  2. Committing to a selected branch will only work if you're already on this branch, Therefore switching to the chosen branch is necessary before committing (git checkout "branch").
  3. It will not commit any new files to the chosen repository. This won't work because any new files haven't been added to the local repository yet. To do this git add . or similar needs to be called.

Anyway, according to Tim Hoffmann's recommendation I modified the code, substituting buildManager.runCommand() with the system()-function. This way execution of following commands can be halted until the previous finish executing. I also added lines for swithcing branch and adding new files, and also inserting current date and time. Here's my solution:

%SCRIPT
//Current time
var today = new Date();
    var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    var monthname = months[today.getMonth()];
    var date = today.getDate() + " " + monthname + " " + today.getFullYear();
    var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds() + " CET";
    var dateTime = date+' '+time;

//New pop-up menu for adding comments and switching branches
dialog = new UniversalInputDialog()
    dialog.setWindowTitle("Git commit and push")
    dialog.add(dateTime, "Comment", "comment")
    dialog.add("master", "Branch", "branch")
    if (dialog.exec() != null) {

        //Getting path to working directory
        filename = editor.fileName();
        var path = filename.substring(0, filename.lastIndexOf("/"));

        //Switching to the selected branch
        var branch = dialog.get("branch")
        var chbranch = system("git checkout  \"" + branch, workingDirectory = path)
            chbranch.waitForFinished()

        //Adding new files to repository
        var gitadd = system("git add .", workingDirectory = path)
            gitadd.waitForFinished()

        //Committing to the selected repository
        var comment = dialog.get("comment")
        var gitcommit = system("git commit -a -m \"" + comment + "\"", workingDirectory = path)
            gitcommit.waitForFinished()

        //Pushing to remote repository
        system("git push origin \"" + branch +"\"", workingDirectory = path)
    }

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .