Class: Tetra::Git
- Inherits:
-
Object
- Object
- Tetra::Git
- Includes:
- Logging, ProcessRunner
- Defined in:
- lib/tetra/facades/git.rb
Overview
facade to git, currently implemented with calls to the git command
Instance Method Summary collapse
-
#archive(directory, id, destination_path) ⇒ Object
archives version id of directory in destination_path.
-
#changed_files(directory, id) ⇒ Object
returns the list of files changed from since_id including changes in the working tree and staging area.
-
#commit_directories(directories, message) ⇒ Object
adds all files in the specified directories, removes all files not in the specified directories, commits with message.
-
#commit_file(path, message) ⇒ Object
commits one single file.
-
#disable_special_files(path) ⇒ Object
renames git special files to 'disable' them.
-
#format_patch(directory, from_id, destination_path) ⇒ Object
generates patch files to changes to directory in destination_path since from_id.
-
#init ⇒ Object
inits a repo.
-
#initialize(directory) ⇒ Git
constructor
inits a new git manager object pointing to the specified directory.
-
#latest_comment(comment_prefix) ⇒ Object
returns the comment of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist.
-
#latest_id(comment_prefix) ⇒ Object
returns the id of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist.
-
#merge_with_id(path, new_path, id) ⇒ Object
3-way merges the git file at path with the one in new_path assuming they have a common ancestor at the specified id returns the conflict count.
-
#revert_directories(directories, id) ⇒ Object
reverts multiple directories' contents as per specified id.
-
#undo_last_commit ⇒ Object
reverts the whole repo to the last commit while leaving changes in the working directory.
Methods included from ProcessRunner
Methods included from Logging
Constructor Details
#initialize(directory) ⇒ Git
inits a new git manager object pointing to the specified directory
13 14 15 |
# File 'lib/tetra/facades/git.rb', line 13 def initialize(directory) @directory = directory end |
Instance Method Details
#archive(directory, id, destination_path) ⇒ Object
archives version id of directory in destination_path
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/tetra/facades/git.rb', line 157 def archive(directory, id, destination_path) Dir.chdir(@directory) do FileUtils.mkdir_p(File.dirname(destination_path)) log.debug "archiving #{directory} from #{id} to #{destination_path}" # This streams stdout from git directly to stdin of xz without loading # data into Ruby memory (which could be big). git_command = ["git", "archive", "--format=tar", id, "--", directory] xz_command = ["xz", "-6", "-T0"] statuses = Open3.pipeline(git_command, xz_command, out: destination_path) unless statuses.all?(&:success?) raise ExecutionFailed.new( "git archive pipeline failed (exit codes: #{statuses.map(&:exitstatus)})", statuses.last.exitstatus ) end end destination_path end |
#changed_files(directory, id) ⇒ Object
returns the list of files changed from since_id including changes in the working tree and staging area
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/tetra/facades/git.rb', line 142 def changed_files(directory, id) Dir.chdir(@directory) do tracked_files = [] begin tracked_files += git_cmd("diff-index", "--name-only", id, "--", directory).split rescue ExecutionFailed => e raise e if e.status != 1 end untracked_files = git_cmd("ls-files", "--exclude-standard", "--others", "--", directory).split tracked_files + untracked_files end end |
#commit_directories(directories, message) ⇒ Object
adds all files in the specified directories, removes all files not in the specified directories, commits with message
49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/tetra/facades/git.rb', line 49 def commit_directories(directories, ) log.debug "committing with message: #{}" Dir.chdir(@directory) do if directories.any? git_cmd("rm", "-r", "--cached", "--ignore-unmatch", *directories) git_cmd("add", *directories) end git_cmd_with_stdin(, "commit", "--allow-empty", "-F", "-") end end |
#commit_file(path, message) ⇒ Object
commits one single file
62 63 64 65 66 67 68 |
# File 'lib/tetra/facades/git.rb', line 62 def commit_file(path, ) Dir.chdir(@directory) do log.debug "committing path #{path} with message: #{}" git_cmd("add", path) git_cmd_with_stdin(, "commit", "--allow-empty", "-F", "-") end end |
#disable_special_files(path) ⇒ Object
renames git special files to 'disable' them
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/tetra/facades/git.rb', line 99 def disable_special_files(path) Dir.chdir(File.join(@directory, path)) do # We look for .git directories or .gitignore files recursively Dir.glob("**/.git*", File::FNM_DOTMATCH).each do |file| next unless file.match?(/\.git(ignore)?$/) FileUtils.mv(file, "#{file}_disabled_by_tetra") end end end |
#format_patch(directory, from_id, destination_path) ⇒ Object
generates patch files to changes to directory in destination_path since from_id
182 183 184 185 186 |
# File 'lib/tetra/facades/git.rb', line 182 def format_patch(directory, from_id, destination_path) Dir.chdir(@directory) do git_cmd("format-patch", "-o", destination_path, "--no-numbered", from_id, "--", directory).split end end |
#init ⇒ Object
inits a repo
18 19 20 21 22 23 24 |
# File 'lib/tetra/facades/git.rb', line 18 def init Dir.chdir(@directory) do raise GitAlreadyInitedError if Dir.exist?(".git") git_cmd("init") end end |
#latest_comment(comment_prefix) ⇒ Object
returns the comment of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist
39 40 41 42 43 44 |
# File 'lib/tetra/facades/git.rb', line 39 def latest_comment(comment_prefix) Dir.chdir(@directory) do id = latest_id(comment_prefix) git_cmd("log", "-1", "--format=%B", id) if id end end |
#latest_id(comment_prefix) ⇒ Object
returns the id of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist
29 30 31 32 33 34 |
# File 'lib/tetra/facades/git.rb', line 29 def latest_id(comment_prefix) Dir.chdir(@directory) do result = git_cmd("rev-list", "--max-count=1", "--grep", comment_prefix, "--fixed-strings", "HEAD") result.strip unless result.empty? end end |
#merge_with_id(path, new_path, id) ⇒ Object
3-way merges the git file at path with the one in new_path assuming they have a common ancestor at the specified id returns the conflict count
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/tetra/facades/git.rb', line 113 def merge_with_id(path, new_path, id) Dir.chdir(@directory) do content = git_cmd("show", "#{id}:#{path}") # Write the old version file manually using Ruby temp_old_version = "#{path}.old_version" File.write(temp_old_version, content) conflict_count = 0 begin git_cmd("merge-file", path, temp_old_version, new_path, "-L", "newly generated", "-L", "previously generated", "-L", "user edited") rescue ExecutionFailed => e raise e unless e.status.positive? conflict_count = e.status ensure # Clean up the temporary file FileUtils.rm_f(temp_old_version) end conflict_count end end |
#revert_directories(directories, id) ⇒ Object
reverts multiple directories' contents as per specified id
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/tetra/facades/git.rb', line 71 def revert_directories(directories, id) Dir.chdir(@directory) do directories.each do |directory| git_cmd("checkout", "-f", id, "--", directory) # Returns list of files relative to current dir files_in_commit = git_cmd("ls-tree", "--name-only", "-r", id, "--", directory).split("\n") files_in_head = git_cmd("ls-tree", "--name-only", "-r", "HEAD", "--", directory).split("\n") files_added = git_cmd("ls-files", "-o", "--", directory).split("\n") files_to_delete = (files_in_head - files_in_commit) + files_added files_to_delete.each do |file| FileUtils.rm_rf(file) end end end end |
#undo_last_commit ⇒ Object
reverts the whole repo to the last commit while leaving changes in the working directory
92 93 94 95 96 |
# File 'lib/tetra/facades/git.rb', line 92 def undo_last_commit Dir.chdir(@directory) do git_cmd("reset", "HEAD~") end end |