How to execute git command in a identified path? - python

I want to execute git command in python program.
I have tried
os.system("git-command")
As we know, git command can be executed correctly only in the directories which contains repositories. I have tried to print current path and this path is not what I hope for, it does not contains repositories.
Now my question is how to execute git command in a identified path.

Use the subprocess module; pick one of the functions that suits your needs (based on what output you need). The functions all take a cwd argument that lets you specify the directory to operate in:
import subprocess
output = subprocess.check_output(['git', 'status'], cwd='/path/to/git/workingdir')

Using GitPython:
from git import *
repo = Repo("/path/to/repo")
git = repo.git
print git.status()

Related

Print bash script output in Python

I have a Python code that will run a script file.The script file will output the version tag of specific git repository.
My script file named 'start.sh' is as follows:
#!/bin/sh
git clone https://xxxxxxxxxx:x-oauth-basic#github.com/xxxxxxx/xxxxx.git
cd xxxxxxxx
git config --global user.email "xxxxxxxx"
git config --global user.name "xxxxxxxxx"
IMAGE_TAG=`echo \`git describe --tags\``
echo $IMAGE_TAG
My Python code is as follows:
import os
git_tag = os.popen('sh start.sh')
print(git_tag)
When I run the script file separately, it will return me the git tag. But, Whenever I try to print it in the Python code, it's not working.
How can I solve this issue?
Since you are using Python anyway, you could think of using GitPython as an alternative. You can list all your tags with:
from git import Repo
repo = Repo("path/to/repo")
print(repo.tags)
Try like this
from subprocess import check_output
out = check_output(['sh', 'start.sh'])
print(out)
According to python's documentation, os.popen() function has been deprecated since version 2.6. You might want to use subprocess module.
P.S: I wanted to comment but couldn't hence this answer.
For python3-X:
from subprocess
git_tag = subprocess.run(['sh', 'start.sh'], capture_output=True, text=True)
print(git_tag.stdout)

Execute bash commands that are within a list from python

i got this list
commands = ['cd var','cd www','cd html','sudo rm -r folder']
I'm trying to execute one by one all the elements inside as a bash script, with no success. Do i need a for loop here?
how to achieve that?, thanks all!!!!
for command in commands:
os.system(command)
is one way you could do it ... although just cd'ing into a bunch of directories isnt going to have much impact
NOTE this will run each command in its own subshell ... so they would not remember their state (ie any directory changes or environmental variables)
if you need to run them all in one subshell than you need to chain them together with "&&"
os.system(" && ".join(commands)) # would run all of the commands in a single subshell
as noted in the comments, in general it is preferred to use subprocess module with check_call or one of the other variants. however in this specific instance i personally think that you are in a 6 to 1 half a dozen to the other, and os.system was less typing (and its gonna exist whether you are using python3.7 or python2.5 ... but in general use subprocess exactly which call probably depends on the version of python you are using ... there is a great description in the post linked in the comments by #triplee why you should use subprocess instead)
really you should reformat your commands to simply
commands = ["sudo rm -rf var/www/html/folder"] note that you will probably need to add your python file to your sudoers file
also Im not sure exactly what you are trying to accomplish here ... but i suspect this might not be the ideal way to go about it (although it should work...)
This is just a suggestion, but if your just wanting to change directories and delete folders, you could use os.chdir() and shutil.rmtree():
from os import chdir
from os import getcwd
from shutil import rmtree
directories = ['var','www','html','folder']
print(getcwd())
# current working directory: $PWD
for directory in directories[:-1]:
chdir(directory)
print(getcwd())
# current working directory: $PWD/var/www/html
rmtree(directories[-1])
Which will cd three directories deep into html, and delelte folder. The current working directory changes when you call chdir(), as seen when you call os.getcwd().
declare -a command=("cd var","cd www","cd html","sudo rm -r folder")
## now loop through the above array
for i in "${command[#]}"
do
echo "$i"
# or do whatever with individual element of the array
done
# You can access them using echo "${arr[0]}", "${arr[1]}" also

How to download single file from a git repository using python

I want to download single file from my git repository using python.
Currently I am using gitpython lib. Git clone is working fine with below code but I don't want to download entire directory.
import os
from git import Repo
git_url = 'stack#127.0.1.7:/home2/git/stack.git'
repo_dir = '/root/gitrepo/'
if __name__ == "__main__":
Repo.clone_from(git_url, repo_dir, branch='master', bare=True)
print("OK")
Don't think of a Git repo as a collection of files, but a collection of snapshots. Git doesn't allow you to select what files you download, but allows you to select how many snapshots you download:
git clone stack#127.0.1.7:/home2/git/stack.git
will download all snapshots for all files, while
git clone --depth 1 stack#127.0.1.7:/home2/git/stack.git
will only download the latest snapshot of all files. You will still download all files, but at least leave out all of their history.
Of these files you can simply select the one you want, and delete the rest:
import os
import git
import shutil
import tempfile
# Create temporary dir
t = tempfile.mkdtemp()
# Clone into temporary dir
git.Repo.clone_from('stack#127.0.1.7:/home2/git/stack.git', t, branch='master', depth=1)
# Copy desired file from temporary dir
shutil.move(os.path.join(t, 'setup.py'), '.')
# Remove temporary dir
shutil.rmtree(t)
You can also use subprocess in python:
import subprocess
args = ['git', 'clone', '--depth=1', 'stack#127.0.1.7:/home2/git/stack.git']
res = subprocess.Popen(args, stdout=subprocess.PIPE)
output, _error = res.communicate()
if not _error:
print(output)
else:
print(_error)
However, your main problem remains.
Git does not support downloading parts of the repository. You have to download all of it. But you should be able to do this with GitHub. Reference
You need to request the raw version of the file! You can get it from raw.github.com
I don't want to flag this as a direct duplicate, since it does not fully reflect the scope of this question, but part of what Lucifer said in his answer seems the way to go, according to this SO post. In short, git does not allow for a partial download, but certain providers (like GitHub) do, via raw content.
That being said, Python does provide quite a number of different libraries to download, with the best-known being urllib.request.

How to use the previous command output to use as a part of another command: python

I have been trying to use the output of a system command to use it as a part of the command in the next portion. However, I cannot seem to join it up properly and hence not being able to run the second command properly. The OS used is KALI LINUX and python 2.7
#IMPORTS
import commands, os, subprocess
os.system('mkdir -p ~/Desktop/TOOLS')
checkdir = commands.getoutput('ls ~/Desktop')
if 'TOOLS' in checkdir:
currentwd = subprocess.check_output('pwd', shell=True)
cmd = 'cp -R {}/RAW ~/Desktop/TOOLS/'.format(currentwd)
os.system(cmd)
os.system('cd ~/Desktop/TOOLS')
os.system('pwd')
The errors are:
cp: missing destination file operand after ‘/media/root/ARSENAL’
Try 'cp --help' for more information.
sh: 2: /RAW: not found
/media/root/ARSENAL
It seems that the reading of the first command is alright but it can't join with the RAW portion. I have read many other solutions, but they seem to be for shell scripting instead.
Assuming you haven't called os.chdir() anywhere prior to the cp -R, then you can use a relative path. Changing the code to...
if 'TOOLS' in checkdir:
cmd = 'cp -R RAW ~/Desktop/TOOLS'
os.system(cmd)
...should do the trick.
Note that the line...
os.system('cd ~/Desktop/TOOLS')
...will not do what you expect. os.system() spawns a subshell, so it will just change the working directory for that process and then exit. The calling process's working directory will remain unchanged.
If you want to change the working directory for the calling process, use...
os.chdir(os.path.expanduser('~/Desktop/TOOLS'))
However, Python has all this functionality built-in, so you can do it without spawning any subshells...
import os, shutil
# Specify your path constants once only, so it's easier to change
# them later
SOURCE_PATH = 'RAW'
DEST_PATH = os.path.expanduser('~/Desktop/TOOLS/RAW')
# Recursively copy the files, creating the destination path if necessary.
shutil.copytree(SOURCE_PATH, DEST_PATH)
# Change to the new directory
os.chdir(DEST_PATH)
# Print the current working directory
print os.getcwd()

Git diff call in pre-commit throws "fatal: unable to read [SHA1]"

I am working in windows and attempting to run a git diff command in the pre-commit script (Python) of a repository. My Python call looks like this:
repo_dir = 'D:/git/current_uic/src/gtc/resource'
cmd = ['diff', '--name-only']
print(Popen(['git', '--git-dir={}'.format(repo_dir + '/.git'),
'--work-tree={}'.format(repo_dir)] + cmd,
stdin=PIPE, stdout=PIPE).communicate())
Whenever I go to commit in the "D:/git/current_uic/src/gtc" repo, I get the following:
fatal: unable to read 6ff96bd371691b9e93520e133ebc4d84c74cd0f6
Note that this is a pre-commit hook for the 'D:/git/current_uic/src/gtc' repository and that 'D:/git/current_uic/src/gtc/resource' is a submodule of 'D:/git/current_uic/src/gtc'. Also note that if I pop open Git bash and run the following:
git --git-dir=D:/git/current_uic/src/gtc/resource/.git
--work-tree=D:/git/current_uic/src/gtc/resource diff --name-only
or if I just run the script straight from Git bash I get exactly what I want, regardless of working directory.
Any ideas as to what is going on here?
The Problem:
Upon running a hook, Git sets some environment variables that are accessible by the hook script. The problem is that Git itself uses these environment variables, and the normal way in which Git sets/uses them seems to be overridden by the values set when the hook gets fired off. In this particular instance, the environment variable GIT_INDEX_FILE has been set to the path to the index file corresponding to the repository which had called the hook (D:/git/current_uic/src/.git/modules/gtc/index), causing a mismatch between the (incorrect) index and the (correct) change tree.
The Fix:
In the hook script, set the environment variable GIT_INDEX_FILE to the correct value before making any git calls. In this case, you could do the following:
set GIT_INDEX_FILE=D:/git/current_uic/src/.git/modules/gtc/modules/resource/index
git --git-dir=D:/git/current_uic/src/gtc/resource/.git
--work-tree=D:/git/current_uic/src/gtc/resource diff --name-only
Additional Info
More information about these Git environment variables and which hooks set them can be found here.
Got exactly same issue but using gitpython.
I solved it like this:
repo = git.Repo()
for submodule in repo.submodules:
back_index = os.getenv('GIT_INDEX_FILE')
os.environ['GIT_INDEX_FILE'] = submodule.module().index.path
commit = submodule.module().head.commit
print([item.a_path for item in commit.diff(None)])
os.environ['GIT_INDEX_FILE'] = back_index

Categories