
    	D,jY              	       N   d dl Z d dlZd dlZd dlmZmZ 	 d dlZej        j        ej        j	        ej        j
        ej        j        gZn# e$ r dZg ZY nw xY wd dlZd dlmZmZ ddlmZ ddlmZ eeeeeeeeegz  Z ee          Ze j        d             Z G d d	          Z dS )
    N)PathPurePosixPath)promptsutils   )dump)WaitingSpinnerc              #      K   |t           j        | <   	 dV  ||t           j        | <   dS | t           j        v rt           j        | = dS dS # ||t           j        | <   n| t           j        v rt           j        | = w xY w)z+Temporarily set a Git environment variable.N)osenviron)var_namevalueoriginal_values      Y/home/rurouni/.local/share/uv/tools/aider-chat/lib/python3.11/site-packages/aider/repo.pyset_git_envr   '   s       !BJx%%#1BJx   ##
8$$$ $# %#1BJx  ##
8$$$$$s   A	 	/A8c                       e Zd ZdZdZdZdZdZdZi Z	dZ
	 	 	 	 	 	 	 	 	 	 ddZddZd ZddZdd	Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd ZddZd ZddZddZdS )GitRepoNr   FTc                    || _         || _        i | _        i | _        || _        || _        || _        |	| _        || _        |
| _	        || _
        || _        i | _        |r|g}n|r|}ndg}g }|D ]}t          |          }|                                }|                                s |j                                        r|j        }	 t#          j        |d          j        }t)          j        |          }|                    |           # t.          $ r Y w xY wt1          t3          |                    }|dk    rt4          |dk    r!| j                             d           t4          t#          j        |                                t"          j                  | _        t)          j        | j        j                  | _         |rt          |          | _!        d S d S )N.T)search_parent_directoriesr   r   z!Files are in different git repos.)odbt)"iomodelsnormalized_path
tree_filesattribute_authorattribute_committerattribute_commit_message_author"attribute_commit_message_committerattribute_co_authored_bycommit_promptsubtree_onlygit_commit_verifyignore_file_cacher   resolveexistsparentgitRepoworking_dirr   safe_abs_pathappendANY_GIT_ERRORlensetFileNotFoundError
tool_errorpopGitDBrepoworking_tree_dirrootaider_ignore_file)selfr   fnames	git_dnamer7   r   r   r   r   r   r!   r"   r#   r    check_fnames
repo_pathsfname	repo_path	num_reposs                      r   __init__zGitRepo.__init__>   s     ! 0#6 /N,2T/(@%*(!2!# 	!%;LL 	!!LL5L
! 	 	EKKEMMOOE<<>> %el&9&9&;&; %HUdKKKW	!/	::	!!),,,,     J((	>>##q==GBCCC## HZ^^--CI>>>	'	(BCC	 	=%)*;%<%<D"""	= 	=s   AD
DDc                     |s j                                         sdS                      |          }|sdS |r|}n8d}|r|j        }|s|                                }                     |||          }|rMt          |d          r=|j        j        }	|j        j	        }
|j        j
        }|j        j        }|j        j        }n# j        }	 j	        }
 j
        } j        } j        }|	du}|
du}|	dn|	}|
dn|
}|o|p|}d}|r4|r2d}|r(t          |d          r|j        j        r|j        j        }d| d}|o|o| p|}|o|o| p|}|sd	}|rd
|z   }||z   }d|g} j        s|                    d           |rt fd|D             }|D ]Y}	  j         j                            |           ## t&          $ r*} j                            d| d|            Y d}~Rd}~ww xY w|dg|z   z  }n|dgz  } j         j                            dd          }t.          j                            d          }t.          j                            d          }| d}	 t5          j                    5 }|r$|                    t;          d||                     |r$|                    t;          d||                      j         j                            |                                d          }  j                             d|  d| d           | |fcddd           S # 1 swxY w Y   dS # t&          $ r(} j                            d|            Y d}~dS d}~ww xY w)a  
        Commit the specified files or all dirty files if none are specified.

        Args:
            fnames (list, optional): List of filenames to commit. Defaults to None (commit all
                                     dirty files).
            context (str, optional): Context for generating commit message. Defaults to None.
            message (str, optional): Explicit commit message. Defaults to None (generate message).
            aider_edits (bool, optional): Whether the changes were made by Aider. Defaults to False.
                                          This affects attribution logic.
            coder (Coder, optional): The Coder instance, used for config and model info.
                                     Defaults to None.

        Returns:
            tuple(str, str) or None: The commit hash and commit message if successful,
                                     else None.

        Attribution Logic:
        ------------------
        This method handles Git commit attribution based on configuration flags and whether
        Aider generated the changes (`aider_edits`).

        Key Concepts:
        - Author: The person who originally wrote the code changes.
        - Committer: The person who last applied the commit to the repository.
        - aider_edits=True: Changes were generated by Aider (LLM).
        - aider_edits=False: Commit is user-driven (e.g., /commit manually staged changes).
        - Explicit Setting: A flag (--attribute-...) is set to True or False
          via command line or config file.
        - Implicit Default: A flag is not explicitly set, defaulting to None in args, which is
          interpreted as True unless overridden by other logic.

        Flags:
        - --attribute-author: Modify Author name to "User Name (aider)".
        - --attribute-committer: Modify Committer name to "User Name (aider)".
        - --attribute-co-authored-by: Add
          "Co-authored-by: aider (<model>) <aider@aider.chat>" trailer to commit message.

        Behavior Summary:

        1. When aider_edits = True (AI Changes):
           - If --attribute-co-authored-by=True:
             - Co-authored-by trailer IS ADDED.
             - Author/Committer names are NOT modified by default (co-authored-by takes precedence).
             - EXCEPTION: If --attribute-author/--attribute-committer is EXPLICITLY True, the
               respective name IS modified (explicit overrides precedence).
           - If --attribute-co-authored-by=False:
             - Co-authored-by trailer is NOT added.
             - Author/Committer names ARE modified by default (implicit True).
             - EXCEPTION: If --attribute-author/--attribute-committer is EXPLICITLY False,
               the respective name is NOT modified.

        2. When aider_edits = False (User Changes):
           - --attribute-co-authored-by is IGNORED (trailer never added).
           - Author name is NEVER modified (--attribute-author ignored).
           - Committer name IS modified by default (implicit True, as Aider runs `git commit`).
           - EXCEPTION: If --attribute-committer is EXPLICITLY False, the name is NOT modified.

        Resulting Scenarios:
        - Standard AI edit (defaults): Co-authored-by=False -> Author=You(aider),
          Committer=You(aider)
        - AI edit with Co-authored-by (default): Co-authored-by=True -> Author=You,
          Committer=You, Trailer added
        - AI edit with Co-authored-by + Explicit Author: Co-authored-by=True,
          --attribute-author -> Author=You(aider), Committer=You, Trailer added
        - User commit (defaults): aider_edits=False -> Author=You, Committer=You(aider)
        - User commit with explicit no-committer: aider_edits=False,
          --no-attribute-committer -> Author=You, Committer=You
        NargsT zunknown-model
main_modelz

Co-authored-by: aider (z) <aider@aider.chat>z(no commit message provided)zaider: z-mz--no-verifyc                 T    g | ]$}t                              |                    %S  )strabs_root_path).0fnr8   s     r   
<listcomp>z"GitRepo.commit.<locals>.<listcomp>  s/    CCCbc$,,R0011CCC    zUnable to add z: --z-az--getz	user.nameGIT_COMMITTER_NAMEGIT_AUTHOR_NAMEz (aider))shortzCommit  )boldzUnable to commit: )!r4   is_dirty	get_diffscommit_languageget_user_languageget_commit_messagehasattrrB   r   r   r   r   r    rD   namer#   r,   r(   addr-   r   r1   configr   r   get
contextlib	ExitStackenter_contextr   commitget_head_commit_shatool_output)!r8   r9   contextmessageaider_editscoderdiffscommit_messageuser_languager   r   r   r   r    author_explicitcommitter_expliciteffective_authoreffective_committerprefix_commit_messagecommit_message_trailer
model_nameuse_attribute_authoruse_attribute_committerfull_commit_messagecmdr=   erroriginal_user_nameoriginal_committer_name_envoriginal_author_name_envcommitter_namestackcommit_hashs!   `                                r   r`   zGitRepo.commit   s   L  	di0022 	Fv&& 	F 	T$NN M > % 5$ >$)$;$;$=$=M!44UG]SSN  	EWUF++ 	E$z:"'*"@.3j.X+161^.',z'J$$  $4"&":.2.R+151X.'+'D$ +$60< $4#;44AQ&9&AddGZ !, !
+Q/Q 	
 "$ 	d3 	d(J 355 3%:J:O 3"-2
%c:%c%c%c" b,b6N2N2aRa 	 #6 #
9!9:P>P 	   	<;N  	8&7N,/EE()% 	&JJ}%%% 		CCCCFCCCF H HHIM%%e,,,,$ H H HG&&'F'F'F'F'FGGGGGGGGHD6F?"CCD6MC!Y]11';GG&(jnn5I&J&J##%:>>2C#D#D .888	;%'' 35* ''#0.B]   
 ( ''#$5~G_``  
 	$$S)))"66T6BB##$Lk$L$LN$L$LSW#XXX"N2!3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3$  	; 	; 	;G9C99:::::::::	;sU   F00
G$: GG$L/ .B'L"L/ "L&&L/ )L&*L/ /
M!9MM!c                     	 t           j                            | j        j        t          j                              S # t          t          f$ r | j        j        cY S w xY wN)r   pathrelpathr4   git_dirgetcwd
ValueErrorOSErrorr8   s    r   get_rel_repo_dirzGitRepo.get_rel_repo_dir@  sY    	%7??49#4bikkBBBG$ 	% 	% 	%9$$$$	%s   := AAc                 ,   d|z   }d}|r||dz   z  }||z  }| j         pt          j        }d}|rd| d}|                    |          }d }| j        D ]}d|j         }	t          |	          5  |j        r|j        dz   |z   }
n|}
t          d|
	          t          d
|	          g}|	                    |          }|j
                            d          pd}|r||k    r	 d d d            |                    |          }|r	 d d d             n	 d d d            n# 1 swxY w Y   |s| j                            d           d S |                                }|r4|d         dk    r(|d         dk    r|dd                                         }|S )Nz	# Diffs:
rC   
z
- Is written in r   )language_instructionzGenerating commit message with system)rolecontentusermax_input_tokensr   z"Failed to generate commit message!"r   )r!   r   commit_systemformatr   rY   r	   system_prompt_prefixdicttoken_countinfor\   simple_send_with_retriesr   r1   strip)r8   rg   rc   ri   r   system_contentr   rh   modelspinner_textcurrent_system_contentmessages
num_tokens
max_tokenss                 r   rW   zGitRepo.get_commit_messageF  s   u$ 	&w~%G5+Dw/D! 	I#H#H#H#H '..DX.YY[ 	 	EIUZIIL--  - <-2-G$-NQ_-_**-;* h0FGGGfg666
 #..x88
"Z^^,>??D1
 *z"9"9      " "'!?!?!I!I! '       $%              *  	GCDDDF'--// 	:nQ/366>";MQT;T;T+AbD17799Ns   .A4D .D  D$	'D$	c                 >   d}	 | j         j        }	 | j                             |          }t          |          }n# t          $ r Y nw xY wn# t
          ft          z   $ r Y nw xY w|sg }d}|D ] }|                     |          s	|d| dz  }!	 |rNddgt          |          z   }| | j         j        j	        |ddi
                    | j        j        d          z  }|S dgt          |          z   }d	g|z   }	| | j         j        j	        |	ddi
                    | j        j        d          z  }| | j         j        j	        |ddi
                    | j        j        d          z  }|S # t          $ r(}
| j                            d
|
            Y d }
~
d S d }
~
ww xY w)NFrC   zAdded r   HEADrM   stdout_as_stringreplace--cachedzUnable to diff: )r4   active_branchiter_commitsanyr-   	TypeErrorpath_in_repolistr(   diffdecoder   encodingr1   )r8   r9   current_branch_has_commitsr   commitsrg   r=   rB   wd_args
index_argsru   s              r   rT   zGitRepo.get_diffsw  s0    &+"	 I3M)00??-0\\**    |m+ 	 	 	D	  	F 	, 	,E$$U++ ,+%++++	9) ~V4++TJEJJQQG$i   ftF||+G$/J'TY]'LeLLSS )  E 'TY]'I5IIPP )  E L 	9 	9 	9G7#77888888888	9sQ   A ); A 
AA AA A"!A"AE* B
E* *
F4FFc                     g }|r|dgz  }n|dgz  }|||gz  } | j         j        j        |ddi                    | j        j        d          }|S )Nz--colorz--color=neverr   Fr   )r4   r(   r   r   r   r   )r8   prettyfrom_commit	to_commitrB   rg   s         r   diff_commitszGitRepo.diff_commits  su     	&YKDD_%%Di(("	"DA5AAHHGi
 
 rL   c                      j         sg S 	  j         j        j        }nd# t          $ r d }Y nVt          $ rJ}| _         j                            d|             j                            d           g cY d }~S d }~ww xY wt                      }|r+| j
        v r j
        |         }n	 |j                                        }d }	 	 t          |          }|j        dk    r|                    |j                   n5# t"          $ r  j                            d           Y ]t&          $ r Y nw xY wlnW# t          $ rJ}| _         j                            d|             j                            d           g cY d }~S d }~ww xY wt           fd|D                       }t          |           j
        |<    j         j        }	 d |j                                        D             }|                     fd|D                        n4# t          $ r'} j                            d	|            Y d }~nd }~ww xY w fd
|D             }|S )Nz"Unable to list files in git repo: zIs your git repo corrupted?TblobzIGitRepo: Index error encountered while reading git tree object. Skipping.c              3   B   K   | ]}                     |          V  d S r}   normalize_pathrI   r~   r8   s     r   	<genexpr>z,GitRepo.get_tracked_files.<locals>.<genexpr>  s1      HH$D//55HHHHHHrL   c                     g | ]\  }}|S rF   rF   )rI   r~   _s      r   rK   z-GitRepo.get_tracked_files.<locals>.<listcomp>  s    EEEWT1DEEErL   c              3   B   K   | ]}                     |          V  d S r}   r   r   s     r   r   z,GitRepo.get_tracked_files.<locals>.<genexpr>  s1      LLt,,T22LLLLLLrL   zUnable to read staged files: c                 >    g | ]}                     |          |S rF   )ignored_file)rI   r=   r8   s     r   rK   z-GitRepo.get_tracked_files.<locals>.<listcomp>  s,    HHHt/@/@/G/GHuHHHrL   )r4   headr`   r   r-   git_repo_errorr   r1   rb   r/   r   treetraversenexttyperZ   r~   
IndexErrortool_warningStopIterationindexentrieskeysupdate)	r8   r`   ru   filesiteratorr   r   staged_filesress	   `        r   get_tracked_fileszGitRepo.get_tracked_files  s   y 	I	Y^*FF 	 	 	FFF 	 	 	"%DGICIIJJJG =>>>IIIIII		  	5((/%{3355HD""#'>>D#yF22 %		$) 4 4 4) % % % !G00!-   %H, " " "!E"" "$   *-D'G&&'QC'Q'QRRRG''(EFFFIIIIII	
 HHHH%HHHHH*-e**' 		FEE0B0B0D0DEEELLLLLLL|LLLLLLL 	F 	F 	FGDsDDEEEEEEEE	F IHHH%HHH
s    A?	A??A:4A?:A?,D5 	4C> =D5 >$D0"D5 $	D0-D5 /D00D5 5
F	??F>F	F	AH 
IH<<Ic           	         |}| j                             |          }|r|S t          t          t	          t          | j                  |z                      | j                                                }|| j         |<   |S r}   )r   r\   rG   r   r   r6   relative_to)r8   r~   	orig_pathr   s       r   r   zGitRepo.normalize_path  sv    	"&&y11 	J4tDI'=&J&J49&U&UVVWWXX*.Y'rL   c                    | j         sd S t          j                    }|| j        z
  dk     rd S || _        | j                                         sd S | j                                         j        }|| j        k    ro|| _        i | _        | j                                         	                                }t          j                            t          j        j        |          | _        d S d S )Nr   )r7   timeaider_ignore_last_checkis_filestatst_mtimeaider_ignore_tsr$   	read_text
splitlinespathspecPathSpec
from_linespatternsGitWildMatchPatternaider_ignore_spec)r8   current_timemtimeliness       r   refresh_aider_ignorezGitRepo.refresh_aider_ignore  s    % 	Fy{{$66::F'3$%--// 	F&++--6D(((#(D %'D"*4466AACCE%-%6%A%A!5& &D"""	 )(rL   c                 t    | j         sd S 	 | j                             |          rdS d S # t          $ r Y dS w xY wNTF)r4   ignoredr-   r8   r~   s     r   git_ignored_filezGitRepo.git_ignored_file  s_    y 	F	y  && t  	 	 	55	s   ) 
77c                     |                                   || j        v r| j        |         S |                     |          }|| j        |<   |S r}   )r   r$   ignored_file_raw)r8   r=   results      r   r   zGitRepo.ignored_file  sU    !!###D***)%00&&u--(.u%rL   c                    | j         r	 t          |                     |                    }t          j                                                                        t          | j                                                            }n# t          $ r Y dS w xY w||j        vr||k    rdS | j	        r| j	        
                                sdS 	 |                     |          }n# t          $ r Y dS w xY w| j                            |          S r   )r"   r   r   cwdr%   r   r6   r   parentsr7   r   r   
match_file)r8   r=   
fname_pathcwd_paths       r   r   zGitRepo.ignored_file_raw  s&    	!$"5"5e"<"<==
8::--//;;DOO<S<S<U<UVV   
 tt z111jH6L6Lt% 	T-C-K-K-M-M 	5	''..EE 	 	 	44	 %00777s$   A>B 
BBC# #
C10C1c                     | j         sd S |sd S t          |                                           }|                     |          |v S r}   )r4   r/   r   r   )r8   r~   tracked_filess      r   r   zGitRepo.path_in_repo7  sP    y 	F 	FD224455""4((M99rL   c                 X    t          | j                  |z  }t          j        |          S r}   )r   r6   r   r+   )r8   r~   r   s      r   rH   zGitRepo.abs_root_path@  s%    49oo$"3'''rL   c                 V   t                      }| j        j                            dd                                          }|                    |           | j        j                            d                                          }|                    |           t          |          S )z
        Returns a list of all files which are dirty (not committed), either staged or in the working
        directory.
        z--name-onlyr   )r/   r4   r(   r   r   r   r   )r8   dirty_filesr   unstaged_filess       r   get_dirty_fileszGitRepo.get_dirty_filesD  s    
 ee y}))-DDOOQQ<((( ++M::EEGG>***K   rL   c                 j    |r|                      |          sdS | j                            |          S )NT)r~   )r   r4   rS   r   s     r   rS   zGitRepo.is_dirtyU  s=     	))$// 	4y!!t!,,,rL   c                 Z    	 | j         j        j        S # t          ft          z   $ r Y d S w xY wr}   )r4   r   r`   r   r-   r   s    r   get_head_commitzGitRepo.get_head_commit[  s=    	9>((}}, 	 	 	44	s    **c                 b    |                                  }|sd S |r|j        d d         S |j        S )N   )r  hexsha)r8   rP   r`   s      r   ra   zGitRepo.get_head_commit_shaa  sA    %%'' 	F 	%=!$$}rL   c                 @    |                                  }|s|S |j        S r}   )r  rd   )r8   defaultr`   s      r   get_head_commit_messagezGitRepo.get_head_commit_messagei  s(    %%'' 	N~rL   )
NNTTFFNFTF)NNNFNr}   )F)__name__
__module____qualname__r4   r7   r   r   r   r"   r$   r   r@   r`   r   rW   rT   r   r   r   r   r   r   r   r   rH   r   rS   r  ra   r  rF   rL   r   r   r   4   s       DOLN  (-+0!&C= C= C= C=Jz; z; z; z;z% % %/ / / /b*9 *9 *9 *9X  7 7 7r    .    8 8 82: : :( ( (! ! !"- - - -          rL   r   )!r]   r   r   pathlibr   r   r(   excODBErrorGitErrorInvalidGitRepositoryErrorGitCommandNotFoundr-   ImportErrorr   aiderr   r   r   waitingr	   r   r   BufferErrorr   r   AttributeErrorAssertionErrorTimeoutErrortuplecontextmanagerr   r   rF   rL   r   <module>r     sy       				  ' ' ' ' ' ' ' 'JJJ 	)"	MM    
CMMM                        # # # # # # 	 	 m$$ 	% 	% 	%y y y y y y y y y ys   2A	 		AA