2017-03-08 18 views
5

Tôi đang làm việc trên một dự án C++ lớn sử dụng nhiều nhánh Git khác nhau. Chúng tôi đang sử dụng mô hình Git Flow. Điều này có nghĩa là tôi thường xuyên chuyển đổi giữa các nhánh Git. Tôi sử dụng helm-gtags trong Emacs để điều hướng mã. Hiện tại tôi chưa đặt các tệp thẻ GNU Global (GTAGS, GRTAGS, GPATH) trong điều khiển phiên bản Git, chúng chỉ đơn giản là đặt bất kỳ khi nào tôi thay đổi để làm việc trên một nhánh khác. Nhưng điều này có nghĩa là tôi có các biểu tượng trong các tệp thẻ không có trong mã và ngược lại. Tôi có thể cập nhật các tệp thẻ (helm-gtags-update-tags) nhưng điều này không xóa các ký hiệu khỏi các tệp thẻ không có trong mã, nó chỉ thêm hoặc cập nhật các ký hiệu thực sự có trong mã.Sử dụng đúng các tệp thẻ GNU Toàn cầu trong các chi nhánh Git khác nhau

Cách tốt nhất để làm việc với tệp thẻ GNU Global trong mã là phiên bản được kiểm soát bởi Git là gì? Các tệp thẻ có nên được thêm vào Git để chúng cụ thể cho từng chi nhánh không? Hoặc có lẽ tôi nên xóa các tập tin thẻ mỗi khi tôi chuyển nhánh để tạo ra một bộ thẻ mới? Hoặc là có một cách khác?

+0

Tôi đồng ý, hãy tiếp tục và di chuyển. –

+0

Đặt 'global -u' vào .git/hooks/post-checkout. – politza

+0

@politza hiện 'toàn cầu-' đối phó với vấn đề "không loại bỏ các biểu tượng từ các tệp thẻ không có trong mã, nó chỉ thêm hoặc cập nhật các biểu tượng thực sự có trong mã"? Tôi chỉ có thể tưởng tượng rằng 'helm-gtags-update-tags' đang gọi' global -u', vì vậy có vẻ như nó không đủ. Nếu đó là tất cả những gì cần thiết, tuy nhiên, và nó đủ thông minh để nhận thấy tất cả các tập tin thay đổi, sau đó tôi sẽ đồng ý rằng đây rõ ràng là giải pháp đơn giản nhất. – phils

Trả lời

0

Kể từ khi các tập tin thẻ được liên kết với một phiên bản cụ thể của mã này, tôi tin rằng bạn nên kiểm tra chúng trong.

Mặt khác, họ đang tập tin cụ thể cho một phong cách làm việc với các mã này, và vì vậy không thường áp dụng cho dự án, và do đó có thể lập luận rằng nó không nên được kiểm tra. Họ sẽ liên tục thay đổi và thêm nhiều tiếng ồn cho mỗi cam kết. Tiếng ồn mà mọi người khác phải nhìn vào.

Điều tôi muốn đề xuất thay vào đó là xem xét định cấu hình các emacs để nó tự động cập nhật chế độ xem của tệp tự động khi chúng thay đổi. Đây là những gì các biên tập viên hiện đại nhất làm. Here's a technique using inotify. Hoặc, và tôi biết đây là dị giáo, có thể là thời gian cho một biên tập viên mới. Tôi chuyển từ emacs sang Atom năm nay.

0

Cam kết chúng dường như không phải là ý tưởng tốt nhất, và tùy thuộc vào thời gian để toàn cầu reindex toàn bộ dự án của bạn, bạn có thể thấy không mong muốn xây dựng lại toàn bộ cơ sở dữ liệu mỗi khi bạn thay đổi chi nhánh.

Nếu quá trình xây dựng lại hoàn toàn mất quá nhiều thời gian, đây là móc nối post-checkout git mà tôi đã viết để quản lý các tệp không được theo dõi trên cơ sở từng chi nhánh. Đối với mỗi chi nhánh, bạn chỉ cần sao chép các tệp GTAGS, GRTAGS, GPATH của bạn vào thư mục con được đặt tên thích hợp của thư mục .branches được tập lệnh này sử dụng, sau đó tập lệnh sẽ hoán đổi các tệp bất kỳ khi nào bạn thay đổi nhánh.

#!/bin/sh 

# Git hook (post-checkout) to manage *untracked* files on a per-branch basis. 
# Author: Phil S. 
# Version 1.1 
# URL: http://stackoverflow.com/a/42686433 

## Commentary: 
# 
# This hook is very useful when you have development-specific files which 
# you never want to commit to the repository, but which can vary on a 
# branch-by-branch basis. Branch-specific configuration files are a 
# prime use-case (to specify the database to use, for instance). 
# 
# With this hook, those files are automatically copied into the working 
# copy when you checkout the branch they are associated with, and moved 
# back again when you checkout another branch. 
# 
# The hook uses a .branches directory in the root of the repository, 
# so you should add this to your .gitignore file. 
# 
# To start managing files for a branch, simply copy them into a sub- 
# directory (of .branches) named after the branch in question, changing 
# any forward slashes in the branch name into double-underscores. 


## Example: 
# 
# [phil/master] ~/site$ grep .branches .gitignore 
# .branches 
# 
# [phil/master] ~/site$ find .branches/ 
# .branches/ 
# .branches/phil__master 
# .branches/phil__master/sites 
# .branches/phil__master/sites/default 
# .branches/phil__master/sites/default/settings.branch.php 
# .branches/phil__media 
# .branches/phil__media/sites 
# .branches/phil__media/sites/default 
# .branches/phil__media/sites/default/settings.branch.php 
# 
# [phil/master] ~/site$ git checkout phil/media 
# Switched to branch 'phil/media' 
# Removing untracked per-branch files for: phil__master 
# `../.././sites/default/settings.branch.php' -> `./sites/default/settings.branch.php' 
# Adding untracked per-branch files for: phil__media 
# >f+++++++++ sites/default/settings.branch.php 


## Caveat: 
# 
# An early version of this script had issues whenever a git operation checked 
# out a detached HEAD, such that the .branches/.current_branch file contained 
# "HEAD" rather than the branch directory name, and so the intended untracked 
# files were not copied. 
# 
# I never got caught out by this, because my prompt always shows me the 
# .current_branch value (see comments at the end of the hook), so I notice 
# when it says HEAD unexpectedly; however I do not recall this happening at 
# all in the past few years, so I believe it is no longer a concern. 
# 
# If it were to happen to you, simply running git checkout (branch) for the 
# branch you are already on fixes it up. The log file may also help to debug 
# any such issues. 
# 
# n.b. It's feasible that git could update the HEAD ref without performing 
# a checkout (after initially checking out a detached head), but the cases 
# I've observed (and fixed) were associated with rebasing, where this script 
# had (undesirably) permitted its own processing to occur after an initial 
# checkout of a detached HEAD, and had then exited early (as intended when 
# rebasing) after the subsequent checkout of the eventual branch. The solution 
# was to improve the detection of the cases in which we wish to exit early, 
# to cover the former case as well as the latter. 


## Changelog: 
# 
# v1.1: Handle additional text following "rebase" in GIT_REFLOG_ACTION. 
#  Renamed $git_dir to $root (it's the working copy root, not .git) 
#  Log git environment vars even when aborting. 


## General information on Git post-checkout hooks: 
# 
# This hook is invoked when a git checkout is run after having updated 
# the worktree. The hook is given three parameters: the ref of the 
# previous HEAD, the ref of the new HEAD (which may or may not have 
# changed), and a flag indicating whether the checkout was a branch 
# checkout (changing branches, flag=1) or a file checkout (retrieving 
# a file from the index, flag=0). This hook cannot affect the outcome 
# of git checkout. 
# 
# It is also run after git clone, unless the --no-checkout (-n) option 
# is used. The first parameter given to the hook is the null-ref, the 
# second the ref of the new HEAD and the flag is always 1. 
# 
# This hook can be used to perform repository validity checks, 
# auto-display differences from the previous HEAD if different, or set 
# working dir metadata properties. 

############################################################################## 

head_old=$1 
head_new=$2 
flag=$3 

# n.b. pwd will be this working copy's root directory. 
root=$(pwd) 

# Debug log. 
log=".branches/post-checkout.log" 
echo "\n$(date)" >>${log} 2>&1 
if test -f .branches/.current_branch; then 
    echo ".current_branch: $(cat .branches/.current_branch)" >>${log} 2>&1 
else 
    echo ".current_branch (file missing)" >>${log} 2>&1 
fi 
echo "Old: $(git log --max-count=1 --decorate ${head_old} | head -1)" >>${log} 2>&1 
echo "New: $(git log --max-count=1 --decorate ${head_new} | head -1)" >>${log} 2>&1 

# Log the GIT environment variables. This is primarily to assist with finding 
# workarounds for any edge cases that might crop up. (This is how I discovered 
# GIT_REFLOG_ACTION.) 
set | grep GIT >>${log} 2>&1 

# Check the 'flag' parameter ($3). 
if test "$flag" != "1"; then # not a branch switch. 
    echo "$0 aborted (not a branch switch)." 2>&1 | tee -a ${log} 
    echo "Check ${log} for details." 
    exit 0 
fi 

# This hook is also invoked with flag=1 when rebasing, which we never want. 
# We only want to move the untracked files around when we have explictly 
# requested a checkout (which also means that the .current_branch file must 
# only ever be updated at those same times). 
if test "${GIT_REFLOG_ACTION##rebase}" != "${GIT_REFLOG_ACTION}"; then 
    echo "$0 aborted (GIT_REFLOG_ACTION indicated rebase)." 2>&1 | tee -a ${log} 
    echo "Check ${log} for details." 
    exit 0 
elif test -d "$root/.git/rebase-merge"; then 
    echo "$0 aborted (.git/rebase-merge indicated rebase)." 2>&1 | tee -a ${log} 
    echo "Check ${log} for details." 
    exit 0 
fi 

# Determine which .branches directory we were originally using. 
# There is no pre-checkout hook, but we can include a marker file amongst 
# the untracked files identifying the current branch name, and use that to 
# update the versions of the files under .branches from the current versions 
# before copying the new versions. 
cd "$root" 
if test -f .branches/.current_branch; then 
    oldbranch=$(cat .branches/.current_branch) 
    oldbranch_dir=".branches/$oldbranch" 
    if test -d "$oldbranch_dir"; then 
     echo "Removing untracked per-branch files for: $oldbranch" 
     cd "$oldbranch_dir" 
     find . -type f -print0 | xargs -0r -I{} mv -v -f ../../{} {} 
    fi 
fi 

# Establish the name of the newly checked-out branch. 
cd "$root" 
newbranch=$(git symbolic-ref -q HEAD) 
newbranch=${newbranch##refs/heads/} 
newbranch=${newbranch:-HEAD} 
newbranch=$(echo $newbranch | sed 's/\//__/') 
newbranch_dir=".branches/$newbranch" 

# Create/update marker file. 
test -d .branches || mkdir .branches 
echo $newbranch >.branches/.current_branch 
echo ".current_branch: $(cat .branches/.current_branch)" >>${log} 2>&1 

# Copy across the untracked files needed for the new branch. 
echo "Adding untracked per-branch files for: $newbranch" 

if ! test -d "$newbranch_dir"; then 
    echo "$newbranch_dir not found; nothing to update." 
    exit 0 
fi 

cd "$newbranch_dir" 
rsync -r -i . ../../ 

# You can also set a fancy prompt in bash to show you which branch you're in. 
# (Used to be super-useful when rebasing was a problem, but probably still 
# handy just for confirming that things are as they should be.) 
# PS1="${debian_chroot:+($debian_chroot)}\[email protected] [\$(cat /var/www/(site)/.branches/.current_branch | sed 's/__/\//')] \w\$ " 

# Local Variables: 
# outline-regexp: "^##" 
# eval: (outline-minor-mode 1) 
# eval: (while (re-search-forward "^## .+:" nil t) (outline-toggle-children)) 
# End: 

Cá nhân tôi chưa bao giờ thực hiện chuyển đổi từ Ctags đến toàn cầu, và tôi sử dụng một cách tiếp cận khá brute-force cho vấn đề chung của việc giữ TAGS tôi nộp lên cho đến nay, đó là sử dụng một bộ đếm thời gian để chạy một lệnh shell không đồng bộ để xác định xem có bất kỳ tệp nào đã được sửa đổi gần đây hơn TAGS và, nếu có, hãy tạo một tệp TAGS mới. Nếu tệp mới khác với tệp cũ, tôi thay thế tệp cũ và đặt bảng hoàn thành thẻ của Emacs thành 0 để nó sẽ đọc lại tệp TAGS lần sau.

Việc xây dựng lại tệp TAGS là giải pháp của tôi để thực hiện thay đổi mã trong nhánh hiện tại cũng như chuyển sang nhánh khác, vì vậy tôi chưa bao giờ có lý do gì để sử dụng móc sau khi thanh toán của mình cho mục đích này Tôi đã đề xuất ở đây. Tùy thuộc vào thời điểm bộ hẹn giờ kích hoạt, có thể có sự chậm trễ vài phút giữa các thay đổi mã và tệp TAGS đang bắt kịp, do đó, phản hồi tức thì sẽ đẹp hơn.

0

Đây là những gì tôi đã làm cuối cùng. Tôi bắt đầu thêm các tệp thẻ vào git. Nhưng điều này được chứng minh là không hoạt động tốt với phân nhánh và hợp nhất và cuối cùng các tệp thẻ sẽ không chứa tất cả các biểu tượng trong nhánh hiện tại và không có gì hơn nữa. câu trả lời phils đã dẫn tôi đến kiểm tra trên git hooks.Tôi đã xóa các tệp thẻ khỏi phiên bản git và tạo một móc hậu kiểm xuất tự động xóa tất cả các tệp thẻ hiện diện khi thay đổi nhánh. Khi helm-gtags trong Emacs phát hiện ra rằng không có tệp thẻ nào mà nó cung cấp để tạo chúng. Đối với dự án của tôi mà là khá lớn, nó không mất nhiều thời gian. helm-gtags cũng phát hiện khi một tệp đã thay đổi và tự động cập nhật các tệp thẻ chỉ với những thay đổi này. Vì vậy, bây giờ tôi có một hệ thống tự động giữ các tập tin thẻ cập nhật với tất cả các biểu tượng trong nhánh hiện tại. Cho đến nay nó hoạt động tốt.

Các vấn đề liên quan